Merge "Use the right openssl header" into main
diff --git a/Android.bp b/Android.bp
index e9390b9..133c182 100644
--- a/Android.bp
+++ b/Android.bp
@@ -97,7 +97,8 @@
name: "cf_cc_defaults",
module_type: "cc_defaults",
config_namespace: "cvdhost",
- bool_variables: ["enforce_mac80211_hwsim", "vhost_user_vsock_by_default"],
+ bool_variables: ["enforce_mac80211_hwsim"],
+ value_variables: ["default_userdata_fs_type"],
properties: ["cflags"],
}
@@ -112,10 +113,12 @@
cflags: [],
}
},
- vhost_user_vsock_by_default: {
- cflags: ["-DVHOST_USER_VSOCK_BY_DEFAULT=true"],
+ // TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE sets this from BoardConfig.mk
+ // The only user is the page agnostic cf target
+ default_userdata_fs_type: {
+ cflags: ["-DUSERDATA_FILE_SYSTEM_TYPE=\"%s\""],
conditions_default: {
- cflags: [],
+ cflags: ["-DUSERDATA_FILE_SYSTEM_TYPE=\"f2fs\""],
}
}
}
diff --git a/Android.mk b/Android.mk
index eca8725..fd9e410 100644
--- a/Android.mk
+++ b/Android.mk
@@ -26,7 +26,6 @@
$(eval $(call declare-copy-files-license-metadata,device/google/cuttlefish,wpa_supplicant_overlay.conf,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,))
$(eval $(call declare-copy-files-license-metadata,device/google/cuttlefish,wpa_supplicant.rc,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,))
$(eval $(call declare-copy-files-license-metadata,device/google/cuttlefish,init.cutf_cvm.rc,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,))
-$(eval $(call declare-copy-files-license-metadata,device/google/cuttlefish,bt_vhci_forwarder.rc,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,))
$(eval $(call declare-copy-files-license-metadata,device/google/cuttlefish,fstab.cf.f2fs.hctr2,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,))
$(eval $(call declare-copy-files-license-metadata,device/google/cuttlefish,fstab.cf.f2fs.cts,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,))
$(eval $(call declare-copy-files-license-metadata,device/google/cuttlefish,fstab.cf.ext4.hctr2,SPDX-license-identifier-Apache-2.0,notice,build/soong/licenses/LICENSE,))
diff --git a/apex/com.google.aosp_cf_phone.rros/Android.bp b/apex/com.google.aosp_cf.rros/Android.bp
similarity index 85%
rename from apex/com.google.aosp_cf_phone.rros/Android.bp
rename to apex/com.google.aosp_cf.rros/Android.bp
index 325e1b3..acb3add 100644
--- a/apex/com.google.aosp_cf_phone.rros/Android.bp
+++ b/apex/com.google.aosp_cf.rros/Android.bp
@@ -17,19 +17,18 @@
}
apex {
- name: "com.google.aosp_cf_phone.rros",
+ name: "com.google.aosp_cf.rros",
manifest: "apex_manifest.json",
key: "com.google.cf.apex.key",
certificate: ":com.google.cf.apex.certificate",
file_contexts: "file_contexts",
- use_vndk_as_stable: true,
updatable: false,
- // Install the apex in /vendor/apex
soc_specific: true,
+
+ // RROs shared across CF-derived devices
rros: [
"cuttlefish_overlay_connectivity",
"cuttlefish_overlay_frameworks_base_core",
"cuttlefish_overlay_settings_provider",
- "cuttlefish_phone_overlay_frameworks_base_core",
],
}
diff --git a/apex/com.google.aosp_cf.rros/apex_manifest.json b/apex/com.google.aosp_cf.rros/apex_manifest.json
new file mode 100644
index 0000000..faf4eef
--- /dev/null
+++ b/apex/com.google.aosp_cf.rros/apex_manifest.json
@@ -0,0 +1,4 @@
+{
+ "name": "com.google.aosp_cf.rros",
+ "version": 1
+}
diff --git a/apex/com.google.aosp_cf_slim.rros/file_contexts b/apex/com.google.aosp_cf.rros/file_contexts
similarity index 100%
rename from apex/com.google.aosp_cf_slim.rros/file_contexts
rename to apex/com.google.aosp_cf.rros/file_contexts
diff --git a/apex/com.google.aosp_cf_phone.rros/apex_manifest.json b/apex/com.google.aosp_cf_phone.rros/apex_manifest.json
deleted file mode 100644
index e5ebe27..0000000
--- a/apex/com.google.aosp_cf_phone.rros/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.google.aosp_cf_phone.rros",
- "version": 1
-}
diff --git a/apex/com.google.aosp_cf_phone.rros/file_contexts b/apex/com.google.aosp_cf_phone.rros/file_contexts
deleted file mode 100644
index cb7fd8d..0000000
--- a/apex/com.google.aosp_cf_phone.rros/file_contexts
+++ /dev/null
@@ -1,2 +0,0 @@
-(/.*)? u:object_r:vendor_file:s0
-/overlay(/.*)? u:object_r:vendor_overlay_file:s0
diff --git a/apex/com.google.aosp_cf_slim.rros/Android.bp b/apex/com.google.aosp_cf_slim.rros/Android.bp
deleted file mode 100644
index 1a98d1c..0000000
--- a/apex/com.google.aosp_cf_slim.rros/Android.bp
+++ /dev/null
@@ -1,38 +0,0 @@
-// Copyright (C) 2022 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.
-
-soong_namespace {
- imports: [
- "device/generic/goldfish",
- ],
-}
-
-package {
- default_applicable_licenses: ["Android-Apache-2.0"],
-}
-
-apex {
- name: "com.google.aosp_cf_slim.rros",
- manifest: "apex_manifest.json",
- key: "com.google.cf.apex.key",
- certificate: ":com.google.cf.apex.certificate",
- file_contexts: "file_contexts",
- use_vndk_as_stable: true,
- updatable: false,
- // Install the apex in /vendor/apex
- soc_specific: true,
- rros: [
- "slim_overlay_frameworks_base_core",
- ],
-}
diff --git a/apex/com.google.aosp_cf_slim.rros/apex_manifest.json b/apex/com.google.aosp_cf_slim.rros/apex_manifest.json
deleted file mode 100644
index 26c7bd5..0000000
--- a/apex/com.google.aosp_cf_slim.rros/apex_manifest.json
+++ /dev/null
@@ -1,4 +0,0 @@
-{
- "name": "com.google.aosp_cf_slim.rros",
- "version": 1
-}
diff --git a/apex/com.google.cf.bt/Android.bp b/apex/com.google.cf.bt/Android.bp
index 8a20aa6..6fa580c 100644
--- a/apex/com.google.cf.bt/Android.bp
+++ b/apex/com.google.cf.bt/Android.bp
@@ -22,29 +22,60 @@
installable: false,
}
+prebuilt_etc {
+ name: "android.hardware.bluetooth-service.default.xml",
+ src: ":manifest_android.hardware.bluetooth-service.default.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "android.hardware.bluetooth.finder-service.default.xml",
+ src: ":manifest_android.hardware.bluetooth.finder-service.default.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "android.hardware.bluetooth.ranging-service.default.xml",
+ src: ":manifest_android.hardware.bluetooth.ranging-service.default.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
+prebuilt_etc {
+ name: "android.hardware.bluetooth.lmp_event-service.default.xml",
+ src: ":manifest_android.hardware.bluetooth.lmp_event-service.default.xml",
+ sub_dir: "vintf",
+ installable: false,
+}
+
apex {
name: "com.google.cf.bt",
manifest: "manifest.json",
file_contexts: "file_contexts",
key: "com.google.cf.apex.key",
certificate: ":com.google.cf.apex.certificate",
- use_vndk_as_stable: true,
updatable: false,
soc_specific: true,
+
binaries: [
"android.hardware.bluetooth-service.default",
"android.hardware.bluetooth.finder-service.default",
"android.hardware.bluetooth.ranging-service.default",
+ "android.hardware.bluetooth.lmp_event-service.default",
"bt_vhci_forwarder",
],
prebuilts: [
+ // permissions
"android.hardware.bluetooth_le.prebuilt.xml",
"android.hardware.bluetooth.prebuilt.xml",
+ // vintf
+ "android.hardware.bluetooth-service.default.xml",
+ "android.hardware.bluetooth.finder-service.default.xml",
+ "android.hardware.bluetooth.ranging-service.default.xml",
+ "android.hardware.bluetooth.lmp_event-service.default.xml",
+ // init rc
"com.google.cf.bt.rc",
],
- vintf_fragments: [
- ":manifest_android.hardware.bluetooth-service.default.xml",
- ":manifest_android.hardware.bluetooth.finder-service.default.xml",
- ":manifest_android.hardware.bluetooth.ranging-service.default.xml",
- ],
}
diff --git a/apex/com.google.cf.bt/com.google.cf.bt.rc b/apex/com.google.cf.bt/com.google.cf.bt.rc
index 183f4aa..9401dda 100644
--- a/apex/com.google.cf.bt/com.google.cf.bt.rc
+++ b/apex/com.google.cf.bt/com.google.cf.bt.rc
@@ -23,3 +23,9 @@
user bluetooth
group bluetooth net_admin net_bt_admin
capabilities NET_ADMIN
+
+service bt_lmp_event /apex/com.google.cf.bt/bin/hw/android.hardware.bluetooth.lmp_event-service.default
+ class hal
+ user bluetooth
+ group bluetooth net_admin net_bt_admin
+ capabilities NET_ADMIN
diff --git a/apex/com.google.cf.bt/file_contexts b/apex/com.google.cf.bt/file_contexts
index b5dd759..a3e9dfb 100644
--- a/apex/com.google.cf.bt/file_contexts
+++ b/apex/com.google.cf.bt/file_contexts
@@ -2,5 +2,6 @@
/bin/hw/android.hardware.bluetooth-service.default u:object_r:hal_bluetooth_btlinux_exec:s0
/bin/hw/android.hardware.bluetooth.finder-service.default u:object_r:hal_bluetooth_btlinux_exec:s0
/bin/hw/android.hardware.bluetooth.ranging-service.default u:object_r:hal_bluetooth_btlinux_exec:s0
+/bin/hw/android.hardware.bluetooth.lmp_event-service.default u:object_r:hal_bluetooth_btlinux_exec:s0
/bin/bt_vhci_forwarder u:object_r:bt_vhci_forwarder_exec:s0
-/etc/permissions(/.*)? u:object_r:vendor_configs_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
diff --git a/apex/com.google.cf.rild/Android.bp b/apex/com.google.cf.rild/Android.bp
index aee3fac..5a256bd 100644
--- a/apex/com.google.cf.rild/Android.bp
+++ b/apex/com.google.cf.rild/Android.bp
@@ -23,8 +23,9 @@
}
prebuilt_etc {
- name: "ld.config.txt",
- src: "ld.config.txt",
+ name: "com.google.cf.rild.xml",
+ src: ":libril-modem-lib-manifests",
+ sub_dir: "vintf",
installable: false,
}
@@ -34,10 +35,9 @@
key: "com.google.cf.apex.key",
certificate: ":com.google.cf.apex.certificate",
file_contexts: "file_contexts",
- use_vndk_as_stable: true,
updatable: false,
- // Install the apex in /vendor/apex
soc_specific: true,
+
binaries: [
"libcuttlefish-rild",
],
@@ -47,11 +47,9 @@
prebuilts: [
"android.hardware.telephony.gsm.prebuilt.xml",
"android.hardware.telephony.ims.prebuilt.xml",
- "android.hardware.telephony.satellite.prebuilt.xml",
"com.google.cf.rild.rc",
- "ld.config.txt",
+ "com.google.cf.rild.xml",
],
- vintf_fragments: [":libril-modem-lib-manifests"],
overrides: [
"libril",
"libreference-ril",
diff --git a/apex/com.google.cf.rild/file_contexts b/apex/com.google.cf.rild/file_contexts
index fc0d328..643f7b9 100644
--- a/apex/com.google.cf.rild/file_contexts
+++ b/apex/com.google.cf.rild/file_contexts
@@ -1,3 +1,3 @@
(/.*)? u:object_r:vendor_file:s0
/bin/hw/libcuttlefish-rild u:object_r:libcuttlefish_rild_exec:s0
-/etc/permissions(/.*)? u:object_r:vendor_configs_file:s0
+/etc(/.*)? u:object_r:vendor_configs_file:s0
diff --git a/apex/com.google.cf.rild/ld.config.txt b/apex/com.google.cf.rild/ld.config.txt
deleted file mode 100644
index c088357..0000000
--- a/apex/com.google.cf.rild/ld.config.txt
+++ /dev/null
@@ -1,7 +0,0 @@
-dir.myapex = /apex/com.google.cf.rild/bin
-
-[myapex]
-additional.namespaces = vndk
-namespace.default.search.paths = /apex/com.google.cf.rild/${LIB}
-# For android.hardware.radio-service.compat
-namespace.vndk.permitted.paths = /vendor/${LIB}/hw
diff --git a/build/Android.bp b/build/Android.bp
index 38c159c..4644730 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -140,6 +140,7 @@
"casimir",
"snapshot_util_cvd",
"run_cvd",
+ "screen_recording_server",
"secure_env",
"sefcontext_compile",
"cvd_send_sms",
diff --git a/common/libs/utils/proto.h b/common/libs/utils/proto.h
new file mode 100644
index 0000000..77b356c
--- /dev/null
+++ b/common/libs/utils/proto.h
@@ -0,0 +1,57 @@
+//
+// Copyright (C) 2023 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 <type_traits>
+#include <vector>
+
+#include <fmt/core.h>
+#include <google/protobuf/message.h>
+#include <google/protobuf/text_format.h>
+#include <google/protobuf/util/json_util.h>
+
+/* Format proto messages as textproto with {} or {:t} and json with {:j}. */
+template <typename T>
+struct fmt::formatter<
+ T,
+ std::enable_if_t<std::is_base_of_v<google::protobuf::Message, T>, char>> {
+ public:
+ constexpr format_parse_context::iterator parse(format_parse_context& ctx) {
+ auto it = ctx.begin();
+ for (; it != ctx.end() && *it != '}'; it++) {
+ format_ = *it;
+ }
+ return it;
+ }
+ format_context::iterator format(const T& proto, format_context& ctx) const {
+ std::string text;
+ if (format_ == 't') {
+ if (!google::protobuf::TextFormat::PrintToString(proto, &text)) {
+ return fmt::format_to(ctx.out(), "(proto format error");
+ }
+ } else if (format_ == 'j') {
+ auto result = google::protobuf::util::MessageToJsonString(proto, &text);
+ if (!result.ok()) {
+ return fmt::format_to(ctx.out(), "(json error: {})",
+ result.message().ToString());
+ }
+ } else {
+ return fmt::format_to(ctx.out(), "(unknown format specifier)");
+ }
+ return fmt::format_to(ctx.out(), "{}", text);
+ }
+
+ private:
+ char format_ = 't';
+};
diff --git a/common/libs/utils/result.h b/common/libs/utils/result.h
index 6ad2a42..2aca246 100644
--- a/common/libs/utils/result.h
+++ b/common/libs/utils/result.h
@@ -23,10 +23,9 @@
#include <utility>
#include <vector>
+#include <android-base/format.h> // IWYU pragma: export
#include <android-base/logging.h>
#include <android-base/result.h> // IWYU pragma: export
-#include <fmt/core.h> // IWYU pragma: export
-#include <fmt/format.h>
namespace cuttlefish {
@@ -232,8 +231,12 @@
}
break;
case FormatSpecifier::kPrettyFunction:
- out = fmt::format_to(out, "{}{}{}", kTerminalCyan, pretty_function_,
- kTerminalReset);
+ if (color) {
+ out = fmt::format_to(out, "{}{}{}", kTerminalCyan, pretty_function_,
+ kTerminalReset);
+ } else {
+ out = fmt::format_to(out, "{}", pretty_function_);
+ }
break;
case FormatSpecifier::kShort: {
auto last_slash = file_.rfind("/");
@@ -290,9 +293,11 @@
std::stringstream message_;
};
-inline std::string ResultErrorFormat() {
+inline std::string ResultErrorFormat(bool color) {
auto error_format = getenv("CF_ERROR_FORMAT");
- std::string fmt_str = error_format == nullptr ? "cns/acLFEm" : error_format;
+ std::string default_error_format = (color ? "cns/acLFEm" : "ns/aLFEm");
+ std::string fmt_str =
+ error_format == nullptr ? default_error_format : error_format;
if (fmt_str.find("}") != std::string::npos) {
fmt_str = "v";
}
@@ -360,12 +365,14 @@
}
const std::vector<StackTraceEntry>& Stack() const { return stack_; }
- std::string Message() const { return fmt::format("{:m}", *this); }
+ std::string Message() const {
+ return fmt::format(fmt::runtime("{:m}"), *this);
+ }
- std::string Trace() const { return fmt::format("{:v}", *this); }
+ std::string Trace() const { return fmt::format(fmt::runtime("{:v}"), *this); }
- std::string FormatForEnv() const {
- return fmt::format(ResultErrorFormat(), *this);
+ std::string FormatForEnv(bool color = (isatty(STDERR_FILENO) == 1)) const {
+ return fmt::format(fmt::runtime(ResultErrorFormat(color)), *this);
}
template <typename T>
diff --git a/common/libs/utils/tee_logging.cpp b/common/libs/utils/tee_logging.cpp
index bfc2d05..a8cb52e9 100644
--- a/common/libs/utils/tee_logging.cpp
+++ b/common/libs/utils/tee_logging.cpp
@@ -204,7 +204,7 @@
}
// TODO(schuffelen): Do something less primitive.
-static std::string StripColorCodes(const std::string& str) {
+std::string StripColorCodes(const std::string& str) {
std::stringstream sstream;
bool in_color_code = false;
for (char c : str) {
diff --git a/common/libs/utils/tee_logging.h b/common/libs/utils/tee_logging.h
index cc14907..af86e59 100644
--- a/common/libs/utils/tee_logging.h
+++ b/common/libs/utils/tee_logging.h
@@ -70,4 +70,6 @@
const std::string& log_prefix = "",
MetadataLevel stderr_level = MetadataLevel::ONLY_MESSAGE);
+std::string StripColorCodes(const std::string& str);
+
} // namespace cuttlefish
diff --git a/guest/commands/bt_vhci_forwarder/hci/h4_packetizer.cc b/guest/commands/bt_vhci_forwarder/hci/h4_packetizer.cc
index 9564669..2529a11 100644
--- a/guest/commands/bt_vhci_forwarder/hci/h4_packetizer.cc
+++ b/guest/commands/bt_vhci_forwarder/hci/h4_packetizer.cc
@@ -83,7 +83,8 @@
return;
}
- LOG_ALWAYS_FATAL("Read error in %d: %s", h4_parser_.CurrentState(),
+ LOG_ALWAYS_FATAL("Read error in %d: %s",
+ static_cast<int>(h4_parser_.CurrentState()),
strerror(errno));
}
h4_parser_.Consume(buffer.data(), bytes_read);
diff --git a/guest/hals/ril/reference-libril/ril_service.cpp b/guest/hals/ril/reference-libril/ril_service.cpp
index f2ff6fd..6d5a51c 100644
--- a/guest/hals/ril/reference-libril/ril_service.cpp
+++ b/guest/hals/ril/reference-libril/ril_service.cpp
@@ -16,11 +16,11 @@
#define LOG_TAG "RILC"
-#include "RefRadioSim.h"
#include "RefImsMedia.h"
#include "RefRadioIms.h"
#include "RefRadioModem.h"
#include "RefRadioNetwork.h"
+#include "RefRadioSim.h"
#include <android-base/logging.h>
#include <android/binder_manager.h>
@@ -13450,6 +13450,7 @@
std::string("default"));
publishRadioHal<cf::ril::RefRadioModem>(context, radioHidl, callbackMgr, slot);
publishRadioHal<cf::ril::RefRadioSim>(context, radioHidl, callbackMgr, slot);
+
RLOGD("registerService: OemHook is enabled = %s", kOemHookEnabled ? "true" : "false");
if (kOemHookEnabled) {
oemHookService[i] = new OemHookImpl;
diff --git a/guest/monitoring/tombstone_transmit/tombstone_transmit.cpp b/guest/monitoring/tombstone_transmit/tombstone_transmit.cpp
index a8def06..5430009 100644
--- a/guest/monitoring/tombstone_transmit/tombstone_transmit.cpp
+++ b/guest/monitoring/tombstone_transmit/tombstone_transmit.cpp
@@ -23,6 +23,7 @@
#include <sys/inotify.h>
#include <unistd.h>
#include <fstream>
+#include <regex>
#include <cutils/properties.h>
#include <gflags/gflags.h>
@@ -44,7 +45,7 @@
}
int watch_descriptor = inotify_add_watch(file_close_notification_handle,
- TOMBSTONE_DIR, IN_CLOSE_WRITE);
+ TOMBSTONE_DIR, IN_CREATE);
if (watch_descriptor == -1) {
ALOGE("%s: Could not add watch for '%s', error: '%s' (%d)", __FUNCTION__,
TOMBSTONE_DIR, strerror(errno), errno);
@@ -115,11 +116,14 @@
property_set("tombstone_transmit.init_done", "true");
#endif
+ std::regex re(R"(tombstone_\d+(\.pb)?)");
while (true) {
std::vector<std::string> ts_names = cuttlefish::GetFileListFromInotifyFd(
- tombstone_create_notification_handle, IN_CLOSE_WRITE);
+ tombstone_create_notification_handle, IN_CREATE);
for (auto& ts_name : ts_names) {
- tombstone_send_to_host(std::string(TOMBSTONE_DIR) + ts_name);
+ if (regex_match(ts_name, re)) {
+ tombstone_send_to_host(std::string(TOMBSTONE_DIR) + ts_name);
+ }
}
}
diff --git a/host/commands/assemble_cvd/boot_config.cc b/host/commands/assemble_cvd/boot_config.cc
index d67111c..655e226 100644
--- a/host/commands/assemble_cvd/boot_config.cc
+++ b/host/commands/assemble_cvd/boot_config.cc
@@ -78,7 +78,7 @@
std::optional<std::uint16_t> partition_num,
std::ostream& env) {
std::string partition_str =
- partition_num ? fmt::format("setenv devplist {};", *partition_num) : "";
+ partition_num ? fmt::format("setenv devplist {:x};", *partition_num) : "";
WritePausedEntrypoint(
partition_str +
"load virtio 0:${devplist} ${loadaddr} efi/boot/bootaa64.efi "
@@ -108,13 +108,16 @@
WriteAndroidEnvironment(env, instance);
break;
case CuttlefishConfig::InstanceSpecific::BootFlow::AndroidEfiLoader:
- case CuttlefishConfig::InstanceSpecific::BootFlow::Linux:
- case CuttlefishConfig::InstanceSpecific::BootFlow::Fuchsia:
- WriteEFIEnvironment(instance, {}, env);
- break;
case CuttlefishConfig::InstanceSpecific::BootFlow::ChromeOs:
WriteEFIEnvironment(instance, 2, env);
break;
+ case CuttlefishConfig::InstanceSpecific::BootFlow::ChromeOsDisk:
+ WriteEFIEnvironment(instance, 12, env);
+ break;
+ case CuttlefishConfig::InstanceSpecific::BootFlow::Fuchsia:
+ case CuttlefishConfig::InstanceSpecific::BootFlow::Linux:
+ WriteEFIEnvironment(instance, {}, env);
+ break;
}
std::string env_str = env.str();
diff --git a/host/commands/assemble_cvd/disk_builder.cpp b/host/commands/assemble_cvd/disk_builder.cpp
index 189bc2c..b7f6b41 100644
--- a/host/commands/assemble_cvd/disk_builder.cpp
+++ b/host/commands/assemble_cvd/disk_builder.cpp
@@ -46,6 +46,15 @@
return ret;
}
+DiskBuilder& DiskBuilder::EntireDisk(std::string disk) & {
+ entire_disk_ = std::move(disk);
+ return *this;
+}
+DiskBuilder DiskBuilder::EntireDisk(std::string disk) && {
+ entire_disk_ = std::move(disk);
+ return *this;
+}
+
DiskBuilder& DiskBuilder::Partitions(std::vector<ImagePartition> partitions) & {
partitions_ = std::move(partitions);
return *this;
@@ -133,10 +142,14 @@
CF_EXPECT(!vm_manager_.empty(), "Missing vm_manager");
disk_conf << vm_manager_ << "\n";
- CF_EXPECT(!partitions_.empty(), "No partitions");
+ CF_EXPECT(!partitions_.empty() ^ !entire_disk_.empty(),
+ "Specify either partitions or a whole disk");
for (auto& partition : partitions_) {
disk_conf << partition.image_file_path << "\n";
}
+ if (!entire_disk_.empty()) {
+ disk_conf << entire_disk_;
+ }
return disk_conf.str();
}
@@ -151,7 +164,12 @@
return true;
}
- CF_EXPECT(!partitions_.empty(), "No partitions");
+ CF_EXPECT(!partitions_.empty() ^ !entire_disk_.empty(),
+ "Specify either partitions or a whole disk");
+ if (!entire_disk_.empty()) {
+ LOG(DEBUG) << "No composite disk to build";
+ return false;
+ }
auto last_component_mod_time = LastUpdatedInputDisk(partitions_);
CF_EXPECT(!composite_disk_path_.empty(), "No composite disk path");
@@ -169,6 +187,10 @@
}
Result<bool> DiskBuilder::BuildCompositeDiskIfNecessary() {
+ if (!entire_disk_.empty()) {
+ LOG(DEBUG) << "No composite disk to build";
+ return false;
+ }
if (!CF_EXPECT(WillRebuildCompositeDisk())) {
return false;
}
diff --git a/host/commands/assemble_cvd/disk_builder.h b/host/commands/assemble_cvd/disk_builder.h
index 7a23a5a..424a5ad 100644
--- a/host/commands/assemble_cvd/disk_builder.h
+++ b/host/commands/assemble_cvd/disk_builder.h
@@ -27,6 +27,9 @@
class DiskBuilder {
public:
+ DiskBuilder& EntireDisk(std::string path) &;
+ DiskBuilder EntireDisk(std::string path) &&;
+
DiskBuilder& Partitions(std::vector<ImagePartition> partitions) &;
DiskBuilder Partitions(std::vector<ImagePartition> partitions) &&;
@@ -64,6 +67,7 @@
Result<std::string> TextConfig();
std::vector<ImagePartition> partitions_;
+ std::string entire_disk_;
std::string header_path_;
std::string footer_path_;
std::string vm_manager_;
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
index 7d12703..f321def 100644
--- a/host/commands/assemble_cvd/disk_flags.cc
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -101,6 +101,8 @@
DEFINE_string(linux_root_image, CF_DEFAULTS_LINUX_ROOT_IMAGE,
"Location of linux root filesystem image for cuttlefish otheros flow.");
+DEFINE_string(chromeos_disk, CF_DEFAULTS_CHROMEOS_DISK,
+ "Location of a complete ChromeOS GPT disk");
DEFINE_string(chromeos_kernel_path, CF_DEFAULTS_CHROMEOS_KERNEL_PATH,
"Location of the chromeos kernel for the chromeos flow.");
DEFINE_string(chromeos_root_image, CF_DEFAULTS_CHROMEOS_ROOT_IMAGE,
@@ -489,6 +491,8 @@
return AndroidEfiLoaderCompositeDiskConfig(instance);
case CuttlefishConfig::InstanceSpecific::BootFlow::ChromeOs:
return chromeos_composite_disk_config(instance);
+ case CuttlefishConfig::InstanceSpecific::BootFlow::ChromeOsDisk:
+ return {};
case CuttlefishConfig::InstanceSpecific::BootFlow::Linux:
return linux_composite_disk_config(instance);
case CuttlefishConfig::InstanceSpecific::BootFlow::Fuchsia:
@@ -498,15 +502,21 @@
DiskBuilder OsCompositeDiskBuilder(const CuttlefishConfig& config,
const CuttlefishConfig::InstanceSpecific& instance) {
- return DiskBuilder()
- .Partitions(GetOsCompositeDiskConfig(instance))
- .VmManager(config.vm_manager())
- .CrosvmPath(instance.crosvm_binary())
- .ConfigPath(instance.PerInstancePath("os_composite_disk_config.txt"))
+ auto builder =
+ DiskBuilder()
+ .VmManager(config.vm_manager())
+ .CrosvmPath(instance.crosvm_binary())
+ .ConfigPath(instance.PerInstancePath("os_composite_disk_config.txt"))
+ .ResumeIfPossible(FLAGS_resume);
+ if (instance.boot_flow() ==
+ CuttlefishConfig::InstanceSpecific::BootFlow::ChromeOsDisk) {
+ return builder.EntireDisk(instance.chromeos_disk())
+ .CompositeDiskPath(instance.chromeos_disk());
+ }
+ return builder.Partitions(GetOsCompositeDiskConfig(instance))
.HeaderPath(instance.PerInstancePath("os_composite_gpt_header.img"))
.FooterPath(instance.PerInstancePath("os_composite_gpt_footer.img"))
- .CompositeDiskPath(instance.os_composite_disk_path())
- .ResumeIfPossible(FLAGS_resume);
+ .CompositeDiskPath(instance.os_composite_disk_path());
}
DiskBuilder ApCompositeDiskBuilder(const CuttlefishConfig& config,
@@ -715,6 +725,8 @@
std::vector<std::string> android_efi_loader =
android::base::Split(FLAGS_android_efi_loader, ",");
+ std::vector<std::string> chromeos_disk =
+ android::base::Split(FLAGS_chromeos_disk, ",");
std::vector<std::string> chromeos_kernel_path =
android::base::Split(FLAGS_chromeos_kernel_path, ",");
std::vector<std::string> chromeos_root_image =
@@ -824,6 +836,11 @@
} else {
instance.set_android_efi_loader(android_efi_loader[instance_index]);
}
+ if (instance_index >= chromeos_disk.size()) {
+ instance.set_chromeos_disk(chromeos_disk[0]);
+ } else {
+ instance.set_chromeos_disk(chromeos_disk[instance_index]);
+ }
if (instance_index >= chromeos_kernel_path.size()) {
instance.set_chromeos_kernel_path(chromeos_kernel_path[0]);
} else {
diff --git a/host/commands/assemble_cvd/flags_defaults.h b/host/commands/assemble_cvd/flags_defaults.h
index ecf1aa9..aac68a8 100644
--- a/host/commands/assemble_cvd/flags_defaults.h
+++ b/host/commands/assemble_cvd/flags_defaults.h
@@ -42,11 +42,7 @@
#define CF_DEFAULTS_DAEMON false
#define CF_DEFAULTS_VM_MANAGER CF_DEFAULTS_DYNAMIC_STRING
#define CF_DEFAULTS_VSOCK_GUEST_CID cuttlefish::GetDefaultVsockCid()
-#ifdef VHOST_USER_VSOCK_BY_DEFAULT
-#define CF_DEFAULTS_VHOST_USER_VSOCK true
-#else
#define CF_DEFAULTS_VHOST_USER_VSOCK false
-#endif // VHOST_USER_VSOCK_BY_DEFAULT
#define CF_DEFAULTS_ENABLE_MINIMAL_MODE false
#define CF_DEFAULTS_RESTART_SUBPROCESSES false
#define CF_DEFAULTS_SETUPWIZARD_MODE "DISABLED"
@@ -72,7 +68,7 @@
#define CF_DEFAULTS_ENABLE_VIRTIOFS false
// Qemu default parameters
-#define CF_DEFAULTS_QEMU_BINARY_DIR "/usr/bin"
+#define CF_DEFAULTS_QEMU_BINARY_DIR cuttlefish::DefaultQemuBinaryDir()
// Gem5 default parameters
#define CF_DEFAULTS_GEM5_BINARY_DIR HostBinaryPath("gem5")
@@ -113,6 +109,7 @@
#define CF_DEFAULTS_DATA_IMAGE CF_DEFAULTS_DYNAMIC_STRING
#define CF_DEFAULTS_INIT_BOOT_IMAGE CF_DEFAULTS_DYNAMIC_STRING
#define CF_DEFAULTS_ANDROID_EFI_LOADER CF_DEFAULTS_DYNAMIC_STRING
+#define CF_DEFAULTS_CHROMEOS_DISK ""
#define CF_DEFAULTS_CHROMEOS_KERNEL_PATH ""
#define CF_DEFAULTS_CHROMEOS_ROOT_IMAGE ""
#define CF_DEFAULTS_LINUX_INITRAMFS_PATH CF_DEFAULTS_DYNAMIC_STRING
@@ -133,7 +130,7 @@
// Policy default parameters
#define CF_DEFAULTS_DATA_POLICY "use_existing"
-#define CF_DEFAULTS_USERDATA_FORMAT "f2fs"
+#define CF_DEFAULTS_USERDATA_FORMAT USERDATA_FILE_SYSTEM_TYPE
#define CF_DEFAULTS_BLANK_DATA_IMAGE_MB CF_DEFAULTS_DYNAMIC_INT
// Graphics default parameters
diff --git a/host/commands/cvd/client.cpp b/host/commands/cvd/client.cpp
index b797da7..bbd738b 100644
--- a/host/commands/cvd/client.cpp
+++ b/host/commands/cvd/client.cpp
@@ -28,6 +28,7 @@
#include "common/libs/fs/shared_buf.h"
#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/environment.h"
+#include "common/libs/utils/proto.h"
#include "common/libs/utils/result.h"
#include "common/libs/utils/subprocess.h"
#include "host/commands/cvd/common_utils.h"
@@ -189,7 +190,7 @@
return connection;
}
-cvd::Version CvdClient::GetClientVersion() {
+static cvd::Version ClientVersion() {
cvd::Version client_version;
client_version.set_major(cvd::kVersionMajor);
client_version.set_minor(cvd::kVersionMinor);
@@ -496,18 +497,8 @@
}
Result<std::string> CvdClient::HandleVersion() {
- using google::protobuf::TextFormat;
- std::stringstream result;
- std::string output;
- auto server_version = CF_EXPECT(GetServerVersion());
- CF_EXPECT(TextFormat::PrintToString(server_version, &output),
- "converting server_version to string failed");
- result << "Server version:" << std::endl << std::endl << output << std::endl;
-
- CF_EXPECT(TextFormat::PrintToString(CvdClient::GetClientVersion(), &output),
- "converting client version to string failed");
- result << "Client version:" << std::endl << std::endl << output << std::endl;
- return {result.str()};
+ return fmt::format("Server version:\n\n{}\nClient version:\n\n{}\n",
+ CF_EXPECT(GetServerVersion()), ClientVersion());
}
Result<Json::Value> CvdClient::ListSubcommands(const cvd_common::Envs& envs) {
diff --git a/host/commands/cvd/client.h b/host/commands/cvd/client.h
index f936504..acc5866 100644
--- a/host/commands/cvd/client.h
+++ b/host/commands/cvd/client.h
@@ -83,7 +83,6 @@
Result<Json::Value> ListSubcommands(const cvd_common::Envs& envs);
Result<SharedFD> ConnectToServer();
- static cvd::Version GetClientVersion();
Result<void> RestartServer(const cvd::Version& server_version);
diff --git a/host/commands/cvd/command_sequence.cpp b/host/commands/cvd/command_sequence.cpp
index b44834b..c754ec6 100644
--- a/host/commands/cvd/command_sequence.cpp
+++ b/host/commands/cvd/command_sequence.cpp
@@ -137,4 +137,9 @@
return std::vector<std::string>{subcmds.begin(), subcmds.end()};
}
+Result<CvdServerHandler*> CommandSequenceExecutor::GetHandler(
+ const RequestWithStdio& request) {
+ return CF_EXPECT(RequestHandler(request, server_handlers_));
+}
+
} // namespace cuttlefish
diff --git a/host/commands/cvd/command_sequence.h b/host/commands/cvd/command_sequence.h
index 427802c..49d50b7 100644
--- a/host/commands/cvd/command_sequence.h
+++ b/host/commands/cvd/command_sequence.h
@@ -36,6 +36,7 @@
Result<cvd::Response> ExecuteOne(const RequestWithStdio&, SharedFD report);
std::vector<std::string> CmdList() const;
+ Result<CvdServerHandler*> GetHandler(const RequestWithStdio& request);
private:
const std::vector<std::unique_ptr<CvdServerHandler>>& server_handlers_;
diff --git a/host/commands/cvd/instance_manager.cpp b/host/commands/cvd/instance_manager.cpp
index 17f2a9b..de64f23 100644
--- a/host/commands/cvd/instance_manager.cpp
+++ b/host/commands/cvd/instance_manager.cpp
@@ -36,6 +36,7 @@
#include "common/libs/utils/subprocess.h"
#include "cvd_server.pb.h"
#include "host/commands/cvd/common_utils.h"
+#include "host/commands/cvd/selector/instance_database_types.h"
#include "host/commands/cvd/selector/instance_database_utils.h"
#include "host/commands/cvd/selector/selector_constants.h"
#include "host/commands/cvd/server_constants.h"
@@ -155,12 +156,12 @@
const auto host_artifacts_path = group_info.host_artifacts_path;
const auto product_out_path = group_info.product_out_path;
const auto& per_instance_info = group_info.instances;
-
- auto new_group = CF_EXPECT(
- instance_db.AddInstanceGroup({.group_name = group_name,
- .home_dir = home_dir,
- .host_artifacts_path = host_artifacts_path,
- .product_out_path = product_out_path}));
+ auto new_group = CF_EXPECT(instance_db.AddInstanceGroup(
+ {.group_name = group_name,
+ .home_dir = home_dir,
+ .host_artifacts_path = host_artifacts_path,
+ .product_out_path = product_out_path,
+ .start_time = selector::CvdServerClock::now()}));
using InstanceInfo = selector::InstanceDatabase::InstanceInfo;
std::vector<InstanceInfo> instances_info;
@@ -349,7 +350,7 @@
return *(output.begin());
}
-std::vector<std::string> InstanceManager::AllGroupNames(const uid_t uid) const {
+std::vector<std::string> InstanceManager::AllGroupNames(uid_t uid) const {
std::lock_guard lock(instance_db_mutex_);
if (!Contains(instance_dbs_, uid)) {
return {};
@@ -364,4 +365,34 @@
return group_names;
}
+Result<InstanceManager::UserGroupSelectionSummary>
+InstanceManager::GroupSummaryMenu(uid_t uid) const {
+ std::lock_guard lock(instance_db_mutex_);
+ CF_EXPECT(Contains(instance_dbs_, uid));
+ const auto& db = instance_dbs_.at(uid);
+
+ UserGroupSelectionSummary summary;
+
+ // List of Cuttlefish Instance Groups:
+ // [i] : group_name (created: TIME)
+ // <a> instance0.device_name() (id: instance_id)
+ // <b> instance1.device_name() (id: instance_id)
+ std::stringstream ss;
+ ss << "List of Cuttlefish Instance Groups:" << std::endl;
+ int group_idx = 0;
+ for (const auto& group : db.InstanceGroups()) {
+ fmt::print(ss, " [{}] : {} (created: {})\n", group_idx, group->GroupName(),
+ selector::Format(group->StartTime()));
+ summary.idx_to_group_name[group_idx] = group->GroupName();
+ char instance_idx = 'a';
+ for (const auto& instance : CF_EXPECT(group->FindAllInstances())) {
+ fmt::print(ss, " <{}> {} (id : {})\n", instance_idx++,
+ instance.Get().DeviceName(), instance.Get().InstanceId());
+ }
+ group_idx++;
+ }
+ summary.menu = ss.str();
+ return summary;
+}
+
} // namespace cuttlefish
diff --git a/host/commands/cvd/instance_manager.h b/host/commands/cvd/instance_manager.h
index fa51dcf..45a7ddc 100644
--- a/host/commands/cvd/instance_manager.h
+++ b/host/commands/cvd/instance_manager.h
@@ -103,7 +103,16 @@
const Queries& queries) const;
Result<Json::Value> Serialize(const uid_t uid);
Result<void> LoadFromJson(const uid_t uid, const Json::Value&);
- std::vector<std::string> AllGroupNames(const uid_t uid) const;
+ std::vector<std::string> AllGroupNames(uid_t uid) const;
+
+ struct UserGroupSelectionSummary {
+ // Index to group name. This is the index printed in the menu
+ // This field offers mapping between the number/index the user
+ // selects and the group that is to be chosen
+ std::unordered_map<int, std::string> idx_to_group_name;
+ std::string menu;
+ };
+ Result<UserGroupSelectionSummary> GroupSummaryMenu(uid_t uid) const;
private:
Result<void> IssueStopCommand(const SharedFD& out, const SharedFD& err,
diff --git a/host/commands/cvd/logger.cpp b/host/commands/cvd/logger.cpp
index 68e2691..890af67 100644
--- a/host/commands/cvd/logger.cpp
+++ b/host/commands/cvd/logger.cpp
@@ -117,7 +117,8 @@
auto output_string =
StderrOutputGenerator(now, getpid(), android::base::GetThreadId(),
severity, tag, file, line, message);
- WriteAll(target_, output_string);
+ const bool color = target_->IsOpen() && target_->IsATTY();
+ WriteAll(target_, (color ? output_string : StripColorCodes(output_string)));
}
void ServerLogger::ScopedLogger::SetSeverity(const LogSeverity severity) {
diff --git a/host/commands/cvd/main.cc b/host/commands/cvd/main.cc
index 998a083..2e1959a 100644
--- a/host/commands/cvd/main.cc
+++ b/host/commands/cvd/main.cc
@@ -200,7 +200,8 @@
// TODO: we should not print the stack trace, instead, we should rely on
// each handler to print the error message directly in the client's
// std::cerr. We print the stack trace only in the verbose mode.
- std::cerr << result.error().FormatForEnv() << std::endl;
+ std::cerr << result.error().FormatForEnv(isatty(STDERR_FILENO))
+ << std::endl;
// TODO(kwstephenkim): better coloring
constexpr char kUserReminder[] =
R"( If the error above is unclear, please copy the text into an issue at:)";
diff --git a/host/commands/cvd/metrics/cvd_metrics_api.cpp b/host/commands/cvd/metrics/cvd_metrics_api.cpp
index ec41765..58e144c 100644
--- a/host/commands/cvd/metrics/cvd_metrics_api.cpp
+++ b/host/commands/cvd/metrics/cvd_metrics_api.cpp
@@ -34,6 +34,9 @@
constexpr int kCppClientType =
19; // C++ native client type (clientanalytics.proto)
+const std::string kInternalEmail = "@google.com";
+const std::vector<std::string> kInternalHostname = {"google"};
+
std::string GenerateUUID() {
uuid_t uuid;
uuid_generate_random(uuid);
@@ -103,6 +106,42 @@
return commandLine;
}
+std::string GetUserEmail() {
+ std::string email;
+ FILE* pipe = popen("git config --get user.email 2>/dev/null", "r");
+ if (!pipe) {
+ LOG(ERROR) << "popen() failed!";
+ return "";
+ }
+ char buffer[128];
+ while (fgets(buffer, sizeof(buffer), pipe) != nullptr) {
+ email += buffer;
+ }
+ pclose(pipe);
+ email.erase(std::remove(email.begin(), email.end(), '\n'), email.end());
+ return email;
+}
+
+UserType GetUserType() {
+ std::string email = GetUserEmail();
+ if (email.find(kInternalEmail) != std::string::npos) {
+ return UserType::GOOGLE;
+ }
+
+ char hostname[1024];
+ hostname[1023] = '\0';
+ gethostname(hostname, sizeof(hostname) - 1);
+ std::string host_str(hostname);
+
+ for (const auto& internal_host : kInternalHostname) {
+ if (host_str.find(internal_host) != std::string::npos) {
+ return UserType::GOOGLE;
+ }
+ }
+
+ return UserType::EXTERNAL;
+}
+
} // namespace
int CvdMetrics::SendLaunchCommand(const std::string& command_line) {
@@ -124,6 +163,9 @@
}
int CvdMetrics::SendCvdMetrics(const std::vector<std::string>& args) {
+ if (GetUserType() != UserType::GOOGLE) {
+ return 0;
+ }
std::string command_line = createCommandLine(args);
return CvdMetrics::SendLaunchCommand(command_line);
}
diff --git a/host/commands/cvd/metrics/proto/clientanalytics.proto b/host/commands/cvd/metrics/proto/clientanalytics.proto
index a120a91..e088384 100644
--- a/host/commands/cvd/metrics/proto/clientanalytics.proto
+++ b/host/commands/cvd/metrics/proto/clientanalytics.proto
@@ -14,6 +14,7 @@
* limitations under the License.
*/
syntax = "proto2";
+package cuttlefish;
message LogRequest {
optional ClientInfo client_info = 1;
diff --git a/host/commands/cvd/metrics/utils.h b/host/commands/cvd/metrics/utils.h
index ff4d40d..283d6ff 100644
--- a/host/commands/cvd/metrics/utils.h
+++ b/host/commands/cvd/metrics/utils.h
@@ -35,7 +35,7 @@
std::string GetCompany();
std::string GetVmmVersion();
uint64_t GetEpochTimeMs();
-std::string ProtoToString(LogEvent* event);
+std::string ProtoToString(cuttlefish::LogEvent* event);
cuttlefish::MetricsExitCodes PostRequest(const std::string& output,
ClearcutServer server);
diff --git a/host/commands/cvd/parser/load_configs_parser.cpp b/host/commands/cvd/parser/load_configs_parser.cpp
index 79a90c4..0197f6d 100644
--- a/host/commands/cvd/parser/load_configs_parser.cpp
+++ b/host/commands/cvd/parser/load_configs_parser.cpp
@@ -154,7 +154,6 @@
std::vector<Flag> GetFlagsVector(LoadFlags& load_flags) {
std::vector<Flag> flags;
- flags.emplace_back(GflagsCompatFlag("help", load_flags.help));
flags.emplace_back(
GflagsCompatFlag("credential_source", load_flags.credential_source));
flags.emplace_back(
@@ -181,42 +180,9 @@
path.insert(0, working_dir + "/");
}
-} // namespace
-
-Result<LoadFlags> GetFlags(std::vector<std::string>& args,
- const std::string& working_directory) {
- LoadFlags load_flags;
- auto flags = GetFlagsVector(load_flags);
- CF_EXPECT(ParseFlags(flags, args));
- CF_EXPECT(load_flags.help || args.size() > 0,
- "No arguments provided to cvd load command, please provide at "
- "least one argument (help or path to json file)");
-
- if (load_flags.base_dir.empty()) {
- load_flags.base_dir = DefaultBaseDir();
- }
- MakeAbsolute(load_flags.base_dir, working_directory);
-
- load_flags.config_path = args.front();
- MakeAbsolute(load_flags.config_path, working_directory);
-
- if (!load_flags.credential_source.empty()) {
- for (const auto& flag : load_flags.overrides) {
- CF_EXPECT(!android::base::StartsWith(flag.config_path,
- kCredentialSourceOverride),
- "Specifying both --override=fetch.credential_source and the "
- "--credential_source flag is not allowed.");
- }
- load_flags.overrides.emplace_back(
- Override{.config_path = std::string(kCredentialSourceOverride),
- .new_value = load_flags.credential_source});
- }
- return load_flags;
-}
-
Result<Json::Value> ParseJsonFile(const std::string& file_path) {
CF_EXPECTF(FileExists(file_path),
- "Provided file \"{}\" to cvd load does not exist", file_path);
+ "Provided file \"{}\" to cvd command does not exist", file_path);
std::string file_content;
using android::base::ReadFileToString;
@@ -258,12 +224,6 @@
return result;
}
-std::ostream& operator<<(std::ostream& out, const Override& override) {
- fmt::print(out, "(config_path=\"{}\", new_value=\"{}\")",
- override.config_path, override.new_value);
- return out;
-}
-
Result<LoadDirectories> GenerateLoadDirectories(
const std::string& parent_directory,
std::vector<std::string>& system_image_path_configs,
@@ -319,7 +279,63 @@
.selector_flags = CF_EXPECT(ParseSelectorConfigs(root)),
.fetch_cvd_flags = CF_EXPECT(ParseFetchCvdConfigs(
root, load_directories.target_directory,
- load_directories.target_subdirectories))};
+ load_directories.target_subdirectories)),
+ .load_directories = load_directories};
+}
+
+} // namespace
+
+std::ostream& operator<<(std::ostream& out, const Override& override) {
+ fmt::print(out, "(config_path=\"{}\", new_value=\"{}\")",
+ override.config_path, override.new_value);
+ return out;
+}
+
+Result<LoadFlags> GetFlags(std::vector<std::string>& args,
+ const std::string& working_directory) {
+ LoadFlags load_flags;
+ auto flags = GetFlagsVector(load_flags);
+ CF_EXPECT(ParseFlags(flags, args));
+ CF_EXPECT(
+ args.size() > 0,
+ "No arguments provided to cvd command, please provide path to json file");
+
+ if (load_flags.base_dir.empty()) {
+ load_flags.base_dir = DefaultBaseDir();
+ }
+ MakeAbsolute(load_flags.base_dir, working_directory);
+
+ load_flags.config_path = args.front();
+ MakeAbsolute(load_flags.config_path, working_directory);
+
+ if (!load_flags.credential_source.empty()) {
+ for (const auto& flag : load_flags.overrides) {
+ CF_EXPECT(!android::base::StartsWith(flag.config_path,
+ kCredentialSourceOverride),
+ "Specifying both --override=fetch.credential_source and the "
+ "--credential_source flag is not allowed.");
+ }
+ load_flags.overrides.emplace_back(
+ Override{.config_path = std::string(kCredentialSourceOverride),
+ .new_value = load_flags.credential_source});
+ }
+ return load_flags;
+}
+
+Result<CvdFlags> GetCvdFlags(const LoadFlags& flags) {
+ Json::Value json_configs =
+ CF_EXPECT(GetOverriddenConfig(flags.config_path, flags.overrides));
+
+ std::vector<std::string> system_image_path_configs =
+ CF_EXPECT(GetConfiguredSystemImagePaths(json_configs));
+ std::optional<std::string> host_package_dir =
+ GetConfiguredSystemHostPath(json_configs);
+
+ const auto load_directories = CF_EXPECT(GenerateLoadDirectories(
+ flags.base_dir, system_image_path_configs, host_package_dir,
+ json_configs["instances"].size()));
+ return CF_EXPECT(ParseCvdConfigs(json_configs, load_directories),
+ "Parsing json configs failed");
}
} // namespace cuttlefish
diff --git a/host/commands/cvd/parser/load_configs_parser.h b/host/commands/cvd/parser/load_configs_parser.h
index b279332..15d1f57 100644
--- a/host/commands/cvd/parser/load_configs_parser.h
+++ b/host/commands/cvd/parser/load_configs_parser.h
@@ -26,12 +26,6 @@
namespace cuttlefish {
-typedef struct _CvdFlags {
- std::vector<std::string> launch_cvd_flags;
- std::vector<std::string> selector_flags;
- std::vector<std::string> fetch_cvd_flags;
-} CvdFlags;
-
struct LoadDirectories {
std::string target_directory;
std::vector<std::string> target_subdirectories;
@@ -40,6 +34,13 @@
std::string system_image_directory_flag;
};
+struct CvdFlags {
+ std::vector<std::string> launch_cvd_flags;
+ std::vector<std::string> selector_flags;
+ std::vector<std::string> fetch_cvd_flags;
+ LoadDirectories load_directories;
+};
+
struct Override {
std::string config_path;
std::string new_value;
@@ -48,7 +49,6 @@
std::ostream& operator<<(std::ostream& out, const Override& override);
struct LoadFlags {
- bool help = false;
std::vector<Override> overrides;
std::string config_path;
std::string credential_source;
@@ -58,22 +58,6 @@
Result<LoadFlags> GetFlags(std::vector<std::string>& args,
const std::string& working_directory);
-Result<Json::Value> ParseJsonFile(const std::string& file_path);
-
-Result<std::vector<std::string>> GetConfiguredSystemImagePaths(
- Json::Value& root);
-std::optional<std::string> GetConfiguredSystemHostPath(Json::Value& root);
-
-Result<Json::Value> GetOverriddenConfig(
- const std::string& config_path,
- const std::vector<Override>& override_flags);
-
-Result<LoadDirectories> GenerateLoadDirectories(
- const std::string& parent_directory,
- std::vector<std::string>& system_image_path_configs,
- std::optional<std::string> system_host_path, const int num_instances);
-
-Result<CvdFlags> ParseCvdConfigs(Json::Value& root,
- const LoadDirectories& load_directories);
+Result<CvdFlags> GetCvdFlags(const LoadFlags& flags);
}; // namespace cuttlefish
diff --git a/host/commands/cvd/request_context.cpp b/host/commands/cvd/request_context.cpp
index 8be2ed7..146947f 100644
--- a/host/commands/cvd/request_context.cpp
+++ b/host/commands/cvd/request_context.cpp
@@ -21,6 +21,7 @@
#include <android-base/logging.h>
+#include "common/libs/utils/result.h"
#include "host/commands/cvd/command_sequence.h"
#include "host/commands/cvd/instance_manager.h"
#include "host/commands/cvd/server_client.h"
@@ -36,6 +37,7 @@
#include "host/commands/cvd/server_command/handler_proxy.h"
#include "host/commands/cvd/server_command/help.h"
#include "host/commands/cvd/server_command/host_tool_target_manager.h"
+#include "host/commands/cvd/server_command/lint.h"
#include "host/commands/cvd/server_command/load_configs.h"
#include "host/commands/cvd/server_command/power.h"
#include "host/commands/cvd/server_command/reset.h"
@@ -83,7 +85,8 @@
instance_manager_, subprocess_waiter_, host_tool_target_manager_));
request_handlers_.emplace_back(
NewCvdServerHandlerProxy(command_sequence_executor_));
- request_handlers_.emplace_back(NewCvdHelpHandler(command_sequence_executor_));
+ request_handlers_.emplace_back(NewCvdHelpHandler(this->request_handlers_));
+ request_handlers_.emplace_back(NewLintCommand());
request_handlers_.emplace_back(
NewLoadConfigsCommand(command_sequence_executor_));
request_handlers_.emplace_back(NewCvdDevicePowerCommandHandler(
diff --git a/host/commands/cvd/request_context.h b/host/commands/cvd/request_context.h
index 7b73757..339ba5e 100644
--- a/host/commands/cvd/request_context.h
+++ b/host/commands/cvd/request_context.h
@@ -19,6 +19,7 @@
#include <atomic>
#include <vector>
+#include "common/libs/utils/result.h"
#include "host/commands/cvd/command_sequence.h"
#include "host/commands/cvd/instance_manager.h"
#include "host/commands/cvd/server_client.h"
diff --git a/host/commands/cvd/selector/instance_database.h b/host/commands/cvd/selector/instance_database.h
index 80ce576..7459084 100644
--- a/host/commands/cvd/selector/instance_database.h
+++ b/host/commands/cvd/selector/instance_database.h
@@ -39,6 +39,8 @@
using ConstInstanceHandler = ConstHandler<LocalInstance>;
public:
+ static constexpr const char kJsonGroups[] = "Groups";
+
InstanceDatabase();
bool IsEmpty() const;
@@ -47,6 +49,7 @@
std::string home_dir;
std::string host_artifacts_path;
std::string product_out_path;
+ TimeStamp start_time;
};
/** Adds instance group.
*
@@ -149,8 +152,6 @@
std::vector<std::unique_ptr<LocalInstanceGroup>> local_instance_groups_;
Map<FieldName, ConstGroupHandler> group_handlers_;
Map<FieldName, ConstInstanceHandler> instance_handlers_;
-
- static constexpr const char kJsonGroups[] = "Groups";
};
} // namespace selector
diff --git a/host/commands/cvd/selector/instance_database_impl.cpp b/host/commands/cvd/selector/instance_database_impl.cpp
index 9001045..73dc561 100644
--- a/host/commands/cvd/selector/instance_database_impl.cpp
+++ b/host/commands/cvd/selector/instance_database_impl.cpp
@@ -65,7 +65,8 @@
new LocalInstanceGroup({.group_name = param.group_name,
.home_dir = param.home_dir,
.host_artifacts_path = param.host_artifacts_path,
- .product_out_path = param.product_out_path});
+ .product_out_path = param.product_out_path,
+ .start_time = param.start_time});
CF_EXPECT(new_group != nullptr);
local_instance_groups_.emplace_back(new_group);
const auto raw_ptr = local_instance_groups_.back().get();
@@ -295,11 +296,26 @@
group_json[LocalInstanceGroup::kJsonHostArtifactPath].asString();
const std::string product_out_path =
group_json[LocalInstanceGroup::kJsonProductOutPath].asString();
+ TimeStamp start_time = CvdServerClock::now();
+
+ // test if the field is available as the field has been added
+ // recently as of b/315855286
+ if (group_json.isMember(LocalInstanceGroup::kJsonStartTime)) {
+ auto restored_start_time_result = DeserializeTimePoint(group_json);
+ if (restored_start_time_result.ok()) {
+ start_time = std::move(*restored_start_time_result);
+ } else {
+ LOG(ERROR) << "Start time restoration from json failed, so we use "
+ << " the current system time. Reasons: "
+ << restored_start_time_result.error().FormatForEnv();
+ }
+ }
const auto new_group_ref =
CF_EXPECT(AddInstanceGroup({.group_name = group_name,
.home_dir = home_dir,
.host_artifacts_path = host_artifacts_path,
- .product_out_path = product_out_path}));
+ .product_out_path = product_out_path,
+ .start_time = std::move(start_time)}));
android::base::ScopeGuard remove_already_added_new_group(
[&new_group_ref, this]() {
this->RemoveInstanceGroup(new_group_ref.Get());
diff --git a/host/commands/cvd/selector/instance_database_types.cpp b/host/commands/cvd/selector/instance_database_types.cpp
index 994917c..bb7920e 100644
--- a/host/commands/cvd/selector/instance_database_types.cpp
+++ b/host/commands/cvd/selector/instance_database_types.cpp
@@ -16,11 +16,49 @@
#include "host/commands/cvd/selector/instance_database_types.h"
+#include <android-base/parseint.h>
+#include <fmt/core.h>
+
+#include "host/commands/cvd/selector/instance_group_record.h"
+
namespace cuttlefish {
namespace selector {
Query::Query(const std::string& field_name, const std::string& field_value)
: field_name_(field_name), field_value_(field_value) {}
+std::string SerializeTimePoint(const TimeStamp& present) {
+ const auto duration =
+ std::chrono::duration_cast<CvdTimeDuration>(present.time_since_epoch());
+ return fmt::format("{}", duration.count());
+}
+
+Result<TimeStamp> DeserializeTimePoint(const Json::Value& group_json) {
+ std::string group_name = "unknown";
+ if (group_json.isMember(LocalInstanceGroup::kJsonGroupName)) {
+ group_name = group_json[LocalInstanceGroup::kJsonGroupName].asString();
+ }
+ CF_EXPECTF(group_json.isMember(LocalInstanceGroup::kJsonStartTime),
+ "The serialized instance database in json file for group \"{}\""
+ " is missing the start time field: {}",
+ group_name, LocalInstanceGroup::kJsonStartTime);
+ std::string serialized(
+ group_json[LocalInstanceGroup::kJsonStartTime].asString());
+
+ using CountType = decltype(((const CvdTimeDuration*)nullptr)->count());
+ CountType count = 0;
+ CF_EXPECTF(android::base::ParseInt(serialized, &count),
+ "Failed to serialize: {}", serialized);
+ CvdTimeDuration duration(count);
+ TimeStamp restored_time(duration);
+ LOG(VERBOSE) << "The start time of the group \"" << group_name
+ << "\" is restored as: " << Format(restored_time);
+ return restored_time;
+}
+
+std::string Format(const TimeStamp& time_point) {
+ return fmt::format("{:%b-%d-%Y %H:%M:%S}", time_point);
+}
+
} // namespace selector
} // namespace cuttlefish
diff --git a/host/commands/cvd/selector/instance_database_types.h b/host/commands/cvd/selector/instance_database_types.h
index 7710483..7b69b76 100644
--- a/host/commands/cvd/selector/instance_database_types.h
+++ b/host/commands/cvd/selector/instance_database_types.h
@@ -16,12 +16,17 @@
#pragma once
+#include <chrono>
+#include <iostream>
#include <string>
#include <type_traits>
#include <unordered_map>
#include <unordered_set>
#include <vector>
+#include "common/libs/utils/json.h"
+#include "common/libs/utils/result.h"
+
namespace cuttlefish {
namespace selector {
namespace selector_impl {
@@ -62,5 +67,13 @@
template <typename K, typename V>
using Map = std::unordered_map<K, V>;
+using CvdServerClock = std::chrono::system_clock;
+using TimeStamp = std::chrono::time_point<CvdServerClock>;
+using CvdTimeDuration = std::chrono::milliseconds;
+
+std::string SerializeTimePoint(const TimeStamp&);
+Result<TimeStamp> DeserializeTimePoint(const Json::Value& group_json);
+std::string Format(const TimeStamp&);
+
} // namespace selector
} // namespace cuttlefish
diff --git a/host/commands/cvd/selector/instance_group_record.cpp b/host/commands/cvd/selector/instance_group_record.cpp
index 6db8122..d07b586 100644
--- a/host/commands/cvd/selector/instance_group_record.cpp
+++ b/host/commands/cvd/selector/instance_group_record.cpp
@@ -16,6 +16,7 @@
#include "host/commands/cvd/selector/instance_group_record.h"
+#include "host/commands/cvd/selector/instance_database_types.h"
#include "host/commands/cvd/selector/instance_database_utils.h"
#include "host/commands/cvd/selector/selector_constants.h"
@@ -27,7 +28,11 @@
host_artifacts_path_{param.host_artifacts_path},
product_out_path_{param.product_out_path},
internal_group_name_(GenInternalGroupName()),
- group_name_(param.group_name) {}
+ group_name_(param.group_name),
+ start_time_(param.start_time) {
+ LOG(VERBOSE) << "Creating a group \"" << group_name_ << "\" ("
+ << Format(start_time_) << ")";
+}
LocalInstanceGroup::LocalInstanceGroup(const LocalInstanceGroup& src)
: home_dir_{src.home_dir_},
@@ -35,6 +40,7 @@
product_out_path_{src.product_out_path_},
internal_group_name_{src.internal_group_name_},
group_name_{src.group_name_},
+ start_time_{src.start_time_},
instances_{CopyInstances(src.instances_)} {}
LocalInstanceGroup& LocalInstanceGroup::operator=(
@@ -133,6 +139,8 @@
group_json[kJsonHomeDir] = home_dir_;
group_json[kJsonHostArtifactPath] = host_artifacts_path_;
group_json[kJsonProductOutPath] = product_out_path_;
+ group_json[kJsonStartTime] = SerializeTimePoint(start_time_);
+
int i = 0;
Json::Value instances_array_json;
for (const auto& instance : instances_) {
diff --git a/host/commands/cvd/selector/instance_group_record.h b/host/commands/cvd/selector/instance_group_record.h
index db86a6f..91103bd 100644
--- a/host/commands/cvd/selector/instance_group_record.h
+++ b/host/commands/cvd/selector/instance_group_record.h
@@ -54,6 +54,7 @@
return instances_;
}
Json::Value Serialize() const;
+ auto StartTime() const { return start_time_; }
/**
* return error if instance id of instance is taken AND that taken id
@@ -76,12 +77,21 @@
// returns all instances in the dedicated data type
Result<Set<ConstRef<LocalInstance>>> FindAllInstances() const;
+ static constexpr const char kJsonGroupName[] = "Group Name";
+ static constexpr const char kJsonHomeDir[] = "Runtime/Home Dir";
+ static constexpr const char kJsonHostArtifactPath[] = "Host Tools Dir";
+ static constexpr const char kJsonProductOutPath[] = "Product Out Dir";
+ static constexpr const char kJsonStartTime[] = "Start Time";
+ static constexpr const char kJsonInstances[] = "Instances";
+ static constexpr const char kJsonParent[] = "Parent Group";
+
private:
struct InstanceGroupParam {
std::string group_name;
std::string home_dir;
std::string host_artifacts_path;
std::string product_out_path;
+ TimeStamp start_time;
};
LocalInstanceGroup(const InstanceGroupParam& param);
// Eventually copies the instances of a src to *this
@@ -96,18 +106,9 @@
// for now, "cvd", which is "cvd-".remove_suffix(1)
std::string internal_group_name_;
std::string group_name_;
- // This will be initialized after the LocalInstanceGroup is created,
- // which is also after the device completes the boot.
- std::optional<std::string> build_id_;
+ TimeStamp start_time_;
Set<std::unique_ptr<LocalInstance>> instances_;
- static constexpr const char kJsonGroupName[] = "Group Name";
- static constexpr const char kJsonHomeDir[] = "Runtime/Home Dir";
- static constexpr const char kJsonHostArtifactPath[] = "Host Tools Dir";
- static constexpr const char kJsonProductOutPath[] = "Product Out Dir";
- static constexpr const char kJsonInstances[] = "Instances";
- static constexpr const char kJsonParent[] = "Parent Group";
-
/*
* Expose constructor to the tests in InstanceRecord unit test suite.
*
diff --git a/host/commands/cvd/selector/instance_record.cpp b/host/commands/cvd/selector/instance_record.cpp
index 82312d8..debc311 100644
--- a/host/commands/cvd/selector/instance_record.cpp
+++ b/host/commands/cvd/selector/instance_record.cpp
@@ -67,13 +67,15 @@
.home_dir = src.ParentGroup().HomeDir(),
.host_artifacts_path = src.ParentGroup().HostArtifactsPath(),
.internal_group_name = src.ParentGroup().InternalGroupName(),
- .group_name = src.ParentGroup().GroupName()}} {}
+ .group_name = src.ParentGroup().GroupName(),
+ .start_time = src.ParentGroup().StartTime()}} {}
LocalInstance::Copy::MockParent::MockParent(const MockParentParam& params)
: home_dir_{params.home_dir},
host_artifacts_path_{params.host_artifacts_path},
internal_group_name_{params.internal_group_name},
- group_name_{params.group_name} {}
+ group_name_{params.group_name},
+ start_time_{params.start_time} {}
} // namespace selector
} // namespace cuttlefish
diff --git a/host/commands/cvd/selector/instance_record.h b/host/commands/cvd/selector/instance_record.h
index f6bdf9a..db7e690 100644
--- a/host/commands/cvd/selector/instance_record.h
+++ b/host/commands/cvd/selector/instance_record.h
@@ -16,10 +16,10 @@
#pragma once
-#include <optional>
#include <string>
#include "common/libs/utils/result.h"
+#include "host/commands/cvd/selector/instance_database_types.h"
namespace cuttlefish {
namespace selector {
@@ -36,6 +36,9 @@
friend class InstanceDatabase;
public:
+ static constexpr const char kJsonInstanceId[] = "Instance Id";
+ static constexpr const char kJsonInstanceName[] = "Per-Instance Name";
+
/* names:
*
* Many components in Cuttlefish traditionally expect the name to be "cvd-N,"
@@ -61,6 +64,7 @@
std::string host_artifacts_path;
std::string internal_group_name;
std::string group_name;
+ TimeStamp start_time;
};
public:
@@ -79,12 +83,14 @@
const std::string& HostArtifactsPath() const {
return host_artifacts_path_;
}
+ auto StartTime() const { return start_time_; }
private:
std::string home_dir_;
std::string host_artifacts_path_;
std::string internal_group_name_;
std::string group_name_;
+ TimeStamp start_time_;
};
Copy(const LocalInstance& src);
const std::string& InternalName() const { return internal_name_; }
@@ -110,9 +116,6 @@
LocalInstance(const LocalInstanceGroup& parent_group,
const unsigned instance_id, const std::string& instance_name);
- static constexpr const char kJsonInstanceId[] = "Instance Id";
- static constexpr const char kJsonInstanceName[] = "Per-Instance Name";
-
const LocalInstanceGroup& parent_group_;
unsigned instance_id_;
std::string internal_name_; ///< for now, it is to_string(instance_id_)
diff --git a/host/commands/cvd/server.cc b/host/commands/cvd/server.cc
index 87e427d..540ebe6 100644
--- a/host/commands/cvd/server.cc
+++ b/host/commands/cvd/server.cc
@@ -283,8 +283,9 @@
if (!response.ok()) {
cvd::Response failure_message;
failure_message.mutable_status()->set_code(cvd::Status::INTERNAL);
+ const bool color = request->Err()->IsOpen() && request->Err()->IsATTY();
failure_message.mutable_status()->set_message(
- response.error().FormatForEnv());
+ response.error().FormatForEnv(color));
CF_EXPECT(SendResponse(event.fd, failure_message));
return {}; // Error already sent to the client, don't repeat on the server
}
diff --git a/host/commands/cvd/server_command/Android.bp b/host/commands/cvd/server_command/Android.bp
index 575d742..0ae8c7f 100644
--- a/host/commands/cvd/server_command/Android.bp
+++ b/host/commands/cvd/server_command/Android.bp
@@ -36,6 +36,7 @@
"generic.cpp",
"handler_proxy.cpp",
"help.cpp",
+ "lint.cpp",
"load_configs.cpp",
"power.cpp",
"reset.cpp",
diff --git a/host/commands/cvd/server_command/fetch.cpp b/host/commands/cvd/server_command/fetch.cpp
index c258c3f..cb86c01 100644
--- a/host/commands/cvd/server_command/fetch.cpp
+++ b/host/commands/cvd/server_command/fetch.cpp
@@ -16,10 +16,13 @@
#include "host/commands/cvd/server_command/fetch.h"
+#include <android-base/strings.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 "common/libs/utils/subprocess.h"
#include "host/commands/cvd/server_command/server_handler.h"
#include "host/commands/cvd/server_command/utils.h"
#include "host/commands/cvd/types.h"
@@ -36,6 +39,9 @@
Result<cvd::Response> Handle(const RequestWithStdio& request) override;
Result<void> Interrupt() override;
cvd_common::Args CmdList() const override { return fetch_cmd_list_; }
+ Result<std::string> SummaryHelp() const override;
+ virtual bool ShouldInterceptHelp() const { return true; }
+ Result<std::string> DetailedHelp(std::vector<std::string>&) const override;
private:
SubprocessWaiter& subprocess_waiter_;
@@ -107,6 +113,22 @@
return {};
}
+Result<std::string> CvdFetchCommandHandler::SummaryHelp() const {
+ return "Retrieve build artifacts based on branch and target names";
+}
+
+Result<std::string> CvdFetchCommandHandler::DetailedHelp(
+ std::vector<std::string>&) const {
+ Command fetch_command("/proc/self/exe");
+ fetch_command.SetName("fetch_cvd");
+ fetch_command.SetExecutable("/proc/self/exe");
+ fetch_command.AddParameter("--help");
+
+ std::string output;
+ RunWithManagedStdio(std::move(fetch_command), nullptr, nullptr, &output);
+ return output;
+}
+
std::unique_ptr<CvdServerHandler> NewCvdFetchCommandHandler(
SubprocessWaiter& subprocess_waiter) {
return std::unique_ptr<CvdServerHandler>(
diff --git a/host/commands/cvd/server_command/fleet.cpp b/host/commands/cvd/server_command/fleet.cpp
index 12c52e3..c1d5d27 100644
--- a/host/commands/cvd/server_command/fleet.cpp
+++ b/host/commands/cvd/server_command/fleet.cpp
@@ -28,6 +28,8 @@
#include "common/libs/utils/files.h"
#include "common/libs/utils/json.h"
#include "common/libs/utils/result.h"
+#include "host/commands/cvd/selector/instance_database_types.h"
+#include "host/commands/cvd/selector/selector_constants.h"
#include "host/commands/cvd/server_client.h"
#include "host/commands/cvd/server_command/server_handler.h"
#include "host/commands/cvd/server_command/status_fetcher.h"
@@ -110,8 +112,19 @@
auto all_group_names = instance_manager_.AllGroupNames(uid);
envs.erase(kCuttlefishInstanceEnvVarName);
for (const auto& group_name : all_group_names) {
+ auto group_obj_copy_result = instance_manager_.SelectGroup(
+ {}, InstanceManager::Queries{{selector::kGroupNameField, group_name}},
+ {}, uid);
+ if (!group_obj_copy_result.ok()) {
+ LOG(DEBUG) << "Group \"" << group_name
+ << "\" has already been removed. Skipped.";
+ continue;
+ }
+
Json::Value group_json(Json::objectValue);
group_json["group_name"] = group_name;
+ group_json["start_time"] =
+ selector::Format(group_obj_copy_result->StartTime());
auto request_message = MakeRequest(
{.cmd_args = {"cvd", "status", "--print", "--all_instances"},
diff --git a/host/commands/cvd/server_command/generic.cpp b/host/commands/cvd/server_command/generic.cpp
index 5ffc2b5..79ec7fe 100644
--- a/host/commands/cvd/server_command/generic.cpp
+++ b/host/commands/cvd/server_command/generic.cpp
@@ -22,6 +22,7 @@
#include <mutex>
#include <android-base/file.h>
+#include <android-base/parseint.h>
#include <android-base/scopeguard.h>
#include "common/libs/fs/shared_buf.h"
@@ -35,6 +36,7 @@
#include "host/commands/cvd/command_sequence.h"
#include "host/commands/cvd/common_utils.h"
#include "host/commands/cvd/instance_manager.h"
+#include "host/commands/cvd/interruptible_terminal.h"
#include "host/commands/cvd/selector/selector_constants.h"
#include "host/commands/cvd/server_command/host_tool_target_manager.h"
#include "host/commands/cvd/server_command/server_handler.h"
@@ -67,12 +69,19 @@
std::vector<std::string> args;
cvd_common::Envs envs;
};
+ enum class UiResponseType : int {
+ kNoGroup = 1, // no group is active
+ kNoTTY = 2, // there are groups to select but no tty for user input
+ kUserSelection = 3, // selector couldn't pick so asked the user
+ kCvdServerPick = 4, // selector picks based on selector flags, env, etc
+ };
struct ExtractedInfo {
CommandInvocationInfo invocation_info;
std::optional<selector::LocalInstanceGroup> group;
bool is_non_help_cvd;
+ UiResponseType ui_response_type;
};
- Result<ExtractedInfo> ExtractInfo(const RequestWithStdio& request) const;
+ Result<ExtractedInfo> ExtractInfo(const RequestWithStdio& request);
Result<std::string> GetBin(const std::string& subcmd) const;
Result<std::string> GetBin(const std::string& subcmd,
const std::string& host_artifacts_path) const;
@@ -100,6 +109,7 @@
using BinGeneratorType = std::function<Result<std::string>(
const std::string& host_artifacts_path)>;
std::map<std::string, std::string> command_to_binary_map_;
+ std::unique_ptr<InterruptibleTerminal> terminal_ = nullptr;
static constexpr char kHostBugreportBin[] = "cvd_internal_host_bugreport";
static constexpr char kLnBin[] = "ln";
@@ -134,6 +144,13 @@
Result<void> CvdGenericCommandHandler::Interrupt() {
std::scoped_lock interrupt_lock(interruptible_);
interrupted_ = true;
+ if (terminal_) {
+ auto terminal_interrupt_result = terminal_->Interrupt();
+ // TODO(b/316202887): utilize the multi-CF_EXPECT feature
+ if (!terminal_interrupt_result.ok()) {
+ LOG(ERROR) << "Failed to interrupt terminal";
+ }
+ }
CF_EXPECT(subprocess_waiter_.Interrupt());
return {};
}
@@ -141,9 +158,7 @@
Result<cvd::Response> CvdGenericCommandHandler::Handle(
const RequestWithStdio& request) {
std::unique_lock interrupt_lock(interruptible_);
- if (interrupted_) {
- return CF_ERR("Interrupted");
- }
+ CF_EXPECT(!interrupted_, "Interrupted");
CF_EXPECT(CanHandle(request));
CF_EXPECT(request.Credentials() != std::nullopt);
const uid_t uid = request.Credentials()->uid;
@@ -158,17 +173,26 @@
precondition_verified.error().Message());
return response;
}
- auto [invocation_info, group_opt, is_non_help_cvd] =
+
+ interrupt_lock.unlock();
+ auto [invocation_info, group_opt, is_non_help_cvd, ui_response_type] =
CF_EXPECT(ExtractInfo(request));
+
+ interrupt_lock.lock();
+ CF_EXPECT(!interrupted_, "Interrupted");
if (invocation_info.bin == kClearBin) {
*response.mutable_status() =
instance_manager_.CvdClear(request.Out(), request.Err());
return response;
}
- if (is_non_help_cvd && !group_opt) {
+ // besides the two cases, the rest will be handled by running subprocesses
+ if (is_non_help_cvd && ui_response_type == UiResponseType::kNoGroup) {
return CF_EXPECT(NoGroupResponse(request));
}
+ if (is_non_help_cvd && ui_response_type == UiResponseType::kNoTTY) {
+ return CF_EXPECT(NoTTYResponse(request));
+ }
ConstructCommandParam construct_cmd_param{
.bin_path = invocation_info.bin_path,
@@ -278,7 +302,7 @@
*
*/
Result<CvdGenericCommandHandler::ExtractedInfo>
-CvdGenericCommandHandler::ExtractInfo(const RequestWithStdio& request) const {
+CvdGenericCommandHandler::ExtractInfo(const RequestWithStdio& request) {
auto result_opt = request.Credentials();
CF_EXPECT(result_opt != std::nullopt);
const uid_t uid = result_opt->uid;
@@ -311,18 +335,87 @@
.args = cmd_args,
.envs = envs},
.group = std::nullopt,
- .is_non_help_cvd = false};
+ .is_non_help_cvd = false,
+ .ui_response_type = UiResponseType::kCvdServerPick,
+ };
}
auto instance_group_result =
instance_manager_.SelectGroup(selector_args, envs, uid);
- ExtractedInfo extracted_info;
- extracted_info.is_non_help_cvd = true;
+ ExtractedInfo extracted_info{
+ .invocation_info = CommandInvocationInfo(),
+ .group = std::nullopt,
+ .is_non_help_cvd = true,
+ .ui_response_type = UiResponseType::kCvdServerPick,
+ };
+ std::string chosen_group_name;
if (!instance_group_result.ok()) {
- CF_EXPECT(!instance_manager_.HasInstanceGroups(uid),
- instance_group_result.error().FormatForEnv());
- return extracted_info;
+ if (!instance_manager_.HasInstanceGroups(uid)) {
+ extracted_info.ui_response_type = UiResponseType::kNoGroup;
+ return extracted_info;
+ }
+
+ if (!request.In()->IsOpen() || !request.In()->IsATTY()) {
+ // can't take the user input
+ extracted_info.ui_response_type = UiResponseType::kNoTTY;
+ return extracted_info;
+ }
+
+ extracted_info.ui_response_type = UiResponseType::kUserSelection;
+ std::unique_lock lock(interruptible_);
+ CF_EXPECT(!interrupted_, "Interrupted");
+ // show the menu and let the user choose
+ auto group_summaries = CF_EXPECT(instance_manager_.GroupSummaryMenu(uid));
+ auto& group_summary_menu = group_summaries.menu;
+ CF_EXPECT_EQ(WriteAll(request.Out(), group_summary_menu + "\n"),
+ group_summary_menu.size() + 1);
+ terminal_ = std::make_unique<InterruptibleTerminal>(request.In());
+ lock.unlock();
+
+ const bool is_tty = request.Err()->IsOpen() && request.Err()->IsATTY();
+ while (true) {
+ lock.lock();
+ std::string question = fmt::format(
+ "For which instance group would you like to run {}? ", subcmd);
+ CF_EXPECT_EQ(WriteAll(request.Out(), question), question.size());
+ lock.unlock();
+
+ std::string input_line = CF_EXPECT(terminal_->ReadLine());
+ int selection = -1;
+ if (android::base::ParseInt(input_line, &selection)) {
+ const auto n_groups = group_summaries.idx_to_group_name.size();
+ if (n_groups <= selection || selection < 0) {
+ std::string out_of_range = fmt::format(
+ "\n Selection {}{}{} is beyond the range {}[0, {}]{}\n\n",
+ TerminalColor(is_tty, TerminalColors::kBoldRed), selection,
+ TerminalColor(is_tty, TerminalColors::kReset),
+ TerminalColor(is_tty, TerminalColors::kCyan), n_groups - 1,
+ TerminalColor(is_tty, TerminalColors::kReset));
+ CF_EXPECT_EQ(WriteAll(request.Err(), out_of_range),
+ out_of_range.size());
+ continue;
+ }
+ chosen_group_name = group_summaries.idx_to_group_name[selection];
+ } else {
+ chosen_group_name = android::base::Trim(input_line);
+ }
+
+ InstanceManager::Queries extra_queries{
+ {selector::kGroupNameField, chosen_group_name}};
+ instance_group_result = instance_manager_.SelectGroup(
+ selector_args, extra_queries, envs, uid);
+ if (instance_group_result.ok()) {
+ break;
+ }
+ std::string cannot_find_group_name = fmt::format(
+ "\n Failed to find a group whose name is {}\"{}\"{}\n\n",
+ TerminalColor(is_tty, TerminalColors::kBoldRed), chosen_group_name,
+ TerminalColor(is_tty, TerminalColors::kReset));
+ CF_EXPECT_EQ(WriteAll(request.Err(), cannot_find_group_name),
+ cannot_find_group_name.size());
+ }
}
+
auto& instance_group = *instance_group_result;
auto android_host_out = instance_group.HostArtifactsPath();
auto home = instance_group.HomeDir();
diff --git a/host/commands/cvd/server_command/handler_proxy.cpp b/host/commands/cvd/server_command/handler_proxy.cpp
index 7d6bc78..7747ac6 100644
--- a/host/commands/cvd/server_command/handler_proxy.cpp
+++ b/host/commands/cvd/server_command/handler_proxy.cpp
@@ -97,11 +97,20 @@
interrupt_lock.unlock();
SharedFD dev_null = SharedFD::Open("/dev/null", O_RDWR);
CF_EXPECT(dev_null->IsOpen(), "Failed to open /dev/null");
- const auto responses =
- CF_EXPECT(executor_.Execute({std::move(forwarded_request)}, dev_null));
- CF_EXPECT_EQ(responses.size(), 1);
- // TODO(moelsherif): check the response for failed command
- return responses.front();
+
+ cvd::Response response;
+ auto invocation_args =
+ ParseInvocation(forwarded_request.Message()).arguments;
+ auto handler = CF_EXPECT(executor_.GetHandler(forwarded_request));
+ if (CF_EXPECT(IsHelpSubcmd(invocation_args)) &&
+ handler->ShouldInterceptHelp()) {
+ std::string output =
+ CF_EXPECT(handler->DetailedHelp(invocation_args)) + "\n";
+ response = CF_EXPECT(WriteToFd(forwarded_request.Out(), output));
+ } else {
+ response = CF_EXPECT(executor_.ExecuteOne(forwarded_request, dev_null));
+ }
+ return response;
}
Result<void> Interrupt() override {
diff --git a/host/commands/cvd/server_command/help.cpp b/host/commands/cvd/server_command/help.cpp
index b98303a..dad5b32 100644
--- a/host/commands/cvd/server_command/help.cpp
+++ b/host/commands/cvd/server_command/help.cpp
@@ -16,17 +16,31 @@
#include "host/commands/cvd/server_command/help.h"
+#include <fcntl.h>
+
+#include <memory>
#include <mutex>
+#include <ostream>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include <android-base/strings.h>
#include "common/libs/fs/shared_buf.h"
+#include "common/libs/fs/shared_fd.h"
+#include "common/libs/utils/result.h"
+#include "cvd_server.pb.h"
#include "host/commands/cvd/command_sequence.h"
+#include "host/commands/cvd/request_context.h"
#include "host/commands/cvd/server.h"
#include "host/commands/cvd/server_command/utils.h"
#include "host/commands/cvd/types.h"
namespace cuttlefish {
+namespace {
-static constexpr char kHelpMessage[] = R"(Cuttlefish Virtual Device (CVD) CLI.
+constexpr char kHelpIntroText[] = R"(Cuttlefish Virtual Device (CVD) CLI.
usage: cvd <selector/driver options> <command> <args>
@@ -45,39 +59,27 @@
-acquire_file_lock If the flag is given, the cvd server attempts to
acquire the instance lock file lock. (default: true)
-Commands:
- help Print this message.
- help <command> Print help for a command.
- start Start a device.
- stop Stop a running device.
- clear Stop all running devices and delete all instance and
- assembly directories.
- fleet View the current fleet status.
- kill-server Kill the cvd_server background process.
- server-kill Same as kill-server
- powerwash Delivers powerwash command to the selected device
- restart Restart the device without reinitializing the disks
- restart-server Restart the cvd_server background process.
- status Check and print the state of a running instance.
- env Control the environment of running instances like wifi
- or geolocation.
- host_bugreport Capture a host bugreport, including configs, logs, and
- tombstones.
+Commands (cvd help <command> for more information):)";
-Args:
- <command args> Each command has its own set of args.
- See cvd help <command>.
+constexpr char kSummaryHelpText[] =
+ "Used to display help information for other commands";
-Experimental:
- reset See cvd reset --help. Requires cvd >= v1.2
- snapshot_take cvd snapshot_take --help. Requires crosvm, cvd >= v1.4
- suspend cvd suspend --help. Requires crosvm, cvd >= v1.4
- resume cvd resume --help. Requires crosvm, cvd >= v1.4
+constexpr char kDetailedHelpText[] =
+ R"(cvd help - used to display help text for cvd and its commands
+
+Example usage:
+ cvd help - displays summary help for available commands
+
+ cvd help <command> - displays more detailed help for the specific command
)";
+} // namespace
+
class CvdHelpHandler : public CvdServerHandler {
public:
- CvdHelpHandler(CommandSequenceExecutor& executor) : executor_(executor) {}
+ CvdHelpHandler(
+ const std::vector<std::unique_ptr<CvdServerHandler>>& request_handlers)
+ : request_handlers_(request_handlers) {}
Result<bool> CanHandle(const RequestWithStdio& request) const override {
auto invocation = ParseInvocation(request.Message());
@@ -89,81 +91,85 @@
if (interrupted_) {
return CF_ERR("Interrupted");
}
-
- cvd::Response response;
- response.mutable_command_response(); // Sets oneof member
- response.mutable_status()->set_code(cvd::Status::OK);
-
CF_EXPECT(CanHandle(request));
- auto [subcmd, subcmd_args] = ParseInvocation(request.Message());
- const auto supported_subcmd_list = executor_.CmdList();
-
- /*
- * cvd help, cvd help invalid_token, cvd help help
- */
- if (subcmd_args.empty() ||
- !Contains(supported_subcmd_list, subcmd_args.front()) ||
- subcmd_args.front() == "help") {
- WriteAll(request.Out(), kHelpMessage);
- return response;
+ std::string output;
+ auto args = ParseInvocation(request.Message()).arguments;
+ if (args.empty()) {
+ output = CF_EXPECT(TopLevelHelp());
+ } else {
+ output = CF_EXPECT(SubCommandHelp(args));
}
-
- cvd::Request modified_proto = HelpSubcommandToFlag(request);
-
- RequestWithStdio inner_cmd(request.Client(), modified_proto,
- request.FileDescriptors(),
- request.Credentials());
-
+ auto response = CF_EXPECT(WriteToFd(request.Out(), output));
interrupt_lock.unlock();
- CF_EXPECT(
- executor_.Execute({inner_cmd}, SharedFD::Open("/dev/null", O_RDWR)));
-
return response;
}
Result<void> Interrupt() override {
std::scoped_lock interrupt_lock(interruptible_);
interrupted_ = true;
- CF_EXPECT(executor_.Interrupt());
return {};
}
cvd_common::Args CmdList() const override { return {"help"}; }
+ Result<std::string> SummaryHelp() const override { return kSummaryHelpText; }
+
+ bool ShouldInterceptHelp() const override { return true; }
+
+ Result<std::string> DetailedHelp(std::vector<std::string>&) const override {
+ return kDetailedHelpText;
+ }
+
private:
- cvd::Request HelpSubcommandToFlag(const RequestWithStdio& request);
+ Result<RequestWithStdio> GetLookupRequest(const std::string& arg) {
+ cvd::Request lookup;
+ auto& lookup_cmd = *lookup.mutable_command_request();
+ lookup_cmd.add_args("cvd");
+ lookup_cmd.add_args(arg);
+ auto dev_null = SharedFD::Open("/dev/null", O_RDWR);
+ CF_EXPECT(dev_null->IsOpen(), dev_null->StrError());
+ return RequestWithStdio(dev_null, lookup, {dev_null, dev_null, dev_null},
+ {});
+ }
+
+ Result<std::string> TopLevelHelp() {
+ std::stringstream help_message;
+ help_message << kHelpIntroText << std::endl;
+ for (const auto& handler : request_handlers_) {
+ std::string command_list = android::base::Join(handler->CmdList(), ", ");
+ // exclude commands without any command list values as not intended for
+ // use by users or sub-subcommands
+ if (!command_list.empty()) {
+ help_message << "\t" << command_list << " - ";
+ help_message << CF_EXPECT(handler->SummaryHelp()) << std::endl
+ << std::endl;
+ }
+ }
+ return help_message.str();
+ }
+
+ Result<std::string> SubCommandHelp(std::vector<std::string>& args) {
+ CF_EXPECT(
+ !args.empty(),
+ "Cannot process subcommand help without valid subcommand argument");
+ auto lookup_request = CF_EXPECT(GetLookupRequest(args.front()));
+ auto handler = CF_EXPECT(RequestHandler(lookup_request, request_handlers_));
+
+ std::stringstream help_message;
+ help_message << CF_EXPECT(handler->DetailedHelp(args)) << std::endl;
+ return help_message.str();
+ }
std::mutex interruptible_;
bool interrupted_ = false;
- CommandSequenceExecutor& executor_;
+ const std::vector<std::unique_ptr<CvdServerHandler>>& request_handlers_;
};
-cvd::Request CvdHelpHandler::HelpSubcommandToFlag(
- const RequestWithStdio& request) {
- cvd::Request modified_proto = request.Message();
- auto all_args =
- cvd_common::ConvertToArgs(modified_proto.command_request().args());
- auto& args = *modified_proto.mutable_command_request()->mutable_args();
- args.Clear();
- // there must be one or more "help" in all_args
- // delete the first "help"
- bool found_help = false;
- for (const auto& cmd_arg : all_args) {
- if (cmd_arg != "help" || found_help) {
- args.Add(cmd_arg.c_str());
- continue;
- }
- // skip first help
- found_help = true;
- }
- args.Add("--help");
- return modified_proto;
-}
-
std::unique_ptr<CvdServerHandler> NewCvdHelpHandler(
- CommandSequenceExecutor& executor) {
- return std::unique_ptr<CvdServerHandler>(new CvdHelpHandler(executor));
+ const std::vector<std::unique_ptr<CvdServerHandler>>& request_handlers) {
+ return std::unique_ptr<CvdServerHandler>(
+ new CvdHelpHandler(request_handlers));
}
} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/help.h b/host/commands/cvd/server_command/help.h
index 28014b2..38085b3 100644
--- a/host/commands/cvd/server_command/help.h
+++ b/host/commands/cvd/server_command/help.h
@@ -17,13 +17,12 @@
#pragma once
#include <memory>
+#include <vector>
-#include "host/commands/cvd/command_sequence.h"
#include "host/commands/cvd/server_command/server_handler.h"
namespace cuttlefish {
std::unique_ptr<CvdServerHandler> NewCvdHelpHandler(
- CommandSequenceExecutor& executor);
-
+ const std::vector<std::unique_ptr<CvdServerHandler>>& server_handlers);
}
diff --git a/host/commands/cvd/server_command/host_tool_target_manager.cpp b/host/commands/cvd/server_command/host_tool_target_manager.cpp
index 9f85b8f..b8ceb6b 100644
--- a/host/commands/cvd/server_command/host_tool_target_manager.cpp
+++ b/host/commands/cvd/server_command/host_tool_target_manager.cpp
@@ -63,7 +63,7 @@
if (!host_target.IsDirty()) {
return {};
}
- LOG(ERROR) << artifacts_path << " is new, so updating HostToolTarget";
+ LOG(INFO) << artifacts_path << " is new, so updating HostToolTarget";
host_target_table_.erase(artifacts_path);
HostToolTarget new_host_tool_target =
CF_EXPECT(HostToolTarget::Create(artifacts_path));
diff --git a/host/commands/cvd/server_command/lint.cpp b/host/commands/cvd/server_command/lint.cpp
new file mode 100644
index 0000000..716f0ca
--- /dev/null
+++ b/host/commands/cvd/server_command/lint.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2023 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 "host/commands/cvd/server_command/lint.h"
+
+#include <iostream>
+#include <memory>
+#include <sstream>
+#include <string>
+#include <string_view>
+#include <vector>
+
+#include <json/json.h>
+
+#include "common/libs/fs/shared_buf.h"
+#include "common/libs/utils/result.h"
+#include "host/commands/cvd/command_sequence.h"
+#include "host/commands/cvd/common_utils.h"
+#include "host/commands/cvd/parser/load_configs_parser.h"
+#include "host/commands/cvd/selector/selector_constants.h"
+#include "host/commands/cvd/server_client.h"
+#include "host/commands/cvd/server_command/server_handler.h"
+#include "host/commands/cvd/server_command/utils.h"
+#include "host/commands/cvd/types.h"
+
+namespace cuttlefish {
+
+class LintCommandHandler : public CvdServerHandler {
+ public:
+ LintCommandHandler() {}
+
+ Result<bool> CanHandle(const RequestWithStdio& request) const {
+ auto invocation = ParseInvocation(request.Message());
+ return invocation.command == kLintSubCmd;
+ }
+
+ Result<cvd::Response> Handle(const RequestWithStdio& request) override {
+ CF_EXPECT(CanHandle(request));
+
+ auto args = ParseInvocation(request.Message()).arguments;
+ auto working_directory =
+ request.Message().command_request().working_directory();
+ const auto config_path = CF_EXPECT(ValidateConfig(args, working_directory));
+
+ std::stringstream message_stream;
+ message_stream << "Lint of flags and config \"" << config_path
+ << "\" succeeded\n";
+ const auto message = message_stream.str();
+ CF_EXPECT_EQ(WriteAll(request.Out(), message), message.size(),
+ "Error writing message");
+ cvd::Response response;
+ response.mutable_command_response();
+ response.mutable_status()->set_code(cvd::Status::OK);
+ return response;
+ }
+
+ Result<void> Interrupt() override { return CF_ERR("Can't interrupt"); }
+
+ cvd_common::Args CmdList() const override { return {kLintSubCmd}; }
+
+ private:
+ Result<std::string> ValidateConfig(std::vector<std::string>& args,
+ const std::string& working_directory) {
+ const LoadFlags flags = CF_EXPECT(GetFlags(args, working_directory));
+ CF_EXPECT(GetCvdFlags(flags));
+ return flags.config_path;
+ }
+
+ static constexpr char kLintSubCmd[] = "lint";
+};
+
+std::unique_ptr<CvdServerHandler> NewLintCommand() {
+ return std::unique_ptr<CvdServerHandler>(new LintCommandHandler());
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/lint.h b/host/commands/cvd/server_command/lint.h
new file mode 100644
index 0000000..a860e49
--- /dev/null
+++ b/host/commands/cvd/server_command/lint.h
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2023 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 <memory>
+
+#include "host/commands/cvd/server_command/server_handler.h"
+
+namespace cuttlefish {
+
+std::unique_ptr<CvdServerHandler> NewLintCommand();
+
+} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/load_configs.cpp b/host/commands/cvd/server_command/load_configs.cpp
index 2863b9a..2707b60 100644
--- a/host/commands/cvd/server_command/load_configs.cpp
+++ b/host/commands/cvd/server_command/load_configs.cpp
@@ -35,6 +35,25 @@
#include "host/commands/cvd/types.h"
namespace cuttlefish {
+namespace {
+
+constexpr char kSummaryHelpText[] =
+ R"(Loads the given JSON configuration file and launches devices based on the options provided)";
+
+constexpr char kDetailedHelpText[] = R"(
+Warning: This command is deprecated, use cvd start --config_file instead.
+
+Usage:
+cvd load <config_filepath> [--override=<key>:<value>]
+
+Reads the fields in the JSON configuration file and translates them to corresponding start command and flags.
+
+Optionally fetches remote artifacts prior to launching the cuttlefish environment.
+
+The --override flag can be used to give new values for properties in the config file without needing to edit the file directly. Convenient for one-off invocations.
+)";
+
+} // namespace
class LoadConfigsCommand : public CvdServerHandler {
public:
@@ -69,40 +88,24 @@
cvd_common::Args CmdList() const override { return {kLoadSubCmd}; }
+ Result<std::string> SummaryHelp() const override { return kSummaryHelpText; }
+
+ bool ShouldInterceptHelp() const override { return true; }
+
+ Result<std::string> DetailedHelp(std::vector<std::string>&) const override {
+ return kDetailedHelpText;
+ }
+
Result<std::vector<RequestWithStdio>> CreateCommandSequence(
const RequestWithStdio& request) {
auto args = ParseInvocation(request.Message()).arguments;
auto working_directory =
request.Message().command_request().working_directory();
const LoadFlags flags = CF_EXPECT(GetFlags(args, working_directory));
-
- if (flags.help) {
- std::stringstream help_msg_stream;
- help_msg_stream << "Usage: cvd " << kLoadSubCmd << "\n";
- const auto help_msg = help_msg_stream.str();
- CF_EXPECT(WriteAll(request.Out(), help_msg) == help_msg.size());
- return {};
- }
-
- Json::Value json_configs =
- CF_EXPECT(GetOverriddenConfig(flags.config_path, flags.overrides));
-
- Result<std::vector<std::string>> system_image_path_configs =
- CF_EXPECT(GetConfiguredSystemImagePaths(json_configs));
-
- std::optional<std::string> host_package_dir =
- GetConfiguredSystemHostPath(json_configs);
-
- const auto& client_env = request.Message().command_request().env();
-
- const auto load_directories = CF_EXPECT(GenerateLoadDirectories(
- flags.base_dir, *system_image_path_configs, host_package_dir,
- json_configs["instances"].size()));
-
- auto cvd_flags = CF_EXPECT(ParseCvdConfigs(json_configs, load_directories),
- "parsing json configs failed");
+ auto cvd_flags = CF_EXPECT(GetCvdFlags(flags));
std::vector<cvd::Request> req_protos;
+ const auto& client_env = request.Message().command_request().env();
if (!cvd_flags.fetch_cvd_flags.empty()) {
auto& fetch_cmd = *req_protos.emplace_back().mutable_command_request();
@@ -119,17 +122,18 @@
mkdir_cmd.add_args("cvd");
mkdir_cmd.add_args("mkdir");
mkdir_cmd.add_args("-p");
- mkdir_cmd.add_args(load_directories.launch_home_directory);
+ mkdir_cmd.add_args(cvd_flags.load_directories.launch_home_directory);
auto& launch_cmd = *req_protos.emplace_back().mutable_command_request();
- launch_cmd.set_working_directory(load_directories.host_package_directory);
+ launch_cmd.set_working_directory(
+ cvd_flags.load_directories.host_package_directory);
*launch_cmd.mutable_env() = client_env;
(*launch_cmd.mutable_env())["HOME"] =
- load_directories.launch_home_directory;
+ cvd_flags.load_directories.launch_home_directory;
(*launch_cmd.mutable_env())[kAndroidHostOut] =
- load_directories.host_package_directory;
+ cvd_flags.load_directories.host_package_directory;
(*launch_cmd.mutable_env())[kAndroidSoongHostOut] =
- load_directories.host_package_directory;
+ cvd_flags.load_directories.host_package_directory;
if (Contains(*launch_cmd.mutable_env(), kAndroidProductOut)) {
(*launch_cmd.mutable_env()).erase(kAndroidProductOut);
}
@@ -145,7 +149,7 @@
launch_cmd.add_args(parsed_flag);
}
// Add system flag for multi-build scenario
- launch_cmd.add_args(load_directories.system_image_directory_flag);
+ launch_cmd.add_args(cvd_flags.load_directories.system_image_directory_flag);
auto selector_opts = launch_cmd.mutable_selector_opts();
diff --git a/host/commands/cvd/server_command/server_handler.h b/host/commands/cvd/server_command/server_handler.h
index 4d327f5..ec523fa 100644
--- a/host/commands/cvd/server_command/server_handler.h
+++ b/host/commands/cvd/server_command/server_handler.h
@@ -16,6 +16,9 @@
#pragma once
+#include <string>
+#include <vector>
+
#include "common/libs/utils/result.h"
#include "host/commands/cvd/server_client.h"
#include "host/commands/cvd/types.h"
@@ -31,6 +34,14 @@
virtual Result<void> Interrupt() = 0;
// returns the list of subcommand it can handle
virtual cvd_common::Args CmdList() const = 0;
+ // TODO make pure virtual once every implementation has overrides
+ virtual Result<std::string> SummaryHelp() const {
+ return "Consider contributing a CL with help text if you read this :)";
+ }
+ virtual bool ShouldInterceptHelp() const { return false; }
+ virtual Result<std::string> DetailedHelp(std::vector<std::string>&) const {
+ return "Consider contributing a CL with help text if you read this :)";
+ }
};
} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/start.cpp b/host/commands/cvd/server_command/start.cpp
index 871301c..6ca849b 100644
--- a/host/commands/cvd/server_command/start.cpp
+++ b/host/commands/cvd/server_command/start.cpp
@@ -18,6 +18,7 @@
#include <sys/types.h>
+#include <algorithm>
#include <array>
#include <atomic>
#include <cstdint>
@@ -81,6 +82,23 @@
request.FileDescriptors(), request.Credentials());
}
+// link might be a directory, so we clean that up, and create a link from
+// target to link
+Result<void> EnsureSymlink(const std::string& target, const std::string link) {
+ if (DirectoryExists(link, /* follow_symlinks */ false)) {
+ CF_EXPECTF(RecursivelyRemoveDirectory(link),
+ "Failed to remove legacy directory \"{}\"", link);
+ }
+ if (FileExists(link, /* follow_symlinks */ false)) {
+ CF_EXPECTF(RemoveFile(link), "Failed to remove file \"{}\": {}", link,
+ std::strerror(errno));
+ }
+ CF_EXPECTF(symlink(target.c_str(), link.c_str()) == 0,
+ "symlink(\"{}\", \"{}\") failed: {}", target, link,
+ std::strerror(errno));
+ return {};
+}
+
} // namespace
class CvdStartCommandHandler : public CvdServerHandler {
@@ -470,7 +488,7 @@
}
}
ss << " " << bin << " " << args;
- LOG(ERROR) << "launcher command: " << ss.str();
+ LOG(INFO) << "launcher command: " << ss.str();
}
static void ShowLaunchCommand(const std::string& bin,
@@ -527,63 +545,33 @@
// when HOME is NOT overridden and selector flags are NOT given.
Result<void> CvdStartCommandHandler::CreateSymlinks(
const selector::GroupCreationInfo& group_creation_info) {
- std::string instance_home_dir = "";
+ CF_EXPECT(EnsureDirectoryExists(group_creation_info.home));
auto system_wide_home = CF_EXPECT(SystemWideUserHome());
+ auto smallest_id = std::numeric_limits<unsigned>::max();
for (const auto& instance : group_creation_info.instances) {
- std::string legacy_path = system_wide_home + "/cuttlefish_runtime.";
- legacy_path = ConcatToString(legacy_path, instance.instance_id_);
- instance_home_dir = group_creation_info.home;
- instance_home_dir = instance_home_dir + "/cuttlefish/instances/cvd-";
- instance_home_dir = ConcatToString(instance_home_dir, instance.instance_id_);
- if (DirectoryExists(legacy_path, /* follow_symlinks */ true)) {
- CF_EXPECT(RecursivelyRemoveDirectory(legacy_path),
- "Failed to remove legacy directory " << legacy_path);
- }
- if (symlink(instance_home_dir.c_str(), legacy_path.c_str())) {
- return CF_ERRNO("symlink(\"" << instance_home_dir << "\", \""
- << legacy_path << "\") failed");
- }
- legacy_path = system_wide_home + "/cuttlefish_runtime";
- if (DirectoryExists(legacy_path, true)) {
- CF_EXPECT(RecursivelyRemoveDirectory(legacy_path),
- "Failed to remove legacy directory " << legacy_path);
- }
- if (symlink(instance_home_dir.c_str(), legacy_path.c_str())) {
- return CF_ERRNO("symlink(\"" << instance_home_dir << "\", \""
- << legacy_path << "\") failed");
- }
- std::string cuttlefish_path = group_creation_info.home + "/cuttlefish/";
- legacy_path = system_wide_home + "/cuttlefish";
- if (DirectoryExists(legacy_path, true)) {
- CF_EXPECT(RecursivelyRemoveDirectory(legacy_path),
- "Failed to remove legacy directory " << legacy_path);
- }
- if (symlink(cuttlefish_path.c_str(), legacy_path.c_str())) {
- return CF_ERRNO("symlink(\"" << cuttlefish_path << "\", \"" << legacy_path
- << "\") failed");
- }
- std::string cuttlefish_assembly_path = cuttlefish_path + "assembly/";
- legacy_path = system_wide_home + "/cuttlefish_assembly";
- if (DirectoryExists(legacy_path, true)) {
- CF_EXPECT(RecursivelyRemoveDirectory(legacy_path),
- "Failed to remove legacy directory " << legacy_path);
- }
- if (symlink(cuttlefish_assembly_path.c_str(), legacy_path.c_str())) {
- return CF_ERRNO("symlink(\"" << cuttlefish_assembly_path << "\", \""
- << legacy_path << "\") failed");
- }
- std::string config_path =
- cuttlefish_assembly_path + "cuttlefish_config.json";
- legacy_path = system_wide_home + "/.cuttlefish_config.json";
- if (FileExists(legacy_path, false)) {
- CF_EXPECT(RemoveFile(legacy_path),
- "Failed to remove instance_dir symlink " << legacy_path);
- }
- if (symlink(config_path.c_str(), legacy_path.c_str())) {
- return CF_ERRNO("symlink(\"" << config_path << "\", \"" << legacy_path
- << "\") failed");
- }
+ // later on, we link cuttlefish_runtime to cuttlefish_runtime.smallest_id
+ smallest_id = std::min(smallest_id, instance.instance_id_);
+ const std::string instance_home_dir =
+ fmt::format("{}/cuttlefish/instances/cvd-{}", group_creation_info.home,
+ instance.instance_id_);
+ CF_EXPECT(
+ EnsureSymlink(instance_home_dir,
+ fmt::format("{}/cuttlefish_runtime.{}", system_wide_home,
+ instance.instance_id_)));
+ CF_EXPECT(EnsureSymlink(group_creation_info.home + "/cuttlefish",
+ system_wide_home + "/cuttlefish"));
+ CF_EXPECT(EnsureSymlink(group_creation_info.home +
+ "/cuttlefish/assembly/cuttlefish_config.json",
+ system_wide_home + "/.cuttlefish_config.json"));
}
+
+ // create cuttlefish_runtime to cuttlefish_runtime.id
+ CF_EXPECT_NE(std::numeric_limits<unsigned>::max(), smallest_id,
+ "The group did not have any instance, which is not expected.");
+ const std::string instance_runtime_dir =
+ fmt::format("{}/cuttlefish_runtime.{}", system_wide_home, smallest_id);
+ const std::string runtime_dir_link = system_wide_home + "/cuttlefish_runtime";
+ CF_EXPECT(EnsureSymlink(instance_runtime_dir, runtime_dir_link));
return {};
}
diff --git a/host/commands/cvd/server_command/status.cpp b/host/commands/cvd/server_command/status.cpp
index 9655264..7e0eda2 100644
--- a/host/commands/cvd/server_command/status.cpp
+++ b/host/commands/cvd/server_command/status.cpp
@@ -202,6 +202,10 @@
return HandleHelp(request);
}
+ const auto uid = CF_EXPECT(request.Credentials()).uid;
+ if (instance_manager_.AllGroupNames(uid).empty()) {
+ return CF_EXPECT(NoGroupResponse(request));
+ }
RequestWithStdio new_request = CF_EXPECT(ProcessInstanceNameFlag(request));
auto [entire_stderr_msg, instances_json, response] =
diff --git a/host/commands/cvd/server_command/utils.cpp b/host/commands/cvd/server_command/utils.cpp
index cf6566e..b1697b8 100644
--- a/host/commands/cvd/server_command/utils.cpp
+++ b/host/commands/cvd/server_command/utils.cpp
@@ -19,6 +19,7 @@
#include <fmt/core.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/files.h"
#include "common/libs/utils/flag_parser.h"
@@ -211,20 +212,77 @@
static constexpr char kTerminalRed[] = "\033[0;31m";
static constexpr char kTerminalReset[] = "\033[0m";
+std::string TerminalColor(const bool is_tty, TerminalColors color) {
+ if (!is_tty) {
+ return "";
+ }
+ switch (color) {
+ case TerminalColors::kReset: {
+ return kTerminalReset;
+ }
+ case TerminalColors::kBoldRed: {
+ return kTerminalBoldRed;
+ }
+ case TerminalColors::kCyan: {
+ return kTerminalCyan;
+ }
+ case TerminalColors::kRed: {
+ return kTerminalRed;
+ }
+ default:
+ return kTerminalReset;
+ }
+}
+
Result<cvd::Response> NoGroupResponse(const RequestWithStdio& request) {
cvd::Response response;
response.mutable_command_response();
response.mutable_status()->set_code(cvd::Status::OK);
const uid_t uid = CF_EXPECT(request.Credentials()).uid;
+ const bool is_tty = request.Out()->IsOpen() && request.Out()->IsATTY();
auto notice = fmt::format(
- "Command `{}{}{}` is not applicable: {}{}{} (uid: '{}{}{}')",
- kTerminalRed, fmt::join(request.Message().command_request().args(), " "),
- kTerminalReset, kTerminalBoldRed, "no device", kTerminalReset,
- kTerminalCyan, uid, kTerminalReset);
+ "Command `{}{}{}` is not applicable:\n {}{}{} (uid: '{}{}{}')",
+ TerminalColor(is_tty, TerminalColors::kRed),
+ fmt::join(request.Message().command_request().args(), " "),
+ TerminalColor(is_tty, TerminalColors::kReset),
+ TerminalColor(is_tty, TerminalColors::kBoldRed), "no device",
+ TerminalColor(is_tty, TerminalColors::kReset),
+ TerminalColor(is_tty, TerminalColors::kCyan), uid,
+ TerminalColor(is_tty, TerminalColors::kReset));
CF_EXPECT_EQ(WriteAll(request.Out(), notice + "\n"), notice.size() + 1);
response.mutable_status()->set_message(notice);
return response;
}
+Result<cvd::Response> NoTTYResponse(const RequestWithStdio& request) {
+ cvd::Response response;
+ response.mutable_command_response();
+ response.mutable_status()->set_code(cvd::Status::OK);
+ const uid_t uid = CF_EXPECT(request.Credentials()).uid;
+ const bool is_tty = request.Out()->IsOpen() && request.Out()->IsATTY();
+ auto notice = fmt::format(
+ "Command `{}{}{}` is not applicable:\n {}{}{} (uid: '{}{}{}')",
+ TerminalColor(is_tty, TerminalColors::kRed),
+ fmt::join(request.Message().command_request().args(), " "),
+ TerminalColor(is_tty, TerminalColors::kReset),
+ TerminalColor(is_tty, TerminalColors::kBoldRed),
+ "No terminal/tty for selecting one of multiple Cuttlefish groups",
+ TerminalColor(is_tty, TerminalColors::kReset),
+ TerminalColor(is_tty, TerminalColors::kCyan), uid,
+ TerminalColor(is_tty, TerminalColors::kReset));
+ CF_EXPECT_EQ(WriteAll(request.Out(), notice + "\n"), notice.size() + 1);
+ response.mutable_status()->set_message(notice);
+ return response;
+}
+
+Result<cvd::Response> WriteToFd(SharedFD fd, const std::string& output) {
+ cvd::Response response;
+ auto written_size = WriteAll(fd, output);
+ CF_EXPECT_EQ(output.size(), written_size, fd->StrError());
+ response.mutable_command_response(); // Sets oneof member
+ response.mutable_status()->set_code(cvd::Status::OK);
+ return response;
+}
+
} // namespace cuttlefish
diff --git a/host/commands/cvd/server_command/utils.h b/host/commands/cvd/server_command/utils.h
index 9052d5c..8da9a43 100644
--- a/host/commands/cvd/server_command/utils.h
+++ b/host/commands/cvd/server_command/utils.h
@@ -25,6 +25,7 @@
#include "cvd_server.pb.h"
+#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/result.h"
#include "common/libs/utils/subprocess.h"
#include "host/commands/cvd/server_client.h"
@@ -81,4 +82,19 @@
// The function does not verify that.
Result<cvd::Response> NoGroupResponse(const RequestWithStdio& request);
+// Call this when there is more than one group, which the selector flags are
+// not sufficients to choose one from. The function does not verify that.
+Result<cvd::Response> NoTTYResponse(const RequestWithStdio& request);
+
+enum class TerminalColors : int {
+ kReset = 0,
+ kBoldRed = 1,
+ kCyan = 2,
+ kRed = 3,
+};
+
+std::string TerminalColor(const bool is_tty, TerminalColors color);
+
+Result<cvd::Response> WriteToFd(SharedFD fd, const std::string& output);
+
} // namespace cuttlefish
diff --git a/host/commands/run_cvd/Android.bp b/host/commands/run_cvd/Android.bp
index a358b04..75f072b 100644
--- a/host/commands/run_cvd/Android.bp
+++ b/host/commands/run_cvd/Android.bp
@@ -40,6 +40,7 @@
"launch/root_canal.cpp",
"launch/casimir.cpp",
"launch/pica.cpp",
+ "launch/screen_recording_server.cpp",
"launch/secure_env.cpp",
"launch/secure_env_files.cpp",
"launch/webrtc_recorder.cpp",
diff --git a/host/commands/run_cvd/launch/launch.h b/host/commands/run_cvd/launch/launch.h
index a78dde9..8d17311 100644
--- a/host/commands/run_cvd/launch/launch.h
+++ b/host/commands/run_cvd/launch/launch.h
@@ -109,6 +109,8 @@
const CuttlefishConfig::InstanceSpecific>>
NetsimServerComponent();
+Result<std::optional<MonitorCommand>> ScreenRecordingServer(GrpcSocketCreator&);
+
Result<MonitorCommand> SecureEnv(const CuttlefishConfig&,
const CuttlefishConfig::InstanceSpecific&,
AutoSecureEnvFiles::Type&,
diff --git a/host/commands/run_cvd/launch/screen_recording_server.cpp b/host/commands/run_cvd/launch/screen_recording_server.cpp
new file mode 100644
index 0000000..7848784
--- /dev/null
+++ b/host/commands/run_cvd/launch/screen_recording_server.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2023 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 "host/commands/run_cvd/launch/launch.h"
+
+#include <string>
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+#include <fruit/fruit.h>
+
+#include "common/libs/utils/files.h"
+#include "common/libs/utils/result.h"
+#include "host/commands/run_cvd/launch/grpc_socket_creator.h"
+#include "host/libs/config/command_source.h"
+#include "host/libs/config/known_paths.h"
+
+namespace cuttlefish {
+
+Result<std::optional<MonitorCommand>> ScreenRecordingServer(
+ GrpcSocketCreator& grpc_socket) {
+ Command screen_recording_server_cmd(ScreenRecordingServerBinary());
+ screen_recording_server_cmd.AddParameter(
+ "-grpc_uds_path=", grpc_socket.CreateGrpcSocket("ScreenRecordingServer"));
+ return screen_recording_server_cmd;
+}
+
+} // namespace cuttlefish
diff --git a/host/commands/run_cvd/main.cc b/host/commands/run_cvd/main.cc
index 015b91f..d8db441 100644
--- a/host/commands/run_cvd/main.cc
+++ b/host/commands/run_cvd/main.cc
@@ -140,6 +140,7 @@
.install(FastbootConfigFragmentComponent)
.install(bootStateMachineComponent)
.install(AutoCmd<CasimirControlServer>::Component)
+ .install(AutoCmd<ScreenRecordingServer>::Component)
.install(ConfigFlagPlaceholder)
.install(CustomActionsComponent)
.install(LaunchAdbComponent)
@@ -253,7 +254,9 @@
CF_EXPECT(late_injected->LateInject(injector));
}
- MetricsReceiver::LogMetricsVMStart();
+ if (config->enable_metrics() == cuttlefish::CuttlefishConfig::Answer::kYes) {
+ MetricsReceiver::LogMetricsVMStart();
+ }
auto instance_bindings = injector.getMultibindings<InstanceLifecycle>();
CF_EXPECT(instance_bindings.size() == 1);
diff --git a/host/commands/run_cvd/server_loop_impl.cpp b/host/commands/run_cvd/server_loop_impl.cpp
index 985f102..825cd88 100644
--- a/host/commands/run_cvd/server_loop_impl.cpp
+++ b/host/commands/run_cvd/server_loop_impl.cpp
@@ -227,10 +227,8 @@
client->Write(&response, sizeof(response));
break;
}
- auto powerwash = PowerwashFiles();
- if (!powerwash.ok()) {
- LOG(ERROR) << "Powerwashing files failed:\n"
- << powerwash.error().FormatForEnv();
+ if (!PowerwashFiles()) {
+ LOG(ERROR) << "Powerwashing files failed.";
auto response = LauncherResponse::kError;
client->Write(&response, sizeof(response));
break;
@@ -309,7 +307,7 @@
}
}
-Result<void> ServerLoopImpl::PowerwashFiles() {
+bool ServerLoopImpl::PowerwashFiles() {
DeleteFifos();
// TODO(b/269669405): Figure out why this file is not being deleted
@@ -320,15 +318,15 @@
auto kregistry_path = instance_.access_kregistry_path();
unlink(kregistry_path.c_str());
- CF_EXPECT(CreateBlankImage(kregistry_path, 2 /* mb */, "none"));
+ CreateBlankImage(kregistry_path, 2 /* mb */, "none");
auto hwcomposer_pmem_path = instance_.hwcomposer_pmem_path();
unlink(hwcomposer_pmem_path.c_str());
- CF_EXPECT(CreateBlankImage(hwcomposer_pmem_path, 2 /* mb */, "none"));
+ CreateBlankImage(hwcomposer_pmem_path, 2 /* mb */, "none");
auto pstore_path = instance_.pstore_path();
unlink(pstore_path.c_str());
- CF_EXPECT(CreateBlankImage(pstore_path, 2 /* mb */, "none"));
+ CreateBlankImage(pstore_path, 2 /* mb */, "none");
auto sdcard_path = instance_.sdcard_path();
auto sdcard_size = FileSize(sdcard_path);
@@ -336,7 +334,7 @@
// round up
auto sdcard_mb_size = (sdcard_size + (1 << 20) - 1) / (1 << 20);
LOG(DEBUG) << "Size in mb is " << sdcard_mb_size;
- CF_EXPECT(CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard"));
+ CreateBlankImage(sdcard_path, sdcard_mb_size, "sdcard");
struct OverlayFile {
std::string name;
@@ -358,10 +356,13 @@
auto composite_disk_path = overlay_file.composite_disk_path.c_str();
unlink(overlay_path.c_str());
- CF_EXPECT(CreateQcowOverlay(instance_.crosvm_binary(), composite_disk_path,
- overlay_path));
+ if (!CreateQcowOverlay(instance_.crosvm_binary(), composite_disk_path,
+ overlay_path)) {
+ LOG(ERROR) << "CreateQcowOverlay failed";
+ return false;
+ }
}
- return {};
+ return true;
}
void ServerLoopImpl::RestartRunCvd(int notification_fd) {
diff --git a/host/commands/run_cvd/server_loop_impl.h b/host/commands/run_cvd/server_loop_impl.h
index 8166d4f..81494e2 100644
--- a/host/commands/run_cvd/server_loop_impl.h
+++ b/host/commands/run_cvd/server_loop_impl.h
@@ -84,7 +84,7 @@
ProcessMonitor& process_monitor);
void DeleteFifos();
- Result<void> PowerwashFiles();
+ bool PowerwashFiles();
void RestartRunCvd(int notification_fd);
static bool CreateQcowOverlay(const std::string& crosvm_path,
const std::string& backing_file,
diff --git a/host/commands/screen_recording_server/Android.bp b/host/commands/screen_recording_server/Android.bp
new file mode 100644
index 0000000..e228310
--- /dev/null
+++ b/host/commands/screen_recording_server/Android.bp
@@ -0,0 +1,116 @@
+// Copyright 2023 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.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "libscreen_recording_server",
+ shared_libs: [
+ "libprotobuf-cpp-full",
+ "libgrpc++_unsecure",
+ ],
+ static_libs: [
+ "libgflags",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+ generated_headers: [
+ "ScreenRecordingServerProto_h",
+ ],
+ generated_sources: [
+ "ScreenRecordingServerProto_cc",
+ ],
+ export_generated_headers: [
+ "ScreenRecordingServerProto_h",
+ ],
+ defaults: ["cuttlefish_host"],
+ include_dirs: [
+ "external/grpc-grpc/include",
+ "external/protobuf/src",
+ ],
+ target: {
+ darwin: {
+ enabled: true,
+ },
+ },
+}
+
+cc_binary_host {
+ name: "screen_recording_server",
+ shared_libs: [
+ "libprotobuf-cpp-full",
+ "libgrpc++_unsecure",
+ ],
+ static_libs: [
+ "libcuttlefish_host_config",
+ "libgflags",
+ "libscreen_recording_server",
+ "libgrpc++_reflection",
+ ],
+ srcs: [
+ "main.cpp",
+ ],
+ cflags: [
+ "-Wno-unused-parameter",
+ ],
+ defaults: ["cuttlefish_host"],
+ target: {
+ darwin: {
+ enabled: true,
+ },
+ },
+}
+
+filegroup {
+ name: "ScreenRecordingServerProto",
+ srcs: [
+ "screen_recording.proto",
+ ":libprotobuf-internal-protos",
+ ],
+}
+
+genrule {
+ name: "ScreenRecordingServerProto_h",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Idevice/google/cuttlefish/host/commands/screen_recording_server -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":ScreenRecordingServerProto",
+ ],
+ out: [
+ "screen_recording.grpc.pb.h",
+ "screen_recording.pb.h",
+ ],
+}
+
+genrule {
+ name: "ScreenRecordingServerProto_cc",
+ tools: [
+ "aprotoc",
+ "protoc-gen-grpc-cpp-plugin",
+ ],
+ cmd: "$(location aprotoc) -Idevice/google/cuttlefish/host/commands/screen_recording_server -Iexternal/protobuf/src --plugin=protoc-gen-grpc=$(location protoc-gen-grpc-cpp-plugin) $(in) --grpc_out=$(genDir) --cpp_out=$(genDir)",
+ srcs: [
+ ":ScreenRecordingServerProto",
+ ],
+ out: [
+ "screen_recording.grpc.pb.cc",
+ "screen_recording.pb.cc",
+ ],
+}
diff --git a/host/commands/screen_recording_server/main.cpp b/host/commands/screen_recording_server/main.cpp
new file mode 100644
index 0000000..308ec49
--- /dev/null
+++ b/host/commands/screen_recording_server/main.cpp
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2023 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 <iostream>
+#include <memory>
+#include <string>
+
+#include <gflags/gflags.h>
+#include <grpcpp/ext/proto_server_reflection_plugin.h>
+#include <grpcpp/grpcpp.h>
+#include <grpcpp/health_check_service_interface.h>
+
+#include "screen_recording.grpc.pb.h"
+
+using google::protobuf::Empty;
+using grpc::Server;
+using grpc::ServerBuilder;
+using grpc::ServerContext;
+using grpc::Status;
+using screenrecordingserver::ExampleReply;
+using screenrecordingserver::ScreenRecordingService;
+
+DEFINE_string(grpc_uds_path, "", "grpc_uds_path");
+
+class ScreenRecordingServiceImpl final
+ : public ScreenRecordingService::Service {
+ // TODO(b/315845821): Remove this example method, and fill with real contents.
+ Status ExampleMethod(ServerContext* context, const Empty* request,
+ ExampleReply* reply) override {
+ reply->set_message("This is a example method");
+ return Status::OK;
+ }
+};
+
+void RunServer() {
+ std::string server_address("unix:" + FLAGS_grpc_uds_path);
+ ScreenRecordingServiceImpl service;
+
+ grpc::EnableDefaultHealthCheckService(true);
+ grpc::reflection::InitProtoReflectionServerBuilderPlugin();
+ ServerBuilder builder;
+ // Listen on the given address without any authentication mechanism.
+ builder.AddListeningPort(server_address, grpc::InsecureServerCredentials());
+ // Register "service" as the instance through which we'll communicate with
+ // clients. In this case it corresponds to an *synchronous* service.
+ builder.RegisterService(&service);
+ // Finally assemble the server.
+ std::unique_ptr<Server> server(builder.BuildAndStart());
+ std::cout << "Server listening on " << server_address << std::endl;
+
+ // Wait for the server to shutdown. Note that some other thread must be
+ // responsible for shutting down the server for this call to ever return.
+ server->Wait();
+}
+
+int main(int argc, char** argv) {
+ ::gflags::ParseCommandLineFlags(&argc, &argv, true);
+ RunServer();
+
+ return 0;
+}
diff --git a/host/commands/screen_recording_server/screen_recording.proto b/host/commands/screen_recording_server/screen_recording.proto
new file mode 100644
index 0000000..62d5b4f
--- /dev/null
+++ b/host/commands/screen_recording_server/screen_recording.proto
@@ -0,0 +1,28 @@
+// Copyright 2023 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.
+
+syntax = "proto3";
+
+package screenrecordingserver;
+
+import "google/protobuf/empty.proto";
+
+service ScreenRecordingService {
+ // TODO(b/315845821): Remove this example method, and fill with real contents.
+ rpc ExampleMethod (google.protobuf.Empty) returns (ExampleReply) {}
+}
+
+message ExampleReply {
+ string message = 1;
+}
diff --git a/host/commands/secure_env/encrypted_serializable.cpp b/host/commands/secure_env/encrypted_serializable.cpp
index 75891fc..6c1c200 100644
--- a/host/commands/secure_env/encrypted_serializable.cpp
+++ b/host/commands/secure_env/encrypted_serializable.cpp
@@ -42,7 +42,7 @@
TPM2B_PRIVATE* key_private_out, // out
TpmObjectSlot* key_slot_out) { // out
TPM2B_AUTH authValue = {};
- auto rc = Esys_TR_SetAuth(resource_manager.Esys(), parent_key, &authValue);
+ auto rc = Esys_TR_SetAuth(*resource_manager.Esys(), parent_key, &authValue);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
<< " (" << Tss2_RC_Decode(rc) << ")";
@@ -90,16 +90,16 @@
TPM2B_PRIVATE* key_private = nullptr;
// TODO(schuffelen): Use Esys_Create when key_slot is NULL
rc = Esys_CreateLoaded(
- /* esysContext */ resource_manager.Esys(),
- /* primaryHandle */ parent_key,
- /* shandle1 */ ESYS_TR_PASSWORD,
- /* shandle2 */ ESYS_TR_NONE,
- /* shandle3 */ ESYS_TR_NONE,
- /* inSensitive */ &in_sensitive,
- /* inPublic */ &public_template,
- /* objectHandle */ &raw_handle,
- /* outPrivate */ &key_private,
- /* outPublic */ &key_public);
+ /* esysContext */ *resource_manager.Esys(),
+ /* primaryHandle */ parent_key,
+ /* shandle1 */ ESYS_TR_PASSWORD,
+ /* shandle2 */ ESYS_TR_NONE,
+ /* shandle3 */ ESYS_TR_NONE,
+ /* inSensitive */ &in_sensitive,
+ /* inPublic */ &public_template,
+ /* objectHandle */ &raw_handle,
+ /* outPrivate */ &key_private,
+ /* outPublic */ &key_public);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc
<< " (" << Tss2_RC_Decode(rc) << ")";
@@ -113,7 +113,7 @@
Esys_Free(key_public);
Esys_Free(key_private);
if (key_slot_out) {
- rc = Esys_TR_SetAuth(resource_manager.Esys(), raw_handle, &authValue);
+ rc = Esys_TR_SetAuth(*resource_manager.Esys(), raw_handle, &authValue);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
<< " (" << Tss2_RC_Decode(rc) << ")";
@@ -138,15 +138,9 @@
LOG(ERROR) << "No slots available";
return {};
}
- auto rc = Esys_Load(
- resource_manager.Esys(),
- parent_key,
- ESYS_TR_PASSWORD,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- key_private,
- key_public,
- &raw_handle);
+ auto rc = Esys_Load(*resource_manager.Esys(), parent_key, ESYS_TR_PASSWORD,
+ ESYS_TR_NONE, ESYS_TR_NONE, key_private, key_public,
+ &raw_handle);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_Load failed with return code " << rc
<< " (" << Tss2_RC_Decode(rc) << ")";
@@ -203,7 +197,7 @@
TPM2B_IV iv;
iv.size = sizeof(iv.buffer);
- auto rc = TpmRandomSource(resource_manager_.Esys())
+ auto rc = TpmRandomSource(resource_manager_)
.GenerateRandom(iv.buffer, sizeof(iv.buffer));
if (rc != KM_ERROR_OK) {
LOG(ERROR) << "Failed to get random data";
@@ -222,7 +216,7 @@
}
std::vector<uint8_t> encrypted(encrypted_size, 0);
if (!TpmEncrypt( //
- resource_manager_.Esys(), key_slot->get(), TpmAuth(ESYS_TR_PASSWORD),
+ *resource_manager_.Esys(), key_slot->get(), TpmAuth(ESYS_TR_PASSWORD),
iv, unencrypted.data(), encrypted.data(), encrypted_size)) {
LOG(ERROR) << "Encryption failed";
return buf;
@@ -305,7 +299,7 @@
}
std::vector<uint8_t> decrypted_data(encrypted_size, 0);
if (!TpmDecrypt( //
- resource_manager_.Esys(), key_slot->get(), TpmAuth(ESYS_TR_PASSWORD),
+ *resource_manager_.Esys(), key_slot->get(), TpmAuth(ESYS_TR_PASSWORD),
iv, encrypted_data.data(), decrypted_data.data(), encrypted_size)) {
LOG(ERROR) << "Failed to decrypt encrypted data";
return false;
diff --git a/host/commands/secure_env/primary_key_builder.cpp b/host/commands/secure_env/primary_key_builder.cpp
index 173f31e..ff0d2d7 100644
--- a/host/commands/secure_env/primary_key_builder.cpp
+++ b/host/commands/secure_env/primary_key_builder.cpp
@@ -67,7 +67,7 @@
TpmResourceManager& resource_manager) {
TPM2B_AUTH authValue = {};
auto rc =
- Esys_TR_SetAuth(resource_manager.Esys(), ESYS_TR_RH_OWNER, &authValue);
+ Esys_TR_SetAuth(*resource_manager.Esys(), ESYS_TR_RH_OWNER, &authValue);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_TR_SetAuth failed with return code " << rc
<< " (" << Tss2_RC_Decode(rc) << ")";
@@ -97,16 +97,16 @@
// Since this is a primary key, it's generated deterministically. It would
// also be possible to generate this once and hold it in storage.
rc = Esys_CreateLoaded(
- /* esysContext */ resource_manager.Esys(),
- /* primaryHandle */ ESYS_TR_RH_OWNER,
- /* shandle1 */ ESYS_TR_PASSWORD,
- /* shandle2 */ ESYS_TR_NONE,
- /* shandle3 */ ESYS_TR_NONE,
- /* inSensitive */ &in_sensitive,
- /* inPublic */ &public_template,
- /* objectHandle */ &raw_handle,
- /* outPrivate */ nullptr,
- /* outPublic */ nullptr);
+ /* esysContext */ *resource_manager.Esys(),
+ /* primaryHandle */ ESYS_TR_RH_OWNER,
+ /* shandle1 */ ESYS_TR_PASSWORD,
+ /* shandle2 */ ESYS_TR_NONE,
+ /* shandle3 */ ESYS_TR_NONE,
+ /* inSensitive */ &in_sensitive,
+ /* inPublic */ &public_template,
+ /* objectHandle */ &raw_handle,
+ /* outPrivate */ nullptr,
+ /* outPublic */ nullptr);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_CreateLoaded failed with return code " << rc
<< " (" << Tss2_RC_Decode(rc) << ")";
diff --git a/host/commands/secure_env/rust/Android.bp b/host/commands/secure_env/rust/Android.bp
index c5d6b01..6b04e7b 100644
--- a/host/commands/secure_env/rust/Android.bp
+++ b/host/commands/secure_env/rust/Android.bp
@@ -39,7 +39,7 @@
"liblibc",
"liblog_rust",
"libnix",
- "libprotobuf_deprecated",
+ "libprotobuf",
"libsecure_env_tpm",
],
defaults: ["cuttlefish_buildhost_only"],
@@ -73,7 +73,7 @@
"liblibc",
"liblog_rust",
"libnix",
- "libprotobuf_deprecated",
+ "libprotobuf",
"libsecure_env_tpm",
],
defaults: ["cuttlefish_buildhost_only"],
diff --git a/host/commands/secure_env/storage/tpm_storage.cpp b/host/commands/secure_env/storage/tpm_storage.cpp
index f1d451f..4bdb54e 100644
--- a/host/commands/secure_env/storage/tpm_storage.cpp
+++ b/host/commands/secure_env/storage/tpm_storage.cpp
@@ -58,26 +58,26 @@
auto handle_optional = CF_EXPECT(GetHandle(key));
auto handle = CF_EXPECT(handle_optional.value());
auto close_tr = [this](ESYS_TR* handle) {
- Esys_TR_Close(resource_manager_.Esys(), handle);
+ Esys_TR_Close(*resource_manager_.Esys(), handle);
delete handle;
};
std::unique_ptr<ESYS_TR, decltype(close_tr)> nv_handle(new ESYS_TR, close_tr);
auto rc = Esys_TR_FromTPMPublic(
- /* esysContext */ resource_manager_.Esys(),
- /* tpm_handle */ handle,
- /* optionalSession1 */ ESYS_TR_NONE,
- /* optionalSession2 */ ESYS_TR_NONE,
- /* optionalSession3 */ ESYS_TR_NONE,
- /* object */ nv_handle.get());
+ /* esysContext */ *resource_manager_.Esys(),
+ /* tpm_handle */ handle,
+ /* optionalSession1 */ ESYS_TR_NONE,
+ /* optionalSession2 */ ESYS_TR_NONE,
+ /* optionalSession3 */ ESYS_TR_NONE,
+ /* object */ nv_handle.get());
CF_EXPECTF(rc == TPM2_RC_SUCCESS, "Esys_TR_FromTPMPublic failed: {}: {}",
rc, Tss2_RC_Decode(rc));
TPM2B_AUTH auth = { .size = 0, .buffer = {} };
- Esys_TR_SetAuth(resource_manager_.Esys(), *nv_handle, &auth);
+ Esys_TR_SetAuth(*resource_manager_.Esys(), *nv_handle, &auth);
TPM2B_NV_PUBLIC* public_area;
rc = Esys_NV_ReadPublic(
- /* esysContext */ resource_manager_.Esys(),
+ /* esysContext */ *resource_manager_.Esys(),
/* nvIndex */ *nv_handle,
/* shandle1 */ ESYS_TR_NONE,
/* shandle2 */ ESYS_TR_NONE,
@@ -90,7 +90,7 @@
std::unique_ptr<TPM2B_NV_PUBLIC, decltype(Esys_Free)*> public_deleter(public_area, Esys_Free);
TPM2B_MAX_NV_BUFFER* buffer = nullptr;
rc = Esys_NV_Read(
- /* esysContext */ resource_manager_.Esys(),
+ /* esysContext */ *resource_manager_.Esys(),
/* authHandle */ *nv_handle,
/* nvIndex */ *nv_handle,
/* shandle1 */ ESYS_TR_PASSWORD,
@@ -116,7 +116,7 @@
auto handle = CF_EXPECT(handle_optional.value());
ESYS_TR nv_handle;
auto rc = Esys_TR_FromTPMPublic(
- /* esysContext */ resource_manager_.Esys(),
+ /* esysContext */ *resource_manager_.Esys(),
/* tpm_handle */ handle,
/* optionalSession1 */ ESYS_TR_NONE,
/* optionalSession2 */ ESYS_TR_NONE,
@@ -126,14 +126,14 @@
rc, Tss2_RC_Decode(rc));
TPM2B_AUTH auth = { .size = 0, .buffer = {} };
- Esys_TR_SetAuth(resource_manager_.Esys(), nv_handle, &auth);
+ Esys_TR_SetAuth(*resource_manager_.Esys(), nv_handle, &auth);
TPM2B_MAX_NV_BUFFER buffer;
buffer.size = data.size;
std::memcpy(buffer.buffer, data.payload, data.size);
rc = Esys_NV_Write(
- /* esysContext */ resource_manager_.Esys(),
+ /* esysContext */ *resource_manager_.Esys(),
/* authHandle */ nv_handle,
/* nvIndex */ nv_handle,
/* shandle1 */ ESYS_TR_PASSWORD,
@@ -141,7 +141,7 @@
/* shandle3 */ ESYS_TR_NONE,
/* data */ &buffer,
/* offset */ 0);
- Esys_TR_Close(resource_manager_.Esys(), &nv_handle);
+ Esys_TR_Close(*resource_manager_.Esys(), &nv_handle);
CF_EXPECTF(rc == TSS2_RC_SUCCESS, "Esys_NV_Write failed with return code {} ({})",
rc, Tss2_RC_Decode(rc));
@@ -149,7 +149,7 @@
}
TPM2_HANDLE TpmStorage::GenerateRandomHandle() {
- TpmRandomSource random_source{resource_manager_.Esys()};
+ TpmRandomSource random_source{resource_manager_};
TPM2_HANDLE handle = 0;
random_source.GenerateRandom(reinterpret_cast<uint8_t*>(&handle), sizeof(handle));
if (handle == 0) {
@@ -191,22 +191,22 @@
}
};
TPM2B_AUTH auth = { .size = 0, .buffer = {} };
- Esys_TR_SetAuth(resource_manager_.Esys(), ESYS_TR_RH_OWNER, &auth);
+ Esys_TR_SetAuth(*resource_manager_.Esys(), ESYS_TR_RH_OWNER, &auth);
ESYS_TR nv_handle;
auto rc = Esys_NV_DefineSpace(
- /* esysContext */ resource_manager_.Esys(),
- /* authHandle */ ESYS_TR_RH_OWNER,
- /* shandle1 */ ESYS_TR_PASSWORD,
- /* shandle2 */ ESYS_TR_NONE,
- /* shandle3 */ ESYS_TR_NONE,
- /* auth */ &auth,
- /* publicInfo */ &public_info,
- /* nvHandle */ &nv_handle);
+ /* esysContext */ *resource_manager_.Esys(),
+ /* authHandle */ ESYS_TR_RH_OWNER,
+ /* shandle1 */ ESYS_TR_PASSWORD,
+ /* shandle2 */ ESYS_TR_NONE,
+ /* shandle3 */ ESYS_TR_NONE,
+ /* auth */ &auth,
+ /* publicInfo */ &public_info,
+ /* nvHandle */ &nv_handle);
if (rc == TPM2_RC_NV_DEFINED) {
LOG(VERBOSE) << "Esys_NV_DefineSpace failed with TPM2_RC_NV_DEFINED";
continue;
} else if (rc == TPM2_RC_SUCCESS) {
- Esys_TR_Close(resource_manager_.Esys(), &nv_handle);
+ Esys_TR_Close(*resource_manager_.Esys(), &nv_handle);
break;
} else {
LOG(DEBUG) << "Esys_NV_DefineSpace failed with " << rc << ": "
diff --git a/host/commands/secure_env/suspend_resume_handler.cpp b/host/commands/secure_env/suspend_resume_handler.cpp
index af14c8a..f1f126c 100644
--- a/host/commands/secure_env/suspend_resume_handler.cpp
+++ b/host/commands/secure_env/suspend_resume_handler.cpp
@@ -82,7 +82,8 @@
const auto action_type = launcher_action.type;
CF_EXPECTF(action_type == ExtendedActionType::kSuspend ||
action_type == ExtendedActionType::kResume,
- "Unsupported ExtendedActionType \"{}\"", action_type);
+ "Unsupported ExtendedActionType \"{}\"",
+ fmt::underlying(action_type));
return action_type;
}
diff --git a/host/commands/secure_env/tpm_gatekeeper.cpp b/host/commands/secure_env/tpm_gatekeeper.cpp
index 3a3c44e..7cd9ec0 100644
--- a/host/commands/secure_env/tpm_gatekeeper.cpp
+++ b/host/commands/secure_env/tpm_gatekeeper.cpp
@@ -85,7 +85,7 @@
void TpmGatekeeper::GetRandom(void* random, uint32_t requested_size) const {
auto random_uint8 = reinterpret_cast<uint8_t*>(random);
- TpmRandomSource(resource_manager_.Esys())
+ TpmRandomSource(resource_manager_)
.GenerateRandom(random_uint8, requested_size);
}
diff --git a/host/commands/secure_env/tpm_hmac.cpp b/host/commands/secure_env/tpm_hmac.cpp
index cbb6a53..a0b6a85 100644
--- a/host/commands/secure_env/tpm_hmac.cpp
+++ b/host/commands/secure_env/tpm_hmac.cpp
@@ -16,6 +16,7 @@
#include "tpm_hmac.h"
#include <android-base/logging.h>
+#include <tss2/tss2_esys.h>
#include <tss2/tss2_rc.h>
#include "host/commands/secure_env/primary_key_builder.h"
@@ -40,15 +41,9 @@
buffer.size = data_size;
memcpy(buffer.buffer, data, data_size);
TPM2B_DIGEST* out_hmac = nullptr;
- auto rc = Esys_HMAC(
- resource_manager.Esys(),
- key_handle,
- auth.auth1(),
- auth.auth2(),
- auth.auth3(),
- &buffer,
- TPM2_ALG_NULL,
- &out_hmac);
+ auto rc =
+ Esys_HMAC(*resource_manager.Esys(), key_handle, auth.auth1(),
+ auth.auth2(), auth.auth3(), &buffer, TPM2_ALG_NULL, &out_hmac);
if (rc != TPM2_RC_SUCCESS) {
LOG(ERROR) << "TPM2_HMAC failed: " << Tss2_RC_Decode(rc) << "(" << rc << ")";
return {};
@@ -77,23 +72,18 @@
LOG(ERROR) << "No slots available";
return {};
}
- auto rc = Esys_HMAC_Start(
- resource_manager.Esys(),
- key_handle,
- key_auth.auth1(),
- key_auth.auth2(),
- key_auth.auth3(),
- &sequence_auth,
- TPM2_ALG_NULL,
- &sequence_handle);
+ auto locked_esys = resource_manager.Esys();
+ auto rc = Esys_HMAC_Start(*locked_esys, key_handle, key_auth.auth1(),
+ key_auth.auth2(), key_auth.auth3(), &sequence_auth,
+ TPM2_ALG_NULL, &sequence_handle);
if (rc != TPM2_RC_SUCCESS) {
LOG(ERROR) << "TPM2_HMAC_Start failed: " << Tss2_RC_Decode(rc)
<< "(" << rc << ")";
return {};
}
slot->set(sequence_handle);
- rc = Esys_TR_SetAuth(
- resource_manager.Esys(), sequence_handle, &sequence_auth);
+ rc = Esys_TR_SetAuth(*locked_esys, sequence_handle,
+ &sequence_auth);
if (rc != TPM2_RC_SUCCESS) {
LOG(ERROR) << "Esys_TR_SetAuth failed: " << Tss2_RC_Decode(rc)
<< "(" << rc << ")";
@@ -105,13 +95,8 @@
buffer.size = TPM2_MAX_DIGEST_BUFFER;
memcpy(buffer.buffer, &data[hashed], TPM2_MAX_DIGEST_BUFFER);
hashed += TPM2_MAX_DIGEST_BUFFER;
- rc = Esys_SequenceUpdate(
- resource_manager.Esys(),
- sequence_handle,
- ESYS_TR_PASSWORD,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- &buffer);
+ rc = Esys_SequenceUpdate(*locked_esys, sequence_handle, ESYS_TR_PASSWORD,
+ ESYS_TR_NONE, ESYS_TR_NONE, &buffer);
if (rc != TPM2_RC_SUCCESS) {
LOG(ERROR) << "Esys_SequenceUpdate failed: " << Tss2_RC_Decode(rc)
<< "(" << rc << ")";
@@ -122,16 +107,9 @@
memcpy(buffer.buffer, &data[hashed], buffer.size);
TPM2B_DIGEST* out_hmac = nullptr;
TPMT_TK_HASHCHECK* validation = nullptr;
- rc = Esys_SequenceComplete(
- resource_manager.Esys(),
- sequence_handle,
- ESYS_TR_PASSWORD,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- &buffer,
- TPM2_RH_OWNER,
- &out_hmac,
- &validation);
+ rc = Esys_SequenceComplete(*locked_esys, sequence_handle, ESYS_TR_PASSWORD,
+ ESYS_TR_NONE, ESYS_TR_NONE, &buffer, TPM2_RH_OWNER,
+ &out_hmac, &validation);
if (rc != TPM2_RC_SUCCESS) {
LOG(ERROR) << "Esys_SequenceComplete failed: " << Tss2_RC_Decode(rc)
<< "(" << rc << ")";
@@ -155,7 +133,6 @@
size_t data_size) {
auto fn = data_size > TPM2_MAX_DIGEST_BUFFER ? SegmentedHmac : OneshotHmac;
- auto with_tpm = resource_manager.Guard();
return fn(resource_manager, key_handle, auth, data, data_size);
}
diff --git a/host/commands/secure_env/tpm_keymaster_context.cpp b/host/commands/secure_env/tpm_keymaster_context.cpp
index bca81b8..dbd9e87 100644
--- a/host/commands/secure_env/tpm_keymaster_context.cpp
+++ b/host/commands/secure_env/tpm_keymaster_context.cpp
@@ -80,7 +80,7 @@
: resource_manager_(resource_manager),
enforcement_(enforcement),
key_blob_maker_(new TpmKeyBlobMaker(resource_manager_)),
- random_source_(new TpmRandomSource(resource_manager_.Esys())),
+ random_source_(new TpmRandomSource(resource_manager_)),
attestation_context_(new TpmAttestationRecordContext),
remote_provisioning_context_(
new TpmRemoteProvisioningContext(resource_manager_)) {
diff --git a/host/commands/secure_env/tpm_keymaster_enforcement.cpp b/host/commands/secure_env/tpm_keymaster_enforcement.cpp
index 4a4af14..ef37453 100644
--- a/host/commands/secure_env/tpm_keymaster_enforcement.cpp
+++ b/host/commands/secure_env/tpm_keymaster_enforcement.cpp
@@ -172,7 +172,7 @@
HmacSharingParameters* params) {
if (!have_saved_params_) {
saved_params_.seed = {};
- TpmRandomSource random_source{resource_manager_.Esys()};
+ TpmRandomSource random_source{resource_manager_};
auto rc = random_source.GenerateRandom(saved_params_.nonce,
sizeof(saved_params_.nonce));
if (rc != KM_ERROR_OK) {
diff --git a/host/commands/secure_env/tpm_random_source.cpp b/host/commands/secure_env/tpm_random_source.cpp
index 569edbc..9b8e3ae 100644
--- a/host/commands/secure_env/tpm_random_source.cpp
+++ b/host/commands/secure_env/tpm_random_source.cpp
@@ -13,16 +13,17 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "tpm_random_source.h"
+#include "host/commands/secure_env/tpm_random_source.h"
#include <android-base/logging.h>
+#include "tpm_resource_manager.h"
#include "tss2/tss2_esys.h"
#include "tss2/tss2_rc.h"
namespace cuttlefish {
-TpmRandomSource::TpmRandomSource(ESYS_CONTEXT* esys) : esys_(esys) {
-}
+TpmRandomSource::TpmRandomSource(TpmResourceManager& resource_manager)
+ : resource_manager_(resource_manager) {}
keymaster_error_t TpmRandomSource::GenerateRandom(
uint8_t* random, size_t requested_length) const {
@@ -32,9 +33,9 @@
// TODO(b/158790549): Pipeline these calls.
TPM2B_DIGEST* generated = nullptr;
while (requested_length > sizeof(generated->buffer)) {
- auto rc = Esys_GetRandom(esys_, ESYS_TR_NONE, ESYS_TR_NONE,
- ESYS_TR_NONE, sizeof(generated->buffer),
- &generated);
+ auto rc =
+ Esys_GetRandom(*resource_manager_.Esys(), ESYS_TR_NONE, ESYS_TR_NONE,
+ ESYS_TR_NONE, sizeof(generated->buffer), &generated);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_GetRandom failed with " << rc << " ("
<< Tss2_RC_Decode(rc) << ")";
@@ -46,8 +47,9 @@
requested_length -= sizeof(generated->buffer);
Esys_Free(generated);
}
- auto rc = Esys_GetRandom(esys_, ESYS_TR_NONE, ESYS_TR_NONE,
- ESYS_TR_NONE, requested_length, &generated);
+ auto rc =
+ Esys_GetRandom(*resource_manager_.Esys(), ESYS_TR_NONE, ESYS_TR_NONE,
+ ESYS_TR_NONE, requested_length, &generated);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_GetRandom failed with " << rc << " ("
<< Tss2_RC_Decode(rc) << ")";
@@ -75,12 +77,8 @@
in_data.size = MAX_STIR_RANDOM_BUFFER_SIZE;
buffer += MAX_STIR_RANDOM_BUFFER_SIZE;
size -= MAX_STIR_RANDOM_BUFFER_SIZE;
- auto rc = Esys_StirRandom(
- esys_,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- &in_data);
+ auto rc = Esys_StirRandom(*resource_manager_.Esys(), ESYS_TR_NONE,
+ ESYS_TR_NONE, ESYS_TR_NONE, &in_data);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_StirRandom failed with " << rc << "("
<< Tss2_RC_Decode(rc) << ")";
@@ -91,12 +89,8 @@
return KM_ERROR_OK;
}
memcpy(in_data.buffer, buffer, size);
- auto rc = Esys_StirRandom(
- esys_,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- ESYS_TR_NONE,
- &in_data);
+ auto rc = Esys_StirRandom(*resource_manager_.Esys(), ESYS_TR_NONE,
+ ESYS_TR_NONE, ESYS_TR_NONE, &in_data);
if (rc != TSS2_RC_SUCCESS) {
LOG(ERROR) << "Esys_StirRandom failed with " << rc << "("
<< Tss2_RC_Decode(rc) << ")";
diff --git a/host/commands/secure_env/tpm_random_source.h b/host/commands/secure_env/tpm_random_source.h
index c9a91c7..12d4de7 100644
--- a/host/commands/secure_env/tpm_random_source.h
+++ b/host/commands/secure_env/tpm_random_source.h
@@ -17,7 +17,7 @@
#include <keymaster/random_source.h>
-struct ESYS_CONTEXT;
+#include "host/commands/secure_env/tpm_resource_manager.h"
namespace cuttlefish {
@@ -28,15 +28,16 @@
*/
class TpmRandomSource : public keymaster::RandomSource {
public:
- TpmRandomSource(ESYS_CONTEXT* esys);
- virtual ~TpmRandomSource() = default;
+ TpmRandomSource(TpmResourceManager& resource_manager);
+ virtual ~TpmRandomSource() = default;
- keymaster_error_t GenerateRandom(
- uint8_t* buffer, size_t length) const override;
+ keymaster_error_t GenerateRandom(uint8_t* buffer,
+ size_t length) const override;
- keymaster_error_t AddRngEntropy(const uint8_t*, size_t) const;
+ keymaster_error_t AddRngEntropy(const uint8_t*, size_t) const;
+
private:
- ESYS_CONTEXT* esys_;
+ TpmResourceManager& resource_manager_;
};
} // namespace cuttlefish
diff --git a/host/commands/secure_env/tpm_resource_manager.cpp b/host/commands/secure_env/tpm_resource_manager.cpp
index defe153..c177078 100644
--- a/host/commands/secure_env/tpm_resource_manager.cpp
+++ b/host/commands/secure_env/tpm_resource_manager.cpp
@@ -13,13 +13,19 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-#include "tpm_resource_manager.h"
+#include "host/commands/secure_env/tpm_resource_manager.h"
+
+#include <mutex>
#include <android-base/logging.h>
+#include <tss2/tss2_esys.h>
#include <tss2/tss2_rc.h>
namespace cuttlefish {
+EsysLock::EsysLock(ESYS_CONTEXT* esys, std::unique_lock<std::mutex> guard)
+ : esys_(esys), guard_(std::move(guard)) {}
+
TpmResourceManager::ObjectSlot::ObjectSlot(TpmResourceManager* resource_manager)
: ObjectSlot(resource_manager, ESYS_TR_NONE) {
}
@@ -65,8 +71,8 @@
}
}
-ESYS_CONTEXT* TpmResourceManager::Esys() {
- return esys_;
+EsysLock TpmResourceManager::Esys() {
+ return EsysLock(esys_, std::unique_lock<std::mutex>(mu_));
}
TpmObjectSlot TpmResourceManager::ReserveSlot() {
diff --git a/host/commands/secure_env/tpm_resource_manager.h b/host/commands/secure_env/tpm_resource_manager.h
index b5bf9ec..0713bfa 100644
--- a/host/commands/secure_env/tpm_resource_manager.h
+++ b/host/commands/secure_env/tpm_resource_manager.h
@@ -24,6 +24,19 @@
namespace cuttlefish {
+class EsysLock {
+ public:
+ ESYS_CONTEXT* operator*() const { return esys_; }
+
+ private:
+ EsysLock(ESYS_CONTEXT*, std::unique_lock<std::mutex>);
+
+ ESYS_CONTEXT* esys_;
+ std::unique_lock<std::mutex> guard_;
+
+ friend class TpmResourceManager;
+};
+
/**
* Object slot manager for TPM memory. The TPM can only hold a fixed number of
* objects at once. Some TPM operations are defined to consume slots either
@@ -54,14 +67,12 @@
TpmResourceManager(ESYS_CONTEXT* esys);
~TpmResourceManager();
- ESYS_CONTEXT* Esys();
+ // Returns a wrapped ESYS_CONTEXT* that can be used with Esys calls that also
+ // holds a lock. Callers should not hold onto the inner ESYS_CONTEXT* past the
+ // lifetime of the lock.
+ EsysLock Esys();
std::shared_ptr<ObjectSlot> ReserveSlot();
- // Return a lock guard to serialize access to the TPM.
- std::lock_guard<std::mutex> Guard() {
- return std::lock_guard<std::mutex>(mu_);
- }
-
private:
std::mutex mu_;
ESYS_CONTEXT* esys_;
diff --git a/host/commands/stop/main.cc b/host/commands/stop/main.cc
index 69449a6..206b580 100644
--- a/host/commands/stop/main.cc
+++ b/host/commands/stop/main.cc
@@ -269,6 +269,11 @@
*/
return 134;
}
- cuttlefish::MetricsReceiver::LogMetricsVMStop();
+
+ if (cuttlefish::CuttlefishConfig::Get()->enable_metrics() ==
+ cuttlefish::CuttlefishConfig::Answer::kYes) {
+ cuttlefish::MetricsReceiver::LogMetricsVMStop();
+ }
+
return cuttlefish::StopCvdMain(wait_for_launcher, clear_instance_dirs);
}
diff --git a/host/cvd_test_configs/validation_failures/field_name_error.json b/host/cvd_test_configs/validation_failures/field_name_error.json
new file mode 100644
index 0000000..930fdf4
--- /dev/null
+++ b/host/cvd_test_configs/validation_failures/field_name_error.json
@@ -0,0 +1,18 @@
+{
+ "common": {
+ "host_package": "@ab/aosp-main/aosp_cf_x86_64_phone-trunk_staging-userdebug"
+ },
+ "instances": [
+ {
+ "@import": "phone",
+ "vm-typo": {
+ "memory_mb": 8192,
+ "setupwizard_mode": "OPTIONAL",
+ "cpus": 4
+ },
+ "disk-typo": {
+ "default_build": "@ab/git_main/cf_x86_64_phone-trunk_staging-userdebug"
+ }
+ }
+ ]
+}
diff --git a/host/cvd_test_configs/validation_failures/type_error.json b/host/cvd_test_configs/validation_failures/type_error.json
new file mode 100644
index 0000000..1d90710
--- /dev/null
+++ b/host/cvd_test_configs/validation_failures/type_error.json
@@ -0,0 +1,18 @@
+{
+ "common": {
+ "host_package": "@ab/aosp-main/aosp_cf_x86_64_phone-trunk_staging-userdebug"
+ },
+ "instances": [
+ {
+ "@import": "phone",
+ "vm": {
+ "memory_mb": "8192",
+ "setupwizard_mode": "OPTIONAL",
+ "cpus": "4"
+ },
+ "disk": {
+ "default_build": "@ab/git_main/cf_x86_64_phone-trunk_staging-userdebug"
+ }
+ }
+ ]
+}
diff --git a/host/frontend/webrtc/html_client/js/app.js b/host/frontend/webrtc/html_client/js/app.js
index 44395ea..912ccc2 100644
--- a/host/frontend/webrtc/html_client/js/app.js
+++ b/host/frontend/webrtc/html_client/js/app.js
@@ -947,6 +947,11 @@
}
#onKeyEvent(e) {
+ if (e.cancelable) {
+ // Some keyboard events cause unwanted side effects, like elements losing
+ // focus, if the default behavior is not prevented.
+ e.preventDefault();
+ }
this.#deviceConnection.sendKeyEvent(e.code, e.type);
}
diff --git a/host/libs/config/config_utils.cpp b/host/libs/config/config_utils.cpp
index df61b24..0ee9911 100644
--- a/host/libs/config/config_utils.cpp
+++ b/host/libs/config/config_utils.cpp
@@ -107,11 +107,24 @@
file_name;
}
+std::string HostBinaryDir() {
+ return DefaultHostArtifactsPath("bin");
+}
+
+std::string DefaultQemuBinaryDir() {
+ const std::string target_prod_str = StringFromEnv("TARGET_PRODUCT", "");
+ if (HostArch() == Arch::X86_64 &&
+ target_prod_str.find("arm") == std::string::npos) {
+ return HostBinaryDir();
+ }
+ return "/usr/bin";
+}
+
std::string HostBinaryPath(const std::string& binary_name) {
#ifdef __ANDROID__
return binary_name;
#else
- return DefaultHostArtifactsPath("bin/" + binary_name);
+ return HostBinaryDir() + "/" + binary_name;
#endif
}
diff --git a/host/libs/config/config_utils.h b/host/libs/config/config_utils.h
index 58b3a69..1f9ca28 100644
--- a/host/libs/config/config_utils.h
+++ b/host/libs/config/config_utils.h
@@ -48,6 +48,7 @@
std::string RandomSerialNumber(const std::string& prefix);
std::string DefaultHostArtifactsPath(const std::string& file);
+std::string DefaultQemuBinaryDir();
std::string HostBinaryPath(const std::string& file);
std::string HostUsrSharePath(const std::string& file);
std::string DefaultGuestImagePath(const std::string& file);
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 71334f3..6d2b5a2 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -423,7 +423,14 @@
std::string audio_server_path() const;
- enum class BootFlow { Android, AndroidEfiLoader, ChromeOs, Linux, Fuchsia };
+ enum class BootFlow {
+ Android,
+ AndroidEfiLoader,
+ ChromeOs,
+ ChromeOsDisk,
+ Linux,
+ Fuchsia
+ };
BootFlow boot_flow() const;
@@ -623,8 +630,9 @@
// android efi loader flow
std::string android_efi_loader() const;
- //
- // linux artifacts for otheros flow
+
+ // chromeos artifacts for otheros flow
+ std::string chromeos_disk() const;
std::string chromeos_kernel_path() const;
std::string chromeos_root_image() const;
@@ -818,6 +826,7 @@
void set_system_target_zip(const std::string& system_target_zip);
void set_otheros_esp_image(const std::string& otheros_esp_image);
void set_android_efi_loader(const std::string& android_efi_loader);
+ void set_chromeos_disk(const std::string& chromeos_disk);
void set_chromeos_kernel_path(const std::string& linux_kernel_path);
void set_chromeos_root_image(const std::string& linux_root_image);
void set_linux_kernel_path(const std::string& linux_kernel_path);
@@ -946,3 +955,6 @@
extern const char* const kHwComposerRanchu;
extern const char* const kHwComposerNone;
} // namespace cuttlefish
+
+template <>
+struct fmt::formatter<cuttlefish::ExternalNetworkMode> : ostream_formatter {};
diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp
index 51da6d9..04d287a 100644
--- a/host/libs/config/cuttlefish_config_instance.cpp
+++ b/host/libs/config/cuttlefish_config_instance.cpp
@@ -254,6 +254,14 @@
const std::string& android_efi_loader) {
(*Dictionary())[kAndroidEfiLoader] = android_efi_loader;
}
+static constexpr char kChromeOsDisk[] = "chromeos_disk";
+std::string CuttlefishConfig::InstanceSpecific::chromeos_disk() const {
+ return (*Dictionary())[kChromeOsDisk].asString();
+}
+void CuttlefishConfig::MutableInstanceSpecific::set_chromeos_disk(
+ const std::string& chromeos_disk) {
+ (*Dictionary())[kChromeOsDisk] = chromeos_disk;
+}
static constexpr char kChromeOsKernelPath[] = "chromeos_kernel_path";
std::string CuttlefishConfig::InstanceSpecific::chromeos_kernel_path() const {
return (*Dictionary())[kChromeOsKernelPath].asString();
@@ -1238,6 +1246,8 @@
CuttlefishConfig::InstanceSpecific::BootFlow CuttlefishConfig::InstanceSpecific::boot_flow() const {
const bool android_efi_loader_flow_used = !android_efi_loader().empty();
+ const bool chromeos_disk_flow_used = !chromeos_disk().empty();
+
const bool chromeos_flow_used =
!chromeos_kernel_path().empty() || !chromeos_root_image().empty();
@@ -1253,6 +1263,8 @@
return BootFlow::AndroidEfiLoader;
} else if (chromeos_flow_used) {
return BootFlow::ChromeOs;
+ } else if (chromeos_disk_flow_used) {
+ return BootFlow::ChromeOsDisk;
} else if (linux_flow_used) {
return BootFlow::Linux;
} else if (fuchsia_flow_used) {
diff --git a/host/libs/config/known_paths.cpp b/host/libs/config/known_paths.cpp
index d98c093..b50cc19 100644
--- a/host/libs/config/known_paths.cpp
+++ b/host/libs/config/known_paths.cpp
@@ -78,6 +78,10 @@
std::string CasimirBinary() { return HostBinaryPath("casimir"); }
+std::string ScreenRecordingServerBinary() {
+ return HostBinaryPath("screen_recording_server");
+}
+
std::string SecureEnvBinary() { return HostBinaryPath("secure_env"); }
std::string SocketVsockProxyBinary() {
diff --git a/host/libs/config/known_paths.h b/host/libs/config/known_paths.h
index 1ec7515..4952227 100644
--- a/host/libs/config/known_paths.h
+++ b/host/libs/config/known_paths.h
@@ -36,6 +36,7 @@
std::string ProcessRestarterBinary();
std::string RootCanalBinary();
std::string CasimirBinary();
+std::string ScreenRecordingServerBinary();
std::string SecureEnvBinary();
std::string SocketVsockProxyBinary();
std::string StopCvdBinary();
diff --git a/shared/BoardConfig.mk b/shared/BoardConfig.mk
index 2281b1d..094d74c 100644
--- a/shared/BoardConfig.mk
+++ b/shared/BoardConfig.mk
@@ -225,6 +225,7 @@
# enough space for other cases (such as remount, etc)
BOARD_USERDATAIMAGE_PARTITION_SIZE := $(TARGET_USERDATAIMAGE_PARTITION_SIZE)
BOARD_USERDATAIMAGE_FILE_SYSTEM_TYPE := $(TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE)
+$(call soong_config_append,cvdhost,default_userdata_fs_type,$(TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE))
ifeq ($(TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE),f2fs)
TARGET_USERIMAGES_USE_F2FS := true
endif
@@ -424,7 +425,3 @@
ifneq ($(PRODUCT_BUILD_VBMETA_IMAGE), false)
AB_OTA_PARTITIONS += vbmeta
endif
-
-ifeq ($(TARGET_ARCH),arm64)
-$(call soong_config_append,cvdhost,vhost_user_vsock_by_default,true)
-endif
\ No newline at end of file
diff --git a/shared/auto/device_vendor.mk b/shared/auto/device_vendor.mk
index 1c134e8..08712a4 100644
--- a/shared/auto/device_vendor.mk
+++ b/shared/auto/device_vendor.mk
@@ -45,6 +45,9 @@
frameworks/native/data/etc/android.hardware.sensor.compass.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.compass.xml
endif
+PRODUCT_PRODUCT_PROPERTIES += \
+ ro.boot.uwbcountrycode=US
+
PRODUCT_COPY_FILES += \
frameworks/native/data/etc/car_core_hardware.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/car_core_hardware.xml \
frameworks/native/data/etc/android.hardware.broadcastradio.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.broadcastradio.xml \
diff --git a/shared/bluetooth/device_vendor.mk b/shared/bluetooth/device_vendor.mk
index b8b4554..451f300 100644
--- a/shared/bluetooth/device_vendor.mk
+++ b/shared/bluetooth/device_vendor.mk
@@ -30,29 +30,7 @@
PRODUCT_COPY_FILES += \
frameworks/av/services/audiopolicy/config/bluetooth_audio_policy_configuration_7_0.xml:$(TARGET_COPY_OUT_VENDOR)/etc/bluetooth_audio_policy_configuration_7_0.xml \
-#
-# Bluetooth HAL and Compatibility Bluetooth library (for older revs).
-#
-ifneq ($(LOCAL_PREFER_VENDOR_APEX),true)
-PRODUCT_COPY_FILES +=\
- frameworks/native/data/etc/android.hardware.bluetooth.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth.xml \
- frameworks/native/data/etc/android.hardware.bluetooth_le.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.bluetooth_le.xml
-
-PRODUCT_PACKAGES += \
- android.hardware.bluetooth-service.default \
- android.hardware.bluetooth.finder-service.default \
- android.hardware.bluetooth.ranging-service.default \
- bt_vhci_forwarder
-
-# Bluetooth initialization configuration is copied to the init folder here instead of being added
-# as an init_rc attribute of the bt_vhci_forward binary. The bt_vhci_forward binary is used by
-# multiple targets with different initialization configurations.
-PRODUCT_COPY_FILES += \
- device/google/cuttlefish/guest/commands/bt_vhci_forwarder/bt_vhci_forwarder.rc:$(TARGET_COPY_OUT_VENDOR)/etc/init/bt_vhci_forwarder.rc
-
-else
PRODUCT_PACKAGES += com.google.cf.bt
-endif
#
# Bluetooth Audio AIDL HAL
diff --git a/shared/config/input/Crosvm_Virtio_Multitouch_Touchpad_0.idc b/shared/config/input/Crosvm_Virtio_Multitouch_Touchpad_0.idc
index 18868dc..1d88567 100644
--- a/shared/config/input/Crosvm_Virtio_Multitouch_Touchpad_0.idc
+++ b/shared/config/input/Crosvm_Virtio_Multitouch_Touchpad_0.idc
@@ -2,3 +2,6 @@
touch.deviceType = touchPad
touch.orientationAware = 0
+
+# Allow touches while the screen is off
+touch.enableForInactiveViewport = 1
diff --git a/shared/device.mk b/shared/device.mk
index 962a34b..30ad25d 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -87,7 +87,7 @@
# Explanation of specific properties:
# ro.hardware.keystore_desede=true needed for CtsKeystoreTestCases
PRODUCT_VENDOR_PROPERTIES += \
- tombstoned.max_tombstone_count=500 \
+ tombstoned.max_tombstone_count=100 \
ro.carrier=unknown \
ro.com.android.dataroaming?=false \
ro.hardware.virtual_device=1 \
@@ -180,13 +180,7 @@
hidl_lazy_cb_test_server
# Runtime Resource Overlays
-ifneq ($(LOCAL_PREFER_VENDOR_APEX),true)
-PRODUCT_PACKAGES += \
- cuttlefish_overlay_connectivity \
- cuttlefish_overlay_frameworks_base_core \
- cuttlefish_overlay_settings_provider
-
-endif
+PRODUCT_PACKAGES += com.google.aosp_cf.rros
#
# Satellite vendor service for CF
@@ -310,6 +304,7 @@
libpreprocessingaidl \
libpresetreverbsw \
libreverbaidl \
+ libspatializersw \
libtinyxml2 \
libvirtualizersw \
libvisualizeraidl \
@@ -623,3 +618,5 @@
ifeq ($(RELEASE_DEPRECATE_VNDK),true)
KEEP_VNDK ?= false
endif
+
+TARGET_BOARD_FASTBOOT_INFO_FILE = device/google/cuttlefish/shared/fastboot-info.txt
\ No newline at end of file
diff --git a/shared/fastboot-info.txt b/shared/fastboot-info.txt
new file mode 100644
index 0000000..0448334
--- /dev/null
+++ b/shared/fastboot-info.txt
@@ -0,0 +1,14 @@
+# cuttlefish
+version 1
+flash boot
+flash init_boot
+flash vendor_boot
+flash --apply-vbmeta vbmeta
+flash vbmeta_system
+flash vbmeta_vendor_dlkm
+flash vbmeta_system_dlkm
+reboot fastboot
+update-super
+flash super
+if-wipe erase userdata
+if-wipe erase metadata
\ No newline at end of file
diff --git a/shared/phone/device_vendor.mk b/shared/phone/device_vendor.mk
index e7f1276..e22a22f 100644
--- a/shared/phone/device_vendor.mk
+++ b/shared/phone/device_vendor.mk
@@ -59,11 +59,7 @@
DEVICE_PACKAGE_OVERLAYS += device/google/cuttlefish/shared/phone/overlay
# Runtime Resource Overlays
-ifeq ($(LOCAL_PREFER_VENDOR_APEX),true)
-PRODUCT_PACKAGES += com.google.aosp_cf_phone.rros
-else
PRODUCT_PACKAGES += cuttlefish_phone_overlay_frameworks_base_core
-endif
# NFC AIDL HAL
PRODUCT_PACKAGES += \
diff --git a/shared/phone/vendor.prop b/shared/phone/vendor.prop
index 5bb745a..8157fa0 100644
--- a/shared/phone/vendor.prop
+++ b/shared/phone/vendor.prop
@@ -5,4 +5,5 @@
bluetooth.profile.ccp.server.enabled=true
bluetooth.profile.csip.set_coordinator.enabled=true
bluetooth.profile.hap.client.enabled=true
+bluetooth.profile.mcp.server.enabled=true
bluetooth.profile.vcp.controller.enabled=true
diff --git a/shared/sensors/device_vendor.mk b/shared/sensors/device_vendor.mk
index 73c1c5e..f497fb9 100644
--- a/shared/sensors/device_vendor.mk
+++ b/shared/sensors/device_vendor.mk
@@ -14,11 +14,24 @@
# limitations under the License.
#
+# set LOCAL_SENSOR_FILE_OVERRIDES := true if a device has a custom list of sensors. Otherwise
+# install the default set like below
+ifneq ($(LOCAL_SENSOR_FILE_OVERRIDES),true)
+ PRODUCT_COPY_FILES += \
+ frameworks/native/data/etc/android.hardware.sensor.ambient_temperature.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.ambient_temperature.xml \
+ frameworks/native/data/etc/android.hardware.sensor.barometer.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.barometer.xml \
+ frameworks/native/data/etc/android.hardware.sensor.gyroscope.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.gyroscope.xml \
+ frameworks/native/data/etc/android.hardware.sensor.hinge_angle.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.hinge_angle.xml \
+ frameworks/native/data/etc/android.hardware.sensor.light.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.light.xml \
+ frameworks/native/data/etc/android.hardware.sensor.proximity.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.proximity.xml \
+ frameworks/native/data/etc/android.hardware.sensor.relative_humidity.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.sensor.relative_humidity.xml
+endif
+
PRODUCT_SOONG_NAMESPACES += device/google/cuttlefish/shared/sensors/multihal
-#
-# Sensors
-#
+# Set LOCAL_SENSOR_PRODUCT_PACKAGE := <package list> if a device wants to install custom implementations
+# Should check if the default feature list is okay with the implementation. Otherwise, it should set
+# LOCAL_SENSOR_FILE_OVERRIDES and copy feature files.
ifeq ($(LOCAL_SENSOR_PRODUCT_PACKAGE),)
LOCAL_SENSOR_PRODUCT_PACKAGE := com.android.hardware.sensors
endif
diff --git a/shared/sepolicy/system_ext/private/hal_audio_parser_service.te b/shared/sepolicy/system_ext/private/hal_audio_parser_service.te
new file mode 100644
index 0000000..0a68d01
--- /dev/null
+++ b/shared/sepolicy/system_ext/private/hal_audio_parser_service.te
@@ -0,0 +1,2 @@
+# Currently this is a stub. This service is only actually implemented by SoC vendors.
+allow audioserver hal_audio_vendor_parameter_parser_service:service_manager find;
diff --git a/shared/sepolicy/system_ext/private/service.te b/shared/sepolicy/system_ext/private/service.te
new file mode 100644
index 0000000..50e7415
--- /dev/null
+++ b/shared/sepolicy/system_ext/private/service.te
@@ -0,0 +1 @@
+type hal_audio_vendor_parameter_parser_service, service_manager_type;
diff --git a/shared/sepolicy/system_ext/private/service_contexts b/shared/sepolicy/system_ext/private/service_contexts
new file mode 100644
index 0000000..afee8ca
--- /dev/null
+++ b/shared/sepolicy/system_ext/private/service_contexts
@@ -0,0 +1 @@
+android.media.audio.IHalAdapterVendorExtension/default u:object_r:hal_audio_vendor_parameter_parser_service:s0
diff --git a/shared/slim/device_vendor.mk b/shared/slim/device_vendor.mk
index 127ac4a..e980edf 100644
--- a/shared/slim/device_vendor.mk
+++ b/shared/slim/device_vendor.mk
@@ -48,16 +48,9 @@
frameworks/native/data/etc/android.hardware.faketouch.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.faketouch.xml \
frameworks/native/data/etc/android.hardware.fingerprint.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.fingerprint.xml \
-
# Runtime Resource Overlays
-ifeq ($(LOCAL_PREFER_VENDOR_APEX),true)
-PRODUCT_PACKAGES += \
- com.google.aosp_cf_phone.rros \
- com.google.aosp_cf_slim.rros
-else
PRODUCT_PACKAGES += \
cuttlefish_phone_overlay_frameworks_base_core \
slim_overlay_frameworks_base_core
-endif
TARGET_BOARD_INFO_FILE ?= device/google/cuttlefish/shared/slim/android-info.txt
diff --git a/shared/telephony/device_vendor.mk b/shared/telephony/device_vendor.mk
index bd78cc6..954076e 100644
--- a/shared/telephony/device_vendor.mk
+++ b/shared/telephony/device_vendor.mk
@@ -27,21 +27,10 @@
ro.com.android.dataroaming=true \
ro.telephony.default_network=9 \
-ifeq ($(LOCAL_PREFER_VENDOR_APEX),true)
-PRODUCT_PACKAGES += com.google.cf.rild
-else
# If downstream target provides its own RILD, set TARGET_USES_CF_RILD := false
-# If the target prefers vendor APEX, this feature is not supported
TARGET_USES_CF_RILD ?= true
ifeq ($(TARGET_USES_CF_RILD),true)
-PRODUCT_PACKAGES += \
- libcuttlefish-ril-2 \
- libcuttlefish-rild
+ PRODUCT_PACKAGES += com.google.cf.rild
endif
-PRODUCT_COPY_FILES += \
- frameworks/native/data/etc/android.hardware.telephony.gsm.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.gsm.xml \
- frameworks/native/data/etc/android.hardware.telephony.ims.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.ims.xml \
- frameworks/native/data/etc/android.hardware.telephony.satellite.xml:$(TARGET_COPY_OUT_VENDOR)/etc/permissions/android.hardware.telephony.satellite.xml
-endif # if not LOCAL_PREFER_VENDOR_APEX
-endif # if not TARGET_NO_TELEPHONY
+endif # if not TARGET_NO_TELEPHONY
\ No newline at end of file
diff --git a/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java b/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java
index 668cb52..cecf83b 100644
--- a/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java
+++ b/tests/snapshot/src/com/android/cuttlefish/tests/SnapshotTest.java
@@ -75,6 +75,7 @@
// validating the feature itself so it's fine
boolean restoreRes = false;
try {
+ handler = new DeviceSnapshotHandler();
restoreRes = handler.restoreSnapshotDevice(getDevice(), String.format("snapshot_img%d", mTestCount));
} catch (DeviceNotAvailableException e) {
CLog.e(e);
diff --git a/tools/cvd_uncolor_text.sh b/tools/cvd_uncolor_text.sh
new file mode 100755
index 0000000..90188ed
--- /dev/null
+++ b/tools/cvd_uncolor_text.sh
@@ -0,0 +1,3 @@
+#!/usr/bin/env bash
+
+sed -E 's|[^[:alnum:]]\[[^m]+m||g' "$@"
diff --git a/tools/launch_cvd_arm64_server.sh b/tools/launch_cvd_arm64_server.sh
index 6c429bb..60c7a49 100755
--- a/tools/launch_cvd_arm64_server.sh
+++ b/tools/launch_cvd_arm64_server.sh
@@ -87,10 +87,13 @@
# sets up SSH port forwarding to the remote server for various ports and launch cvd instance
adb_port_forwarding=""
+print_launcher_logs=""
for instance_num in $(seq $base_instance_num $(($base_instance_num+$num_instances-1))); do
+ device_name="cvd_$base_instance_num-$instance_num"
adb_port=$((6520+$instance_num-1))
- echo -e "Device-$instance_num is using adb port $adb_port. Try ${color_cyan}adb connect 127.0.0.1:${adb_port}${color_plain} if you want to connect to this device"
+ echo -e "$device_name is using adb port $adb_port. Try ${color_cyan}adb connect 127.0.0.1:${adb_port}${color_plain} if you want to connect to this device"
adb_port_forwarding+="-L $adb_port:127.0.0.1:$adb_port "
+ print_launcher_logs+="tail -f ~/$cvd_home_dir/cuttlefish/instances/cvd-$instance_num/logs/launcher.log | sed 's/^/[$device_name] /' &"
done
ports_forwarding="-L $web_ui_port:127.0.0.1:1443 \
@@ -100,4 +103,4 @@
$adb_port_forwarding"
echo "Set up ssh ports forwarding: $ports_forwarding"
echo -e "${color_yellow}Please stop the running instances by ctrl+c${color_plain}"
-ssh -N $server $ports_forwarding
+ssh $server $ports_forwarding $print_launcher_logs
diff --git a/vsoc_arm64_pgagnostic/BoardConfig.mk b/vsoc_arm64_pgagnostic/BoardConfig.mk
index 5a2773a..5ae28c4 100644
--- a/vsoc_arm64_pgagnostic/BoardConfig.mk
+++ b/vsoc_arm64_pgagnostic/BoardConfig.mk
@@ -44,6 +44,7 @@
HOST_CROSS_2ND_ARCH :=
-include device/google/cuttlefish/shared/BoardConfig.mk
+-include device/google/cuttlefish/shared/bluetooth/BoardConfig.mk
-include device/google/cuttlefish/shared/camera/BoardConfig.mk
-include device/google/cuttlefish/shared/graphics/BoardConfig.mk
-include device/google/cuttlefish/shared/identity/BoardConfig.mk
diff --git a/vsoc_x86_64_pgagnostic/BoardConfig.mk b/vsoc_x86_64_pgagnostic/BoardConfig.mk
index b8f2d1d..a9870f6 100644
--- a/vsoc_x86_64_pgagnostic/BoardConfig.mk
+++ b/vsoc_x86_64_pgagnostic/BoardConfig.mk
@@ -28,6 +28,9 @@
TARGET_NATIVE_BRIDGE_CPU_VARIANT := generic
TARGET_NATIVE_BRIDGE_ABI := arm64-v8a
+TARGET_USERDATAIMAGE_FILE_SYSTEM_TYPE := ext4
+TARGET_RO_FILE_SYSTEM_TYPE := ext4
+
AUDIOSERVER_MULTILIB := first
-include device/google/cuttlefish/shared/BoardConfig.mk