Merge "debuggerd_handler: increase thread stack size."
diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp
index 5066046..9c80765 100644
--- a/fastboot/device/usb_client.cpp
+++ b/fastboot/device/usb_client.cpp
@@ -297,3 +297,7 @@
CloseFunctionFs(handle_.get());
return 0;
}
+
+int ClientUsbTransport::Reset() {
+ return 0;
+}
diff --git a/fastboot/device/usb_client.h b/fastboot/device/usb_client.h
index 3694f9a..e6a1a8b 100644
--- a/fastboot/device/usb_client.h
+++ b/fastboot/device/usb_client.h
@@ -29,6 +29,7 @@
ssize_t Read(void* data, size_t len) override;
ssize_t Write(const void* data, size_t len) override;
int Close() override;
+ int Reset() override;
private:
std::unique_ptr<usb_handle> handle_;
diff --git a/fastboot/fuzzy_fastboot/Android.bp b/fastboot/fuzzy_fastboot/Android.bp
index d48cfa9..bb54fd9 100644
--- a/fastboot/fuzzy_fastboot/Android.bp
+++ b/fastboot/fuzzy_fastboot/Android.bp
@@ -5,7 +5,7 @@
srcs: [
"main.cpp",
"extensions.cpp",
- "usb_transport_sniffer.cpp",
+ "transport_sniffer.cpp",
"fixtures.cpp",
"test_utils.cpp",
],
diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp
index bc13a8c..bd76ff4 100644
--- a/fastboot/fuzzy_fastboot/fixtures.cpp
+++ b/fastboot/fuzzy_fastboot/fixtures.cpp
@@ -48,12 +48,13 @@
#include <gtest/gtest.h>
#include "fastboot_driver.h"
+#include "tcp.h"
#include "usb.h"
#include "extensions.h"
#include "fixtures.h"
#include "test_utils.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
using namespace std::literals::chrono_literals;
@@ -74,7 +75,14 @@
return 0;
}
+bool FastBootTest::IsFastbootOverTcp() {
+ // serial contains ":" is treated as host ip and port number
+ return (device_serial.find(":") != std::string::npos);
+}
+
bool FastBootTest::UsbStillAvailible() {
+ if (IsFastbootOverTcp()) return true;
+
// For some reason someone decided to prefix the path with "usb:"
std::string prefix("usb:");
if (std::equal(prefix.begin(), prefix.end(), device_path.begin())) {
@@ -113,15 +121,19 @@
ASSERT_TRUE(UsbStillAvailible()); // The device disconnected
}
- const auto matcher = [](usb_ifc_info* info) -> int {
- return MatchFastboot(info, device_serial);
- };
- for (int i = 0; i < MAX_USB_TRIES && !transport; i++) {
- std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
- if (usb)
- transport = std::unique_ptr<UsbTransportSniffer>(
- new UsbTransportSniffer(std::move(usb), serial_port));
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ if (IsFastbootOverTcp()) {
+ ConnectTcpFastbootDevice();
+ } else {
+ const auto matcher = [](usb_ifc_info* info) -> int {
+ return MatchFastboot(info, device_serial);
+ };
+ for (int i = 0; i < MAX_USB_TRIES && !transport; i++) {
+ std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
+ if (usb)
+ transport = std::unique_ptr<TransportSniffer>(
+ new TransportSniffer(std::move(usb), serial_port));
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
}
ASSERT_TRUE(transport); // no nullptr
@@ -154,6 +166,8 @@
// TODO, this should eventually be piped to a file instead of stdout
void FastBootTest::TearDownSerial() {
+ if (IsFastbootOverTcp()) return;
+
if (!transport) return;
// One last read from serial
transport->ProcessSerial();
@@ -167,9 +181,34 @@
}
}
+void FastBootTest::ConnectTcpFastbootDevice() {
+ std::size_t found = device_serial.find(":");
+ if (found != std::string::npos) {
+ for (int i = 0; i < MAX_TCP_TRIES && !transport; i++) {
+ std::string error;
+ std::unique_ptr<Transport> tcp(
+ tcp::Connect(device_serial.substr(0, found), tcp::kDefaultPort, &error)
+ .release());
+ if (tcp)
+ transport =
+ std::unique_ptr<TransportSniffer>(new TransportSniffer(std::move(tcp), 0));
+ if (transport != nullptr) break;
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ }
+}
+
void FastBootTest::ReconnectFastbootDevice() {
fb.reset();
transport.reset();
+
+ if (IsFastbootOverTcp()) {
+ ConnectTcpFastbootDevice();
+ device_path = cb_scratch;
+ fb = std::unique_ptr<FastBootDriver>(new FastBootDriver(transport.get(), {}, true));
+ return;
+ }
+
while (UsbStillAvailible())
;
printf("WAITING FOR DEVICE\n");
@@ -180,8 +219,8 @@
while (!transport) {
std::unique_ptr<UsbTransport> usb(usb_open(matcher, USB_TIMEOUT));
if (usb) {
- transport = std::unique_ptr<UsbTransportSniffer>(
- new UsbTransportSniffer(std::move(usb), serial_port));
+ transport = std::unique_ptr<TransportSniffer>(
+ new TransportSniffer(std::move(usb), serial_port));
}
std::this_thread::sleep_for(1s);
}
diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h
index c71c897..2468868 100644
--- a/fastboot/fuzzy_fastboot/fixtures.h
+++ b/fastboot/fuzzy_fastboot/fixtures.h
@@ -31,7 +31,7 @@
#include "fastboot_driver.h"
#include "extensions.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
namespace fastboot {
@@ -45,11 +45,14 @@
static int serial_port;
static std::string device_serial;
static constexpr int MAX_USB_TRIES = 10;
+ static constexpr int MAX_TCP_TRIES = 6000;
static int MatchFastboot(usb_ifc_info* info, const std::string& local_serial = "");
+ static bool IsFastbootOverTcp();
bool UsbStillAvailible();
bool UserSpaceFastboot();
void ReconnectFastbootDevice();
+ void ConnectTcpFastbootDevice();
protected:
RetCode DownloadCommand(uint32_t size, std::string* response = nullptr,
@@ -64,7 +67,7 @@
void TearDownSerial();
void SetLockState(bool unlock, bool assert_change = true);
- std::unique_ptr<UsbTransportSniffer> transport;
+ std::unique_ptr<TransportSniffer> transport;
std::unique_ptr<FastBootDriver> fb;
private:
diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp
index a1d69d2..b9784fe 100644
--- a/fastboot/fuzzy_fastboot/main.cpp
+++ b/fastboot/fuzzy_fastboot/main.cpp
@@ -54,7 +54,7 @@
#include "extensions.h"
#include "fixtures.h"
#include "test_utils.h"
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
namespace fastboot {
@@ -1756,16 +1756,19 @@
}
setbuf(stdout, NULL); // no buffering
- printf("<Waiting for Device>\n");
- const auto matcher = [](usb_ifc_info* info) -> int {
- return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
- };
- Transport* transport = nullptr;
- while (!transport) {
- transport = usb_open(matcher);
- std::this_thread::sleep_for(std::chrono::milliseconds(10));
+
+ if (!fastboot::FastBootTest::IsFastbootOverTcp()) {
+ printf("<Waiting for Device>\n");
+ const auto matcher = [](usb_ifc_info* info) -> int {
+ return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial);
+ };
+ Transport* transport = nullptr;
+ while (!transport) {
+ transport = usb_open(matcher);
+ std::this_thread::sleep_for(std::chrono::milliseconds(10));
+ }
+ transport->Close();
}
- transport->Close();
if (args.find("serial_port") != args.end()) {
fastboot::FastBootTest::serial_port = fastboot::ConfigureSerial(args.at("serial_port"));
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp b/fastboot/fuzzy_fastboot/transport_sniffer.cpp
similarity index 91%
rename from fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
rename to fastboot/fuzzy_fastboot/transport_sniffer.cpp
index 7c595f4..b55ffd3 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.cpp
+++ b/fastboot/fuzzy_fastboot/transport_sniffer.cpp
@@ -1,4 +1,4 @@
-#include "usb_transport_sniffer.h"
+#include "transport_sniffer.h"
#include <android-base/stringprintf.h>
#include <sys/select.h>
#include <sys/time.h>
@@ -8,15 +8,15 @@
namespace fastboot {
-UsbTransportSniffer::UsbTransportSniffer(std::unique_ptr<UsbTransport> transport,
+TransportSniffer::TransportSniffer(std::unique_ptr<Transport> transport,
const int serial_fd)
: transport_(std::move(transport)), serial_fd_(serial_fd) {}
-UsbTransportSniffer::~UsbTransportSniffer() {
+TransportSniffer::~TransportSniffer() {
Close();
}
-ssize_t UsbTransportSniffer::Read(void* data, size_t len) {
+ssize_t TransportSniffer::Read(void* data, size_t len) {
ProcessSerial();
ssize_t ret = transport_->Read(data, len);
@@ -37,7 +37,7 @@
return ret;
}
-ssize_t UsbTransportSniffer::Write(const void* data, size_t len) {
+ssize_t TransportSniffer::Write(const void* data, size_t len) {
ProcessSerial();
size_t ret = transport_->Write(data, len);
@@ -58,11 +58,11 @@
return ret;
}
-int UsbTransportSniffer::Close() {
+int TransportSniffer::Close() {
return transport_->Close();
}
-int UsbTransportSniffer::Reset() {
+int TransportSniffer::Reset() {
ProcessSerial();
int ret = transport_->Reset();
std::vector<char> buf;
@@ -72,7 +72,7 @@
return ret;
}
-const std::vector<UsbTransportSniffer::Event> UsbTransportSniffer::Transfers() {
+const std::vector<TransportSniffer::Event> TransportSniffer::Transfers() {
return transfers_;
}
@@ -81,7 +81,7 @@
* the failure. This method will look through its log of captured events, and
* create a clean printable string of everything that happened.
*/
-std::string UsbTransportSniffer::CreateTrace() {
+std::string TransportSniffer::CreateTrace() {
std::string ret;
const auto no_print = [](char c) -> bool { return !isprint(c); };
@@ -158,7 +158,7 @@
// This is a quick call to flush any UART logs the device might have sent
// to our internal event log. It will wait up to 10ms for data to appear
-void UsbTransportSniffer::ProcessSerial() {
+void TransportSniffer::ProcessSerial() {
if (serial_fd_ <= 0) return;
fd_set set;
diff --git a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h b/fastboot/fuzzy_fastboot/transport_sniffer.h
similarity index 90%
rename from fastboot/fuzzy_fastboot/usb_transport_sniffer.h
rename to fastboot/fuzzy_fastboot/transport_sniffer.h
index 8119aea..2cbb9fe 100644
--- a/fastboot/fuzzy_fastboot/usb_transport_sniffer.h
+++ b/fastboot/fuzzy_fastboot/transport_sniffer.h
@@ -42,12 +42,12 @@
/* A special class for sniffing reads and writes
*
* A useful debugging tool is to see the raw fastboot transactions going between
- * the host and device. This class wraps the UsbTransport class, and snoops and saves
+ * the host and device. This class is a special subclass of Transport that snoops and saves
* all the transactions going on. Additionally, if there is a console serial port
* from the device, this class can monitor it as well and capture the interleaving of
* transport transactions and UART log messages.
*/
-class UsbTransportSniffer : public UsbTransport {
+class TransportSniffer : public Transport {
public:
enum EventType {
READ,
@@ -67,8 +67,8 @@
const std::vector<char> buf;
};
- UsbTransportSniffer(std::unique_ptr<UsbTransport> transport, const int serial_fd = 0);
- ~UsbTransportSniffer() override;
+ TransportSniffer(std::unique_ptr<Transport> transport, const int serial_fd = 0);
+ ~TransportSniffer() override;
virtual ssize_t Read(void* data, size_t len) override;
virtual ssize_t Write(const void* data, size_t len) override;
@@ -81,7 +81,7 @@
private:
std::vector<Event> transfers_;
- std::unique_ptr<UsbTransport> transport_;
+ std::unique_ptr<Transport> transport_;
const int serial_fd_;
};
diff --git a/fastboot/tcp.cpp b/fastboot/tcp.cpp
index dd6fbf8..dca306f 100644
--- a/fastboot/tcp.cpp
+++ b/fastboot/tcp.cpp
@@ -64,6 +64,7 @@
ssize_t Read(void* data, size_t length) override;
ssize_t Write(const void* data, size_t length) override;
int Close() override;
+ int Reset() override;
private:
explicit TcpTransport(std::unique_ptr<Socket> sock) : socket_(std::move(sock)) {}
@@ -178,6 +179,10 @@
return result;
}
+int TcpTransport::Reset() {
+ return 0;
+}
+
std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error) {
return internal::Connect(Socket::NewClient(Socket::Protocol::kTcp, hostname, port, error),
error);
diff --git a/fastboot/transport.h b/fastboot/transport.h
index 96b90d2..de0cc92 100644
--- a/fastboot/transport.h
+++ b/fastboot/transport.h
@@ -36,6 +36,8 @@
// Closes the underlying transport. Returns 0 on success.
virtual int Close() = 0;
+ virtual int Reset() = 0;
+
// Blocks until the transport disconnects. Transports that don't support
// this will return immediately. Returns 0 on success.
virtual int WaitForDisconnect() { return 0; }
diff --git a/fastboot/udp.cpp b/fastboot/udp.cpp
index 53fb347..308c96c 100644
--- a/fastboot/udp.cpp
+++ b/fastboot/udp.cpp
@@ -109,6 +109,7 @@
ssize_t Read(void* data, size_t length) override;
ssize_t Write(const void* data, size_t length) override;
int Close() override;
+ int Reset() override;
private:
explicit UdpTransport(std::unique_ptr<Socket> socket) : socket_(std::move(socket)) {}
@@ -370,6 +371,10 @@
return result;
}
+int UdpTransport::Reset() {
+ return 0;
+}
+
std::unique_ptr<Transport> Connect(const std::string& hostname, int port, std::string* error) {
return internal::Connect(Socket::NewClient(Socket::Protocol::kUdp, hostname, port, error),
error);
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index 9e67c66..c67e33d 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -75,6 +75,7 @@
"snapshot.cpp",
"snapshot_metadata_updater.cpp",
"partition_cow_creator.cpp",
+ "return.cpp",
"utility.cpp",
],
}
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/return.h b/fs_mgr/libsnapshot/include/libsnapshot/return.h
new file mode 100644
index 0000000..dedc445
--- /dev/null
+++ b/fs_mgr/libsnapshot/include/libsnapshot/return.h
@@ -0,0 +1,59 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <stdint.h>
+#include <string.h>
+
+#include <libfiemap/fiemap_status.h>
+
+namespace android::snapshot {
+
+// SnapshotManager functions return either bool or Return objects. "Return" types provides
+// more information about the reason of the failure.
+class Return {
+ using FiemapStatus = android::fiemap::FiemapStatus;
+
+ public:
+ enum class ErrorCode : int32_t {
+ SUCCESS = static_cast<int32_t>(FiemapStatus::ErrorCode::SUCCESS),
+ ERROR = static_cast<int32_t>(FiemapStatus::ErrorCode::ERROR),
+ NO_SPACE = static_cast<int32_t>(FiemapStatus::ErrorCode::NO_SPACE),
+ };
+ ErrorCode error_code() const { return error_code_; }
+ bool is_ok() const { return error_code() == ErrorCode::SUCCESS; }
+ operator bool() const { return is_ok(); }
+ // Total required size on /userdata.
+ uint64_t required_size() const { return required_size_; }
+ std::string string() const;
+
+ static Return Ok() { return Return(ErrorCode::SUCCESS); }
+ static Return Error() { return Return(ErrorCode::ERROR); }
+ static Return NoSpace(uint64_t size) { return Return(ErrorCode::NO_SPACE, size); }
+ // Does not set required_size_ properly even when status.error_code() == NO_SPACE.
+ explicit Return(const FiemapStatus& status)
+ : error_code_(FromFiemapStatusErrorCode(status.error_code())), required_size_(0) {}
+
+ private:
+ ErrorCode error_code_;
+ uint64_t required_size_;
+ Return(ErrorCode error_code, uint64_t required_size = 0)
+ : error_code_(error_code), required_size_(required_size) {}
+
+ // FiemapStatus::ErrorCode -> ErrorCode
+ static ErrorCode FromFiemapStatusErrorCode(FiemapStatus::ErrorCode error_code);
+};
+
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
index 61946f7..e503ec3 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -35,6 +35,7 @@
#include <update_engine/update_metadata.pb.h>
#include <libsnapshot/auto_device.h>
+#include <libsnapshot/return.h>
#ifndef FRIEND_TEST
#define FRIEND_TEST(test_set_name, individual_test) \
@@ -91,27 +92,6 @@
using FiemapStatus = android::fiemap::FiemapStatus;
public:
- // SnapshotManager functions return either bool or Return objects. "Return" types provides
- // more information about the reason of the failure.
- class Return : public FiemapStatus {
- public:
- // Total required size on /userdata.
- uint64_t required_size() const { return required_size_; }
-
- static Return Ok() { return Return(FiemapStatus::ErrorCode::SUCCESS); }
- static Return Error() { return Return(FiemapStatus::ErrorCode::ERROR); }
- static Return NoSpace(uint64_t size) {
- return Return(FiemapStatus::ErrorCode::NO_SPACE, size);
- }
- // Does not set required_size_ properly even when status.error_code() == NO_SPACE.
- explicit Return(const FiemapStatus& status) : Return(status.error_code()) {}
-
- private:
- uint64_t required_size_;
- Return(FiemapStatus::ErrorCode code, uint64_t required_size = 0)
- : FiemapStatus(code), required_size_(required_size) {}
- };
-
// Dependency injection for testing.
class IDeviceInfo {
public:
diff --git a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
index 11de6ed..98bf56a 100644
--- a/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
+++ b/fs_mgr/libsnapshot/include_test/libsnapshot/test_helpers.h
@@ -42,7 +42,6 @@
using testing::_;
using testing::AssertionResult;
using testing::NiceMock;
-using testing::Return;
using namespace android::storage_literals;
using namespace std::string_literals;
@@ -117,6 +116,7 @@
class SnapshotTestPropertyFetcher : public android::fs_mgr::testing::MockPropertyFetcher {
public:
SnapshotTestPropertyFetcher(const std::string& slot_suffix) {
+ using testing::Return;
ON_CALL(*this, GetProperty("ro.boot.slot_suffix", _)).WillByDefault(Return(slot_suffix));
ON_CALL(*this, GetBoolProperty("ro.boot.dynamic_partitions", _))
.WillByDefault(Return(true));
diff --git a/fs_mgr/libsnapshot/return.cpp b/fs_mgr/libsnapshot/return.cpp
new file mode 100644
index 0000000..cc64af5
--- /dev/null
+++ b/fs_mgr/libsnapshot/return.cpp
@@ -0,0 +1,44 @@
+// Copyright (C) 2019 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#include <libsnapshot/return.h>
+
+#include <string.h>
+
+using android::fiemap::FiemapStatus;
+
+namespace android::snapshot {
+
+std::string Return::string() const {
+ switch (error_code()) {
+ case ErrorCode::ERROR:
+ return "Error";
+ case ErrorCode::SUCCESS:
+ [[fallthrough]];
+ case ErrorCode::NO_SPACE:
+ return strerror(-static_cast<int>(error_code()));
+ }
+}
+
+Return::ErrorCode Return::FromFiemapStatusErrorCode(FiemapStatus::ErrorCode error_code) {
+ switch (error_code) {
+ case FiemapStatus::ErrorCode::SUCCESS:
+ case FiemapStatus::ErrorCode::ERROR:
+ case FiemapStatus::ErrorCode::NO_SPACE:
+ return static_cast<ErrorCode>(error_code);
+ default:
+ return ErrorCode::ERROR;
+ }
+}
+} // namespace android::snapshot
diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp
index 70a69a5..81ffcaf 100644
--- a/fs_mgr/libsnapshot/snapshot.cpp
+++ b/fs_mgr/libsnapshot/snapshot.cpp
@@ -290,7 +290,7 @@
return true;
}
-SnapshotManager::Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
+Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name) {
CHECK(lock);
CHECK(lock->lock_mode() == LOCK_EX);
if (!EnsureImageManager()) return Return::Error();
@@ -1890,21 +1890,19 @@
}
}
-static SnapshotManager::Return AddRequiredSpace(
- SnapshotManager::Return orig,
- const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
- if (orig.error_code() != SnapshotManager::Return::ErrorCode::NO_SPACE) {
+static Return AddRequiredSpace(Return orig,
+ const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
+ if (orig.error_code() != Return::ErrorCode::NO_SPACE) {
return orig;
}
uint64_t sum = 0;
for (auto&& [name, status] : all_snapshot_status) {
sum += status.cow_file_size();
}
- return SnapshotManager::Return::NoSpace(sum);
+ return Return::NoSpace(sum);
}
-SnapshotManager::Return SnapshotManager::CreateUpdateSnapshots(
- const DeltaArchiveManifest& manifest) {
+Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manifest) {
auto lock = LockExclusive();
if (!lock) return Return::Error();
@@ -1998,7 +1996,7 @@
return Return::Ok();
}
-SnapshotManager::Return SnapshotManager::CreateUpdateSnapshotsInternal(
+Return SnapshotManager::CreateUpdateSnapshotsInternal(
LockedFile* lock, const DeltaArchiveManifest& manifest, PartitionCowCreator* cow_creator,
AutoDeviceList* created_devices,
std::map<std::string, SnapshotStatus>* all_snapshot_status) {
@@ -2131,7 +2129,7 @@
return Return::Ok();
}
-SnapshotManager::Return SnapshotManager::InitializeUpdateSnapshots(
+Return SnapshotManager::InitializeUpdateSnapshots(
LockedFile* lock, MetadataBuilder* target_metadata,
const LpMetadata* exported_target_metadata, const std::string& target_suffix,
const std::map<std::string, SnapshotStatus>& all_snapshot_status) {
diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp
index cea9d69..47ac474 100644
--- a/fs_mgr/libsnapshot/snapshot_test.cpp
+++ b/fs_mgr/libsnapshot/snapshot_test.cpp
@@ -1604,7 +1604,7 @@
ASSERT_TRUE(sm->BeginUpdate());
auto res = sm->CreateUpdateSnapshots(manifest_);
ASSERT_FALSE(res);
- ASSERT_EQ(SnapshotManager::Return::ErrorCode::NO_SPACE, res.error_code());
+ ASSERT_EQ(Return::ErrorCode::NO_SPACE, res.error_code());
ASSERT_GE(res.required_size(), 14_MiB);
ASSERT_LT(res.required_size(), 15_MiB);
}
diff --git a/fs_mgr/libsnapshot/utility.cpp b/fs_mgr/libsnapshot/utility.cpp
index f01500f..3a64448 100644
--- a/fs_mgr/libsnapshot/utility.cpp
+++ b/fs_mgr/libsnapshot/utility.cpp
@@ -86,9 +86,7 @@
}
}
-SnapshotManager::Return InitializeCow(const std::string& device) {
- using Return = SnapshotManager::Return;
-
+Return InitializeCow(const std::string& device) {
// When the kernel creates a persistent dm-snapshot, it requires a CoW file
// to store the modifications. The kernel interface does not specify how
// the CoW is used, and there is no standard associated.
diff --git a/fs_mgr/libsnapshot/utility.h b/fs_mgr/libsnapshot/utility.h
index 0453256..ad46090 100644
--- a/fs_mgr/libsnapshot/utility.h
+++ b/fs_mgr/libsnapshot/utility.h
@@ -111,7 +111,7 @@
android::fs_mgr::MetadataBuilder* builder, const std::string& suffix);
// Initialize a device before using it as the COW device for a dm-snapshot device.
-SnapshotManager::Return InitializeCow(const std::string& device);
+Return InitializeCow(const std::string& device);
// "Atomically" write string to file. This is done by a series of actions:
// 1. Write to path + ".tmp"
diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp
index b811622..1a474fb 100644
--- a/init/mount_namespace.cpp
+++ b/init/mount_namespace.cpp
@@ -107,7 +107,7 @@
}
static Result<void> MountDir(const std::string& path, const std::string& mount_path) {
- if (int ret = mkdir(mount_path.c_str(), 0755); ret != 0 && ret != EEXIST) {
+ if (int ret = mkdir(mount_path.c_str(), 0755); ret != 0 && errno != EEXIST) {
return ErrnoError() << "Could not create mount point " << mount_path;
}
if (mount(path.c_str(), mount_path.c_str(), nullptr, MS_BIND, nullptr) != 0) {
diff --git a/libcutils/Android.bp b/libcutils/Android.bp
index 334364e..65af2b3 100644
--- a/libcutils/Android.bp
+++ b/libcutils/Android.bp
@@ -250,9 +250,8 @@
require_root: true,
}
-cc_test {
- name: "libcutils_test_static",
- test_suites: ["device-tests"],
+cc_defaults {
+ name: "libcutils_test_static_defaults",
defaults: ["libcutils_test_default"],
static_libs: [
"libc",
@@ -272,3 +271,16 @@
},
},
}
+
+cc_test {
+ name: "libcutils_test_static",
+ test_suites: ["device-tests"],
+ defaults: ["libcutils_test_static_defaults"],
+}
+
+cc_test {
+ name: "KernelLibcutilsTest",
+ test_suites: ["general-tests", "vts-core"],
+ defaults: ["libcutils_test_static_defaults"],
+ test_config: "KernelLibcutilsTest.xml",
+}
diff --git a/libcutils/KernelLibcutilsTest.xml b/libcutils/KernelLibcutilsTest.xml
new file mode 100644
index 0000000..e27fac6
--- /dev/null
+++ b/libcutils/KernelLibcutilsTest.xml
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<configuration description="Runs libcutils_test_static.">
+ <option name="test-suite-tag" value="apct" />
+ <option name="test-suite-tag" value="apct-native" />
+
+ <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer">
+ </target_preparer>
+
+ <target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
+ <option name="cleanup" value="true" />
+ <option name="push" value="libcutils_test_static->/data/local/tmp/libcutils_test_static" />
+ </target_preparer>
+
+ <test class="com.android.tradefed.testtype.GTest" >
+ <option name="native-test-device-path" value="/data/local/tmp" />
+ <option name="module-name" value="libcutils_test_static" />
+ <option name="include-filter" value="*AshmemTest*" />
+ </test>
+</configuration>
diff --git a/libprocinfo/process.cpp b/libprocinfo/process.cpp
index 9194cf3..2efd49c 100644
--- a/libprocinfo/process.cpp
+++ b/libprocinfo/process.cpp
@@ -59,7 +59,6 @@
case 'Z':
return kProcessStateZombie;
default:
- LOG(ERROR) << "unknown process state: " << *state;
return kProcessStateUnknown;
}
}
diff --git a/trusty/confirmationui/.clang-format b/trusty/confirmationui/.clang-format
new file mode 100644
index 0000000..b0dc94c
--- /dev/null
+++ b/trusty/confirmationui/.clang-format
@@ -0,0 +1,10 @@
+BasedOnStyle: LLVM
+IndentWidth: 4
+UseTab: Never
+BreakBeforeBraces: Attach
+AllowShortFunctionsOnASingleLine: Inline
+AllowShortIfStatementsOnASingleLine: true
+IndentCaseLabels: false
+ColumnLimit: 100
+PointerBindsToType: true
+SpacesBeforeTrailingComments: 2
diff --git a/trusty/confirmationui/Android.bp b/trusty/confirmationui/Android.bp
new file mode 100644
index 0000000..60e0e71
--- /dev/null
+++ b/trusty/confirmationui/Android.bp
@@ -0,0 +1,95 @@
+// 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.
+//
+
+// WARNING: Everything listed here will be built on ALL platforms,
+// including x86, the emulator, and the SDK. Modules must be uniquely
+// named (liblights.panda), and must build everywhere, or limit themselves
+// to only building on ARM if they include assembly. Individual makefiles
+// are responsible for having their own logic, for fine-grained control.
+
+cc_binary {
+ name: "android.hardware.confirmationui@1.0-service.trusty",
+ relative_install_path: "hw",
+ vendor: true,
+ shared_libs: [
+ "android.hardware.confirmationui@1.0",
+ "android.hardware.confirmationui.not-so-secure-input",
+ "android.hardware.confirmationui@1.0-lib.trusty",
+ "libbase",
+ "libhidlbase",
+ "libutils",
+ ],
+
+ init_rc: ["android.hardware.confirmationui@1.0-service.trusty.rc"],
+
+ vintf_fragments: ["android.hardware.confirmationui@1.0-service.trusty.xml"],
+
+ srcs: [
+ "service.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-DTEEUI_USE_STD_VECTOR",
+ ],
+}
+
+cc_library {
+ name: "android.hardware.confirmationui@1.0-lib.trusty",
+ vendor: true,
+ shared_libs: [
+ "android.hardware.confirmationui@1.0",
+ "android.hardware.keymaster@4.0",
+ "libbase",
+ "libhidlbase",
+ "libteeui_hal_support",
+ "libtrusty",
+ "libutils",
+ ],
+
+ export_include_dirs: ["include"],
+
+ srcs: [
+ "TrustyApp.cpp",
+ "TrustyConfirmationUI.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-DTEEUI_USE_STD_VECTOR",
+ ],
+}
+
+cc_library {
+ name: "android.hardware.confirmationui.not-so-secure-input",
+ vendor: true,
+ shared_libs: [
+ "libbase",
+ "libcrypto",
+ "libteeui_hal_support",
+ ],
+
+ srcs: [
+ "NotSoSecureInput.cpp",
+ ],
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-DTEEUI_USE_STD_VECTOR",
+ ],
+}
\ No newline at end of file
diff --git a/trusty/confirmationui/NotSoSecureInput.cpp b/trusty/confirmationui/NotSoSecureInput.cpp
new file mode 100644
index 0000000..3d9a2d6
--- /dev/null
+++ b/trusty/confirmationui/NotSoSecureInput.cpp
@@ -0,0 +1,207 @@
+/*
+ * Copyright 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/logging.h>
+#include <endian.h>
+#include <memory>
+#include <openssl/hmac.h>
+#include <openssl/rand.h>
+#include <openssl/sha.h>
+#include <secure_input/evdev.h>
+#include <secure_input/secure_input_device.h>
+#include <teeui/utils.h>
+
+#include <initializer_list>
+
+using namespace secure_input;
+
+using teeui::AuthTokenKey;
+using teeui::ByteBufferProxy;
+using teeui::Hmac;
+using teeui::optional;
+using teeui::ResponseCode;
+using teeui::TestKeyBits;
+
+constexpr const auto kTestKey = AuthTokenKey::fill(static_cast<uint8_t>(TestKeyBits::BYTE));
+
+class SecureInputHMacer {
+ public:
+ static optional<Hmac> hmac256(const AuthTokenKey& key,
+ std::initializer_list<ByteBufferProxy> buffers) {
+ HMAC_CTX hmacCtx;
+ HMAC_CTX_init(&hmacCtx);
+ if (!HMAC_Init_ex(&hmacCtx, key.data(), key.size(), EVP_sha256(), nullptr)) {
+ return {};
+ }
+ for (auto& buffer : buffers) {
+ if (!HMAC_Update(&hmacCtx, buffer.data(), buffer.size())) {
+ return {};
+ }
+ }
+ Hmac result;
+ if (!HMAC_Final(&hmacCtx, result.data(), nullptr)) {
+ return {};
+ }
+ return result;
+ }
+};
+
+using HMac = teeui::HMac<SecureInputHMacer>;
+
+Nonce generateNonce() {
+ /*
+ * Completely random nonce.
+ * Running the secure input protocol from the HAL service is not secure
+ * because we don't trust the non-secure world (i.e., HLOS/Android/Linux). So
+ * using a constant "nonce" here does not weaken security. If this code runs
+ * on a truly trustworthy source of input events this function needs to return
+ * hight entropy nonces.
+ * As of this writing the call to RAND_bytes is commented, because the
+ * emulator this HAL service runs on does not have a good source of entropy.
+ * It would block the call to RAND_bytes indefinitely.
+ */
+ Nonce result{0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04,
+ 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04};
+ // RAND_bytes(result.data(), result.size());
+ return result;
+}
+
+/**
+ * This is an implementation of the SecureInput protocol in unserspace. This is
+ * just an example and should not be used as is. The protocol implemented her
+ * should be used by a trusted input device that can assert user events with
+ * high assurance even if the HLOS kernel is compromised. A confirmationui HAL
+ * that links directly against this implementation is not secure and shal not be
+ * used on a production device.
+ */
+class NotSoSecureInput : public SecureInput {
+ public:
+ NotSoSecureInput(HsBeginCb hsBeginCb, HsFinalizeCb hsFinalizeCb, DeliverEventCb deliverEventCb,
+ InputResultCb inputResultCb)
+ : hsBeginCb_{hsBeginCb}, hsFinalizeCb_{hsFinalizeCb}, deliverEventCb_{deliverEventCb},
+ inputResultCb_{inputResultCb}, discardEvents_{true} {}
+
+ operator bool() const override { return true; }
+
+ void handleEvent(const EventDev& evdev) override {
+ bool gotEvent;
+ input_event evt;
+ std::tie(gotEvent, evt) = evdev.readEvent();
+ while (gotEvent) {
+ if (!(discardEvents_) && evt.type == EV_KEY &&
+ (evt.code == KEY_POWER || evt.code == KEY_VOLUMEDOWN || evt.code == KEY_VOLUMEUP) &&
+ evt.value == 1) {
+ DTupKeyEvent event = DTupKeyEvent::RESERVED;
+
+ // Translate the event code into DTupKeyEvent which the TA understands.
+ switch (evt.code) {
+ case KEY_POWER:
+ event = DTupKeyEvent::PWR;
+ break;
+ case KEY_VOLUMEDOWN:
+ event = DTupKeyEvent::VOL_DOWN;
+ break;
+ case KEY_VOLUMEUP:
+ event = DTupKeyEvent::VOL_UP;
+ break;
+ }
+
+ // The event goes into the HMAC in network byte order.
+ uint32_t keyEventBE = htobe32(static_cast<uint32_t>(event));
+ auto signature = HMac::hmac256(kTestKey, kConfirmationUIEventLabel,
+ teeui::bytesCast(keyEventBE), nCi_);
+
+ teeui::ResponseCode rc;
+ InputResponse ir;
+ auto response = std::tie(rc, ir);
+ if (event != DTupKeyEvent::RESERVED) {
+ response = deliverEventCb_(event, *signature);
+ if (rc != ResponseCode::OK) {
+ LOG(ERROR) << "DeliverInputEvent returned with " << uint32_t(rc);
+ inputResultCb_(rc);
+ } else {
+ switch (ir) {
+ case InputResponse::OK:
+ inputResultCb_(rc);
+ break;
+ case InputResponse::PENDING_MORE:
+ rc = performDTUPHandshake();
+ if (rc != ResponseCode::OK) {
+ inputResultCb_(rc);
+ }
+ break;
+ case InputResponse::TIMED_OUT:
+ inputResultCb_(rc);
+ break;
+ }
+ }
+ }
+ }
+ std::tie(gotEvent, evt) = evdev.readEvent();
+ }
+ }
+
+ void start() override {
+ auto rc = performDTUPHandshake();
+ if (rc != ResponseCode::OK) {
+ inputResultCb_(rc);
+ }
+ discardEvents_ = false;
+ };
+
+ private:
+ teeui::ResponseCode performDTUPHandshake() {
+ ResponseCode rc;
+ LOG(INFO) << "Start handshake";
+ Nonce nCo;
+ std::tie(rc, nCo) = hsBeginCb_();
+ if (rc != ResponseCode::OK) {
+ LOG(ERROR) << "Failed to begin secure input handshake (" << uint32_t(rc) << ")";
+ return rc;
+ }
+
+ nCi_ = generateNonce();
+ rc =
+ hsFinalizeCb_(*HMac::hmac256(kTestKey, kConfirmationUIHandshakeLabel, nCo, nCi_), nCi_);
+
+ if (rc != ResponseCode::OK) {
+ LOG(ERROR) << "Failed to finalize secure input handshake (" << uint32_t(rc) << ")";
+ return rc;
+ }
+ return ResponseCode::OK;
+ }
+
+ HsBeginCb hsBeginCb_;
+ HsFinalizeCb hsFinalizeCb_;
+ DeliverEventCb deliverEventCb_;
+ InputResultCb inputResultCb_;
+
+ std::atomic_bool discardEvents_;
+ Nonce nCi_;
+};
+
+namespace secure_input {
+
+std::shared_ptr<SecureInput> createSecureInput(SecureInput::HsBeginCb hsBeginCb,
+ SecureInput::HsFinalizeCb hsFinalizeCb,
+ SecureInput::DeliverEventCb deliverEventCb,
+ SecureInput::InputResultCb inputResultCb) {
+ return std::make_shared<NotSoSecureInput>(hsBeginCb, hsFinalizeCb, deliverEventCb,
+ inputResultCb);
+}
+
+} // namespace secure_input
diff --git a/trusty/confirmationui/README b/trusty/confirmationui/README
new file mode 100644
index 0000000..45d4e76
--- /dev/null
+++ b/trusty/confirmationui/README
@@ -0,0 +1,20 @@
+## Secure UI Architecture
+
+To implement confirmationui a secure UI architecture is required. This entails a way
+to display the confirmation dialog driven by a reduced trusted computing base, typically
+a trusted execution environment (TEE), without having to rely on Linux and the Android
+system for integrity and authenticity of input events. This implementation provides
+neither. But it provides most of the functionlity required to run a full Android Protected
+Confirmation feature when integrated into a secure UI architecture.
+
+## Secure input (NotSoSecureInput)
+
+This implementation does not provide any security guaranties.
+The input method (NotSoSecureInput) runs a cryptographic protocols that is
+sufficiently secure IFF the end point is implemented on a trustworthy
+secure input device. But since the endpoint is currently in the HAL
+service itself this implementation is not secure.
+
+NOTE that a secure input device end point needs a good source of entropy
+for generating nonces. The current implementation (NotSoSecureInput.cpp#generateNonce)
+uses a constant nonce.
\ No newline at end of file
diff --git a/trusty/confirmationui/TrustyApp.cpp b/trusty/confirmationui/TrustyApp.cpp
new file mode 100644
index 0000000..e4c68f9
--- /dev/null
+++ b/trusty/confirmationui/TrustyApp.cpp
@@ -0,0 +1,156 @@
+/*
+ * Copyright 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 "TrustyApp.h"
+
+#include <android-base/logging.h>
+#include <sys/uio.h>
+#include <trusty/tipc.h>
+
+namespace android {
+namespace trusty {
+
+// 0x1000 is the message buffer size but we need to leave some space for a protocol header.
+// This assures that packets can always be read/written in one read/write operation.
+static constexpr const uint32_t kPacketSize = 0x1000 - 32;
+
+enum class PacketType : uint32_t {
+ SND,
+ RCV,
+ ACK,
+};
+
+struct PacketHeader {
+ PacketType type;
+ uint32_t remaining;
+};
+
+const char* toString(PacketType t) {
+ switch (t) {
+ case PacketType::SND:
+ return "SND";
+ case PacketType::RCV:
+ return "RCV";
+ case PacketType::ACK:
+ return "ACK";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static constexpr const uint32_t kHeaderSize = sizeof(PacketHeader);
+static constexpr const uint32_t kPayloadSize = kPacketSize - kHeaderSize;
+
+ssize_t TrustyRpc(int handle, const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
+ uint8_t* iend) {
+ while (obegin != oend) {
+ PacketHeader header = {
+ .type = PacketType::SND,
+ .remaining = uint32_t(oend - obegin),
+ };
+ uint32_t body_size = std::min(kPayloadSize, header.remaining);
+ iovec iov[] = {
+ {
+ .iov_base = &header,
+ .iov_len = kHeaderSize,
+ },
+ {
+ .iov_base = const_cast<uint8_t*>(obegin),
+ .iov_len = body_size,
+ },
+ };
+ int rc = writev(handle, iov, 2);
+ if (!rc) {
+ PLOG(ERROR) << "Error sending SND message. " << rc;
+ return rc;
+ }
+
+ obegin += body_size;
+
+ rc = read(handle, &header, kHeaderSize);
+ if (!rc) {
+ PLOG(ERROR) << "Error reading ACK. " << rc;
+ return rc;
+ }
+
+ if (header.type != PacketType::ACK || header.remaining != oend - obegin) {
+ LOG(ERROR) << "malformed ACK";
+ return -1;
+ }
+ }
+
+ ssize_t remaining = 0;
+ auto begin = ibegin;
+ do {
+ PacketHeader header = {
+ .type = PacketType::RCV,
+ .remaining = 0,
+ };
+
+ iovec iov[] = {
+ {
+ .iov_base = &header,
+ .iov_len = kHeaderSize,
+ },
+ {
+ .iov_base = begin,
+ .iov_len = uint32_t(iend - begin),
+ },
+ };
+
+ ssize_t rc = writev(handle, iov, 1);
+ if (!rc) {
+ PLOG(ERROR) << "Error sending RCV message. " << rc;
+ return rc;
+ }
+
+ rc = readv(handle, iov, 2);
+ if (rc < 0) {
+ PLOG(ERROR) << "Error reading response. " << rc;
+ return rc;
+ }
+
+ uint32_t body_size = std::min(kPayloadSize, header.remaining);
+ if (body_size != rc - kHeaderSize) {
+ LOG(ERROR) << "Unexpected amount of data: " << rc;
+ return -1;
+ }
+
+ remaining = header.remaining - body_size;
+ begin += body_size;
+ } while (remaining);
+
+ return begin - ibegin;
+}
+
+TrustyApp::TrustyApp(const std::string& path, const std::string& appname)
+ : handle_(kInvalidHandle) {
+ handle_ = tipc_connect(path.c_str(), appname.c_str());
+ if (handle_ == kInvalidHandle) {
+ LOG(ERROR) << AT << "failed to connect to Trusty TA \"" << appname << "\" using dev:"
+ << "\"" << path << "\"";
+ }
+ LOG(INFO) << AT << "succeeded to connect to Trusty TA \"" << appname << "\"";
+}
+TrustyApp::~TrustyApp() {
+ if (handle_ != kInvalidHandle) {
+ tipc_close(handle_);
+ }
+ LOG(INFO) << "Done shutting down TrustyApp";
+}
+
+} // namespace trusty
+} // namespace android
diff --git a/trusty/confirmationui/TrustyApp.h b/trusty/confirmationui/TrustyApp.h
new file mode 100644
index 0000000..05a25f6
--- /dev/null
+++ b/trusty/confirmationui/TrustyApp.h
@@ -0,0 +1,155 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <android-base/logging.h>
+#include <errno.h>
+#include <poll.h>
+#include <stdio.h>
+#include <sys/eventfd.h>
+#include <sys/stat.h>
+#include <teeui/msg_formatting.h>
+#include <trusty/tipc.h>
+#include <unistd.h>
+
+#include <fstream>
+#include <functional>
+#include <future>
+#include <iostream>
+#include <sstream>
+#include <thread>
+#include <vector>
+
+#define AT __FILE__ ":" << __LINE__ << ": "
+
+namespace android {
+namespace trusty {
+
+using ::teeui::Message;
+using ::teeui::msg2tuple_t;
+using ::teeui::ReadStream;
+using ::teeui::WriteStream;
+
+#ifndef TEEUI_USE_STD_VECTOR
+/*
+ * TEEUI_USE_STD_VECTOR makes certain wire types like teeui::MsgString and
+ * teeui::MsgVector be aliases for std::vector. This is required for thread safe
+ * message serialization. Always compile this with -DTEEUI_USE_STD_VECTOR set in
+ * CFLAGS of the HAL service.
+ */
+#error "Must be compiled with -DTEEUI_USE_STD_VECTOR."
+#endif
+
+enum class TrustyAppError : int32_t {
+ OK,
+ ERROR = -1,
+ MSG_TOO_LONG = -2,
+};
+
+/*
+ * There is a hard limitation of 0x1800 bytes for the to-be-signed message size. The protocol
+ * overhead is limited, so that 0x2000 is a buffer size that will be sufficient in any benign
+ * mode of operation.
+ */
+static constexpr const size_t kSendBufferSize = 0x2000;
+
+ssize_t TrustyRpc(int handle, const uint8_t* obegin, const uint8_t* oend, uint8_t* ibegin,
+ uint8_t* iend);
+
+class TrustyApp {
+ private:
+ int handle_;
+ static constexpr const int kInvalidHandle = -1;
+ /*
+ * This mutex serializes communication with the trusted app, not handle_.
+ * Calling issueCmd during construction or deletion is undefined behavior.
+ */
+ std::mutex mutex_;
+
+ public:
+ TrustyApp(const std::string& path, const std::string& appname);
+ ~TrustyApp();
+
+ template <typename Request, typename Response, typename... T>
+ std::tuple<TrustyAppError, msg2tuple_t<Response>> issueCmd(const T&... args) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ if (handle_ == kInvalidHandle) {
+ LOG(ERROR) << "TrustyApp not connected";
+ return {TrustyAppError::ERROR, {}};
+ }
+
+ uint8_t buffer[kSendBufferSize];
+ WriteStream out(buffer);
+
+ out = write(Request(), out, args...);
+ if (!out) {
+ LOG(ERROR) << AT << "send command failed: message formatting";
+ return {TrustyAppError::MSG_TOO_LONG, {}};
+ }
+
+ auto rc = TrustyRpc(handle_, &buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
+ &buffer[kSendBufferSize]);
+ if (rc < 0) return {TrustyAppError::ERROR, {}};
+
+ ReadStream in(&buffer[0], rc);
+ auto result = read(Response(), in);
+ if (!std::get<0>(result)) {
+ LOG(ERROR) << "send command failed: message parsing";
+ return {TrustyAppError::ERROR, {}};
+ }
+
+ return {std::get<0>(result) ? TrustyAppError::OK : TrustyAppError::ERROR,
+ tuple_tail(std::move(result))};
+ }
+
+ template <typename Request, typename... T> TrustyAppError issueCmd(const T&... args) {
+ std::lock_guard<std::mutex> lock(mutex_);
+
+ if (handle_ == kInvalidHandle) {
+ LOG(ERROR) << "TrustyApp not connected";
+ return TrustyAppError::ERROR;
+ }
+
+ uint8_t buffer[kSendBufferSize];
+ WriteStream out(buffer);
+
+ out = write(Request(), out, args...);
+ if (!out) {
+ LOG(ERROR) << AT << "send command failed: message formatting";
+ return TrustyAppError::MSG_TOO_LONG;
+ }
+
+ auto rc = TrustyRpc(handle_, &buffer[0], const_cast<const uint8_t*>(out.pos()), &buffer[0],
+ &buffer[kSendBufferSize]);
+ if (rc < 0) {
+ LOG(ERROR) << "send command failed: " << strerror(errno) << " (" << errno << ")";
+ return TrustyAppError::ERROR;
+ }
+
+ if (rc > 0) {
+ LOG(ERROR) << "Unexpected non zero length response";
+ return TrustyAppError::ERROR;
+ }
+ return TrustyAppError::OK;
+ }
+
+ operator bool() const { return handle_ != kInvalidHandle; }
+};
+
+} // namespace trusty
+} // namespace android
diff --git a/trusty/confirmationui/TrustyConfirmationUI.cpp b/trusty/confirmationui/TrustyConfirmationUI.cpp
new file mode 100644
index 0000000..6b25893
--- /dev/null
+++ b/trusty/confirmationui/TrustyConfirmationUI.cpp
@@ -0,0 +1,513 @@
+/*
+ *
+ * Copyright 2019, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "TrustyConfirmationUI.h"
+
+#include <android-base/logging.h>
+#include <android/hardware/confirmationui/1.0/types.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <fcntl.h>
+#include <linux/input.h>
+#include <poll.h>
+#include <pthread.h>
+#include <secure_input/evdev.h>
+#include <secure_input/secure_input_device.h>
+#include <secure_input/secure_input_proto.h>
+#include <signal.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <teeui/msg_formatting.h>
+#include <teeui/utils.h>
+#include <time.h>
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <thread>
+#include <tuple>
+#include <vector>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using namespace secure_input;
+
+using ::android::trusty::TrustyAppError;
+
+using ::teeui::AbortMsg;
+using ::teeui::DeliverTestCommandMessage;
+using ::teeui::DeliverTestCommandResponse;
+using ::teeui::FetchConfirmationResult;
+using ::teeui::MsgString;
+using ::teeui::MsgVector;
+using ::teeui::PromptUserConfirmationMsg;
+using ::teeui::PromptUserConfirmationResponse;
+using ::teeui::ResultMsg;
+
+using ::secure_input::createSecureInput;
+
+using ::android::hardware::keymaster::V4_0::HardwareAuthToken;
+
+using ::std::tie;
+
+using TeeuiRc = ::teeui::ResponseCode;
+
+constexpr const char kTrustyDeviceName[] = "/dev/trusty-ipc-dev0";
+constexpr const char kConfirmationuiAppName[] = "com.android.trusty.confirmationui";
+
+namespace {
+
+class Finalize {
+ private:
+ std::function<void()> f_;
+
+ public:
+ Finalize(std::function<void()> f) : f_(f) {}
+ ~Finalize() {
+ if (f_) f_();
+ }
+ void release() { f_ = {}; }
+};
+
+ResponseCode convertRc(TeeuiRc trc) {
+ static_assert(
+ uint32_t(TeeuiRc::OK) == uint32_t(ResponseCode::OK) &&
+ uint32_t(TeeuiRc::Canceled) == uint32_t(ResponseCode::Canceled) &&
+ uint32_t(TeeuiRc::Aborted) == uint32_t(ResponseCode::Aborted) &&
+ uint32_t(TeeuiRc::OperationPending) == uint32_t(ResponseCode::OperationPending) &&
+ uint32_t(TeeuiRc::Ignored) == uint32_t(ResponseCode::Ignored) &&
+ uint32_t(TeeuiRc::SystemError) == uint32_t(ResponseCode::SystemError) &&
+ uint32_t(TeeuiRc::Unimplemented) == uint32_t(ResponseCode::Unimplemented) &&
+ uint32_t(TeeuiRc::Unexpected) == uint32_t(ResponseCode::Unexpected) &&
+ uint32_t(TeeuiRc::UIError) == uint32_t(ResponseCode::UIError) &&
+ uint32_t(TeeuiRc::UIErrorMissingGlyph) == uint32_t(ResponseCode::UIErrorMissingGlyph) &&
+ uint32_t(TeeuiRc::UIErrorMessageTooLong) ==
+ uint32_t(ResponseCode::UIErrorMessageTooLong) &&
+ uint32_t(TeeuiRc::UIErrorMalformedUTF8Encoding) ==
+ uint32_t(ResponseCode::UIErrorMalformedUTF8Encoding),
+ "teeui::ResponseCode and "
+ "::android::hardware::confirmationui::V1_0::Responsecude are out of "
+ "sync");
+ return ResponseCode(trc);
+}
+
+teeui::UIOption convertUIOption(UIOption uio) {
+ static_assert(uint32_t(UIOption::AccessibilityInverted) ==
+ uint32_t(teeui::UIOption::AccessibilityInverted) &&
+ uint32_t(UIOption::AccessibilityMagnified) ==
+ uint32_t(teeui::UIOption::AccessibilityMagnified),
+ "teeui::UIOPtion and ::android::hardware::confirmationui::V1_0::UIOption "
+ "anre out of sync");
+ return teeui::UIOption(uio);
+}
+
+inline MsgString hidl2MsgString(const hidl_string& s) {
+ return {s.c_str(), s.c_str() + s.size()};
+}
+template <typename T> inline MsgVector<T> hidl2MsgVector(const hidl_vec<T>& v) {
+ return {v};
+}
+
+inline MsgVector<teeui::UIOption> hidl2MsgVector(const hidl_vec<UIOption>& v) {
+ MsgVector<teeui::UIOption> result(v.size());
+ for (unsigned int i = 0; i < v.size(); ++i) {
+ result[i] = convertUIOption(v[i]);
+ }
+ return result;
+}
+
+} // namespace
+
+TrustyConfirmationUI::TrustyConfirmationUI()
+ : listener_state_(ListenerState::None), prompt_result_(ResponseCode::Ignored) {}
+
+TrustyConfirmationUI::~TrustyConfirmationUI() {
+ ListenerState state = listener_state_;
+ if (state == ListenerState::SetupDone || state == ListenerState::Interactive) {
+ abort();
+ }
+ if (state != ListenerState::None) {
+ callback_thread_.join();
+ }
+}
+
+std::tuple<TeeuiRc, MsgVector<uint8_t>, MsgVector<uint8_t>>
+TrustyConfirmationUI::promptUserConfirmation_(const MsgString& promptText,
+ const MsgVector<uint8_t>& extraData,
+ const MsgString& locale,
+ const MsgVector<teeui::UIOption>& uiOptions) {
+ std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+ /*
+ * This is the main listener thread function. The listener thread life cycle
+ * is equivalent to the life cycle of a single confirmation request. The life
+ * cycle is devided in four phases.
+ * * The starting phase:
+ * * The Trusted App gets loaded and/or the connection to it gets established.
+ * * A connection to the secure input device is established.
+ * * The prompt is initiated. This sends all information required by the
+ * confirmation dialog to the TA. The dialog is not yet displayed.
+ * * An event loop is created.
+ * * The event loop listens for user input events, fetches them from the
+ * secure input device, and delivers them to the TA.
+ * * All evdev devices are grabbed to give confirmationui exclusive access
+ * to user input.
+ *
+ * Note: During the starting phase the hwbinder service thread is blocked and
+ * waiting for possible Errors. If the setup phase concludes sucessfully, the
+ * hwbinder service thread gets unblocked and returns successfully. Errors
+ * that occur after the first phase are delivered by callback interface.
+ *
+ * * The 2nd phase - non interactive phase
+ * * The event loop thread is started.
+ * * After a grace period:
+ * * A handshake between the secure input device SecureInput and the TA
+ * is performed.
+ * * The input event handler are armed to process user input events.
+ *
+ * * The 3rd phase - interactive phase
+ * * We wait to any external event
+ * * Abort
+ * * Secure user input asserted
+ * * Secure input delivered (for non interactive VTS testing)
+ * * The result is fetched from the TA.
+ *
+ * * The 4th phase - cleanup
+ * The cleanup phase is given by the scope of automatic variables created
+ * in this function. The cleanup commences in reverse order of their creation.
+ * Here is a list of more complex items in the order in which they go out of
+ * scope
+ * * finalizeSecureTouch - signals and joins the secure touch thread.
+ * * eventloop - signals and joins the event loop thread. The event
+ * handlers also own all EventDev instances which ungrab the event devices.
+ * When the eventloop goes out of scope the EventDevs get destroyed
+ * relinquishing the exclusive hold on the event devices.
+ * * finalizeConfirmationPrompt - calls abort on the TA, making sure a
+ * pending operation gets canceled. If the prompt concluded successfully this
+ * is a spurious call but semantically a no op.
+ * * secureInput - shuts down the connection to the secure input device
+ * SecureInput.
+ * * app - disconnects the TA. Since app is a shared pointer this may not
+ * unload the app here. It is possible that more instances of the shared
+ * pointer are held in TrustyConfirmationUI::deliverSecureInputEvent and
+ * TrustyConfirmationUI::abort. But these instances are extremely short lived
+ * and it is safe if they are destroyed by either.
+ * * stateLock - unlocks the listener_state_lock_ if it happens to be held
+ * at the time of return.
+ */
+
+ std::tuple<TeeuiRc, MsgVector<uint8_t>, MsgVector<uint8_t>> result;
+ TeeuiRc& rc = std::get<TeeuiRc>(result);
+ rc = TeeuiRc::SystemError;
+
+ listener_state_ = ListenerState::Starting;
+
+ auto app = std::make_shared<TrustyApp>(kTrustyDeviceName, kConfirmationuiAppName);
+ if (!app) return result; // TeeuiRc::SystemError
+
+ app_ = app;
+
+ auto hsBegin = [&]() -> std::tuple<TeeuiRc, Nonce> {
+ auto [error, result] =
+ app->issueCmd<secure_input::InputHandshake, secure_input::InputHandshakeResponse>();
+ auto& [rc, nCo] = result;
+
+ if (error != TrustyAppError::OK || rc != TeeuiRc::OK) {
+ LOG(ERROR) << "Failed to begin secure input handshake (" << int32_t(error) << "/"
+ << uint32_t(rc) << ")";
+ rc = error != TrustyAppError::OK ? TeeuiRc::SystemError : rc;
+ }
+ return result;
+ };
+
+ auto hsFinalize = [&](const Signature& sig, const Nonce& nCi) -> TeeuiRc {
+ auto [error, finalizeResponse] =
+ app->issueCmd<FinalizeInputSessionHandshake, FinalizeInputSessionHandshakeResponse>(
+ nCi, sig);
+ auto& [rc] = finalizeResponse;
+ if (error != TrustyAppError::OK || rc != TeeuiRc::OK) {
+ LOG(ERROR) << "Failed to finalize secure input handshake (" << int32_t(error) << "/"
+ << uint32_t(rc) << ")";
+ rc = error != TrustyAppError::OK ? TeeuiRc::SystemError : rc;
+ }
+ return rc;
+ };
+
+ auto deliverInput = [&](DTupKeyEvent event,
+ const Signature& sig) -> std::tuple<TeeuiRc, InputResponse> {
+ auto [error, result] =
+ app->issueCmd<DeliverInputEvent, DeliverInputEventResponse>(event, sig);
+ auto& [rc, ir] = result;
+ if (error != TrustyAppError::OK) {
+ LOG(ERROR) << "Failed to deliver input command";
+ rc = TeeuiRc::SystemError;
+ }
+ return result;
+ };
+
+ std::atomic<TeeuiRc> eventRC = TeeuiRc::OperationPending;
+ auto inputResult = [&](TeeuiRc rc) {
+ TeeuiRc expected = TeeuiRc::OperationPending;
+ if (eventRC.compare_exchange_strong(expected, rc)) {
+ listener_state_condv_.notify_all();
+ }
+ };
+
+ // create Secure Input device.
+ auto secureInput = createSecureInput(hsBegin, hsFinalize, deliverInput, inputResult);
+ if (!secureInput || !(*secureInput)) {
+ LOG(ERROR) << "Failed to open secure input device";
+ return result; // TeeuiRc::SystemError;
+ }
+
+ Finalize finalizeConfirmationPrompt([app] {
+ LOG(INFO) << "Calling abort for cleanup";
+ app->issueCmd<AbortMsg>();
+ });
+
+ // initiate prompt
+ LOG(INFO) << "Initiating prompt";
+ TrustyAppError error;
+ auto initResponse = std::tie(rc);
+ std::tie(error, initResponse) =
+ app->issueCmd<PromptUserConfirmationMsg, PromptUserConfirmationResponse>(
+ promptText, extraData, locale, uiOptions);
+ if (error == TrustyAppError::MSG_TOO_LONG) {
+ LOG(ERROR) << "PromptUserConfirmationMsg failed: message too long";
+ rc = TeeuiRc::UIErrorMessageTooLong;
+ return result;
+ } else if (error != TrustyAppError::OK) {
+ LOG(ERROR) << "PromptUserConfirmationMsg failed: " << int32_t(error);
+ return result; // TeeuiRc::SystemError;
+ }
+ if (rc != TeeuiRc::OK) {
+ LOG(ERROR) << "PromptUserConfirmationMsg failed: " << uint32_t(rc);
+ return result;
+ }
+
+ LOG(INFO) << "Grabbing event devices";
+ EventLoop eventloop;
+ bool grabbed =
+ grabAllEvDevsAndRegisterCallbacks(&eventloop, [&](short flags, const EventDev& evDev) {
+ if (!(flags & POLLIN)) return;
+ secureInput->handleEvent(evDev);
+ });
+
+ if (!grabbed) {
+ rc = TeeuiRc::SystemError;
+ return result;
+ }
+
+ abort_called_ = false;
+ secureInputDelivered_ = false;
+
+ // ############################## Start 2nd Phase #############################################
+ listener_state_ = ListenerState::SetupDone;
+ stateLock.unlock();
+ listener_state_condv_.notify_all();
+
+ if (!eventloop.start()) {
+ rc = TeeuiRc::SystemError;
+ return result;
+ }
+
+ stateLock.lock();
+
+ LOG(INFO) << "going to sleep for the grace period";
+ auto then = std::chrono::system_clock::now() +
+ std::chrono::milliseconds(kUserPreInputGracePeriodMillis) +
+ std::chrono::microseconds(50);
+ listener_state_condv_.wait_until(stateLock, then, [&]() { return abort_called_; });
+ LOG(INFO) << "waking up";
+
+ if (abort_called_) {
+ LOG(ERROR) << "Abort called";
+ result = {TeeuiRc::Aborted, {}, {}};
+ return result;
+ }
+
+ LOG(INFO) << "Arming event poller";
+ // tell the event poller to act on received input events from now on.
+ secureInput->start();
+
+ // ############################## Start 3rd Phase - interactive phase #########################
+ LOG(INFO) << "Transition to Interactive";
+ listener_state_ = ListenerState::Interactive;
+ stateLock.unlock();
+ listener_state_condv_.notify_all();
+
+ stateLock.lock();
+ listener_state_condv_.wait(stateLock, [&]() {
+ return eventRC != TeeuiRc::OperationPending || abort_called_ || secureInputDelivered_;
+ });
+ LOG(INFO) << "Listener waking up";
+ if (abort_called_) {
+ LOG(ERROR) << "Abort called";
+ result = {TeeuiRc::Aborted, {}, {}};
+ return result;
+ }
+
+ if (!secureInputDelivered_) {
+ if (eventRC != TeeuiRc::OK) {
+ LOG(ERROR) << "Bad input response";
+ result = {eventRC, {}, {}};
+ return result;
+ }
+ }
+
+ stateLock.unlock();
+
+ LOG(INFO) << "Fetching Result";
+ std::tie(error, result) = app->issueCmd<FetchConfirmationResult, ResultMsg>();
+ LOG(INFO) << "Result yields " << int32_t(error) << "/" << uint32_t(rc);
+ if (error != TrustyAppError::OK) {
+ result = {TeeuiRc::SystemError, {}, {}};
+ }
+ return result;
+
+ // ############################## Start 4th Phase - cleanup ##################################
+}
+
+// Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
+// follow.
+Return<ResponseCode> TrustyConfirmationUI::promptUserConfirmation(
+ const sp<IConfirmationResultCallback>& resultCB, const hidl_string& promptText,
+ const hidl_vec<uint8_t>& extraData, const hidl_string& locale,
+ const hidl_vec<UIOption>& uiOptions) {
+ std::unique_lock<std::mutex> stateLock(listener_state_lock_, std::defer_lock);
+ if (!stateLock.try_lock()) {
+ return ResponseCode::OperationPending;
+ }
+ switch (listener_state_) {
+ case ListenerState::None:
+ break;
+ case ListenerState::Starting:
+ case ListenerState::SetupDone:
+ case ListenerState::Interactive:
+ return ResponseCode::OperationPending;
+ case ListenerState::Terminating:
+ callback_thread_.join();
+ listener_state_ = ListenerState::None;
+ break;
+ default:
+ return ResponseCode::Unexpected;
+ }
+
+ assert(listener_state_ == ListenerState::None);
+
+ callback_thread_ = std::thread(
+ [this](sp<IConfirmationResultCallback> resultCB, hidl_string promptText,
+ hidl_vec<uint8_t> extraData, hidl_string locale, hidl_vec<UIOption> uiOptions) {
+ auto [trc, msg, token] =
+ promptUserConfirmation_(hidl2MsgString(promptText), hidl2MsgVector(extraData),
+ hidl2MsgString(locale), hidl2MsgVector(uiOptions));
+ bool do_callback = (listener_state_ == ListenerState::Interactive ||
+ listener_state_ == ListenerState::SetupDone) &&
+ resultCB;
+ prompt_result_ = convertRc(trc);
+ listener_state_ = ListenerState::Terminating;
+ if (do_callback) {
+ auto error = resultCB->result(prompt_result_, msg, token);
+ if (!error.isOk()) {
+ LOG(ERROR) << "Result callback failed " << error.description();
+ }
+ } else {
+ listener_state_condv_.notify_all();
+ }
+ },
+ resultCB, promptText, extraData, locale, uiOptions);
+
+ listener_state_condv_.wait(stateLock, [this] {
+ return listener_state_ == ListenerState::SetupDone ||
+ listener_state_ == ListenerState::Interactive ||
+ listener_state_ == ListenerState::Terminating;
+ });
+ if (listener_state_ == ListenerState::Terminating) {
+ callback_thread_.join();
+ listener_state_ = ListenerState::None;
+ return prompt_result_;
+ }
+ return ResponseCode::OK;
+}
+
+Return<ResponseCode>
+TrustyConfirmationUI::deliverSecureInputEvent(const HardwareAuthToken& secureInputToken) {
+ ResponseCode rc = ResponseCode::Ignored;
+ {
+ /*
+ * deliverSecureInputEvent is only used by the VTS test to mock human input. A correct
+ * implementation responds with a mock confirmation token signed with a test key. The
+ * problem is that the non interactive grace period was not formalized in the HAL spec,
+ * so that the VTS test does not account for the grace period. (It probably should.)
+ * This means we can only pass the VTS test if we block until the grace period is over
+ * (SetupDone -> Interactive) before we deliver the input event.
+ *
+ * The true secure input is delivered by a different mechanism and gets ignored -
+ * not queued - until the grace period is over.
+ *
+ */
+ std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+ listener_state_condv_.wait(stateLock,
+ [this] { return listener_state_ != ListenerState::SetupDone; });
+
+ if (listener_state_ != ListenerState::Interactive) return ResponseCode::Ignored;
+ auto sapp = app_.lock();
+ if (!sapp) return ResponseCode::Ignored;
+ auto [error, response] =
+ sapp->issueCmd<DeliverTestCommandMessage, DeliverTestCommandResponse>(
+ static_cast<teeui::TestModeCommands>(secureInputToken.challenge));
+ if (error != TrustyAppError::OK) return ResponseCode::SystemError;
+ auto& [trc] = response;
+ if (trc != TeeuiRc::Ignored) secureInputDelivered_ = true;
+ rc = convertRc(trc);
+ }
+ if (secureInputDelivered_) listener_state_condv_.notify_all();
+ // VTS test expect an OK response if the event was successfully delivered.
+ // But since the TA returns the callback response now, we have to translate
+ // Canceled into OK. Canceled is only returned if the delivered event canceled
+ // the operation, which means that the event was successfully delivered. Thus
+ // we return OK.
+ if (rc == ResponseCode::Canceled) return ResponseCode::OK;
+ return rc;
+}
+
+Return<void> TrustyConfirmationUI::abort() {
+ {
+ std::unique_lock<std::mutex> stateLock(listener_state_lock_);
+ if (listener_state_ == ListenerState::SetupDone ||
+ listener_state_ == ListenerState::Interactive) {
+ auto sapp = app_.lock();
+ if (sapp) sapp->issueCmd<AbortMsg>();
+ abort_called_ = true;
+ }
+ }
+ listener_state_condv_.notify_all();
+ return Void();
+}
+
+android::sp<IConfirmationUI> createTrustyConfirmationUI() {
+ return new TrustyConfirmationUI();
+}
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace confirmationui
+} // namespace hardware
+} // namespace android
diff --git a/trusty/confirmationui/TrustyConfirmationUI.h b/trusty/confirmationui/TrustyConfirmationUI.h
new file mode 100644
index 0000000..3a7c7ef
--- /dev/null
+++ b/trusty/confirmationui/TrustyConfirmationUI.h
@@ -0,0 +1,104 @@
+/*
+ * Copyright 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.
+ */
+
+#ifndef ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
+#define ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+#include <android/hardware/keymaster/4.0/types.h>
+#include <hidl/Status.h>
+
+#include <atomic>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <teeui/generic_messages.h>
+#include <thread>
+
+#include "TrustyApp.h"
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+using ::android::sp;
+using ::android::hardware::hidl_array;
+using ::android::hardware::hidl_string;
+using ::android::hardware::hidl_vec;
+using ::android::hardware::Return;
+using ::android::hardware::Void;
+
+using ::android::trusty::TrustyApp;
+
+class TrustyConfirmationUI : public IConfirmationUI {
+ public:
+ TrustyConfirmationUI();
+ virtual ~TrustyConfirmationUI();
+ // Methods from ::android::hardware::confirmationui::V1_0::IConfirmationUI
+ // follow.
+ Return<ResponseCode> promptUserConfirmation(const sp<IConfirmationResultCallback>& resultCB,
+ const hidl_string& promptText,
+ const hidl_vec<uint8_t>& extraData,
+ const hidl_string& locale,
+ const hidl_vec<UIOption>& uiOptions) override;
+ Return<ResponseCode> deliverSecureInputEvent(
+ const ::android::hardware::keymaster::V4_0::HardwareAuthToken& secureInputToken) override;
+ Return<void> abort() override;
+
+ private:
+ std::weak_ptr<TrustyApp> app_;
+ std::thread callback_thread_;
+
+ enum class ListenerState : uint32_t {
+ None,
+ Starting,
+ SetupDone,
+ Interactive,
+ Terminating,
+ };
+
+ /*
+ * listener_state is protected by listener_state_lock. It makes transitions between phases
+ * of the confirmation operation atomic.
+ * (See TrustyConfirmationUI.cpp#promptUserConfirmation_ for details about operation phases)
+ */
+ ListenerState listener_state_;
+ /*
+ * abort_called_ is also protected by listener_state_lock_ and indicates that the HAL user
+ * called abort.
+ */
+ bool abort_called_;
+ std::mutex listener_state_lock_;
+ std::condition_variable listener_state_condv_;
+ ResponseCode prompt_result_;
+ bool secureInputDelivered_;
+
+ std::tuple<teeui::ResponseCode, teeui::MsgVector<uint8_t>, teeui::MsgVector<uint8_t>>
+ promptUserConfirmation_(const teeui::MsgString& promptText,
+ const teeui::MsgVector<uint8_t>& extraData,
+ const teeui::MsgString& locale,
+ const teeui::MsgVector<teeui::UIOption>& uiOptions);
+};
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace confirmationui
+} // namespace hardware
+} // namespace android
+
+#endif // ANDROID_HARDWARE_CONFIRMATIONUI_V1_0_TRUSTY_CONFIRMATIONUI_H
diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc
new file mode 100644
index 0000000..dc7a03b
--- /dev/null
+++ b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.rc
@@ -0,0 +1,4 @@
+service confirmationui-1-0 /vendor/bin/hw/android.hardware.confirmationui@1.0-service.trusty
+ class hal
+ user nobody
+ group drmrpc input
diff --git a/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml
new file mode 100644
index 0000000..9008b87
--- /dev/null
+++ b/trusty/confirmationui/android.hardware.confirmationui@1.0-service.trusty.xml
@@ -0,0 +1,11 @@
+<manifest version="1.0" type="device">
+ <hal format="hidl">
+ <name>android.hardware.confirmationui</name>
+ <transport>hwbinder</transport>
+ <version>1.0</version>
+ <interface>
+ <name>IConfirmationUI</name>
+ <instance>default</instance>
+ </interface>
+ </hal>
+</manifest>
diff --git a/trusty/confirmationui/include/TrustyConfirmationuiHal.h b/trusty/confirmationui/include/TrustyConfirmationuiHal.h
new file mode 100644
index 0000000..2ab9389
--- /dev/null
+++ b/trusty/confirmationui/include/TrustyConfirmationuiHal.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright 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.
+ */
+
+#pragma once
+
+#include <android/hardware/confirmationui/1.0/IConfirmationUI.h>
+
+namespace android {
+namespace hardware {
+namespace confirmationui {
+namespace V1_0 {
+namespace implementation {
+
+android::sp<IConfirmationUI> createTrustyConfirmationUI();
+
+} // namespace implementation
+} // namespace V1_0
+} // namespace confirmationui
+} // namespace hardware
+} // namespace android
diff --git a/trusty/confirmationui/service.cpp b/trusty/confirmationui/service.cpp
new file mode 100644
index 0000000..dd7e84b
--- /dev/null
+++ b/trusty/confirmationui/service.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 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/logging.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include <TrustyConfirmationuiHal.h>
+
+using android::sp;
+using android::hardware::confirmationui::V1_0::implementation::createTrustyConfirmationUI;
+
+int main() {
+ ::android::hardware::configureRpcThreadpool(1, true /*willJoinThreadpool*/);
+ auto service = createTrustyConfirmationUI();
+ auto status = service->registerAsService();
+ if (status != android::OK) {
+ LOG(FATAL) << "Could not register service for ConfirmationUI 1.0 (" << status << ")";
+ return -1;
+ }
+ ::android::hardware::joinRpcThreadpool();
+ return -1;
+}