Merge "[ANAPIC Review] The radio config type 1.3 hal is removed, need to sync in cuttlefish" into sc-dev
diff --git a/common/libs/semaphore/semaphore.h b/common/libs/concurrency/semaphore.h
similarity index 64%
rename from common/libs/semaphore/semaphore.h
rename to common/libs/concurrency/semaphore.h
index 49a9fbd..5af43a7 100644
--- a/common/libs/semaphore/semaphore.h
+++ b/common/libs/concurrency/semaphore.h
@@ -22,37 +22,31 @@
#include <mutex>
namespace cuttlefish {
-/**
- * An ad-hoc semaphore used to track the number of items in all queue
- */
class Semaphore {
public:
- Semaphore(const int init_val = 0) : count_{init_val} {}
+ Semaphore(const unsigned int init_val = 0, const unsigned int cap = 30000)
+ : count_{init_val}, capacity_{cap} {}
- // called by the threads that consumes all of the multiple queues
void SemWait() {
std::unique_lock<std::mutex> lock(mtx_);
- cv_.wait(lock, [this]() -> bool { return this->count_ > 0; });
+ resoure_cv_.wait(lock, [this]() -> bool { return count_ > 0; });
--count_;
+ room_cv_.notify_one();
}
- // called by each producer thread effectively, whenever an item is added
void SemPost() {
std::unique_lock<std::mutex> lock(mtx_);
- if (++count_ > 0) {
- cv_.notify_all();
- }
+ room_cv_.wait(lock, [this]() -> bool { return count_ <= capacity_; });
+ ++count_;
+ resoure_cv_.notify_one();
}
- void SemWaitItem() { SemWait(); }
-
- // Only called by the producers
- void SemPostItem() { SemPost(); }
-
private:
std::mutex mtx_;
- std::condition_variable cv_;
- int count_;
+ std::condition_variable resoure_cv_;
+ std::condition_variable room_cv_;
+ unsigned int count_;
+ const unsigned int capacity_; // inclusive upper limit
};
} // namespace cuttlefish
diff --git a/common/libs/concurrency/thread_annotations.h b/common/libs/concurrency/thread_annotations.h
new file mode 100644
index 0000000..cd568b3
--- /dev/null
+++ b/common/libs/concurrency/thread_annotations.h
@@ -0,0 +1,72 @@
+#pragma once
+/*
+ * Copyright (C) 2016 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.
+ */
+
+#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
+#else
+#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
+#endif
+
+#define CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
+
+#define SCOPED_CAPABILITY THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
+
+#define GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
+
+#define PT_GUARDED_BY(x) THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
+
+#define ACQUIRED_BEFORE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
+
+#define ACQUIRED_AFTER(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
+
+#define REQUIRES(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
+
+#define REQUIRES_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
+
+#define ACQUIRE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
+
+#define ACQUIRE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
+
+#define RELEASE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
+
+#define RELEASE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
+
+#define TRY_ACQUIRE_SHARED(...) \
+ THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
+
+#define EXCLUDES(...) THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
+
+#define ASSERT_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
+
+#define ASSERT_SHARED_CAPABILITY(x) \
+ THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
+
+#define RETURN_CAPABILITY(x) THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
+
+#define NO_THREAD_SAFETY_ANALYSIS \
+ THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
diff --git a/common/libs/thread_safe_queue/thread_safe_queue.h b/common/libs/concurrency/thread_safe_queue.h
similarity index 99%
rename from common/libs/thread_safe_queue/thread_safe_queue.h
rename to common/libs/concurrency/thread_safe_queue.h
index ca25b75..9105299 100644
--- a/common/libs/thread_safe_queue/thread_safe_queue.h
+++ b/common/libs/concurrency/thread_safe_queue.h
@@ -16,11 +16,11 @@
* limitations under the License.
*/
-#include <mutex>
#include <condition_variable>
#include <deque>
-#include <utility>
#include <iterator>
+#include <mutex>
+#include <utility>
namespace cuttlefish {
// Simple queue with Push and Pop capabilities.
diff --git a/common/libs/threads/thread_annotations.h b/common/libs/threads/thread_annotations.h
deleted file mode 100644
index 3ba67e7..0000000
--- a/common/libs/threads/thread_annotations.h
+++ /dev/null
@@ -1,79 +0,0 @@
-#pragma once
-/*
- * Copyright (C) 2016 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.
- */
-
-#if defined(__SUPPORT_TS_ANNOTATION__) || defined(__clang__)
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) __attribute__((x))
-#else
-#define THREAD_ANNOTATION_ATTRIBUTE__(x) // no-op
-#endif
-
-#define CAPABILITY(x) \
- THREAD_ANNOTATION_ATTRIBUTE__(capability(x))
-
-#define SCOPED_CAPABILITY \
- THREAD_ANNOTATION_ATTRIBUTE__(scoped_lockable)
-
-#define GUARDED_BY(x) \
- THREAD_ANNOTATION_ATTRIBUTE__(guarded_by(x))
-
-#define PT_GUARDED_BY(x) \
- THREAD_ANNOTATION_ATTRIBUTE__(pt_guarded_by(x))
-
-#define ACQUIRED_BEFORE(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(acquired_before(__VA_ARGS__))
-
-#define ACQUIRED_AFTER(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(acquired_after(__VA_ARGS__))
-
-#define REQUIRES(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(requires_capability(__VA_ARGS__))
-
-#define REQUIRES_SHARED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(requires_shared_capability(__VA_ARGS__))
-
-#define ACQUIRE(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(acquire_capability(__VA_ARGS__))
-
-#define ACQUIRE_SHARED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(acquire_shared_capability(__VA_ARGS__))
-
-#define RELEASE(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(release_capability(__VA_ARGS__))
-
-#define RELEASE_SHARED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(release_shared_capability(__VA_ARGS__))
-
-#define TRY_ACQUIRE(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_capability(__VA_ARGS__))
-
-#define TRY_ACQUIRE_SHARED(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(try_acquire_shared_capability(__VA_ARGS__))
-
-#define EXCLUDES(...) \
- THREAD_ANNOTATION_ATTRIBUTE__(locks_excluded(__VA_ARGS__))
-
-#define ASSERT_CAPABILITY(x) \
- THREAD_ANNOTATION_ATTRIBUTE__(assert_capability(x))
-
-#define ASSERT_SHARED_CAPABILITY(x) \
- THREAD_ANNOTATION_ATTRIBUTE__(assert_shared_capability(x))
-
-#define RETURN_CAPABILITY(x) \
- THREAD_ANNOTATION_ATTRIBUTE__(lock_returned(x))
-
-#define NO_THREAD_SAFETY_ANALYSIS \
- THREAD_ANNOTATION_ATTRIBUTE__(no_thread_safety_analysis)
diff --git a/default-permissions.xml b/default-permissions.xml
index 8f2920e..038ffce 100644
--- a/default-permissions.xml
+++ b/default-permissions.xml
@@ -67,17 +67,6 @@
<permission name="android.permission.RECEIVE_SMS" fixed="false"/>
</exception>
- <exception
- package="com.google.android.projection.gearhead"
- sha256-cert-digest="FD:B0:0C:43:DB:DE:8B:51:CB:31:2A:A8:1D:3B:5F:A1:77:13:AD:B9:4B:28:F5:98:D7:7F:8E:B8:9D:AC:EE:DF">
- <!-- For Top Gear -->
- <permission name="android.permission.PROCESS_OUTGOING_CALLS" fixed="false"/>
- <permission name="android.permission.READ_SMS" fixed="false"/>
- <permission name="android.permission.RECEIVE_MMS" fixed="false"/>
- <permission name="android.permission.WRITE_CALL_LOG" fixed="false"/>
- <permission name="android.permission.ACCESS_COARSE_LOCATION" fixed="false"/>
- </exception>
-
<exception package="com.google.android.settings.intelligence">
<!-- Calendar -->
<permission name="android.permission.READ_CALENDAR" fixed="true"/>
diff --git a/guest/commands/rotate/main.cpp b/guest/commands/rotate/main.cpp
deleted file mode 100644
index 8967097..0000000
--- a/guest/commands/rotate/main.cpp
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#include <android-base/chrono_utils.h>
-#include <android-base/logging.h>
-#include <binder/IServiceManager.h>
-#include <utils/StrongPointer.h>
-#include <utils/SystemClock.h>
-
-#include <thread>
-
-#include "android/hardware/sensors/2.0/ISensors.h"
-
-using android::sp;
-using android::hardware::sensors::V1_0::Event;
-using android::hardware::sensors::V1_0::OperationMode;
-using android::hardware::sensors::V1_0::Result;
-using android::hardware::sensors::V1_0::SensorInfo;
-using android::hardware::sensors::V1_0::SensorStatus;
-using android::hardware::sensors::V1_0::SensorType;
-using android::hardware::sensors::V2_0::ISensors;
-
-void InjectOrientation(bool portrait) {
- const sp<ISensors> sensors = ISensors::getService();
- if (sensors == nullptr) {
- LOG(FATAL) << "Unable to get ISensors.";
- }
-
- Result result;
-
- // Place the ISensors HAL into DATA_INJECTION mode so that we can
- // inject events.
- result = sensors->setOperationMode(OperationMode::DATA_INJECTION);
- if (result != Result::OK) {
- LOG(FATAL) << "Unable to set ISensors operation mode to DATA_INJECTION: "
- << toString(result);
- }
-
- // Find the first available accelerometer sensor.
- int accel_handle = -1;
- const auto& getSensorsList_result =
- sensors->getSensorsList([&](const auto& list) {
- for (const SensorInfo& sensor : list) {
- if (sensor.type == SensorType::ACCELEROMETER) {
- accel_handle = sensor.sensorHandle;
- break;
- }
- }
- });
- if (!getSensorsList_result.isOk()) {
- LOG(FATAL) << "Unable to get ISensors sensors list: "
- << getSensorsList_result.description();
- }
- if (accel_handle == -1) {
- LOG(FATAL) << "Unable to find ACCELEROMETER sensor.";
- }
-
- // Create a base ISensors accelerometer event.
- Event event;
- event.sensorHandle = accel_handle;
- event.sensorType = SensorType::ACCELEROMETER;
- if (portrait) {
- event.u.vec3.x = 0;
- event.u.vec3.y = 9.2;
- } else {
- event.u.vec3.x = 9.2;
- event.u.vec3.y = 0;
- }
- event.u.vec3.z = 3.5;
- event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
-
- // Repeatedly inject accelerometer events. The WindowManager orientation
- // listener responds to sustained accelerometer data, not just a single event.
- android::base::Timer timer;
- while (timer.duration() < 1s) {
- event.timestamp = android::elapsedRealtimeNano();
- result = sensors->injectSensorData(event);
- if (result != Result::OK) {
- LOG(FATAL) << "Unable to inject ISensors accelerometer event: "
- << toString(result);
- }
- std::this_thread::sleep_for(10ms);
- }
-
- // Return the ISensors HAL back to NORMAL mode.
- result = sensors->setOperationMode(OperationMode::NORMAL);
- if (result != Result::OK) {
- LOG(FATAL) << "Unable to set sensors operation mode to NORMAL: "
- << toString(result);
- }
-}
-
-int main(int argc, char** argv) {
- if (argc == 1) {
- LOG(FATAL) << "Expected command line arg 'portrait' or 'landscape'";
- }
-
- bool portrait = true;
- if (!strcmp(argv[1], "portrait")) {
- portrait = true;
- } else if (!strcmp(argv[1], "landscape")) {
- portrait = false;
- } else {
- LOG(FATAL) << "Expected command line arg 'portrait' or 'landscape'";
- }
-
- InjectOrientation(portrait);
-}
diff --git a/guest/commands/rotate/Android.bp b/guest/commands/sensor_injection/Android.bp
similarity index 79%
rename from guest/commands/rotate/Android.bp
rename to guest/commands/sensor_injection/Android.bp
index 6568c0e..a29250a 100644
--- a/guest/commands/rotate/Android.bp
+++ b/guest/commands/sensor_injection/Android.bp
@@ -3,11 +3,11 @@
}
cc_binary {
- name: "cuttlefish_rotate",
+ name: "cuttlefish_sensor_injection",
srcs: ["main.cpp"],
shared_libs: [
"[email protected]",
- "[email protected]",
+ "[email protected]",
"libbase",
"libbinder",
"libhidlbase",
diff --git a/guest/commands/sensor_injection/main.cpp b/guest/commands/sensor_injection/main.cpp
new file mode 100644
index 0000000..6eadb4a
--- /dev/null
+++ b/guest/commands/sensor_injection/main.cpp
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2021 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 <android-base/chrono_utils.h>
+#include <android-base/logging.h>
+#include <binder/IServiceManager.h>
+#include <utils/StrongPointer.h>
+#include <utils/SystemClock.h>
+
+#include <thread>
+
+#include "android/hardware/sensors/2.1/ISensors.h"
+
+using android::sp;
+using android::hardware::sensors::V1_0::OperationMode;
+using android::hardware::sensors::V1_0::Result;
+using android::hardware::sensors::V1_0::SensorStatus;
+using android::hardware::sensors::V2_1::Event;
+using android::hardware::sensors::V2_1::ISensors;
+using android::hardware::sensors::V2_1::SensorInfo;
+using android::hardware::sensors::V2_1::SensorType;
+
+sp<ISensors> startSensorInjection() {
+ const sp<ISensors> sensors = ISensors::getService();
+ if (sensors == nullptr) {
+ LOG(FATAL) << "Unable to get ISensors.";
+ }
+
+ // Place the ISensors HAL into DATA_INJECTION mode so that we can
+ // inject events.
+ Result result = sensors->setOperationMode(OperationMode::DATA_INJECTION);
+ if (result != Result::OK) {
+ LOG(FATAL) << "Unable to set ISensors operation mode to DATA_INJECTION: "
+ << toString(result);
+ }
+
+ return sensors;
+}
+
+int getSensorHandle(SensorType type, const sp<ISensors> sensors) {
+ // Find the first available sensor of the given type.
+ int handle = -1;
+ const auto& getSensorsList_result =
+ sensors->getSensorsList_2_1([&](const auto& list) {
+ for (const SensorInfo& sensor : list) {
+ if (sensor.type == type) {
+ handle = sensor.sensorHandle;
+ break;
+ }
+ }
+ });
+ if (!getSensorsList_result.isOk()) {
+ LOG(FATAL) << "Unable to get ISensors sensors list: "
+ << getSensorsList_result.description();
+ }
+ if (handle == -1) {
+ LOG(FATAL) << "Unable to find sensor.";
+ }
+ return handle;
+}
+
+void endSensorInjection(const sp<ISensors> sensors) {
+ // Return the ISensors HAL back to NORMAL mode.
+ Result result = sensors->setOperationMode(OperationMode::NORMAL);
+ if (result != Result::OK) {
+ LOG(FATAL) << "Unable to set sensors operation mode to NORMAL: "
+ << toString(result);
+ }
+}
+
+// Inject ACCELEROMETER events to corresponding to a given physical
+// device orientation: portrait or landscape.
+void InjectOrientation(bool portrait) {
+ sp<ISensors> sensors = startSensorInjection();
+ int handle = getSensorHandle(SensorType::ACCELEROMETER, sensors);
+
+ // Create a base ISensors accelerometer event.
+ Event event;
+ event.sensorHandle = handle;
+ event.sensorType = SensorType::ACCELEROMETER;
+ if (portrait) {
+ event.u.vec3.x = 0;
+ event.u.vec3.y = 9.2;
+ } else {
+ event.u.vec3.x = 9.2;
+ event.u.vec3.y = 0;
+ }
+ event.u.vec3.z = 3.5;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+
+ // Repeatedly inject accelerometer events. The WindowManager orientation
+ // listener responds to sustained accelerometer data, not just a single event.
+ android::base::Timer timer;
+ Result result;
+ while (timer.duration() < 1s) {
+ event.timestamp = android::elapsedRealtimeNano();
+ result = sensors->injectSensorData_2_1(event);
+ if (result != Result::OK) {
+ LOG(FATAL) << "Unable to inject ISensors accelerometer event: "
+ << toString(result);
+ }
+ std::this_thread::sleep_for(10ms);
+ }
+
+ endSensorInjection(sensors);
+}
+
+// Inject a single HINGE_ANGLE event at the given angle.
+void InjectHingeAngle(int angle) {
+ sp<ISensors> sensors = startSensorInjection();
+ int handle = getSensorHandle(SensorType::HINGE_ANGLE, sensors);
+
+ // Create a base ISensors hinge_angle event.
+ Event event;
+ event.sensorHandle = handle;
+ event.sensorType = SensorType::HINGE_ANGLE;
+ event.u.scalar = angle;
+ event.u.vec3.status = SensorStatus::ACCURACY_HIGH;
+ event.timestamp = android::elapsedRealtimeNano();
+ Result result = sensors->injectSensorData_2_1(event);
+ if (result != Result::OK) {
+ LOG(FATAL) << "Unable to inject HINGE_ANGLE data: " << toString(result);
+ }
+
+ endSensorInjection(sensors);
+}
+
+int main(int argc, char** argv) {
+ if (argc == 2) {
+ LOG(FATAL) << "Expected command line args 'rotate <portrait|landscape>' or "
+ "'hinge_angle <value>'";
+ }
+
+ if (!strcmp(argv[1], "rotate")) {
+ bool portrait = true;
+ if (!strcmp(argv[2], "portrait")) {
+ portrait = true;
+ } else if (!strcmp(argv[2], "landscape")) {
+ portrait = false;
+ } else {
+ LOG(FATAL) << "Expected command line arg 'portrait' or 'landscape'";
+ }
+ InjectOrientation(portrait);
+ } else if (!strcmp(argv[1], "hinge_angle")) {
+ int angle = std::stoi(argv[2]);
+ if (angle < 0 || angle > 360) {
+ LOG(FATAL) << "Bad hinge_angle value: " << argv[2];
+ }
+ InjectHingeAngle(angle);
+ } else {
+ LOG(FATAL) << "Unknown arg: " << argv[1];
+ }
+}
diff --git a/guest/hals/audio/audio_hw.c b/guest/hals/audio/audio_hw.c
index f5048df..652d747 100644
--- a/guest/hals/audio/audio_hw.c
+++ b/guest/hals/audio/audio_hw.c
@@ -1532,7 +1532,7 @@
}
if (*mic_count == 0) {
- *mic_count = 1;
+ *mic_count = 0;
return 0;
}
@@ -1561,7 +1561,7 @@
mic_array->orientation.y = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
mic_array->orientation.z = AUDIO_MICROPHONE_COORDINATE_UNKNOWN;
- *mic_count = 1;
+ *mic_count = 0;
return 0;
}
diff --git a/guest/hals/ril/reference-ril/reference-ril.c b/guest/hals/ril/reference-ril/reference-ril.c
index 9cfdaef..ac77d94 100644
--- a/guest/hals/ril/reference-ril/reference-ril.c
+++ b/guest/hals/ril/reference-ril/reference-ril.c
@@ -783,8 +783,7 @@
static bool hasWifiCapability()
{
char propValue[PROP_VALUE_MAX];
- return property_get("ro.kernel.qemu.wifi", propValue, "") > 0 &&
- strcmp("1", propValue) == 0;
+ return property_get("ro.boot.qemu.wifi", propValue, "") > 0 && strcmp("1", propValue) == 0;
}
static const char* getRadioInterfaceName(bool hasWifi)
diff --git a/host/commands/assemble_cvd/Android.bp b/host/commands/assemble_cvd/Android.bp
index c269be9..4ed4452 100644
--- a/host/commands/assemble_cvd/Android.bp
+++ b/host/commands/assemble_cvd/Android.bp
@@ -17,21 +17,6 @@
default_applicable_licenses: ["Android-Apache-2.0"],
}
-cc_library {
- name: "libcdisk_spec",
- srcs: [
- "cdisk_spec.proto",
- ],
- proto: {
- type: "full",
- export_proto_headers: true,
- include_dirs: [
- "external/protobuf/src",
- ],
- },
- defaults: ["cuttlefish_host"],
-}
-
cc_binary {
name: "assemble_cvd",
srcs: [
@@ -42,7 +27,6 @@
"clean.cc",
"disk_flags.cc",
"flags.cc",
- "image_aggregator.cc",
"misc_info.cc",
"super_image_mixer.cc",
],
@@ -63,6 +47,7 @@
static_libs: [
"libcdisk_spec",
"libext2_uuid",
+ "libimage_aggregator",
"libsparse",
"libcuttlefish_graphics_detector",
"libcuttlefish_host_config",
diff --git a/host/commands/assemble_cvd/assemble_cvd.cc b/host/commands/assemble_cvd/assemble_cvd.cc
index 1350bb6..c249473 100644
--- a/host/commands/assemble_cvd/assemble_cvd.cc
+++ b/host/commands/assemble_cvd/assemble_cvd.cc
@@ -144,7 +144,6 @@
preserving.insert("os_composite_gpt_footer.img");
preserving.insert("os_composite.img");
preserving.insert("sdcard.img");
- preserving.insert("uboot_env.img");
preserving.insert("boot_repacked.img");
preserving.insert("vendor_boot_repacked.img");
preserving.insert("access-kregistry");
@@ -153,6 +152,11 @@
preserving.insert("gatekeeper_insecure");
preserving.insert("modem_nvram.json");
preserving.insert("recording");
+ preserving.insert("persistent_composite_disk_config.txt");
+ preserving.insert("persistent_composite_gpt_header.img");
+ preserving.insert("persistent_composite_gpt_footer.img");
+ preserving.insert("persistent_composite.img");
+ preserving.insert("uboot_env.img");
preserving.insert("factory_reset_protected.img");
std::stringstream ss;
for (int i = 0; i < FLAGS_modem_simulator_count; i++) {
diff --git a/host/commands/assemble_cvd/disk_flags.cc b/host/commands/assemble_cvd/disk_flags.cc
index 21a5cca..96a4799 100644
--- a/host/commands/assemble_cvd/disk_flags.cc
+++ b/host/commands/assemble_cvd/disk_flags.cc
@@ -28,11 +28,11 @@
#include "common/libs/utils/subprocess.h"
#include "host/commands/assemble_cvd/boot_config.h"
#include "host/commands/assemble_cvd/boot_image_utils.h"
-#include "host/commands/assemble_cvd/image_aggregator.h"
#include "host/commands/assemble_cvd/super_image_mixer.h"
#include "host/libs/config/bootconfig_args.h"
#include "host/libs/config/cuttlefish_config.h"
#include "host/libs/config/data_image.h"
+#include "host/libs/image_aggregator/image_aggregator.h"
#include "host/libs/vm_manager/crosvm_manager.h"
// Taken from external/avb/libavb/avb_slot_verify.c; this define is not in the headers
@@ -121,14 +121,6 @@
std::vector<ImagePartition> os_composite_disk_config(
const CuttlefishConfig::InstanceSpecific& instance) {
std::vector<ImagePartition> partitions;
-
- // Note that if the positions of env or misc change, the environment for
- // u-boot must be updated as well (see boot_config.cc and
- // configs/cf-x86_defconfig in external/u-boot).
- partitions.push_back(ImagePartition {
- .label = "uboot_env",
- .image_file_path = instance.uboot_env_image_path(),
- });
partitions.push_back(ImagePartition {
.label = "misc",
.image_file_path = FLAGS_misc_image,
@@ -200,10 +192,34 @@
return partitions;
}
+std::vector<ImagePartition> persistent_composite_disk_config(
+ const CuttlefishConfig::InstanceSpecific& instance) {
+ std::vector<ImagePartition> partitions;
+
+ // Note that if the position of uboot_env changes, the environment for
+ // u-boot must be updated as well (see boot_config.cc and
+ // cuttlefish.fragment in external/u-boot).
+ partitions.push_back(ImagePartition{
+ .label = "uboot_env",
+ .image_file_path = instance.uboot_env_image_path(),
+ });
+ if (!FLAGS_protected_vm) {
+ partitions.push_back(ImagePartition{
+ .label = "frp",
+ .image_file_path = instance.factory_reset_protected_path(),
+ });
+ }
+ return partitions;
+}
+
static std::chrono::system_clock::time_point LastUpdatedInputDisk(
const std::vector<ImagePartition>& partitions) {
std::chrono::system_clock::time_point ret;
for (auto& partition : partitions) {
+ if (partition.label == "frp") {
+ continue;
+ }
+
auto partition_mod_time = FileModificationTime(partition.image_file_path);
if (partition_mod_time > ret) {
ret = partition_mod_time;
@@ -216,10 +232,6 @@
std::chrono::system_clock::time_point youngest_disk_img;
for (auto& partition :
os_composite_disk_config(config.ForDefaultInstance())) {
- if (partition.label == "uboot_env") {
- continue;
- }
-
auto partition_mod_time = FileModificationTime(partition.image_file_path);
if (partition_mod_time > youngest_disk_img) {
youngest_disk_img = partition_mod_time;
@@ -338,6 +350,30 @@
return true;
}
+bool CreatePersistentCompositeDisk(
+ const CuttlefishConfig& config,
+ const CuttlefishConfig::InstanceSpecific& instance) {
+ if (!SharedFD::Open(instance.persistent_composite_disk_path().c_str(),
+ O_WRONLY | O_CREAT, 0644)
+ ->IsOpen()) {
+ LOG(ERROR) << "Could not ensure "
+ << instance.persistent_composite_disk_path() << " exists";
+ return false;
+ }
+ if (config.vm_manager() == CrosvmManager::name()) {
+ std::string header_path =
+ instance.PerInstancePath("persistent_composite_gpt_header.img");
+ std::string footer_path =
+ instance.PerInstancePath("persistent_composite_gpt_footer.img");
+ CreateCompositeDisk(persistent_composite_disk_config(instance), header_path,
+ footer_path, instance.persistent_composite_disk_path());
+ } else {
+ AggregateImage(persistent_composite_disk_config(instance),
+ instance.persistent_composite_disk_path());
+ }
+ return true;
+}
+
static void RepackAllBootImages(const CuttlefishConfig* config) {
CHECK(FileHasContent(FLAGS_boot_image))
<< "File not found: " << FLAGS_boot_image;
@@ -414,13 +450,6 @@
if (!FLAGS_protected_vm) {
RepackAllBootImages(config);
- // TODO(b/181812679) remove this block when we no longer need to create the
- // env partition.
- for (auto instance : config->Instances()) {
- CHECK(InitBootloaderEnvPartition(*config, instance))
- << "Failed to create bootloader environment partition";
- }
-
for (const auto& instance : config->Instances()) {
if (!FileExists(instance.access_kregistry_path())) {
CreateBlankImage(instance.access_kregistry_path(), 2 /* mb */, "none");
@@ -435,6 +464,9 @@
FLAGS_blank_sdcard_image_mb, "sdcard");
}
+ CHECK(InitBootloaderEnvPartition(*config, instance))
+ << "Failed to create bootloader environment partition";
+
const auto frp = instance.factory_reset_protected_path();
if (!FileExists(frp)) {
CreateBlankImage(frp, 1 /* mb */, "none");
@@ -442,6 +474,20 @@
}
}
+ for (const auto& instance : config->Instances()) {
+ bool compositeMatchesDiskConfig = DoesCompositeMatchCurrentDiskConfig(
+ instance.PerInstancePath("persistent_composite_disk_config.txt"),
+ persistent_composite_disk_config(instance));
+ bool oldCompositeDisk =
+ ShouldCreateCompositeDisk(instance.persistent_composite_disk_path(),
+ persistent_composite_disk_config(instance));
+
+ if (!compositeMatchesDiskConfig || oldCompositeDisk) {
+ CHECK(CreatePersistentCompositeDisk(*config, instance))
+ << "Failed to create persistent composite disk";
+ }
+ }
+
// libavb expects to be able to read the maximum vbmeta size, so we must
// provide a partition which matches this or the read will fail
for (const auto& vbmeta_image : { FLAGS_vbmeta_image, FLAGS_vbmeta_system_image }) {
diff --git a/host/commands/assemble_cvd/disk_flags.h b/host/commands/assemble_cvd/disk_flags.h
index 122a728..3491c3a 100644
--- a/host/commands/assemble_cvd/disk_flags.h
+++ b/host/commands/assemble_cvd/disk_flags.h
@@ -20,7 +20,6 @@
#include <memory>
#include <vector>
-#include "host/commands/assemble_cvd/image_aggregator.h"
#include "host/libs/config/cuttlefish_config.h"
#include "host/libs/config/fetcher_config.h"
diff --git a/host/commands/assemble_cvd/flags.cc b/host/commands/assemble_cvd/flags.cc
index bfb856b..2d3f9da 100644
--- a/host/commands/assemble_cvd/flags.cc
+++ b/host/commands/assemble_cvd/flags.cc
@@ -708,8 +708,8 @@
{const_instance.PerInstancePath("os_composite.img")});
} else {
std::vector<std::string> virtual_disk_paths = {
- const_instance.PerInstancePath("overlay.img"),
- const_instance.factory_reset_protected_path(),
+ const_instance.PerInstancePath("overlay.img"),
+ const_instance.PerInstancePath("persistent_composite.img"),
};
if (FLAGS_use_sdcard) {
virtual_disk_paths.push_back(const_instance.sdcard_path());
diff --git a/host/commands/console_forwarder/main.cpp b/host/commands/console_forwarder/main.cpp
index d12d66b..df5c9f7 100644
--- a/host/commands/console_forwarder/main.cpp
+++ b/host/commands/console_forwarder/main.cpp
@@ -38,6 +38,8 @@
-1,
"File descriptor for the console's output channel");
+namespace cuttlefish {
+
// Handles forwarding the serial console to a pseudo-terminal (PTY)
// It receives a couple of fds for the console (could be the same fd twice if,
// for example a socket_pair were used).
@@ -49,14 +51,12 @@
// protected by a mutex.
class ConsoleForwarder {
public:
- ConsoleForwarder(std::string console_path,
- cuttlefish::SharedFD console_in,
- cuttlefish::SharedFD console_out,
- cuttlefish::SharedFD console_log) :
- console_path_(console_path),
- console_in_(console_in),
- console_out_(console_out),
- console_log_(console_log) {}
+ ConsoleForwarder(std::string console_path, SharedFD console_in,
+ SharedFD console_out, SharedFD console_log)
+ : console_path_(console_path),
+ console_in_(console_in),
+ console_out_(console_out),
+ console_log_(console_log) {}
[[noreturn]] void StartServer() {
// Create a new thread to handle writes to the console
writer_thread_ = std::thread([this]() { WriteLoop(); });
@@ -65,61 +65,45 @@
ReadLoop();
}
private:
-
- cuttlefish::SharedFD OpenPTY() {
+ SharedFD OpenPTY() {
// Remove any stale symlink to a pts device
auto ret = unlink(console_path_.c_str());
- if (ret < 0 && errno != ENOENT) {
- LOG(ERROR) << "Failed to unlink " << console_path_.c_str()
- << ": " << strerror(errno);
- std::exit(-5);
- }
+ CHECK(!(ret < 0 && errno != ENOENT))
+ << "Failed to unlink " << console_path_ << ": " << strerror(errno);
auto pty = posix_openpt(O_RDWR | O_NOCTTY | O_NONBLOCK);
- if (pty < 0) {
- LOG(ERROR) << "Failed to open a PTY: " << strerror(errno);
- std::exit(-6);
- }
+ CHECK(pty >= 0) << "Failed to open a PTY: " << strerror(errno);
+
grantpt(pty);
unlockpt(pty);
// Disable all echo modes on the PTY
struct termios termios;
- if (tcgetattr(pty, &termios) < 0) {
- LOG(ERROR) << "Failed to get terminal control: " << strerror(errno);
- std::exit(-7);
- }
+ CHECK(tcgetattr(pty, &termios) >= 0)
+ << "Failed to get terminal control: " << strerror(errno);
+
termios.c_lflag &= ~(ECHO | ECHOE | ECHOK | ECHONL);
termios.c_oflag &= ~(ONLCR);
- if (tcsetattr(pty, TCSANOW, &termios) < 0) {
- LOG(ERROR) << "Failed to set terminal control: " << strerror(errno);
- std::exit(-8);
- }
+ CHECK(tcsetattr(pty, TCSANOW, &termios) >= 0)
+ << "Failed to set terminal control: " << strerror(errno);
auto pty_dev_name = ptsname(pty);
- if (pty_dev_name == nullptr) {
- LOG(ERROR) << "Failed to obtain PTY device name: " << strerror(errno);
- std::exit(-9);
- }
+ CHECK(pty_dev_name != nullptr)
+ << "Failed to obtain PTY device name: " << strerror(errno);
- if (symlink(pty_dev_name, console_path_.c_str()) < 0) {
- LOG(ERROR) << "Failed to create symlink to " << pty_dev_name << " at "
- << console_path_.c_str() << ": " << strerror(errno);
- std::exit(-10);
- }
+ CHECK(symlink(pty_dev_name, console_path_.c_str()) >= 0)
+ << "Failed to create symlink to " << pty_dev_name << " at "
+ << console_path_ << ": " << strerror(errno);
- auto pty_shared_fd = cuttlefish::SharedFD::Dup(pty);
+ auto pty_shared_fd = SharedFD::Dup(pty);
close(pty);
- if (!pty_shared_fd->IsOpen()) {
- LOG(ERROR) << "Error dupping fd " << pty << ": "
- << pty_shared_fd->StrError();
- std::exit(-11);
- }
+ CHECK(pty_shared_fd->IsOpen())
+ << "Error dupping fd " << pty << ": " << pty_shared_fd->StrError();
return pty_shared_fd;
}
- void EnqueueWrite(std::shared_ptr<std::vector<char>> buf_ptr, cuttlefish::SharedFD fd) {
+ void EnqueueWrite(std::shared_ptr<std::vector<char>> buf_ptr, SharedFD fd) {
std::lock_guard<std::mutex> lock(write_queue_mutex_);
write_queue_.emplace_back(fd, buf_ptr);
condvar_.notify_one();
@@ -129,7 +113,7 @@
while (true) {
while (!write_queue_.empty()) {
std::shared_ptr<std::vector<char>> buf_ptr;
- cuttlefish::SharedFD fd;
+ SharedFD fd;
{
std::lock_guard<std::mutex> lock(write_queue_mutex_);
auto& front = write_queue_.front();
@@ -170,26 +154,23 @@
}
[[noreturn]] void ReadLoop() {
- cuttlefish::SharedFD client_fd;
+ SharedFD client_fd;
while (true) {
if (!client_fd->IsOpen()) {
client_fd = OpenPTY();
}
- cuttlefish::SharedFDSet read_set;
+ SharedFDSet read_set;
read_set.Set(console_out_);
read_set.Set(client_fd);
- cuttlefish::Select(&read_set, nullptr, nullptr, nullptr);
+ Select(&read_set, nullptr, nullptr, nullptr);
if (read_set.IsSet(console_out_)) {
std::shared_ptr<std::vector<char>> buf_ptr = std::make_shared<std::vector<char>>(4096);
auto bytes_read = console_out_->Read(buf_ptr->data(), buf_ptr->size());
- if (bytes_read <= 0) {
- LOG(ERROR) << "Error reading from console output: "
- << console_out_->StrError();
- // This is likely unrecoverable, so exit here
- std::exit(-12);
- }
+ // This is likely unrecoverable, so exit here
+ CHECK(bytes_read > 0) << "Error reading from console output: "
+ << console_out_->StrError();
buf_ptr->resize(bytes_read);
EnqueueWrite(buf_ptr, console_log_);
if (client_fd->IsOpen()) {
@@ -215,59 +196,53 @@
}
std::string console_path_;
- cuttlefish::SharedFD console_in_;
- cuttlefish::SharedFD console_out_;
- cuttlefish::SharedFD console_log_;
+ SharedFD console_in_;
+ SharedFD console_out_;
+ SharedFD console_log_;
std::thread writer_thread_;
std::mutex write_queue_mutex_;
std::condition_variable condvar_;
- std::deque<std::pair<cuttlefish::SharedFD, std::shared_ptr<std::vector<char>>>> write_queue_;
+ std::deque<std::pair<SharedFD, std::shared_ptr<std::vector<char>>>>
+ write_queue_;
};
-int main(int argc, char** argv) {
- cuttlefish::DefaultSubprocessLogging(argv);
+int ConsoleForwarderMain(int argc, char** argv) {
+ DefaultSubprocessLogging(argv);
::gflags::ParseCommandLineFlags(&argc, &argv, true);
- if (FLAGS_console_in_fd < 0 || FLAGS_console_out_fd < 0) {
- LOG(ERROR) << "Invalid file descriptors: " << FLAGS_console_in_fd << ", "
- << FLAGS_console_out_fd;
- return -1;
- }
+ CHECK(!(FLAGS_console_in_fd < 0 || FLAGS_console_out_fd < 0))
+ << "Invalid file descriptors: " << FLAGS_console_in_fd << ", "
+ << FLAGS_console_out_fd;
- auto console_in = cuttlefish::SharedFD::Dup(FLAGS_console_in_fd);
- close(FLAGS_console_in_fd);
- if (!console_in->IsOpen()) {
- LOG(ERROR) << "Error dupping fd " << FLAGS_console_in_fd << ": "
- << console_in->StrError();
- return -2;
- }
+ auto console_in = SharedFD::Dup(FLAGS_console_in_fd);
+ CHECK(console_in->IsOpen()) << "Error dupping fd " << FLAGS_console_in_fd
+ << ": " << console_in->StrError();
close(FLAGS_console_in_fd);
- auto console_out = cuttlefish::SharedFD::Dup(FLAGS_console_out_fd);
+ auto console_out = SharedFD::Dup(FLAGS_console_out_fd);
+ CHECK(console_out->IsOpen()) << "Error dupping fd " << FLAGS_console_out_fd
+ << ": " << console_out->StrError();
close(FLAGS_console_out_fd);
- if (!console_out->IsOpen()) {
- LOG(ERROR) << "Error dupping fd " << FLAGS_console_out_fd << ": "
- << console_out->StrError();
- return -3;
- }
- auto config = cuttlefish::CuttlefishConfig::Get();
- if (!config) {
- LOG(ERROR) << "Unable to get config object";
- return -4;
- }
+ auto config = CuttlefishConfig::Get();
+ CHECK(config) << "Unable to get config object";
auto instance = config->ForDefaultInstance();
auto console_path = instance.console_path();
auto console_log = instance.PerInstancePath("console_log");
- auto console_log_fd = cuttlefish::SharedFD::Open(console_log.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0666);
+ auto console_log_fd =
+ SharedFD::Open(console_log.c_str(), O_CREAT | O_APPEND | O_WRONLY, 0666);
ConsoleForwarder console_forwarder(console_path, console_in, console_out, console_log_fd);
// Don't get a SIGPIPE from the clients
- if (sigaction(SIGPIPE, nullptr, nullptr) != 0) {
- LOG(FATAL) << "Failed to set SIGPIPE to be ignored: " << strerror(errno);
- return -13;
- }
+ CHECK(sigaction(SIGPIPE, nullptr, nullptr) == 0)
+ << "Failed to set SIGPIPE to be ignored: " << strerror(errno);
console_forwarder.StartServer();
}
+
+} // namespace cuttlefish
+
+int main(int argc, char** argv) {
+ return cuttlefish::ConsoleForwarderMain(argc, argv);
+}
diff --git a/host/commands/fetcher/build_api.cc b/host/commands/fetcher/build_api.cc
index 8f97517..69229f0 100644
--- a/host/commands/fetcher/build_api.cc
+++ b/host/commands/fetcher/build_api.cc
@@ -164,8 +164,21 @@
bool BuildApi::ArtifactToFile(const DeviceBuild& build,
const std::string& artifact,
const std::string& path) {
- std::string url = BUILD_API + "/builds/" + build.id + "/" + build.target
- + "/attempts/latest/artifacts/" + artifact + "?alt=media";
+ std::string url;
+ if (credential_source) {
+ url = BUILD_API + "/builds/" + build.id + "/" + build.target +
+ "/attempts/latest/artifacts/" + artifact + "?alt=media";
+ } else {
+ std::string download_url_endpoint =
+ BUILD_API + "/builds/" + build.id + "/" + build.target +
+ "/attempts/latest/artifacts/" + artifact + "/url";
+ auto download_url_json = curl.DownloadToJson(download_url_endpoint);
+ if (!download_url_json.isMember("signedUrl")) {
+ LOG(ERROR) << "URL endpoint did not have json path";
+ return false;
+ }
+ url = download_url_json["signedUrl"].asString();
+ }
return curl.DownloadToFile(url, path, Headers());
}
diff --git a/host/commands/mk_cdisk/Android.bp b/host/commands/mk_cdisk/Android.bp
new file mode 100644
index 0000000..266dd15
--- /dev/null
+++ b/host/commands/mk_cdisk/Android.bp
@@ -0,0 +1,40 @@
+//
+// Copyright (C) 2021 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_binary {
+ name: "mk_cdisk",
+ srcs: [
+ "mk_cdisk.cc",
+ ],
+ shared_libs: [
+ "libcuttlefish_fs",
+ "libcuttlefish_utils",
+ "libbase",
+ "libjsoncpp",
+ "libprotobuf-cpp-full",
+ "libz",
+ ],
+ static_libs: [
+ "libcdisk_spec",
+ "libext2_uuid",
+ "libimage_aggregator",
+ "libsparse",
+ ],
+ defaults: ["cuttlefish_host"],
+}
diff --git a/host/commands/mk_cdisk/mk_cdisk.cc b/host/commands/mk_cdisk/mk_cdisk.cc
new file mode 100644
index 0000000..a9949dc
--- /dev/null
+++ b/host/commands/mk_cdisk/mk_cdisk.cc
@@ -0,0 +1,146 @@
+//
+// Copyright (C) 2021 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 <fstream>
+#include <iostream>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/result.h>
+#include <json/json.h>
+
+#include "common/libs/utils/files.h"
+#include "host/libs/image_aggregator/image_aggregator.h"
+
+using android::base::ErrnoError;
+using android::base::Error;
+using android::base::Result;
+
+using cuttlefish::CreateCompositeDisk;
+using cuttlefish::FileExists;
+using cuttlefish::ImagePartition;
+using cuttlefish::kLinuxFilesystem;
+
+// Returns `append` is appended to the end of filename preserving the extension.
+std::string AppendFileName(const std::string& filename,
+ const std::string& append) {
+ size_t pos = filename.find_last_of('.');
+ if (pos == std::string::npos) {
+ return filename + append;
+ } else {
+ return filename.substr(0, pos) + append + filename.substr(pos);
+ }
+}
+
+// config JSON schema:
+// {
+// "partitions": [
+// {
+// "label": string,
+// "path": string,
+// (opt) "read_only": bool
+// }
+// ]
+// }
+
+Result<std::vector<ImagePartition>> LoadConfig(std::istream& in) {
+ std::vector<ImagePartition> partitions;
+
+ Json::CharReaderBuilder builder;
+ Json::Value root;
+ Json::String errs;
+ if (!parseFromStream(builder, in, &root, &errs)) {
+ return Error() << "bad config: " << errs;
+ }
+ for (const Json::Value& part : root["partitions"]) {
+ const std::string label = part["label"].asString();
+ const std::string path = part["path"].asString();
+ const bool read_only =
+ part["read_only"].asBool(); // default: false (if null)
+
+ if (!FileExists(path)) {
+ return Error() << "bad config: Can't find \'" << path << '\'';
+ }
+ partitions.push_back(
+ ImagePartition{label, path, kLinuxFilesystem, read_only});
+ }
+
+ if (partitions.empty()) {
+ return Error() << "bad config: no partitions";
+ }
+ return partitions;
+}
+
+Result<std::vector<ImagePartition>> LoadConfig(const std::string& config_file) {
+ if (config_file == "-") {
+ return LoadConfig(std::cin);
+ } else {
+ std::ifstream in(config_file);
+ if (!in) {
+ return ErrnoError() << "Can't open file \'" << config_file << '\'';
+ }
+ return LoadConfig(in);
+ }
+}
+
+struct CompositeDiskArgs {
+ std::string config_file;
+ std::string output_file;
+};
+
+Result<CompositeDiskArgs> ParseCompositeDiskArgs(int argc, char** argv) {
+ if (argc != 3) {
+ std::cerr << fmt::format(
+ "Usage: {0} <config_file> <output_file>\n"
+ " or {0} - <output_file> (read config from STDIN)\n",
+ argv[0]);
+ return Error() << "missing arguments.";
+ }
+ CompositeDiskArgs args{
+ .config_file = argv[1],
+ .output_file = argv[2],
+ };
+ return args;
+}
+
+Result<void> MakeCompositeDiskMain(int argc, char** argv) {
+ setenv("ANDROID_LOG_TAGS", "*:v", /* overwrite */ 0);
+ ::android::base::InitLogging(argv, android::base::StderrLogger);
+
+ auto args = ParseCompositeDiskArgs(argc, argv);
+ if (!args.ok()) {
+ return args.error();
+ }
+ auto partitions = LoadConfig(args->config_file);
+ if (!partitions.ok()) {
+ return partitions.error();
+ }
+
+ // We need two implicit output paths: GPT header/footer
+ // e.g. out.img will have out-header.img and out-footer.img
+ std::string gpt_header = AppendFileName(args->output_file, "-header");
+ std::string gpt_footer = AppendFileName(args->output_file, "-footer");
+ CreateCompositeDisk(*partitions, gpt_header, gpt_footer, args->output_file);
+ return {};
+}
+
+int main(int argc, char** argv) {
+ auto result = MakeCompositeDiskMain(argc, argv);
+ if (!result.ok()) {
+ LOG(ERROR) << result.error();
+ return EXIT_FAILURE;
+ }
+ return 0;
+}
diff --git a/host/commands/modem_simulator/misc_service.cpp b/host/commands/modem_simulator/misc_service.cpp
index 0001c4e..1a2b767 100644
--- a/host/commands/modem_simulator/misc_service.cpp
+++ b/host/commands/modem_simulator/misc_service.cpp
@@ -16,6 +16,7 @@
#include "host/commands/modem_simulator/misc_service.h"
#include <ctime>
+#include <fstream>
#include <iomanip>
namespace cuttlefish {
@@ -23,7 +24,36 @@
MiscService::MiscService(int32_t service_id, ChannelMonitor* channel_monitor,
ThreadLooper* thread_looper)
: ModemService(service_id, this->InitializeCommandHandlers(),
- channel_monitor, thread_looper) {}
+ channel_monitor, thread_looper) {
+ ParseTimeZone();
+}
+
+void MiscService::ParseTimeZone() {
+#if defined(__linux__)
+ constexpr char TIMEZONE_FILENAME[] = "/etc/timezone";
+ std::ifstream ifs(TIMEZONE_FILENAME);
+ if (ifs.is_open()) {
+ std::string line;
+ if (std::getline(ifs, line)) {
+ FixTimeZone(line);
+ timezone_ = line;
+ }
+ }
+#endif
+}
+
+void MiscService::FixTimeZone(std::string& line) {
+ auto slashpos = line.find("/");
+ // "/" will be treated as separator, change it !
+ if (slashpos != std::string::npos) {
+ line.replace(slashpos, 1, "!");
+ }
+}
+
+void MiscService::SetTimeZone(std::string timezone) {
+ FixTimeZone(timezone);
+ timezone_ = timezone;
+}
std::vector<CommandHandler> MiscService::InitializeCommandHandlers() {
std::vector<CommandHandler> command_handlers = {
@@ -118,15 +148,18 @@
auto tzdiff = (int)std::difftime(t_local_time, t_gm_time) / (15 * 60);
std::stringstream ss;
- ss << "%CTZV: \"" << std::setfill('0') << std::setw(2) << local_time.tm_year % 100 << "/"
- << std::setfill('0') << std::setw(2) << local_time.tm_mon + 1 << "/"
- << std::setfill('0') << std::setw(2) << local_time.tm_mday << ","
- << std::setfill('0') << std::setw(2) << local_time.tm_hour << ":"
- << std::setfill('0') << std::setw(2) << local_time.tm_min << ":"
- << std::setfill('0') << std::setw(2) << local_time.tm_sec
- << (tzdiff >= 0 ? '+' : '-')
- << (tzdiff >= 0 ? tzdiff : -tzdiff) << ":"
- << local_time.tm_isdst << "\"";
+ ss << "%CTZV: \"" << std::setfill('0') << std::setw(2)
+ << local_time.tm_year % 100 << "/" << std::setfill('0') << std::setw(2)
+ << local_time.tm_mon + 1 << "/" << std::setfill('0') << std::setw(2)
+ << local_time.tm_mday << "," << std::setfill('0') << std::setw(2)
+ << local_time.tm_hour << ":" << std::setfill('0') << std::setw(2)
+ << local_time.tm_min << ":" << std::setfill('0') << std::setw(2)
+ << local_time.tm_sec << (tzdiff >= 0 ? '+' : '-')
+ << (tzdiff >= 0 ? tzdiff : -tzdiff) << ":" << local_time.tm_isdst;
+ if (!timezone_.empty()) {
+ ss << ":" << timezone_;
+ }
+ ss << "\"";
SendUnsolicitedCommand(ss.str());
}
diff --git a/host/commands/modem_simulator/misc_service.h b/host/commands/modem_simulator/misc_service.h
index e4944ed..e795a06 100644
--- a/host/commands/modem_simulator/misc_service.h
+++ b/host/commands/modem_simulator/misc_service.h
@@ -32,7 +32,12 @@
void TimeUpdate();
+ void SetTimeZone(std::string timezone);
+
private:
+ void ParseTimeZone();
+ void FixTimeZone(std::string& line);
+ std::string timezone_;
std::vector<CommandHandler> InitializeCommandHandlers();
};
diff --git a/host/commands/modem_simulator/modem_simulator.cpp b/host/commands/modem_simulator/modem_simulator.cpp
index 9c63dc2..61a23bd 100644
--- a/host/commands/modem_simulator/modem_simulator.cpp
+++ b/host/commands/modem_simulator/modem_simulator.cpp
@@ -137,6 +137,13 @@
}
}
+bool ModemSimulator::IsRadioOn() const {
+ if (network_service_) {
+ return !network_service_->isRadioOff();
+ }
+ return false;
+}
+
bool ModemSimulator::IsWaitingSmsPdu() {
if (sms_service_) {
return (sms_service_->IsWaitingSmsPdu() |
@@ -145,4 +152,10 @@
return false;
}
+void ModemSimulator::SetTimeZone(std::string timezone) {
+ if (misc_service_) {
+ misc_service_->SetTimeZone(timezone);
+ }
+}
+
} // namespace cuttlefish
diff --git a/host/commands/modem_simulator/modem_simulator.h b/host/commands/modem_simulator/modem_simulator.h
index da3be6d..9340e49 100644
--- a/host/commands/modem_simulator/modem_simulator.h
+++ b/host/commands/modem_simulator/modem_simulator.h
@@ -41,10 +41,13 @@
void OnFirstClientConnected();
void SaveModemState();
bool IsWaitingSmsPdu();
+ bool IsRadioOn() const;
void SetRemoteClient(cuttlefish::SharedFD client, bool is_accepted) {
channel_monitor_->SetRemoteClient(client, is_accepted);
}
+ void SetTimeZone(std::string timezone);
+
private:
int32_t modem_id_;
std::unique_ptr<ChannelMonitor> channel_monitor_;
diff --git a/host/frontend/vnc_server/Android.bp b/host/frontend/vnc_server/Android.bp
index c098e34..bfb5561 100644
--- a/host/frontend/vnc_server/Android.bp
+++ b/host/frontend/vnc_server/Android.bp
@@ -36,10 +36,18 @@
"libjsoncpp",
"liblog",
],
+ header_libs: [
+ "libcuttlefish_confui_host_headers",
+ ],
static_libs: [
"libcuttlefish_host_config",
"libcuttlefish_screen_connector",
"libcuttlefish_wayland_server",
+ "libcuttlefish_confui",
+ "libcuttlefish_confui_host",
+ "libft2.nodep",
+ "libteeui",
+ "libteeui_localization",
"libffi",
"libjpeg",
"libgflags",
diff --git a/host/frontend/vnc_server/blackboard.h b/host/frontend/vnc_server/blackboard.h
index 261774e..af4baea 100644
--- a/host/frontend/vnc_server/blackboard.h
+++ b/host/frontend/vnc_server/blackboard.h
@@ -22,7 +22,7 @@
#include <mutex>
#include <unordered_map>
-#include "common/libs/threads/thread_annotations.h"
+#include "common/libs/concurrency/thread_annotations.h"
#include "host/frontend/vnc_server/vnc_utils.h"
namespace cuttlefish {
diff --git a/host/frontend/vnc_server/frame_buffer_watcher.cpp b/host/frontend/vnc_server/frame_buffer_watcher.cpp
index 697a6d9..3cc39c0 100644
--- a/host/frontend/vnc_server/frame_buffer_watcher.cpp
+++ b/host/frontend/vnc_server/frame_buffer_watcher.cpp
@@ -27,12 +27,12 @@
#include <android-base/logging.h>
#include "host/frontend/vnc_server/vnc_utils.h"
-#include "host/libs/screen_connector/screen_connector.h"
using cuttlefish::vnc::FrameBufferWatcher;
-FrameBufferWatcher::FrameBufferWatcher(BlackBoard* bb)
- : bb_{bb}, hwcomposer{bb_} {
+FrameBufferWatcher::FrameBufferWatcher(BlackBoard* bb,
+ ScreenConnector& screen_connector)
+ : bb_{bb}, hwcomposer{bb_, screen_connector} {
for (auto& stripes_vec : stripes_) {
std::generate_n(std::back_inserter(stripes_vec),
SimulatedHWComposer::NumberOfStripes(),
diff --git a/host/frontend/vnc_server/frame_buffer_watcher.h b/host/frontend/vnc_server/frame_buffer_watcher.h
index d147642..9b559b6 100644
--- a/host/frontend/vnc_server/frame_buffer_watcher.h
+++ b/host/frontend/vnc_server/frame_buffer_watcher.h
@@ -22,16 +22,18 @@
#include <utility>
#include <vector>
-#include "common/libs/threads/thread_annotations.h"
+#include "common/libs/concurrency/thread_annotations.h"
#include "host/frontend/vnc_server/blackboard.h"
#include "host/frontend/vnc_server/jpeg_compressor.h"
#include "host/frontend/vnc_server/simulated_hw_composer.h"
+#include "host/libs/screen_connector/screen_connector.h"
namespace cuttlefish {
namespace vnc {
class FrameBufferWatcher {
public:
- explicit FrameBufferWatcher(BlackBoard* bb);
+ explicit FrameBufferWatcher(BlackBoard* bb,
+ ScreenConnector& screen_connector);
FrameBufferWatcher(const FrameBufferWatcher&) = delete;
FrameBufferWatcher& operator=(const FrameBufferWatcher&) = delete;
~FrameBufferWatcher();
@@ -72,7 +74,7 @@
mutable std::mutex m_;
bool closed_ GUARDED_BY(m_){};
BlackBoard* bb_{};
- SimulatedHWComposer hwcomposer{bb_};
+ SimulatedHWComposer hwcomposer;
};
} // namespace vnc
diff --git a/host/frontend/vnc_server/main.cpp b/host/frontend/vnc_server/main.cpp
index 58c1da6..e036b40 100644
--- a/host/frontend/vnc_server/main.cpp
+++ b/host/frontend/vnc_server/main.cpp
@@ -15,21 +15,40 @@
*/
#include <algorithm>
+#include <memory>
#include <string>
#include <gflags/gflags.h>
+#include "host/frontend/vnc_server/simulated_hw_composer.h"
#include "host/frontend/vnc_server/vnc_server.h"
#include "host/frontend/vnc_server/vnc_utils.h"
#include "host/libs/config/logging.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_server.h"
DEFINE_bool(agressive, false, "Whether to use agressive server");
+DEFINE_int32(frame_server_fd, -1, "");
DEFINE_int32(port, 6444, "Port where to listen for connections");
int main(int argc, char* argv[]) {
cuttlefish::DefaultSubprocessLogging(argv);
google::ParseCommandLineFlags(&argc, &argv, true);
- cuttlefish::vnc::VncServer vnc_server(FLAGS_port, FLAGS_agressive);
+ auto& host_mode_ctrl = cuttlefish::HostModeCtrl::Get();
+ auto screen_connector_ptr = cuttlefish::vnc::ScreenConnector::Get(
+ FLAGS_frame_server_fd, host_mode_ctrl);
+ auto& screen_connector = *(screen_connector_ptr.get());
+
+ // create confirmation UI service, giving host_mode_ctrl and
+ // screen_connector
+ // keep this singleton object alive until the webRTC process ends
+ static auto& host_confui_server =
+ cuttlefish::confui::HostServer::Get(host_mode_ctrl, screen_connector);
+
+ host_confui_server.Start();
+ // lint does not like the spelling of "agressive", so needs NOTYPO
+ cuttlefish::vnc::VncServer vnc_server(FLAGS_port, FLAGS_agressive, // NOTYPO
+ screen_connector, host_confui_server);
vnc_server.MainLoop();
}
diff --git a/host/frontend/vnc_server/simulated_hw_composer.cpp b/host/frontend/vnc_server/simulated_hw_composer.cpp
index ec1df09..b3176b9 100644
--- a/host/frontend/vnc_server/simulated_hw_composer.cpp
+++ b/host/frontend/vnc_server/simulated_hw_composer.cpp
@@ -16,25 +16,23 @@
#include "host/frontend/vnc_server/simulated_hw_composer.h"
-#include <gflags/gflags.h>
-
#include "host/frontend/vnc_server/vnc_utils.h"
#include "host/libs/config/cuttlefish_config.h"
-DEFINE_int32(frame_server_fd, -1, "");
-
using cuttlefish::vnc::SimulatedHWComposer;
+using ScreenConnector = cuttlefish::vnc::ScreenConnector;
-SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb)
+SimulatedHWComposer::SimulatedHWComposer(BlackBoard* bb,
+ ScreenConnector& screen_connector)
:
#ifdef FUZZ_TEST_VNC
engine_{std::random_device{}()},
#endif
bb_{bb},
stripes_(kMaxQueueElements, &SimulatedHWComposer::EraseHalfOfElements),
- screen_connector_(ScreenConnector::Get(FLAGS_frame_server_fd)) {
+ screen_connector_(screen_connector) {
stripe_maker_ = std::thread(&SimulatedHWComposer::MakeStripes, this);
- screen_connector_->SetCallback(std::move(GetScreenConnectorCallback()));
+ screen_connector_.SetCallback(std::move(GetScreenConnectorCallback()));
}
SimulatedHWComposer::~SimulatedHWComposer() {
@@ -77,21 +75,21 @@
SimulatedHWComposer::GetScreenConnectorCallback() {
return [](std::uint32_t display_number, std::uint8_t* frame_pixels,
cuttlefish::vnc::VncScProcessedFrame& processed_frame) {
+ processed_frame.display_number_ = display_number;
// TODO(171305898): handle multiple displays.
if (display_number != 0) {
processed_frame.is_success_ = false;
return;
}
const std::uint32_t display_w =
- SimulatedHWComposer::ScreenConnector::ScreenWidth(display_number);
+ ScreenConnector::ScreenWidth(display_number);
const std::uint32_t display_h =
- SimulatedHWComposer::ScreenConnector::ScreenHeight(display_number);
+ ScreenConnector::ScreenHeight(display_number);
const std::uint32_t display_stride_bytes =
- SimulatedHWComposer::ScreenConnector::ScreenStrideBytes(display_number);
- const std::uint32_t display_bpp =
- SimulatedHWComposer::ScreenConnector::BytesPerPixel();
+ ScreenConnector::ScreenStrideBytes(display_number);
+ const std::uint32_t display_bpp = ScreenConnector::BytesPerPixel();
const std::uint32_t display_size_bytes =
- SimulatedHWComposer::ScreenConnector::ScreenSizeInBytes(display_number);
+ ScreenConnector::ScreenSizeInBytes(display_number);
auto& raw_screen = processed_frame.raw_screen_;
raw_screen.assign(frame_pixels, frame_pixels + display_size_bytes);
@@ -137,12 +135,12 @@
* callback should be set before the first WaitForAtLeastOneClientConnection()
* (b/178504150) and the first OnFrameAfter().
*/
- if (!screen_connector_->IsCallbackSet()) {
+ if (!screen_connector_.IsCallbackSet()) {
LOG(FATAL) << "ScreenConnector callback hasn't been set before MakeStripes";
}
while (!closed()) {
bb_->WaitForAtLeastOneClientConnection();
- auto sim_hw_processed_frame = screen_connector_->OnNextFrame();
+ auto sim_hw_processed_frame = screen_connector_.OnNextFrame();
// sim_hw_processed_frame has display number from the guest
if (!sim_hw_processed_frame.is_success_) {
continue;
@@ -174,5 +172,5 @@
int SimulatedHWComposer::NumberOfStripes() { return kNumStripes; }
void SimulatedHWComposer::ReportClientsConnected() {
- screen_connector_->ReportClientsConnected(true);
+ screen_connector_.ReportClientsConnected(true);
}
diff --git a/host/frontend/vnc_server/simulated_hw_composer.h b/host/frontend/vnc_server/simulated_hw_composer.h
index 2b8abf1..9d62e3e 100644
--- a/host/frontend/vnc_server/simulated_hw_composer.h
+++ b/host/frontend/vnc_server/simulated_hw_composer.h
@@ -24,35 +24,20 @@
#include <thread>
#include <deque>
-#include "common/libs/thread_safe_queue/thread_safe_queue.h"
-#include "common/libs/threads/thread_annotations.h"
+#include "common/libs/concurrency/thread_annotations.h"
+#include "common/libs/concurrency/thread_safe_queue.h"
#include "host/frontend/vnc_server/blackboard.h"
-#include "host/libs/screen_connector/screen_connector.h"
#include "host/frontend/vnc_server/vnc_utils.h"
#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/screen_connector/screen_connector.h"
namespace cuttlefish {
namespace vnc {
-/**
- * ScreenConnectorImpl will generate this, and enqueue
- *
- * It's basically a (processed) frame, so it:
- * must be efficiently std::move-able
- * Also, for the sake of algorithm simplicity:
- * must be default-constructable & assignable
- *
- */
-struct VncScProcessedFrame : public ScreenConnectorFrameInfo {
- Message raw_screen_;
- std::deque<Stripe> stripes_;
-};
-
class SimulatedHWComposer {
public:
- using ScreenConnector = ScreenConnector<VncScProcessedFrame>;
using GenerateProcessedFrameCallback = ScreenConnector::GenerateProcessedFrameCallback;
- SimulatedHWComposer(BlackBoard* bb);
+ SimulatedHWComposer(BlackBoard* bb, ScreenConnector& screen_connector);
SimulatedHWComposer(const SimulatedHWComposer&) = delete;
SimulatedHWComposer& operator=(const SimulatedHWComposer&) = delete;
~SimulatedHWComposer();
@@ -83,7 +68,7 @@
BlackBoard* bb_{};
ThreadSafeQueue<Stripe> stripes_;
std::thread stripe_maker_;
- std::unique_ptr<ScreenConnector> screen_connector_;
+ ScreenConnector& screen_connector_;
};
} // namespace vnc
} // namespace cuttlefish
diff --git a/host/frontend/vnc_server/virtual_inputs.cpp b/host/frontend/vnc_server/virtual_inputs.cpp
index 3143a6d..938210c 100644
--- a/host/frontend/vnc_server/virtual_inputs.cpp
+++ b/host/frontend/vnc_server/virtual_inputs.cpp
@@ -15,6 +15,7 @@
*/
#include "host/frontend/vnc_server/virtual_inputs.h"
+
#include <gflags/gflags.h>
#include <android-base/logging.h>
#include <linux/input.h>
@@ -25,8 +26,10 @@
#include <thread>
#include "keysyms.h"
-#include <common/libs/fs/shared_select.h>
-#include <host/libs/config/cuttlefish_config.h>
+#include "common/libs/confui/confui.h"
+#include "common/libs/fs/shared_select.h"
+#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/config/logging.h"
using cuttlefish::vnc::VirtualInputs;
@@ -347,6 +350,61 @@
VirtualInputs::VirtualInputs() { AddKeyMappings(&keymapping_); }
-VirtualInputs* VirtualInputs::Get() {
- return new SocketVirtualInputs();
+/**
+ * Depending on the host mode (e.g. android, confirmation ui(tee), etc)
+ * deliver the inputs to the right input implementation
+ * e.g. ConfUI's input or regular socket based input
+ */
+class VirtualInputDemux : public VirtualInputs {
+ public:
+ VirtualInputDemux(cuttlefish::confui::HostVirtualInput& confui_input)
+ : confui_input_{confui_input} {}
+ virtual ~VirtualInputDemux() = default;
+
+ virtual void GenerateKeyPressEvent(int code, bool down) override;
+ virtual void PressPowerButton(bool down) override;
+ virtual void HandlePointerEvent(bool touch_down, int x, int y) override;
+
+ private:
+ SocketVirtualInputs socket_virtual_input_;
+ cuttlefish::confui::HostVirtualInput& confui_input_;
+};
+
+void VirtualInputDemux::GenerateKeyPressEvent(int code, bool down) {
+ using cuttlefish::confui::DebugLog;
+ // confui input is active only in the confirmation UI
+ // also, socket virtual input should be inactive in the confirmation
+ // UI session
+ if (confui_input_.IsConfUiActive()) {
+ if (code == cuttlefish::xk::Menu) {
+ // release menu button in confirmation UI means for now cancel
+ confui_input_.PressCancelButton(down);
+ }
+ DebugLog("the key", code, "ignored.",
+ "currently confirmation UI handles menu and power only.");
+ return;
+ }
+ socket_virtual_input_.GenerateKeyPressEvent(code, down);
+}
+
+void VirtualInputDemux::PressPowerButton(bool down) {
+ if (confui_input_.IsConfUiActive()) {
+ confui_input_.PressConfirmButton(down);
+ return;
+ }
+ socket_virtual_input_.PressPowerButton(down);
+}
+
+void VirtualInputDemux::HandlePointerEvent(bool touch_down, int x, int y) {
+ using cuttlefish::confui::DebugLog;
+ if (confui_input_.IsConfUiActive()) {
+ DebugLog("currently confirmation UI ignores pointer events at", x, y);
+ return;
+ }
+ socket_virtual_input_.HandlePointerEvent(touch_down, x, y);
+}
+
+std::shared_ptr<VirtualInputs> VirtualInputs::Get(
+ cuttlefish::confui::HostVirtualInput& confui_input) {
+ return std::make_shared<VirtualInputDemux>(confui_input);
}
diff --git a/host/frontend/vnc_server/virtual_inputs.h b/host/frontend/vnc_server/virtual_inputs.h
index c22de15..f30202e 100644
--- a/host/frontend/vnc_server/virtual_inputs.h
+++ b/host/frontend/vnc_server/virtual_inputs.h
@@ -16,17 +16,20 @@
* limitations under the License.
*/
-#include "vnc_utils.h"
-
#include <map>
+#include <memory>
#include <mutex>
+#include "host/libs/confui/host_virtual_input.h"
+#include "vnc_utils.h"
+
namespace cuttlefish {
namespace vnc {
class VirtualInputs {
public:
- static VirtualInputs* Get();
+ static std::shared_ptr<VirtualInputs> Get(
+ cuttlefish::confui::HostVirtualInput& confui_input);
virtual ~VirtualInputs() = default;
diff --git a/host/frontend/vnc_server/vnc_client_connection.h b/host/frontend/vnc_server/vnc_client_connection.h
index a2c8b70..b26cf86 100644
--- a/host/frontend/vnc_server/vnc_client_connection.h
+++ b/host/frontend/vnc_server/vnc_client_connection.h
@@ -16,8 +16,8 @@
* limitations under the License.
*/
+#include "common/libs/concurrency/thread_annotations.h"
#include "common/libs/fs/shared_fd.h"
-#include "common/libs/threads/thread_annotations.h"
#include <cstdint>
#include <memory>
diff --git a/host/frontend/vnc_server/vnc_server.cpp b/host/frontend/vnc_server/vnc_server.cpp
index dd489b8..eff0d57 100644
--- a/host/frontend/vnc_server/vnc_server.cpp
+++ b/host/frontend/vnc_server/vnc_server.cpp
@@ -16,6 +16,8 @@
#include "host/frontend/vnc_server/vnc_server.h"
+#include <memory>
+
#include <android-base/logging.h>
#include "common/libs/utils/tcp_socket.h"
#include "host/frontend/vnc_server/blackboard.h"
@@ -27,11 +29,13 @@
using cuttlefish::vnc::VncServer;
-VncServer::VncServer(int port, bool aggressive)
+VncServer::VncServer(int port, bool aggressive,
+ cuttlefish::vnc::ScreenConnector& screen_connector,
+ cuttlefish::confui::HostVirtualInput& confui_input)
: server_(port),
- virtual_inputs_(VirtualInputs::Get()),
- frame_buffer_watcher_{&bb_},
- aggressive_{aggressive} {}
+ virtual_inputs_(VirtualInputs::Get(confui_input)),
+ frame_buffer_watcher_{&bb_, screen_connector},
+ aggressive_{aggressive} {}
void VncServer::MainLoop() {
while (true) {
diff --git a/host/frontend/vnc_server/vnc_server.h b/host/frontend/vnc_server/vnc_server.h
index 3ae37d8..2751fd1 100644
--- a/host/frontend/vnc_server/vnc_server.h
+++ b/host/frontend/vnc_server/vnc_server.h
@@ -28,13 +28,18 @@
#include "host/frontend/vnc_server/virtual_inputs.h"
#include "host/frontend/vnc_server/vnc_client_connection.h"
#include "host/frontend/vnc_server/vnc_utils.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_virtual_input.h"
+#include "host/libs/screen_connector/screen_connector.h"
namespace cuttlefish {
namespace vnc {
class VncServer {
public:
- explicit VncServer(int port, bool aggressive);
+ explicit VncServer(int port, bool aggressive,
+ ScreenConnector& screen_connector,
+ cuttlefish::confui::HostVirtualInput& confui_input);
VncServer(const VncServer&) = delete;
VncServer& operator=(const VncServer&) = delete;
@@ -47,8 +52,10 @@
void StartClientThread(ClientSocket sock);
ServerSocket server_;
+
std::shared_ptr<VirtualInputs> virtual_inputs_;
BlackBoard bb_;
+
FrameBufferWatcher frame_buffer_watcher_;
bool aggressive_{};
};
diff --git a/host/frontend/vnc_server/vnc_utils.h b/host/frontend/vnc_server/vnc_utils.h
index 34df434..7ec19f7 100644
--- a/host/frontend/vnc_server/vnc_utils.h
+++ b/host/frontend/vnc_server/vnc_utils.h
@@ -18,12 +18,14 @@
#include <array>
#include <cstdint>
+#include <memory>
#include <utility>
#include <vector>
#include "common/libs/utils/size_utils.h"
#include "common/libs/utils/tcp_socket.h"
#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/screen_connector/screen_connector.h"
namespace cuttlefish {
namespace vnc {
@@ -63,5 +65,26 @@
ScreenOrientation orientation{};
};
+/**
+ * ScreenConnectorImpl will generate this, and enqueue
+ *
+ * It's basically a (processed) frame, so it:
+ * must be efficiently std::move-able
+ * Also, for the sake of algorithm simplicity:
+ * must be default-constructable & assignable
+ *
+ */
+struct VncScProcessedFrame : public ScreenConnectorFrameInfo {
+ Message raw_screen_;
+ std::deque<Stripe> stripes_;
+ std::unique_ptr<VncScProcessedFrame> Clone() {
+ VncScProcessedFrame* cloned_frame = new VncScProcessedFrame();
+ cloned_frame->raw_screen_ = raw_screen_;
+ cloned_frame->stripes_ = stripes_;
+ return std::unique_ptr<VncScProcessedFrame>(cloned_frame);
+ }
+};
+using ScreenConnector = cuttlefish::ScreenConnector<VncScProcessedFrame>;
+
} // namespace vnc
} // namespace cuttlefish
diff --git a/host/frontend/webrtc/Android.bp b/host/frontend/webrtc/Android.bp
index e0890ad..7ee350f 100644
--- a/host/frontend/webrtc/Android.bp
+++ b/host/frontend/webrtc/Android.bp
@@ -83,6 +83,7 @@
header_libs: [
"webrtc_signaling_headers",
"libwebrtc_absl_headers",
+ "libcuttlefish_confui_host_headers",
],
static_libs: [
"libwebrtc_absl_base",
@@ -103,6 +104,11 @@
"libcuttlefish_screen_connector",
"libcuttlefish_utils",
"libcuttlefish_wayland_server",
+ "libcuttlefish_confui",
+ "libcuttlefish_confui_host",
+ "libft2.nodep",
+ "libteeui",
+ "libteeui_localization",
"libdrm",
"libevent",
"libffi",
diff --git a/host/frontend/webrtc/connection_observer.cpp b/host/frontend/webrtc/connection_observer.cpp
index a8613e6..090be3b 100644
--- a/host/frontend/webrtc/connection_observer.cpp
+++ b/host/frontend/webrtc/connection_observer.cpp
@@ -30,6 +30,7 @@
#include <android-base/logging.h>
#include <gflags/gflags.h>
+#include "common/libs/confui/confui.h"
#include "common/libs/fs/shared_buf.h"
#include "host/frontend/webrtc/adb_handler.h"
#include "host/frontend/webrtc/kernel_log_events_handler.h"
@@ -38,6 +39,10 @@
DECLARE_bool(write_virtio_input);
+// LOG(DEBUG) for confirmation UI debugging
+// that stands for LOG(DEBUG) << "ConfUI: " << ...
+using cuttlefish::confui::DebugLog;
+
namespace cuttlefish {
// TODO (b/147511234): de-dup this from vnc server and here
@@ -88,19 +93,24 @@
}
}
-class ConnectionObserverImpl
+/**
+ * connection observer implementation for regular android mode.
+ * i.e. when it is not in the confirmation UI mode (or TEE),
+ * the control flow will fall back to this ConnectionObserverForAndroid
+ */
+class ConnectionObserverForAndroid
: public cuttlefish::webrtc_streaming::ConnectionObserver {
public:
- ConnectionObserverImpl(cuttlefish::InputSockets& input_sockets,
- cuttlefish::SharedFD kernel_log_events_fd,
- std::map<std::string, cuttlefish::SharedFD>
- commands_to_custom_action_servers,
- std::weak_ptr<DisplayHandler> display_handler)
+ ConnectionObserverForAndroid(cuttlefish::InputSockets &input_sockets,
+ cuttlefish::SharedFD kernel_log_events_fd,
+ std::map<std::string, cuttlefish::SharedFD>
+ commands_to_custom_action_servers,
+ std::weak_ptr<DisplayHandler> display_handler)
: input_sockets_(input_sockets),
kernel_log_events_client_(kernel_log_events_fd),
commands_to_custom_action_servers_(commands_to_custom_action_servers),
weak_display_handler_(display_handler) {}
- virtual ~ConnectionObserverImpl() {
+ virtual ~ConnectionObserverForAndroid() {
auto display_handler = weak_display_handler_.lock();
if (display_handler) {
display_handler->DecClientCount();
@@ -258,9 +268,9 @@
// invert the lid_switch_open value that is sent to the input device.
OnSwitchEvent(SW_LID, !evt["lid_switch_open"].asBool());
}
- // TODO(b/181157794) Propagate hinge angle sensor data.
if (evt.isMember("hinge_angle_value")) {
- LOG(WARNING) << "Hinge angle sensor is not yet implemented.";
+ // TODO(b/181157794) Propagate hinge angle sensor data using a custom
+ // Sensor HAL.
}
return;
}
@@ -305,19 +315,106 @@
std::set<int32_t> active_touch_slots_;
};
+class ConnectionObserverDemuxer
+ : public cuttlefish::webrtc_streaming::ConnectionObserver {
+ public:
+ ConnectionObserverDemuxer(
+ /* params for the base class */
+ cuttlefish::InputSockets &input_sockets,
+ cuttlefish::SharedFD kernel_log_events_fd,
+ std::map<std::string, cuttlefish::SharedFD>
+ commands_to_custom_action_servers,
+ std::weak_ptr<DisplayHandler> display_handler,
+ /* params for this class */
+ cuttlefish::confui::HostVirtualInput &confui_input)
+ : android_input_(input_sockets, kernel_log_events_fd,
+ commands_to_custom_action_servers, display_handler),
+ confui_input_{confui_input} {}
+ virtual ~ConnectionObserverDemuxer() = default;
+
+ void OnConnected(std::function<void(const uint8_t *, size_t, bool)>
+ ctrl_msg_sender) override {
+ android_input_.OnConnected(ctrl_msg_sender);
+ }
+
+ void OnTouchEvent(const std::string &label, int x, int y,
+ bool down) override {
+ if (confui_input_.IsConfUiActive()) {
+ DebugLog("touch event ignored in confirmation UI mode");
+ return;
+ }
+ android_input_.OnTouchEvent(label, x, y, down);
+ }
+
+ void OnMultiTouchEvent(const std::string &label, Json::Value id,
+ Json::Value slot, Json::Value x, Json::Value y,
+ bool down, int size) override {
+ if (confui_input_.IsConfUiActive()) {
+ DebugLog("multi-touch event ignored in confirmation UI mode");
+ return;
+ }
+ android_input_.OnMultiTouchEvent(label, id, slot, x, y, down, size);
+ }
+
+ void OnKeyboardEvent(uint16_t code, bool down) override {
+ if (confui_input_.IsConfUiActive()) {
+ switch (code) {
+ case KEY_POWER:
+ confui_input_.PressConfirmButton(down);
+ break;
+ case KEY_MENU:
+ confui_input_.PressCancelButton(down);
+ break;
+ default:
+ DebugLog("key ", code, " is ignored in confirmation UI mode");
+ break;
+ }
+ return;
+ }
+ android_input_.OnKeyboardEvent(code, down);
+ }
+
+ void OnSwitchEvent(uint16_t code, bool state) override {
+ android_input_.OnSwitchEvent(code, state);
+ }
+
+ void OnAdbChannelOpen(std::function<bool(const uint8_t *, size_t)>
+ adb_message_sender) override {
+ android_input_.OnAdbChannelOpen(adb_message_sender);
+ }
+
+ void OnAdbMessage(const uint8_t *msg, size_t size) override {
+ android_input_.OnAdbMessage(msg, size);
+ }
+
+ void OnControlChannelOpen(
+ std::function<bool(const Json::Value)> control_message_sender) override {
+ android_input_.OnControlChannelOpen(control_message_sender);
+ }
+
+ void OnControlMessage(const uint8_t *msg, size_t size) override {
+ android_input_.OnControlMessage(msg, size);
+ }
+
+ private:
+ ConnectionObserverForAndroid android_input_;
+ cuttlefish::confui::HostVirtualInput &confui_input_;
+};
+
CfConnectionObserverFactory::CfConnectionObserverFactory(
- cuttlefish::InputSockets& input_sockets,
- cuttlefish::SharedFD kernel_log_events_fd)
+ cuttlefish::InputSockets &input_sockets,
+ cuttlefish::SharedFD kernel_log_events_fd,
+ cuttlefish::confui::HostVirtualInput &confui_input)
: input_sockets_(input_sockets),
- kernel_log_events_fd_(kernel_log_events_fd) {}
+ kernel_log_events_fd_(kernel_log_events_fd),
+ confui_input_{confui_input} {}
std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>
CfConnectionObserverFactory::CreateObserver() {
return std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver>(
- new ConnectionObserverImpl(input_sockets_,
- kernel_log_events_fd_,
- commands_to_custom_action_servers_,
- weak_display_handler_));
+ new ConnectionObserverDemuxer(input_sockets_, kernel_log_events_fd_,
+ commands_to_custom_action_servers_,
+ weak_display_handler_, confui_input_));
}
void CfConnectionObserverFactory::AddCustomActionServer(
diff --git a/host/frontend/webrtc/connection_observer.h b/host/frontend/webrtc/connection_observer.h
index 9ec1e49..b3ede7d 100644
--- a/host/frontend/webrtc/connection_observer.h
+++ b/host/frontend/webrtc/connection_observer.h
@@ -22,6 +22,7 @@
#include "common/libs/fs/shared_fd.h"
#include "host/frontend/webrtc/display_handler.h"
#include "host/frontend/webrtc/lib/connection_observer.h"
+#include "host/libs/confui/host_virtual_input.h"
namespace cuttlefish {
@@ -37,8 +38,10 @@
class CfConnectionObserverFactory
: public cuttlefish::webrtc_streaming::ConnectionObserverFactory {
public:
- CfConnectionObserverFactory(cuttlefish::InputSockets& input_sockets,
- cuttlefish::SharedFD kernel_log_events_fd);
+ CfConnectionObserverFactory(
+ cuttlefish::InputSockets& input_sockets,
+ cuttlefish::SharedFD kernel_log_events_fd,
+ cuttlefish::confui::HostVirtualInput& confui_input);
~CfConnectionObserverFactory() override = default;
std::shared_ptr<cuttlefish::webrtc_streaming::ConnectionObserver> CreateObserver()
@@ -55,6 +58,7 @@
std::map<std::string, cuttlefish::SharedFD>
commands_to_custom_action_servers_;
std::weak_ptr<DisplayHandler> weak_display_handler_;
+ cuttlefish::confui::HostVirtualInput& confui_input_;
};
} // namespace cuttlefish
diff --git a/host/frontend/webrtc/display_handler.cpp b/host/frontend/webrtc/display_handler.cpp
index 2b4f574..c24ce9d 100644
--- a/host/frontend/webrtc/display_handler.cpp
+++ b/host/frontend/webrtc/display_handler.cpp
@@ -25,9 +25,9 @@
namespace cuttlefish {
DisplayHandler::DisplayHandler(
std::shared_ptr<webrtc_streaming::VideoSink> display_sink,
- std::unique_ptr<ScreenConnector> screen_connector)
- : display_sink_(display_sink), screen_connector_(std::move(screen_connector)) {
- screen_connector_->SetCallback(std::move(GetScreenConnectorCallback()));
+ ScreenConnector& screen_connector)
+ : display_sink_(display_sink), screen_connector_(screen_connector) {
+ screen_connector_.SetCallback(std::move(GetScreenConnectorCallback()));
}
DisplayHandler::GenerateProcessedFrameCallback DisplayHandler::GetScreenConnectorCallback() {
@@ -35,6 +35,7 @@
DisplayHandler::GenerateProcessedFrameCallback callback =
[](std::uint32_t display_number, std::uint8_t* frame_pixels,
WebRtcScProcessedFrame& processed_frame) {
+ processed_frame.display_number_ = display_number;
// TODO(171305898): handle multiple displays.
if (display_number != 0) {
processed_frame.is_success_ = false;
@@ -61,7 +62,7 @@
[[noreturn]] void DisplayHandler::Loop() {
for (;;) {
- auto processed_frame = screen_connector_->OnNextFrame();
+ auto processed_frame = screen_connector_.OnNextFrame();
// processed_frame has display number from the guest
{
std::lock_guard<std::mutex> lock(last_buffer_mutex_);
@@ -101,14 +102,14 @@
void DisplayHandler::IncClientCount() {
client_count_++;
if (client_count_ == 1) {
- screen_connector_->ReportClientsConnected(true);
+ screen_connector_.ReportClientsConnected(true);
}
}
void DisplayHandler::DecClientCount() {
client_count_--;
if (client_count_ == 0) {
- screen_connector_->ReportClientsConnected(false);
+ screen_connector_.ReportClientsConnected(false);
}
}
diff --git a/host/frontend/webrtc/display_handler.h b/host/frontend/webrtc/display_handler.h
index 3045e07..aed38a1 100644
--- a/host/frontend/webrtc/display_handler.h
+++ b/host/frontend/webrtc/display_handler.h
@@ -33,9 +33,17 @@
* must be default-constructable & assignable
*
*/
-struct WebRtcScProcessedFrame : ScreenConnectorFrameInfo {
+struct WebRtcScProcessedFrame : public ScreenConnectorFrameInfo {
// must support move semantic
std::unique_ptr<CvdVideoFrameBuffer> buf_;
+ std::unique_ptr<WebRtcScProcessedFrame> Clone() {
+ // copy internal buffer, not move
+ CvdVideoFrameBuffer* new_buffer = new CvdVideoFrameBuffer(*(buf_.get()));
+ auto cloned_frame = std::make_unique<WebRtcScProcessedFrame>();
+ cloned_frame->buf_ =
+ std::move(std::unique_ptr<CvdVideoFrameBuffer>(new_buffer));
+ return std::move(cloned_frame);
+ }
};
class DisplayHandler {
@@ -43,9 +51,8 @@
using ScreenConnector = cuttlefish::ScreenConnector<WebRtcScProcessedFrame>;
using GenerateProcessedFrameCallback = ScreenConnector::GenerateProcessedFrameCallback;
- DisplayHandler(
- std::shared_ptr<webrtc_streaming::VideoSink> display_sink,
- std::unique_ptr<ScreenConnector> screen_connector);
+ DisplayHandler(std::shared_ptr<webrtc_streaming::VideoSink> display_sink,
+ ScreenConnector& screen_connector);
~DisplayHandler() = default;
[[noreturn]] void Loop();
@@ -57,7 +64,7 @@
private:
GenerateProcessedFrameCallback GetScreenConnectorCallback();
std::shared_ptr<webrtc_streaming::VideoSink> display_sink_;
- std::unique_ptr<ScreenConnector> screen_connector_;
+ ScreenConnector& screen_connector_;
std::shared_ptr<webrtc_streaming::VideoFrameBuffer> last_buffer_;
std::mutex last_buffer_mutex_;
std::mutex next_frame_mutex_;
diff --git a/host/frontend/webrtc/main.cpp b/host/frontend/webrtc/main.cpp
index cdc9563..ce40e1c 100644
--- a/host/frontend/webrtc/main.cpp
+++ b/host/frontend/webrtc/main.cpp
@@ -37,6 +37,8 @@
#include "host/libs/audio_connector/server.h"
#include "host/libs/config/cuttlefish_config.h"
#include "host/libs/config/logging.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_server.h"
#include "host/libs/screen_connector/screen_connector.h"
DEFINE_int32(touch_fd, -1, "An fd to listen on for touch connections.");
@@ -173,8 +175,16 @@
auto cvd_config = cuttlefish::CuttlefishConfig::Get();
auto instance = cvd_config->ForDefaultInstance();
- auto screen_connector =
- cuttlefish::DisplayHandler::ScreenConnector::Get(FLAGS_frame_server_fd);
+ auto& host_mode_ctrl = cuttlefish::HostModeCtrl::Get();
+ auto screen_connector_ptr = cuttlefish::DisplayHandler::ScreenConnector::Get(
+ FLAGS_frame_server_fd, host_mode_ctrl);
+ auto& screen_connector = *(screen_connector_ptr.get());
+
+ // create confirmation UI service, giving host_mode_ctrl and
+ // screen_connector
+ // keep this singleton object alive until the webRTC process ends
+ static auto& host_confui_server =
+ cuttlefish::confui::HostServer::Get(host_mode_ctrl, screen_connector);
StreamerConfig streamer_config;
@@ -195,16 +205,16 @@
}
auto observer_factory = std::make_shared<CfConnectionObserverFactory>(
- input_sockets, kernel_log_events_client);
+ input_sockets, kernel_log_events_client, host_confui_server);
auto streamer = Streamer::Create(streamer_config, observer_factory);
CHECK(streamer) << "Could not create streamer";
auto display_0 = streamer->AddDisplay(
- "display_0", screen_connector->ScreenWidth(0),
- screen_connector->ScreenHeight(0), cvd_config->dpi(), true);
- auto display_handler =
- std::make_shared<DisplayHandler>(display_0, std::move(screen_connector));
+ "display_0", screen_connector.ScreenWidth(0),
+ screen_connector.ScreenHeight(0), cvd_config->dpi(), true);
+ auto display_handler = std::shared_ptr<DisplayHandler>(
+ new DisplayHandler(display_0, screen_connector));
std::unique_ptr<cuttlefish::webrtc_streaming::LocalRecorder> local_recorder;
if (cvd_config->record_screen()) {
@@ -340,6 +350,7 @@
if (audio_handler) {
audio_handler->Start();
}
+ host_confui_server.Start();
display_handler->Loop();
return 0;
diff --git a/host/frontend/webrtc_operator/assets/controls.css b/host/frontend/webrtc_operator/assets/controls.css
index 1971399..5bb0cce 100644
--- a/host/frontend/webrtc_operator/assets/controls.css
+++ b/host/frontend/webrtc_operator/assets/controls.css
@@ -18,7 +18,7 @@
padding-left: 2px;
padding-right: 7px;
border-radius: 10px;
- background-color: #434343;
+ background-color: #5f6368; /* Google grey 700 */
width: 117px;
height: 64px;
}
diff --git a/host/frontend/webrtc_operator/assets/index.html b/host/frontend/webrtc_operator/assets/index.html
index cdbf549..7ab6a72 100644
--- a/host/frontend/webrtc_operator/assets/index.html
+++ b/host/frontend/webrtc_operator/assets/index.html
@@ -25,45 +25,42 @@
</head>
<body>
- <section id='device_selector'>
- <h1>Available devices <span id='refresh_list'>↻</span></h1>
- <ul id="device_list"></ul>
+ <section id='device-selector'>
+ <h1>Available devices <span id='refresh-list'>↻</span></h1>
+ <ul id="device-list"></ul>
</section>
- <section id='device_connection'>
- <div id='control_view'>
- <div id='app_controls'>
- <h2 class="section-title">App Controls</h2>
- <div id="keyboardCaptureCtrl" title="Capture Keyboard"></div>
- <div id="micCaptureCtrl" title="Capture Microphone"></div>
+ <section id='device-connection'>
+ <div id='header'>
+ <div id='app-controls'>
+ <div id="keyboard-capture-control" title="Capture Keyboard"></div>
+ <div id="mic-capture-control" title="Capture Microphone"></div>
+ <audio autoplay controls id="device-audio"></audio>
</div>
- <hr>
- <div id='control_panel'>
- <h2 class="section-title">Device Controls</h2>
- <div id='control_panel_default_buttons'></div>
- <h2 class="section-title" id='custom_controls_title'>Custom Controls</h2>
- <div id='control_panel_custom_buttons'></div>
- </div>
- <h3 id='adb_status_message' class='connecting'>Awaiting bootup and adb connection. Please wait...</h3>
- <div id='device_details'>
- <h2 class="section-title">Device Details</h2>
- <h3>Hardware Configuration</h3>
- <span id='device_details_hardware'>unknown</span>
- </div>
- <div id='device_speakers'>
- <h2 class="section-title">Device Speakers</h2>
- <audio autoplay controls id="deviceAudio"></audio>
+ <div id='status-div'>
+ <h3 id='status-message' class='connecting'>Connecting to device</h3>
</div>
</div>
- <div id='device_view'>
- <h3 id='device_status_message'></h3>
- <video id="deviceScreen" autoplay ></video>
- <h3 id='webrtc_status_message'>
- No connection to the guest device.<br><br>
- Please ensure the WebRTC process on the host machine is active.<br><br>
- Tip: <code>ps aux | grep -i webrtc</code>
- </h3>
+ <div id='controls-and-screens'>
+ <div id='control-panel-default-buttons' class='control-panel-column'>
+ <button id='device-details-button' title='Device Details' class='material-icons'>
+ settings
+ </button>
+ </div>
+ <div id='control-panel-custom-buttons' class='control-panel-column'></div>
+ <div id='screens'>
+ <video id="device-screen" autoplay ></video>
+ </div>
</div>
</section>
+ <div id='device-details-modal'>
+ <div id='device-details-modal-header'>
+ <h2>Device Details</h2>
+ <button id='device-details-close' title='Close' class='material-icons'>close</button>
+ </div>
+ <hr>
+ <h3>Hardware Configuration</h3>
+ <span id='device-details-hardware'>unknown</span>
+ </div>
<script src="js/adb.js"></script>
<script src="js/cf_webrtc.js" type="module"></script>
diff --git a/host/frontend/webrtc_operator/assets/js/app.js b/host/frontend/webrtc_operator/assets/js/app.js
index 3bc6a3c..61a9bf3 100644
--- a/host/frontend/webrtc_operator/assets/js/app.js
+++ b/host/frontend/webrtc_operator/assets/js/app.js
@@ -18,38 +18,41 @@
function ConnectToDevice(device_id) {
console.log('ConnectToDevice ', device_id);
- const keyboardCaptureCtrl = document.getElementById('keyboardCaptureCtrl');
+ const keyboardCaptureCtrl = document.getElementById('keyboard-capture-control');
createToggleControl(keyboardCaptureCtrl, "keyboard", onKeyboardCaptureToggle);
- const micCaptureCtrl = document.getElementById('micCaptureCtrl');
+ const micCaptureCtrl = document.getElementById('mic-capture-control');
createToggleControl(micCaptureCtrl, "mic", onMicCaptureToggle);
+ // TODO(b/163867676): Enable the microphone control when the audio stream is
+ // injected into the guest. Until then, control is disabled.
+ micCaptureCtrl.style.display = 'none';
- const deviceScreen = document.getElementById('deviceScreen');
- const deviceAudio = document.getElementById('deviceAudio');
- const deviceView = document.getElementById('device_view');
- const webrtcStatusMessage = document.getElementById('webrtc_status_message');
- const adbStatusMessage = document.getElementById('adb_status_message');
+ const deviceScreen = document.getElementById('device-screen');
+ const deviceAudio = document.getElementById('device-audio');
+ const statusMessage = document.getElementById('status-message');
- const deviceStatusMessage = document.getElementById('device_status_message');
let connectionAttemptDuration = 0;
const intervalMs = 500;
let deviceStatusEllipsisCount = 0;
let animateDeviceStatusMessage = setInterval(function() {
- deviceStatusEllipsisCount = (deviceStatusEllipsisCount + 1) % 4;
- deviceStatusMessage.textContent = 'Connecting to device'
- + '.'.repeat(deviceStatusEllipsisCount);
-
connectionAttemptDuration += intervalMs;
if (connectionAttemptDuration > 30000) {
- deviceStatusMessage.textContent += '\r\n\r\nConnection should have occurred by now.'
- + '\r\nPlease attempt to restart the guest device.'
- } else if (connectionAttemptDuration > 15000) {
- deviceStatusMessage.textContent += '\r\n\r\nConnection is taking longer than expected...'
+ statusMessage.className = 'error';
+ statusMessage.textContent = 'Connection should have occurred by now. ' +
+ 'Please attempt to restart the guest device.';
+ } else {
+ if (connectionAttemptDuration > 15000) {
+ statusMessage.textContent = 'Connection is taking longer than expected';
+ } else {
+ statusMessage.textContent = 'Connecting to device';
+ }
+ deviceStatusEllipsisCount = (deviceStatusEllipsisCount + 1) % 4;
+ statusMessage.textContent += '.'.repeat(deviceStatusEllipsisCount);
}
}, intervalMs);
deviceScreen.addEventListener('loadeddata', (evt) => {
clearInterval(animateDeviceStatusMessage);
- deviceStatusMessage.style.display = 'none';
+ statusMessage.textContent = 'Awaiting bootup and adb connection. Please wait...';
resizeDeviceView();
deviceScreen.style.visibility = 'visible';
// Enable the buttons after the screen is visible.
@@ -77,11 +80,11 @@
// Certain default adb buttons change screen state, so wait for boot
// completion before enabling these buttons.
if (adbConnected && bootCompleted) {
- adbStatusMessage.className = 'connected';
- adbStatusMessage.textContent =
+ statusMessage.className = 'connected';
+ statusMessage.textContent =
'bootup and adb connection established successfully.';
setTimeout(function() {
- adbStatusMessage.style.visibility = 'hidden';
+ statusMessage.style.visibility = 'hidden';
}, 5000);
for (const [_, button] of Object.entries(buttons)) {
if (button.adb) {
@@ -99,9 +102,9 @@
showBootCompletion();
},
function() {
- adbStatusMessage.className = 'error';
- adbStatusMessage.textContent = 'adb connection failed.';
- adbStatusMessage.style.visibility = 'visible';
+ statusMessage.className = 'error';
+ statusMessage.textContent = 'adb connection failed.';
+ statusMessage.style.visibility = 'visible';
for (const [_, button] of Object.entries(buttons)) {
if (button.adb) {
button.button.disabled = true;
@@ -147,11 +150,12 @@
}
}
+ const screensDiv = document.getElementById('screens');
function resizeDeviceView() {
// Auto-scale the screen based on window size.
// Max window width of 70%, allowing space for the control panel.
- let ww = window.innerWidth * 0.7;
- let wh = window.innerHeight;
+ let ww = screensDiv.offsetWidth * 0.7;
+ let wh = screensDiv.offsetHeight;
let vw = currentDisplayDetails.x_res;
let vh = currentDisplayDetails.y_res;
let scaling = vw * wh > vh * ww ? ww / vw : wh / vh;
@@ -166,19 +170,12 @@
deviceScreen.style.width = vh * scaling;
deviceScreen.style.height = vw * scaling;
}
-
- // Set the deviceView size so that the control panel positions itself next
- // to the screen correctly.
- deviceView.style.width = currentRotation == 0 ? deviceScreen.style.width :
- deviceScreen.style.height;
- deviceView.style.height = currentRotation == 0 ? deviceScreen.style.height :
- deviceScreen.style.width;
}
window.onresize = resizeDeviceView;
function createControlPanelButton(command, title, icon_name,
listener=onControlPanelButton,
- parent_id='control_panel_default_buttons') {
+ parent_id='control-panel-default-buttons') {
let button = document.createElement('button');
document.getElementById(parent_id).appendChild(button);
button.title = title;
@@ -207,14 +204,36 @@
createControlPanelButton('volumedown', 'Volume Down', 'volume_down');
createControlPanelButton('volumeup', 'Volume Up', 'volume_up');
+ const deviceDetailsModal = document.getElementById('device-details-modal');
+ const deviceDetailsButton = document.getElementById('device-details-button');
+ const deviceDetailsClose = document.getElementById('device-details-close');
+ function showHideDeviceDetailsModal(show) {
+ // Position the modal to the right of the device details button.
+ deviceDetailsModal.style.top = deviceDetailsButton.offsetTop;
+ deviceDetailsModal.style.left = deviceDetailsButton.offsetWidth + 30;
+ if (show) {
+ deviceDetailsModal.style.display = 'block';
+ } else {
+ deviceDetailsModal.style.display = 'none';
+ }
+ }
+ // Allow the device details button to toggle the modal,
+ deviceDetailsButton.addEventListener('click',
+ evt => showHideDeviceDetailsModal(deviceDetailsModal.style.display != 'block'));
+ // but the close button always closes.
+ deviceDetailsClose.addEventListener('click',
+ evt => showHideDeviceDetailsModal(false));
+
let options = {
wsUrl: ((location.protocol == 'http:') ? 'ws://' : 'wss://') +
location.host + '/connect_client',
};
function showWebrtcError() {
- webrtcStatusMessage.style.display = 'block';
- deviceStatusMessage.style.display = 'none';
+ statusMessage.className = 'error';
+ statusMessage.textContent = 'No connection to the guest device. ' +
+ 'Please ensure the WebRTC process on the host machine is active.';
+ statusMessage.style.visibility = 'visible';
deviceScreen.style.display = 'none';
for (const [_, button] of Object.entries(buttons)) {
button.button.disabled = true;
@@ -243,26 +262,32 @@
startMouseTracking(); // TODO stopMouseTracking() when disconnected
updateDeviceHardwareDetails(deviceConnection.description.hardware);
updateDeviceDisplayDetails(deviceConnection.description.displays[0]);
- if (deviceConnection.description.custom_control_panel_buttons.length == 0) {
- document.getElementById('custom_controls_title').style.visibility = 'hidden';
- } else {
+ if (deviceConnection.description.custom_control_panel_buttons.length > 0) {
+ document.getElementById('control-panel-custom-buttons').style.display = 'flex';
for (const button of deviceConnection.description.custom_control_panel_buttons) {
if (button.shell_command) {
// This button's command is handled by sending an ADB shell command.
createControlPanelButton(button.command, button.title, button.icon_name,
e => onCustomShellButton(button.shell_command, e),
- 'control_panel_custom_buttons');
+ 'control-panel-custom-buttons');
buttons[button.command].adb = true;
} else if (button.device_states) {
// This button corresponds to variable hardware device state(s).
createControlPanelButton(button.command, button.title, button.icon_name,
getCustomDeviceStateButtonCb(button.device_states),
- 'control_panel_custom_buttons');
+ 'control-panel-custom-buttons');
+ for (const device_state of button.device_states) {
+ // hinge_angle is currently injected via an adb shell command that
+ // triggers a guest binary.
+ if ('hinge_angle_value' in device_state) {
+ buttons[button.command].adb = true;
+ }
+ }
} else {
// This button's command is handled by custom action server.
createControlPanelButton(button.command, button.title, button.icon_name,
onControlPanelButton,
- 'control_panel_custom_buttons');
+ 'control-panel-custom-buttons');
}
}
}
@@ -294,7 +319,7 @@
let hardwareDetailsText = '';
let displayDetailsText = '';
function updateDeviceDetailsText() {
- document.getElementById('device_details_hardware').textContent = [
+ document.getElementById('device-details-hardware').textContent = [
hardwareDetailsText,
displayDetailsText,
].join('\n');
@@ -348,7 +373,7 @@
initializeAdb();
if (e.type == 'mousedown') {
adbShell(
- '/vendor/bin/cuttlefish_rotate ' +
+ '/vendor/bin/cuttlefish_sensor_injection rotate ' +
(currentRotation == 0 ? 'landscape' : 'portrait'))
}
}
@@ -376,6 +401,13 @@
};
deviceConnection.sendControlMessage(JSON.stringify(message));
console.log(JSON.stringify(message));
+ // TODO(b/181157794): Use a custom Sensor HAL for hinge_angle injection
+ // instead of this guest binary.
+ if ('hinge_angle_value' in states[index]) {
+ adbShell(
+ '/vendor/bin/cuttlefish_sensor_injection hinge_angle ' +
+ states[index].hinge_angle_value);
+ }
// Cycle to the next state.
index = (index + 1) % states.length;
}
@@ -608,14 +640,14 @@
function ConnectDeviceCb(dev_id) {
console.log('Connect: ' + dev_id);
// Hide the device selection screen
- document.getElementById('device_selector').style.display = 'none';
+ document.getElementById('device-selector').style.display = 'none';
// Show the device control screen
- document.getElementById('device_connection').style.visibility = 'visible';
+ document.getElementById('device-connection').style.visibility = 'visible';
ConnectToDevice(dev_id);
}
function ShowNewDeviceList(device_ids) {
- let ul = document.getElementById('device_list');
+ let ul = document.getElementById('device-list');
ul.innerHTML = "";
let count = 1;
let device_to_button_map = {};
@@ -649,5 +681,5 @@
// Get any devices that are already connected
UpdateDeviceList();
// Update the list at the user's request
-document.getElementById('refresh_list')
+document.getElementById('refresh-list')
.addEventListener('click', evt => UpdateDeviceList());
diff --git a/host/frontend/webrtc_operator/assets/style.css b/host/frontend/webrtc_operator/assets/style.css
index d1ec542..ca4e7b2 100644
--- a/host/frontend/webrtc_operator/assets/style.css
+++ b/host/frontend/webrtc_operator/assets/style.css
@@ -15,136 +15,160 @@
*/
body {
- background-color:black;
- margin: 0;
+ background-color:black;
+ margin: 0;
}
-#device_selector {
- color: whitesmoke;
+#device-selector {
+ color: whitesmoke;
}
-#device_selector li.device_entry {
- cursor: pointer;
+#device-selector li.device-entry {
+ cursor: pointer;
}
-#refresh_list {
- cursor: pointer;
+#refresh-list {
+ cursor: pointer;
}
-#device_list .device_entry button {
- margin-left: 10px;
+#device-list .device-entry button {
+ margin-left: 10px;
+}
+
+#device-connection {
+ visibility: hidden;
+ max-height: 100vh;
}
-#device_connection {
- visibility: hidden;
+/* Top header row. */
+
+#header {
+ height: 64px;
+ margin-top: 10px;
+ margin-bottom: 10px;
+ /* Items inside this use a row Flexbox.*/
+ display: flex;
+ align-items: center;
}
-#device_view {
- transition: width 1s;
+#app-controls {
+ margin-left: 10px;
}
-#control_view {
- text-align: left;
- padding: 10px;
- min-width: 450px;
+#app-controls > div {
+ display: inline-block;
+ position: relative;
+ margin-right: 6px;
}
-/* Screens >1000px place the device view on the left and the control
- * view on the right. Other screens have deview view on top and control
- * view on bottom. */
-@media screen and (min-width: 1000px) {
- #device_view {
- float: left;
- }
- #control_view {
- float: left;
- }
+#device-audio {
+ margin-bottom: 5px;
}
-#deviceScreen {
- touch-action: none;
- transform-origin: top right;
- object-fit: cover;
+#status-div {
+ flex-grow: 1;
+}
+#status-message {
+ color: white;
+ font-family: 'Open Sans', sans-serif;
+ padding: 10px;
+ margin: 10px;
+}
+#status-message.connecting {
+ /* dark yellow */
+ background-color: #927836;
+}
+#status-message.error {
+ /* dark red */
+ background-color: #900000;
+}
+#status-message.connected {
+ /* dark green */
+ background-color: #007000;
}
-body {
- font-family: 'Open Sans', sans-serif;
+/* Control panel buttons and device screen(s). */
+
+#controls-and-screens {
+ height: calc(100% - 84px);
+
+ /* Items inside this use a row Flexbox.*/
+ display: flex;
+}
+#controls-and-screens div {
+ margin-left: 10px;
+ margin-right: 10px;
}
-h2.section-title {
- color: white;
-}
-
-#app_controls > div {
- display: inline-block;
- position: relative;
- margin-right: 6px;
-}
-
-#device_view h3 {
- padding: 30px;
- font-family: 'Open Sans', sans-serif;
- color: white;
-}
-
-#device_status_message {
- white-space: pre-line;
- width: 400px;
-}
-
-#webrtc_status_message {
- text-align: center;
- /* White text on dark red background. */
- background-color: #900000;
- /* Hidden by default. */
- display: none;
-}
-
-#device_connection button {
- height: 60px;
- min-width: 60px;
- display: inline-block;
- margin: 10px 10px;
- font-size: 48px;
- border-radius: 8px;
- border: none;
- background-color: #dbdbdb;
- transition-duration: 0.2s;
-}
-#control_panel button:hover {
- background-color: #c9c9c9;
-}
-
-#adb_status_message {
- padding: 10px;
- font-family: 'Open Sans', sans-serif;
- color: white;
-}
-#adb_status_message.connecting {
- /* dark yellow */
- background-color: #927836;
-}
-#adb_status_message.error {
- /* dark red */
- background-color: #900000;
-}
-#adb_status_message.connected {
- /* dark green */
- background-color: #007000;
-}
-
-#device_details {
- font-family: 'Open Sans', sans-serif;
- color: white;
- background-color: #383838;
- margin-top: 20px;
- padding: 20px;
- padding-top: 1px;
-}
-#device_details span {
- white-space: pre;
-}
-
-/* This effectively disables the microphone control. It should be enabled again
- * when the audio stream is injected into the guest */
-div#micCaptureCtrl {
+#device-details-modal {
+ /* Start out hidden, and use absolute positioning. */
display: none;
+ position: absolute;
+
+ border-radius: 16px;
+ padding: 20px;
+ padding-top: 1px;
+
+ background-color: #5f6368ea; /* Semi-transparent Google grey 500 */
+ color: white;
+ font-family: 'Open Sans', sans-serif;
+}
+#device-details-modal-header {
+ /* Items inside this use a row Flexbox.*/
+ display: flex;
+ justify-content: space-between;
+}
+#device-details-close {
+ color: white;
+ border: none;
+ outline: none;
+ background-color: transparent;
+}
+#device-details-modal span {
+ white-space: pre;
+}
+
+.control-panel-column {
+ width: 80px;
+ /* Items inside this use a column Flexbox.*/
+ display: flex;
+ flex-direction: column;
+}
+#control-panel-custom-buttons {
+ display: none;
+ /* Give the custom buttons column a blue background. */
+ background-color: #1c4587ff;
+ height: fit-content;
+ border-radius: 16px;
+}
+
+.control-panel-column button {
+ margin: 10px;
+ height: 60px;
+ font-size: 48px;
+
+ color: #e8eaed; /* Google grey 200 */
+ border: none;
+ outline: none;
+ background-color: transparent;
+}
+.control-panel-column button:disabled {
+ color: #9aa0a6; /* Google grey 500 */
+}
+#device-details-button {
+ margin: 0px;
+ height: 80px;
+ border-radius: 16px;
+ background-color: #5f6368; /* Google grey 700 */
+}
+
+#screens {
+ /* Take up the remaining width of the window.*/
+ flex-grow: 1;
+ /* Don't grow taller than the window.*/
+ max-height: 100vh;
+}
+
+#device-screen {
+ touch-action: none;
+ transform-origin: top right;
+ object-fit: cover;
}
diff --git a/host/libs/config/cuttlefish_config.h b/host/libs/config/cuttlefish_config.h
index 54b5c1c..2aafc84 100644
--- a/host/libs/config/cuttlefish_config.h
+++ b/host/libs/config/cuttlefish_config.h
@@ -432,6 +432,8 @@
std::string os_composite_disk_path() const;
+ std::string persistent_composite_disk_path() const;
+
std::string uboot_env_image_path() const;
std::string vendor_boot_image_path() const;
diff --git a/host/libs/config/cuttlefish_config_instance.cpp b/host/libs/config/cuttlefish_config_instance.cpp
index 6ea73e8..9bd8c8a 100644
--- a/host/libs/config/cuttlefish_config_instance.cpp
+++ b/host/libs/config/cuttlefish_config_instance.cpp
@@ -169,6 +169,11 @@
return AbsolutePath(PerInstancePath("os_composite.img"));
}
+std::string CuttlefishConfig::InstanceSpecific::persistent_composite_disk_path()
+ const {
+ return AbsolutePath(PerInstancePath("persistent_composite.img"));
+}
+
std::string CuttlefishConfig::InstanceSpecific::uboot_env_image_path() const {
return AbsolutePath(PerInstancePath("uboot_env.img"));
}
diff --git a/host/libs/confui/host_server.h b/host/libs/confui/host_server.h
index 95cc3ac..05164c9 100644
--- a/host/libs/confui/host_server.h
+++ b/host/libs/confui/host_server.h
@@ -28,9 +28,9 @@
#include <android-base/logging.h>
#include <teeui/utils.h>
+#include "common/libs/concurrency/semaphore.h"
#include "common/libs/confui/confui.h"
#include "common/libs/fs/shared_fd.h"
-#include "common/libs/semaphore/semaphore.h"
#include "host/commands/kernel_log_monitor/utils.h"
#include "host/libs/config/logging.h"
#include "host/libs/confui/host_mode_ctrl.h"
diff --git a/host/libs/confui/multiplexer.h b/host/libs/confui/multiplexer.h
index c0869d0..2ac1928 100644
--- a/host/libs/confui/multiplexer.h
+++ b/host/libs/confui/multiplexer.h
@@ -22,8 +22,8 @@
#include <mutex>
#include <thread>
-#include "common/libs/semaphore/semaphore.h"
-#include "common/libs/thread_safe_queue/thread_safe_queue.h"
+#include "common/libs/concurrency/semaphore.h"
+#include "common/libs/concurrency/thread_safe_queue.h"
namespace cuttlefish {
namespace confui {
diff --git a/host/libs/image_aggregator/Android.bp b/host/libs/image_aggregator/Android.bp
new file mode 100644
index 0000000..491a777
--- /dev/null
+++ b/host/libs/image_aggregator/Android.bp
@@ -0,0 +1,53 @@
+//
+// Copyright (C) 2021 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: "libcdisk_spec",
+ srcs: [
+ "cdisk_spec.proto",
+ ],
+ proto: {
+ type: "full",
+ export_proto_headers: true,
+ include_dirs: [
+ "external/protobuf/src",
+ ],
+ },
+ defaults: ["cuttlefish_host"],
+}
+
+cc_library_static {
+ name: "libimage_aggregator",
+ srcs: [
+ "image_aggregator.cc",
+ ],
+ shared_libs: [
+ "libcuttlefish_fs",
+ "libcuttlefish_utils",
+ "libbase",
+ "libprotobuf-cpp-full",
+ "libz",
+ ],
+ static_libs: [
+ "libcdisk_spec",
+ "libext2_uuid",
+ "libsparse",
+ ],
+ defaults: ["cuttlefish_host"],
+}
diff --git a/host/commands/assemble_cvd/cdisk_spec.proto b/host/libs/image_aggregator/cdisk_spec.proto
similarity index 100%
rename from host/commands/assemble_cvd/cdisk_spec.proto
rename to host/libs/image_aggregator/cdisk_spec.proto
diff --git a/host/commands/assemble_cvd/image_aggregator.cc b/host/libs/image_aggregator/image_aggregator.cc
similarity index 87%
rename from host/commands/assemble_cvd/image_aggregator.cc
rename to host/libs/image_aggregator/image_aggregator.cc
index 46a3f82..8d4027a 100644
--- a/host/commands/assemble_cvd/image_aggregator.cc
+++ b/host/libs/image_aggregator/image_aggregator.cc
@@ -18,7 +18,7 @@
* GUID Partition Table and Composite Disk generation code.
*/
-#include "host/commands/assemble_cvd/image_aggregator.h"
+#include "host/libs/image_aggregator/image_aggregator.h"
#include <sys/types.h>
#include <sys/stat.h>
@@ -29,8 +29,9 @@
#include <string>
#include <vector>
+#include <android-base/file.h>
#include <android-base/logging.h>
-#include <json/json.h>
+#include <cdisk_spec.pb.h>
#include <google/protobuf/text_format.h>
#include <sparse/sparse.h>
#include <uuid.h>
@@ -41,9 +42,7 @@
#include "common/libs/utils/files.h"
#include "common/libs/utils/size_utils.h"
#include "common/libs/utils/subprocess.h"
-#include "host/libs/config/cuttlefish_config.h"
#include "host/libs/config/mbr.h"
-#include "device/google/cuttlefish/host/commands/assemble_cvd/cdisk_spec.pb.h"
namespace cuttlefish {
namespace {
@@ -124,7 +123,8 @@
struct PartitionInfo {
ImagePartition source;
- std::uint64_t size;
+ std::uint64_t guest_size;
+ std::uint64_t host_size;
std::uint64_t offset;
};
@@ -192,15 +192,19 @@
CompositeDiskBuilder() : next_disk_offset_(sizeof(GptBeginning)) {}
void AppendDisk(ImagePartition source) {
- auto size = AlignToPowerOf2(UnsparsedSize(source.image_file_path),
- PARTITION_SIZE_SHIFT);
- partitions_.push_back(PartitionInfo {
- .source = source,
- .size = size,
- .offset = next_disk_offset_,
+ auto host_size = UnsparsedSize(source.image_file_path);
+ auto guest_size = AlignToPowerOf2(host_size, PARTITION_SIZE_SHIFT);
+ CHECK(host_size == guest_size || source.read_only)
+ << "read-write file " << source.image_file_path
+ << " is not aligned to the size of " << (1 << PARTITION_SIZE_SHIFT);
+ partitions_.push_back(PartitionInfo{
+ .source = source,
+ .guest_size = guest_size,
+ .host_size = host_size,
+ .offset = next_disk_offset_,
});
- next_disk_offset_ = AlignToPowerOf2(next_disk_offset_ + size,
- PARTITION_SIZE_SHIFT);
+ next_disk_offset_ =
+ AlignToPowerOf2(next_disk_offset_ + guest_size, PARTITION_SIZE_SHIFT);
}
std::uint64_t DiskSize() const {
@@ -220,18 +224,32 @@
disk.set_length(DiskSize());
ComponentDisk* header = disk.add_component_disks();
- header->set_file_path(header_file);
+ header->set_file_path(AbsolutePath(header_file));
header->set_offset(0);
for (auto& partition : partitions_) {
ComponentDisk* component = disk.add_component_disks();
- component->set_file_path(partition.source.image_file_path);
+ component->set_file_path(AbsolutePath(partition.source.image_file_path));
component->set_offset(partition.offset);
- component->set_read_write_capability(ReadWriteCapability::READ_WRITE);
+ component->set_read_write_capability(
+ partition.source.read_only ? ReadWriteCapability::READ_ONLY
+ : ReadWriteCapability::READ_WRITE);
+ // When partition's size differs from its size on the host
+ // reading the disk within the guest os would fail due to the gap.
+ // Putting any disk bigger than 4K can fill this gap.
+ // Here we reuse the header which is always > 4K.
+ // We don't fill the "writable" disk's hole and it should be an error
+ // because writes in the guest of can't be reflected to the backing file.
+ if (partition.guest_size != partition.host_size) {
+ ComponentDisk* component = disk.add_component_disks();
+ component->set_file_path(AbsolutePath(header_file));
+ component->set_offset(partition.offset + partition.host_size);
+ component->set_read_write_capability(ReadWriteCapability::READ_ONLY);
+ }
}
ComponentDisk* footer = disk.add_component_disks();
- footer->set_file_path(footer_file);
+ footer->set_file_path(AbsolutePath(footer_file));
footer->set_offset(next_disk_offset_);
return disk;
@@ -267,9 +285,10 @@
uuid_generate(gpt.header.disk_guid);
for (std::size_t i = 0; i < partitions_.size(); i++) {
const auto& partition = partitions_[i];
- gpt.entries[i] = GptPartitionEntry {
- .first_lba = partition.offset / SECTOR_SIZE,
- .last_lba = (partition.offset + partition.size) / SECTOR_SIZE - 1,
+ gpt.entries[i] = GptPartitionEntry{
+ .first_lba = partition.offset / SECTOR_SIZE,
+ .last_lba =
+ (partition.offset + partition.guest_size) / SECTOR_SIZE - 1,
};
uuid_generate(gpt.entries[i].unique_partition_guid);
if (uuid_parse(GetPartitionGUID(partition.source),
diff --git a/host/commands/assemble_cvd/image_aggregator.h b/host/libs/image_aggregator/image_aggregator.h
similarity index 98%
rename from host/commands/assemble_cvd/image_aggregator.h
rename to host/libs/image_aggregator/image_aggregator.h
index 7c5719b..97bc13b 100644
--- a/host/commands/assemble_cvd/image_aggregator.h
+++ b/host/libs/image_aggregator/image_aggregator.h
@@ -33,6 +33,7 @@
std::string label;
std::string image_file_path;
ImagePartitionType type;
+ bool read_only;
};
/**
diff --git a/host/libs/screen_connector/Android.bp b/host/libs/screen_connector/Android.bp
index fcfc747..d4e4002 100644
--- a/host/libs/screen_connector/Android.bp
+++ b/host/libs/screen_connector/Android.bp
@@ -28,10 +28,18 @@
"libjsoncpp",
"liblog",
],
+ header_libs: [
+ "libcuttlefish_confui_host_headers",
+ ],
static_libs: [
"libcuttlefish_host_config",
"libcuttlefish_utils",
+ "libcuttlefish_confui",
"libcuttlefish_wayland_server",
+ "libcuttlefish_confui_host",
+ "libft2.nodep",
+ "libteeui",
+ "libteeui_localization",
],
defaults: ["cuttlefish_host"],
}
diff --git a/host/libs/screen_connector/screen_connector.h b/host/libs/screen_connector/screen_connector.h
index 232eea0..6cc6b34 100644
--- a/host/libs/screen_connector/screen_connector.h
+++ b/host/libs/screen_connector/screen_connector.h
@@ -17,21 +17,33 @@
#pragma once
#include <cassert>
+#include <chrono>
#include <cstdint>
#include <functional>
#include <memory>
#include <mutex>
+#include <optional>
#include <thread>
#include <type_traits>
#include <android-base/logging.h>
+#include "common/libs/concurrency/semaphore.h"
+#include "common/libs/confui/confui.h"
+#include "common/libs/fs/shared_fd.h"
#include "common/libs/utils/size_utils.h"
+
#include "host/libs/config/cuttlefish_config.h"
+#include "host/libs/confui/host_mode_ctrl.h"
+#include "host/libs/confui/host_utils.h"
#include "host/libs/screen_connector/screen_connector_common.h"
#include "host/libs/screen_connector/screen_connector_queue.h"
-#include "host/libs/screen_connector/screen_connector_ctrl.h"
#include "host/libs/screen_connector/wayland_screen_connector.h"
+// LOG(X) for confirmation UI debugging
+using cuttlefish::confui::DebugLog;
+using cuttlefish::confui::ErrorLog;
+using cuttlefish::confui::FatalLog;
+
namespace cuttlefish {
template <typename ProcessedFrameType>
@@ -60,14 +72,15 @@
/* ScImpl enqueues this type into the Q */
ProcessedFrameType& msg)>;
- static std::unique_ptr<ScreenConnector<ProcessedFrameType>> Get(const int frames_fd) {
+ static std::unique_ptr<ScreenConnector<ProcessedFrameType>> Get(
+ const int frames_fd, HostModeCtrl& host_mode_ctrl) {
auto config = cuttlefish::CuttlefishConfig::Get();
ScreenConnector<ProcessedFrameType>* raw_ptr = nullptr;
if (config->gpu_mode() == cuttlefish::kGpuModeDrmVirgl ||
config->gpu_mode() == cuttlefish::kGpuModeGfxStream ||
config->gpu_mode() == cuttlefish::kGpuModeGuestSwiftshader) {
raw_ptr = new ScreenConnector<ProcessedFrameType>(
- std::make_unique<WaylandScreenConnector>(frames_fd));
+ std::make_unique<WaylandScreenConnector>(frames_fd), host_mode_ctrl);
} else {
LOG(FATAL) << "Invalid gpu mode: " << config->gpu_mode();
}
@@ -84,14 +97,14 @@
void SetCallback(GenerateProcessedFrameCallback&& frame_callback) {
std::lock_guard<std::mutex> lock(streamer_callback_mutex_);
callback_from_streamer_ = std::move(frame_callback);
+ streamer_callback_set_cv_.notify_all();
/*
* the first WaitForAtLeastOneClientConnection() call from VNC requires the
* Android-frame-processing thread starts beforehands (b/178504150)
*/
- if (!is_frame_fetching_thread_started_) {
- is_frame_fetching_thread_started_ = true;
- sc_android_impl_fetcher_ =
- std::move(std::thread(&ScreenConnector::FrameFetchingLoop, this));
+ if (!sc_android_frame_fetching_thread_.joinable()) {
+ sc_android_frame_fetching_thread_ = cuttlefish::confui::thread::RunThread(
+ "AndroidFetcher", &ScreenConnector::AndroidFrameFetchingLoop, this);
}
}
@@ -108,39 +121,68 @@
* NOTE THAT THIS IS THE ONLY CONSUMER OF THE TWO QUEUES
*/
ProcessedFrameType OnNextFrame() {
- // sc_ctrl has a semaphore internally
- // passing beyond SemWait means either queue has an item
- sc_ctrl_.SemWaitItem();
- return sc_android_queue_.PopFront();
-
- // TODO: add confirmation ui
- /*
- * if (!sc_android_queue_.Empty()) return sc_android_queue_.PopFront();
- * else return conf_ui_queue.PopFront();
- */
+ on_next_frame_cnt_++;
+ while (true) {
+ DebugLog("Streamer waiting Semaphore with host ctrl mode = ",
+ static_cast<std::uint32_t>(host_mode_ctrl_.GetMode()),
+ " and cnd = #", on_next_frame_cnt_);
+ sc_sem_.SemWait();
+ DebugLog("Streamer got Semaphore'ed resources with host ctrl mode = ",
+ static_cast<std::uint32_t>(host_mode_ctrl_.GetMode()),
+ " and cnd = #", on_next_frame_cnt_);
+ // do something
+ if (!sc_android_queue_.Empty()) {
+ auto mode = host_mode_ctrl_.GetMode();
+ if (mode == HostModeCtrl::ModeType::kAndroidMode) {
+ DebugLog("Streamer gets Android frame with host ctrl mode = ",
+ static_cast<std::uint32_t>(mode), " and cnd = #",
+ on_next_frame_cnt_);
+ return sc_android_queue_.PopFront();
+ }
+ // AndroidFrameFetchingLoop could have added 1 or 2 frames
+ // before it becomes Conf UI mode.
+ DebugLog("Streamer ignores Android frame with host ctrl mode = ",
+ static_cast<std::uint32_t>(mode), " and cnd = #",
+ on_next_frame_cnt_);
+ sc_android_queue_.PopFront();
+ continue;
+ }
+ DebugLog("Streamer gets Conf UI frame with host ctrl mode = ",
+ static_cast<std::uint32_t>(host_mode_ctrl_.GetMode()),
+ " and cnd = #", on_next_frame_cnt_);
+ return sc_confui_queue_.PopFront();
+ }
}
- [[noreturn]] void FrameFetchingLoop() {
+ [[noreturn]] void AndroidFrameFetchingLoop() {
+ unsigned long long int loop_cnt = 0;
+ cuttlefish::confui::thread::Set("AndroidFrameFetcher",
+ std::this_thread::get_id());
while (true) {
- sc_ctrl_.WaitAndroidMode( /* pass method to stop sc_android_impl_ */);
- /*
- * TODO: instead of WaitAndroidMode,
- * we could sc_android_impl_->OnFrameAfter but enqueue it only in AndroidMode
- */
- ProcessedFrameType msg;
+ loop_cnt++;
+ ProcessedFrameType processed_frame;
decltype(callback_from_streamer_) cp_of_streamer_callback;
{
std::lock_guard<std::mutex> lock(streamer_callback_mutex_);
cp_of_streamer_callback = callback_from_streamer_;
}
GenerateProcessedFrameCallbackImpl callback_for_sc_impl =
- std::bind(cp_of_streamer_callback,
- std::placeholders::_1, std::placeholders::_2,
- std::ref(msg));
- bool flag = sc_android_impl_->OnNextFrame(callback_for_sc_impl);
- msg.is_success_ = flag && msg.is_success_;
- auto result = ProcessedFrameType{std::move(msg)};
- sc_android_queue_.PushBack(std::move(result));
+ std::bind(cp_of_streamer_callback, std::placeholders::_1,
+ std::placeholders::_2, std::ref(processed_frame));
+ DebugLog(cuttlefish::confui::thread::GetName(std::this_thread::get_id()),
+ " calling Android OnNextFrame. ", " at loop #", loop_cnt);
+ bool flag = sc_android_src_->OnNextFrame(callback_for_sc_impl);
+ processed_frame.is_success_ = flag && processed_frame.is_success_;
+ const bool is_confui_mode = host_mode_ctrl_.IsConfirmatioUiMode();
+ if (!is_confui_mode) {
+ DebugLog(
+ cuttlefish::confui::thread::GetName(std::this_thread::get_id()),
+ " is sending an Android Frame at loop_cnt #", loop_cnt);
+ sc_android_queue_.PushBack(std::move(processed_frame));
+ continue;
+ }
+ DebugLog(cuttlefish::confui::thread::GetName(std::this_thread::get_id()),
+ " is skipping an Android Frame at loop_cnt #", loop_cnt);
}
}
@@ -151,14 +193,29 @@
* Android guest frames if Confirmation UI HAL is not active.
*
*/
- bool RenderConfirmationUi(const std::uint32_t, std::uint8_t*) override {
+ bool RenderConfirmationUi(const std::uint32_t display,
+ std::uint8_t* raw_frame) override {
+ render_confui_cnt_++;
+ // wait callback is not set, the streamer is not ready
+ // return with LOG(ERROR)
+ if (!IsCallbackSet()) {
+ ErrorLog("callback function to process frames is not yet set");
+ return false;
+ }
+ ProcessedFrameType processed_frame;
+ auto this_thread_name = cuttlefish::confui::thread::GetName();
+ DebugLog(this_thread_name, " is sending a #", render_confui_cnt_,
+ " Conf UI frame");
+ callback_from_streamer_(display, raw_frame, processed_frame);
+ // now add processed_frame to the queue
+ sc_confui_queue_.PushBack(std::move(processed_frame));
return true;
}
// Let the screen connector know when there are clients connected
void ReportClientsConnected(bool have_clients) {
// screen connector implementation must implement ReportClientsConnected
- sc_android_impl_->ReportClientsConnected(have_clients);
+ sc_android_src_->ReportClientsConnected(have_clients);
return ;
}
@@ -166,20 +223,28 @@
template <typename T,
typename = std::enable_if_t<
std::is_base_of<ScreenConnectorSource, T>::value, void>>
- ScreenConnector(std::unique_ptr<T>&& impl)
- : sc_android_impl_{std::move(impl)},
- is_frame_fetching_thread_started_(false),
- sc_android_queue_(sc_ctrl_) {}
+ ScreenConnector(std::unique_ptr<T>&& impl, HostModeCtrl& host_mode_ctrl)
+ : sc_android_src_{std::move(impl)},
+ host_mode_ctrl_{host_mode_ctrl},
+ on_next_frame_cnt_{0},
+ render_confui_cnt_{0},
+ sc_android_queue_{sc_sem_},
+ sc_confui_queue_{sc_sem_} {}
ScreenConnector() = delete;
private:
- std::unique_ptr<ScreenConnectorSource> sc_android_impl_; // either socket_based or wayland
- bool is_frame_fetching_thread_started_;
- ScreenConnectorCtrl sc_ctrl_;
+ // either socket_based or wayland
+ std::unique_ptr<ScreenConnectorSource> sc_android_src_;
+ HostModeCtrl& host_mode_ctrl_;
+ unsigned long long int on_next_frame_cnt_;
+ unsigned long long int render_confui_cnt_;
+ Semaphore sc_sem_;
ScreenConnectorQueue<ProcessedFrameType> sc_android_queue_;
+ ScreenConnectorQueue<ProcessedFrameType> sc_confui_queue_;
GenerateProcessedFrameCallback callback_from_streamer_;
- std::thread sc_android_impl_fetcher_;
+ std::thread sc_android_frame_fetching_thread_;
std::mutex streamer_callback_mutex_; // mutex to set & read callback_from_streamer_
+ std::condition_variable streamer_callback_set_cv_;
};
} // namespace cuttlefish
diff --git a/host/libs/screen_connector/screen_connector_ctrl.h b/host/libs/screen_connector/screen_connector_ctrl.h
index 3fed1df..9b90152 100644
--- a/host/libs/screen_connector/screen_connector_ctrl.h
+++ b/host/libs/screen_connector/screen_connector_ctrl.h
@@ -23,7 +23,7 @@
#include <mutex>
#include <thread>
-#include "common/libs/semaphore/semaphore.h"
+#include "common/libs/concurrency/semaphore.h"
namespace cuttlefish {
/**
@@ -42,9 +42,7 @@
kConfUI_Mode
};
- ScreenConnectorCtrl()
- : atomic_mode_(ModeType::kAndroidMode)
- {}
+ ScreenConnectorCtrl() : atomic_mode_(ModeType::kAndroidMode) {}
/**
* The thread that enqueues Android frames will call this to wait until
@@ -89,14 +87,10 @@
return ret_val;
}
- void SemWaitItem() {
- sem_.SemWait();
- }
+ void SemWait() { sem_.SemWait(); }
// Only called by the producers
- void SemPostItem() {
- sem_.SemPost();
- }
+ void SemPost() { sem_.SemPost(); }
private:
std::mutex mode_mtx_;
diff --git a/host/libs/screen_connector/screen_connector_queue.h b/host/libs/screen_connector/screen_connector_queue.h
index f8a76f3..2019168 100644
--- a/host/libs/screen_connector/screen_connector_queue.h
+++ b/host/libs/screen_connector/screen_connector_queue.h
@@ -23,7 +23,7 @@
#include <condition_variable>
#include <chrono>
-#include "host/libs/screen_connector/screen_connector_ctrl.h"
+#include "common/libs/concurrency/semaphore.h"
namespace cuttlefish {
// move-based concurrent queue
@@ -36,10 +36,8 @@
static_assert( is_movable<T>::value,
"Items in ScreenConnectorQueue should be std::mov-able");
- ScreenConnectorQueue(ScreenConnectorCtrl& sc_ctrl_)
- : q_mutex_(std::make_unique<std::mutex>()),
- global_item_tracker_(sc_ctrl_)
- {}
+ ScreenConnectorQueue(Semaphore& sc_sem)
+ : q_mutex_(std::make_unique<std::mutex>()), sc_semaphore_(sc_sem) {}
ScreenConnectorQueue(ScreenConnectorQueue&& cq) = delete;
ScreenConnectorQueue(const ScreenConnectorQueue& cq) = delete;
ScreenConnectorQueue& operator=(const ScreenConnectorQueue& cq) = delete;
@@ -93,13 +91,13 @@
* This IS intended to awake the screen_connector consumer thread
* when one or more items are available at least in one queue
*/
- global_item_tracker_.SemPostItem();
+ sc_semaphore_.SemPost();
}
void PushBack(T& item) = delete;
void PushBack(const T& item) = delete;
/*
- * PopFront must be preceded by global_item_tracker_.SemWaitItem()
+ * PopFront must be preceded by sc_semaphore_.SemWaitItem()
*
*/
T PopFront() {
@@ -121,7 +119,7 @@
std::deque<T> buffer_;
std::unique_ptr<std::mutex> q_mutex_;
std::condition_variable q_empty_;
- ScreenConnectorCtrl& global_item_tracker_;
+ Semaphore& sc_semaphore_;
};
} // namespace cuttlefish
diff --git a/host/libs/vm_manager/crosvm_manager.cpp b/host/libs/vm_manager/crosvm_manager.cpp
index e2ec717..4f136fd 100644
--- a/host/libs/vm_manager/crosvm_manager.cpp
+++ b/host/libs/vm_manager/crosvm_manager.cpp
@@ -20,7 +20,6 @@
#include <sys/types.h>
#include <cassert>
-#include <iomanip>
#include <string>
#include <vector>
@@ -140,10 +139,7 @@
// TODO There is no way to control this assignment with crosvm (yet)
if (HostArch() == Arch::X86_64) {
// crosvm has an additional PCI device for an ISA bridge
- std::stringstream stream;
- stream << std::setfill('0') << std::setw(2) << std::hex
- << 1 + VmManager::kDefaultNumHvcs + VmManager::kMaxDisks - num_disks;
- return "androidboot.boot_devices=pci0000:00/0000:00:" + stream.str() + ".0";
+ return ConfigureMultipleBootDevices("pci0000:00/0000:00:", 1, num_disks);
} else {
// On ARM64 crosvm, block devices are on their own bridge, so we don't
// need to calculate it, and the path is always the same
diff --git a/host/libs/vm_manager/qemu_manager.cpp b/host/libs/vm_manager/qemu_manager.cpp
index ed61c69..f26818a 100644
--- a/host/libs/vm_manager/qemu_manager.cpp
+++ b/host/libs/vm_manager/qemu_manager.cpp
@@ -25,7 +25,6 @@
#include <unistd.h>
#include <cstdlib>
-#include <iomanip>
#include <sstream>
#include <string>
#include <thread>
@@ -125,12 +124,7 @@
case Arch::X86:
case Arch::X86_64: {
// QEMU has additional PCI devices for an ISA bridge and PIIX4
- std::stringstream stream;
- stream << std::setfill('0') << std::setw(2) << std::hex
- << 2 + VmManager::kDefaultNumHvcs + VmManager::kMaxDisks -
- num_disks;
- return "androidboot.boot_devices=pci0000:00/0000:00:" + stream.str() +
- ".0";
+ return ConfigureMultipleBootDevices("pci0000:00/0000:00:", 2, num_disks);
}
case Arch::Arm:
return "androidboot.boot_devices=3f000000.pcie";
diff --git a/host/libs/vm_manager/vm_manager.cpp b/host/libs/vm_manager/vm_manager.cpp
index 3a5a41d..8c2ef57 100644
--- a/host/libs/vm_manager/vm_manager.cpp
+++ b/host/libs/vm_manager/vm_manager.cpp
@@ -16,13 +16,14 @@
#include "host/libs/vm_manager/vm_manager.h"
-#include <memory>
-
#include <android-base/logging.h>
+#include <iomanip>
+#include <memory>
+
#include "host/libs/config/cuttlefish_config.h"
-#include "host/libs/vm_manager/qemu_manager.h"
#include "host/libs/vm_manager/crosvm_manager.h"
+#include "host/libs/vm_manager/qemu_manager.h"
namespace cuttlefish {
namespace vm_manager {
@@ -45,6 +46,21 @@
return vmm;
}
+std::string ConfigureMultipleBootDevices(const std::string& pci_path,
+ int pci_offset, int num_disks) {
+ int num_boot_devices =
+ (num_disks < VmManager::kDefaultNumBootDevices) ? num_disks : VmManager::kDefaultNumBootDevices;
+ std::string boot_devices_prop = "androidboot.boot_devices=";
+ for (int i = 0; i < num_boot_devices; i++) {
+ std::stringstream stream;
+ stream << std::setfill('0') << std::setw(2) << std::hex
+ << pci_offset + i + VmManager::kDefaultNumHvcs + VmManager::kMaxDisks - num_disks;
+ boot_devices_prop += pci_path + stream.str() + ".0,";
+ }
+ boot_devices_prop.pop_back();
+ return {boot_devices_prop};
+}
+
} // namespace vm_manager
} // namespace cuttlefish
diff --git a/host/libs/vm_manager/vm_manager.h b/host/libs/vm_manager/vm_manager.h
index 2af2846..b538e8f 100644
--- a/host/libs/vm_manager/vm_manager.h
+++ b/host/libs/vm_manager/vm_manager.h
@@ -51,6 +51,13 @@
// assigned virtual disk PCI ID (i.e. 2 disks = 7 hvcs, 1 disks = 8 hvcs)
static const int kMaxDisks = 3;
+ // This is the number of virtual disks that contribute to the named partition
+ // list (/dev/block/by-name/*) under Android. The partitions names from
+ // multiple disks *must not* collide. Normally we have one set of partitions
+ // from the powerwashed disk (operating system disk) and another set from
+ // the persistent disk
+ static const int kDefaultNumBootDevices = 2;
+
VmManager(Arch arch) : arch_(arch) {}
virtual ~VmManager() = default;
@@ -68,6 +75,9 @@
std::unique_ptr<VmManager> GetVmManager(const std::string&, Arch arch);
+std::string ConfigureMultipleBootDevices(const std::string& pci_path, int pci_offset,
+ int num_disks);
+
} // namespace vm_manager
} // namespace cuttlefish
diff --git a/shared/config/config_foldable.json b/shared/config/config_foldable.json
index 7a1e731..dd64d17 100644
--- a/shared/config/config_foldable.json
+++ b/shared/config/config_foldable.json
@@ -7,7 +7,8 @@
{
"device_states": [
{
- "lid_switch_open": false
+ "lid_switch_open": false,
+ "hinge_angle_value": 0
}
],
"button":{
@@ -19,7 +20,8 @@
{
"device_states": [
{
- "lid_switch_open": true
+ "lid_switch_open": true,
+ "hinge_angle_value": 180
}
],
"button":{
diff --git a/shared/config/ueventd.rc b/shared/config/ueventd.rc
index 84d2806..3d5a219 100644
--- a/shared/config/ueventd.rc
+++ b/shared/config/ueventd.rc
@@ -29,4 +29,4 @@
/dev/gnss0 0666 system system
# Factory Reset Protection
-/dev/block/vdb 0660 system system
+/dev/block/by-name/frp 0660 system system
diff --git a/shared/device.mk b/shared/device.mk
index 089c662..55325fb 100644
--- a/shared/device.mk
+++ b/shared/device.mk
@@ -32,6 +32,8 @@
PRODUCT_USE_DYNAMIC_PARTITIONS := true
DISABLE_RILD_OEM_HOOK := true
+PRODUCT_SET_DEBUGFS_RESTRICTIONS := true
+
PRODUCT_SOONG_NAMESPACES += device/generic/goldfish-opengl # for vulkan
PRODUCT_FS_COMPRESSION := 1
@@ -73,7 +75,7 @@
# Storage: for factory reset protection feature
PRODUCT_VENDOR_PROPERTIES += \
- ro.frp.pst=/dev/block/vdb
+ ro.frp.pst=/dev/block/by-name/frp
# Explanation of specific properties:
# debug.hwui.swap_with_damage avoids boot failure on M http://b/25152138
@@ -147,7 +149,7 @@
#
PRODUCT_PACKAGES += \
CuttlefishService \
- cuttlefish_rotate \
+ cuttlefish_sensor_injection \
rename_netiface \
setup_wifi \
bt_vhci_forwarder \
diff --git a/shared/foldable/device_state_configuration.xml b/shared/foldable/device_state_configuration.xml
index b32eced..9618b11 100644
--- a/shared/foldable/device_state_configuration.xml
+++ b/shared/foldable/device_state_configuration.xml
@@ -9,13 +9,21 @@
</conditions>
</device-state>
<device-state>
- <!-- TODO(b/181583265): Use the hinge sensor for HALF_OPENED state.
- Currently using an identifier of 3 so that this state never takes
- precedence over the lower-identifier-value CLOSED and OPENED states,
- until a hinge sensor is available. -->
- <identifier>3</identifier>
+ <identifier>1</identifier>
<name>HALF_OPENED</name>
- <conditions></conditions>
+ <conditions>
+ <lid-switch>
+ <open>true</open>
+ </lid-switch>
+ <sensor>
+ <type>android.sensor.hinge_angle</type>
+ <name>Hinge Angle Sensor</name>
+ <value>
+ <min>0</min>
+ <max>180</max>
+ </value>
+ </sensor>
+ </conditions>
</device-state>
<device-state>
<identifier>2</identifier>
diff --git a/shared/sepolicy/vendor/cuttlefish_rotate.te b/shared/sepolicy/vendor/cuttlefish_rotate.te
deleted file mode 100644
index 7d8a9a1..0000000
--- a/shared/sepolicy/vendor/cuttlefish_rotate.te
+++ /dev/null
@@ -1,15 +0,0 @@
-type cuttlefish_rotate, domain;
-type cuttlefish_rotate_exec, exec_type, vendor_file_type, file_type;
-
-# Switch to cuttlefish_rotate domain when executing from shell.
-domain_auto_trans(shell, cuttlefish_rotate_exec, cuttlefish_rotate)
-allow cuttlefish_rotate shell:fd use;
-
-# Allow cuttlefish_rotate to communicate over adb connection.
-allow cuttlefish_rotate adbd:fd use;
-allow cuttlefish_rotate adbd:unix_stream_socket { read write };
-# Needed to run the binary directly via adb socket.
-allow cuttlefish_rotate devpts:chr_file { read write };
-
-# Grant cuttlefish_rotate access to the ISensors HAL.
-hal_client_domain(cuttlefish_rotate, hal_sensors)
diff --git a/shared/sepolicy/vendor/cuttlefish_sensor_injection.te b/shared/sepolicy/vendor/cuttlefish_sensor_injection.te
new file mode 100644
index 0000000..9e7aca5
--- /dev/null
+++ b/shared/sepolicy/vendor/cuttlefish_sensor_injection.te
@@ -0,0 +1,15 @@
+type cuttlefish_sensor_injection, domain;
+type cuttlefish_sensor_injection_exec, exec_type, vendor_file_type, file_type;
+
+# Switch to cuttlefish_sensor_injection domain when executing from shell.
+domain_auto_trans(shell, cuttlefish_sensor_injection_exec, cuttlefish_sensor_injection)
+allow cuttlefish_sensor_injection shell:fd use;
+
+# Allow cuttlefish_sensor_injection to communicate over adb connection.
+allow cuttlefish_sensor_injection adbd:fd use;
+allow cuttlefish_sensor_injection adbd:unix_stream_socket { read write };
+# Needed to run the binary directly via adb socket.
+allow cuttlefish_sensor_injection devpts:chr_file { read write };
+
+# Grant cuttlefish_sensor_injection access to the ISensors HAL.
+hal_client_domain(cuttlefish_sensor_injection, hal_sensors)
diff --git a/shared/sepolicy/vendor/file_contexts b/shared/sepolicy/vendor/file_contexts
index 20c3341..b082bae 100644
--- a/shared/sepolicy/vendor/file_contexts
+++ b/shared/sepolicy/vendor/file_contexts
@@ -11,7 +11,8 @@
/dev/block/by-name/userdata u:object_r:userdata_block_device:s0
/dev/block/by-name/metadata u:object_r:metadata_block_device:s0
-/dev/block/vdb u:object_r:frp_block_device:s0
+/dev/block/by-name/frp u:object_r:frp_block_device:s0
+
/dev/block/pmem0 u:object_r:rebootescrow_device:s0
/dev/block/zram0 u:object_r:swap_block_device:s0
/dev/dri u:object_r:gpu_device:s0
@@ -55,7 +56,7 @@
#############################
# Vendor files
#
-/vendor/bin/cuttlefish_rotate u:object_r:cuttlefish_rotate_exec:s0
+/vendor/bin/cuttlefish_sensor_injection u:object_r:cuttlefish_sensor_injection_exec:s0
/vendor/bin/socket_vsock_proxy u:object_r:socket_vsock_proxy_exec:s0
/vendor/bin/vsoc_input_service u:object_r:vsoc_input_service_exec:s0
/vendor/bin/rename_netiface u:object_r:rename_netiface_exec:s0
diff --git a/shared/sepolicy/vendor/shell.te b/shared/sepolicy/vendor/shell.te
index 60d15fa..cc26032 100644
--- a/shared/sepolicy/vendor/shell.te
+++ b/shared/sepolicy/vendor/shell.te
@@ -1,5 +1,5 @@
allow shell serial_device:chr_file { getattr ioctl read write };
-allow shell cuttlefish_rotate_exec:file rx_file_perms;
+allow shell cuttlefish_sensor_injection_exec:file rx_file_perms;
# TODO(b/130668487): Label the vsock sockets.
allow shell adbd:{ socket vsock_socket } rw_socket_perms_no_ioctl;