Merge "init: add builtin check for perf_event LSM hooks"
diff --git a/Android.bp b/Android.bp
index c6f6251..0b4a925 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2,5 +2,3 @@
name: "android_filesystem_config_header",
srcs: ["include/private/android_filesystem_config.h"],
}
-
-subdirs = ["*"]
diff --git a/adb/Android.bp b/adb/Android.bp
index bd1f124..3e8da8a 100644
--- a/adb/Android.bp
+++ b/adb/Android.bp
@@ -217,6 +217,7 @@
"libcutils",
"libcrypto_utils",
"libcrypto",
+ "liblog",
"libmdnssd",
"libdiagnose_usb",
"libusb",
diff --git a/base/include/android-base/logging.h b/base/include/android-base/logging.h
index d099e52..3a9186a 100644
--- a/base/include/android-base/logging.h
+++ b/base/include/android-base/logging.h
@@ -116,7 +116,6 @@
std::string GetDefaultTag();
void SetDefaultTag(const std::string& tag);
-#ifdef __ANDROID__
// We expose this even though it is the default because a user that wants to
// override the default log buffer will have to construct this themselves.
class LogdLogger {
@@ -129,7 +128,6 @@
private:
LogId default_log_id_;
};
-#endif
// Configure logging based on ANDROID_LOG_TAGS environment variable.
// We need to parse a string that looks like
diff --git a/base/include/android-base/unique_fd.h b/base/include/android-base/unique_fd.h
index 1605daf..c4a0aad 100644
--- a/base/include/android-base/unique_fd.h
+++ b/base/include/android-base/unique_fd.h
@@ -116,6 +116,8 @@
bool operator<(int rhs) const { return get() < rhs; }
bool operator==(int rhs) const { return get() == rhs; }
bool operator!=(int rhs) const { return get() != rhs; }
+ bool operator==(const unique_fd_impl& rhs) const { return get() == rhs.get(); }
+ bool operator!=(const unique_fd_impl& rhs) const { return get() != rhs.get(); }
// Catch bogus error checks (i.e.: "!fd" instead of "fd != -1").
bool operator!() const = delete;
diff --git a/base/logging.cpp b/base/logging.cpp
index 598a522..b46abbf 100644
--- a/base/logging.cpp
+++ b/base/logging.cpp
@@ -45,8 +45,8 @@
#include <vector>
// Headers for LogMessage::LogLine.
-#ifdef __ANDROID__
#include <android/log.h>
+#ifdef __ANDROID__
#include <android/set_abort_message.h>
#else
#include <sys/types.h>
@@ -242,7 +242,6 @@
}
-#ifdef __ANDROID__
LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {
}
@@ -276,7 +275,6 @@
__android_log_buf_print(lg_id, priority, tag, "%s", message);
}
}
-#endif
void InitLogging(char* argv[], LogFunction&& logger, AbortFunction&& aborter) {
SetLogger(std::forward<LogFunction>(logger));
diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh
index 8979b0c..f379d76 100755
--- a/bootstat/boot_reason_test.sh
+++ b/bootstat/boot_reason_test.sh
@@ -636,7 +636,7 @@
rm -r ${ANDROID_PRODUCT_OUT}/obj/ETC/system_build_prop_intermediates ||
true
pushd ${ANDROID_BUILD_TOP} >&2
- make -j50 >&2
+ build/soong/soong_ui.bash --make-mode >&2
if [ ${?} != 0 ]; then
popd >&2
return 1
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp
index 780e48d..c8df3e3 100644
--- a/debuggerd/Android.bp
+++ b/debuggerd/Android.bp
@@ -355,7 +355,3 @@
init_rc: ["tombstoned/tombstoned.rc"],
}
-
-subdirs = [
- "crasher",
-]
diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp
index 6e01289..f8192b5 100644
--- a/debuggerd/handler/debuggerd_handler.cpp
+++ b/debuggerd/handler/debuggerd_handler.cpp
@@ -592,19 +592,20 @@
g_callbacks = *callbacks;
}
- void* thread_stack_allocation =
- mmap(nullptr, PAGE_SIZE * 3, PROT_NONE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+ size_t thread_stack_pages = 8;
+ void* thread_stack_allocation = mmap(nullptr, PAGE_SIZE * (thread_stack_pages + 2), PROT_NONE,
+ MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
if (thread_stack_allocation == MAP_FAILED) {
fatal_errno("failed to allocate debuggerd thread stack");
}
char* stack = static_cast<char*>(thread_stack_allocation) + PAGE_SIZE;
- if (mprotect(stack, PAGE_SIZE, PROT_READ | PROT_WRITE) != 0) {
+ if (mprotect(stack, PAGE_SIZE * thread_stack_pages, PROT_READ | PROT_WRITE) != 0) {
fatal_errno("failed to mprotect debuggerd thread stack");
}
// Stack grows negatively, set it to the last byte in the page...
- stack = (stack + PAGE_SIZE - 1);
+ stack = (stack + thread_stack_pages * PAGE_SIZE - 1);
// and align it.
stack -= 15;
pseudothread_stack = stack;
diff --git a/deprecated-adf/Android.bp b/deprecated-adf/Android.bp
deleted file mode 100644
index b44c296..0000000
--- a/deprecated-adf/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = ["*"]
diff --git a/deprecated-adf/libadf/Android.bp b/deprecated-adf/libadf/Android.bp
index 49e3721..70f0a3b 100644
--- a/deprecated-adf/libadf/Android.bp
+++ b/deprecated-adf/libadf/Android.bp
@@ -24,5 +24,3 @@
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
-
-subdirs = ["tests"]
diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp
index 1a745ab..b7263d9 100644
--- a/fastboot/device/commands.cpp
+++ b/fastboot/device/commands.cpp
@@ -31,7 +31,6 @@
#include <cutils/android_reboot.h>
#include <ext4_utils/wipe.h>
#include <fs_mgr.h>
-#include <fs_mgr/roots.h>
#include <libgsi/libgsi.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
@@ -550,42 +549,6 @@
return UpdateSuper(device, args[1], wipe);
}
-class AutoMountMetadata {
- public:
- AutoMountMetadata() {
- android::fs_mgr::Fstab proc_mounts;
- if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
- LOG(ERROR) << "Could not read /proc/mounts";
- return;
- }
-
- auto iter = std::find_if(proc_mounts.begin(), proc_mounts.end(),
- [](const auto& entry) { return entry.mount_point == "/metadata"; });
- if (iter != proc_mounts.end()) {
- mounted_ = true;
- return;
- }
-
- if (!ReadDefaultFstab(&fstab_)) {
- LOG(ERROR) << "Could not read default fstab";
- return;
- }
- mounted_ = EnsurePathMounted(&fstab_, "/metadata");
- should_unmount_ = true;
- }
- ~AutoMountMetadata() {
- if (mounted_ && should_unmount_) {
- EnsurePathUnmounted(&fstab_, "/metadata");
- }
- }
- explicit operator bool() const { return mounted_; }
-
- private:
- android::fs_mgr::Fstab fstab_;
- bool mounted_ = false;
- bool should_unmount_ = false;
-};
-
bool GsiHandler(FastbootDevice* device, const std::vector<std::string>& args) {
if (args.size() != 2) {
return device->WriteFail("Invalid arguments");
diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp
index 102ebdb..7e7e507 100644
--- a/fastboot/device/flashing.cpp
+++ b/fastboot/device/flashing.cpp
@@ -21,6 +21,7 @@
#include <algorithm>
#include <memory>
+#include <optional>
#include <set>
#include <string>
@@ -56,6 +57,7 @@
Fstab fstab;
ReadDefaultFstab(&fstab);
+ std::optional<AutoMountMetadata> mount_metadata;
for (const auto& entry : fstab) {
auto partition = android::base::Basename(entry.mount_point);
if ("/" == entry.mount_point) {
@@ -63,6 +65,7 @@
}
if ((partition + device->GetCurrentSlot()) == partition_name) {
+ mount_metadata.emplace();
fs_mgr_overlayfs_teardown(entry.mount_point.c_str());
}
}
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/device/utility.cpp b/fastboot/device/utility.cpp
index b3f2d5f..7c6ac89 100644
--- a/fastboot/device/utility.cpp
+++ b/fastboot/device/utility.cpp
@@ -26,6 +26,7 @@
#include <android-base/properties.h>
#include <android-base/strings.h>
#include <fs_mgr.h>
+#include <fs_mgr/roots.h>
#include <fs_mgr_dm_linear.h>
#include <liblp/builder.h>
#include <liblp/liblp.h>
@@ -240,3 +241,29 @@
}
return current_slot_suffix;
}
+
+AutoMountMetadata::AutoMountMetadata() {
+ android::fs_mgr::Fstab proc_mounts;
+ if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
+ LOG(ERROR) << "Could not read /proc/mounts";
+ return;
+ }
+
+ if (GetEntryForMountPoint(&proc_mounts, "/metadata")) {
+ mounted_ = true;
+ return;
+ }
+
+ if (!ReadDefaultFstab(&fstab_)) {
+ LOG(ERROR) << "Could not read default fstab";
+ return;
+ }
+ mounted_ = EnsurePathMounted(&fstab_, "/metadata");
+ should_unmount_ = true;
+}
+
+AutoMountMetadata::~AutoMountMetadata() {
+ if (mounted_ && should_unmount_) {
+ EnsurePathUnmounted(&fstab_, "/metadata");
+ }
+}
diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h
index bfeeb74..3b71ef0 100644
--- a/fastboot/device/utility.h
+++ b/fastboot/device/utility.h
@@ -20,6 +20,7 @@
#include <android-base/unique_fd.h>
#include <android/hardware/boot/1.0/IBootControl.h>
+#include <fstab/fstab.h>
#include <liblp/liblp.h>
// Logical partitions are only mapped to a block device as needed, and
@@ -51,6 +52,18 @@
std::function<void()> closer_;
};
+class AutoMountMetadata {
+ public:
+ AutoMountMetadata();
+ ~AutoMountMetadata();
+ explicit operator bool() const { return mounted_; }
+
+ private:
+ android::fs_mgr::Fstab fstab_;
+ bool mounted_ = false;
+ bool should_unmount_ = false;
+};
+
class FastbootDevice;
// On normal devices, the super partition is always named "super". On retrofit
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/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp
index 30eb5a0..280318e 100644
--- a/fs_mgr/libfiemap/image_manager.cpp
+++ b/fs_mgr/libfiemap/image_manager.cpp
@@ -26,6 +26,7 @@
#include <fs_mgr_dm_linear.h>
#include <libdm/loop_control.h>
#include <libfiemap/split_fiemap_writer.h>
+#include <libgsi/libgsi.h>
#include "metadata.h"
#include "utility.h"
@@ -34,6 +35,7 @@
namespace fiemap {
using namespace std::literals;
+using android::base::ReadFileToString;
using android::base::unique_fd;
using android::dm::DeviceMapper;
using android::dm::DmDeviceState;
@@ -53,6 +55,11 @@
std::unique_ptr<ImageManager> ImageManager::Open(const std::string& dir_prefix) {
auto metadata_dir = "/metadata/gsi/" + dir_prefix;
auto data_dir = "/data/gsi/" + dir_prefix;
+ auto install_dir_file = gsi::DsuInstallDirFile(gsi::GetDsuSlot(dir_prefix));
+ std::string path;
+ if (ReadFileToString(install_dir_file, &path)) {
+ data_dir = path;
+ }
return Open(metadata_dir, data_dir);
}
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index eadcecc..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",
],
}
@@ -127,6 +128,7 @@
"include_test",
],
srcs: [
+ "android/snapshot/snapshot.proto",
"test_helpers.cpp",
],
shared_libs: [
diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
index 629c3a4..a3a518d 100644
--- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
+++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto
@@ -85,3 +85,49 @@
// This is non-zero when |state| == MERGING or MERGE_COMPLETED.
uint64 metadata_sectors = 8;
}
+
+// Next: 8
+enum UpdateState {
+ // No update or merge is in progress.
+ None = 0;
+
+ // An update is applying; snapshots may already exist.
+ Initiated = 1;
+
+ // An update is pending, but has not been successfully booted yet.
+ Unverified = 2;
+
+ // The kernel is merging in the background.
+ Merging = 3;
+
+ // Post-merge cleanup steps could not be completed due to a transient
+ // error, but the next reboot will finish any pending operations.
+ MergeNeedsReboot = 4;
+
+ // Merging is complete, and needs to be acknowledged.
+ MergeCompleted = 5;
+
+ // Merging failed due to an unrecoverable error.
+ MergeFailed = 6;
+
+ // The update was implicitly cancelled, either by a rollback or a flash
+ // operation via fastboot. This state can only be returned by WaitForMerge.
+ Cancelled = 7;
+};
+
+// Next: 5
+message SnapshotUpdateStatus {
+ UpdateState state = 1;
+
+ // Total number of sectors allocated in the COW files before performing the
+ // merge operation. This field is used to keep track of the total number
+ // of sectors modified to monitor and show the progress of the merge during
+ // an update.
+ uint64 sectors_allocated = 2;
+
+ // Total number of sectors of all the snapshot devices.
+ uint64 total_sectors = 3;
+
+ // Sectors allocated for metadata in all the snapshot devices.
+ uint64 metadata_sectors = 4;
+}
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 6e613ba..e503ec3 100644
--- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
+++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h
@@ -26,6 +26,7 @@
#include <vector>
#include <android-base/unique_fd.h>
+#include <android/snapshot/snapshot.pb.h>
#include <fs_mgr_dm_linear.h>
#include <libdm/dm.h>
#include <libfiemap/image_manager.h>
@@ -34,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) \
@@ -80,35 +82,6 @@
NOT_CREATED,
};
-enum class UpdateState : unsigned int {
- // No update or merge is in progress.
- None,
-
- // An update is applying; snapshots may already exist.
- Initiated,
-
- // An update is pending, but has not been successfully booted yet.
- Unverified,
-
- // The kernel is merging in the background.
- Merging,
-
- // Post-merge cleanup steps could not be completed due to a transient
- // error, but the next reboot will finish any pending operations.
- MergeNeedsReboot,
-
- // Merging is complete, and needs to be acknowledged.
- MergeCompleted,
-
- // Merging failed due to an unrecoverable error.
- MergeFailed,
-
- // The update was implicitly cancelled, either by a rollback or a flash
- // operation via fastboot. This state can only be returned by WaitForMerge.
- Cancelled
-};
-std::ostream& operator<<(std::ostream& os, UpdateState state);
-
class SnapshotManager final {
using CreateLogicalPartitionParams = android::fs_mgr::CreateLogicalPartitionParams;
using IPartitionOpener = android::fs_mgr::IPartitionOpener;
@@ -119,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:
@@ -433,7 +385,9 @@
// Interact with /metadata/ota/state.
UpdateState ReadUpdateState(LockedFile* file);
+ SnapshotUpdateStatus ReadSnapshotUpdateStatus(LockedFile* file);
bool WriteUpdateState(LockedFile* file, UpdateState state);
+ bool WriteSnapshotUpdateStatus(LockedFile* file, const SnapshotUpdateStatus& status);
std::string GetStateFilePath() const;
// Helpers for merging.
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 b79b65c..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();
@@ -560,9 +560,26 @@
}
}
+ DmTargetSnapshot::Status initial_target_values = {};
+ for (const auto& snapshot : snapshots) {
+ DmTargetSnapshot::Status current_status;
+ if (!QuerySnapshotStatus(snapshot, nullptr, ¤t_status)) {
+ return false;
+ }
+ initial_target_values.sectors_allocated += current_status.sectors_allocated;
+ initial_target_values.total_sectors += current_status.total_sectors;
+ initial_target_values.metadata_sectors += current_status.metadata_sectors;
+ }
+
+ SnapshotUpdateStatus initial_status;
+ initial_status.set_state(UpdateState::Merging);
+ initial_status.set_sectors_allocated(initial_target_values.sectors_allocated);
+ initial_status.set_total_sectors(initial_target_values.total_sectors);
+ initial_status.set_metadata_sectors(initial_target_values.metadata_sectors);
+
// Point of no return - mark that we're starting a merge. From now on every
// snapshot must be a merge target.
- if (!WriteUpdateState(lock.get(), UpdateState::Merging)) {
+ if (!WriteSnapshotUpdateStatus(lock.get(), initial_status)) {
return false;
}
@@ -1643,15 +1660,7 @@
return OpenLock(LOCK_EX);
}
-UpdateState SnapshotManager::ReadUpdateState(LockedFile* lock) {
- CHECK(lock);
-
- std::string contents;
- if (!android::base::ReadFileToString(GetStateFilePath(), &contents)) {
- PLOG(ERROR) << "Read state file failed";
- return UpdateState::None;
- }
-
+static UpdateState UpdateStateFromString(const std::string& contents) {
if (contents.empty() || contents == "none") {
return UpdateState::None;
} else if (contents == "initiated") {
@@ -1694,18 +1703,54 @@
}
}
+UpdateState SnapshotManager::ReadUpdateState(LockedFile* lock) {
+ SnapshotUpdateStatus status = ReadSnapshotUpdateStatus(lock);
+ return status.state();
+}
+
+SnapshotUpdateStatus SnapshotManager::ReadSnapshotUpdateStatus(LockedFile* lock) {
+ CHECK(lock);
+
+ SnapshotUpdateStatus status = {};
+ std::string contents;
+ if (!android::base::ReadFileToString(GetStateFilePath(), &contents)) {
+ PLOG(ERROR) << "Read state file failed";
+ status.set_state(UpdateState::None);
+ return status;
+ }
+
+ if (!status.ParseFromString(contents)) {
+ LOG(WARNING) << "Unable to parse state file as SnapshotUpdateStatus, using the old format";
+
+ // Try to rollback to legacy file to support devices that are
+ // currently using the old file format.
+ // TODO(b/147409432)
+ status.set_state(UpdateStateFromString(contents));
+ }
+
+ return status;
+}
+
bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state) {
+ SnapshotUpdateStatus status = {};
+ status.set_state(state);
+ return WriteSnapshotUpdateStatus(lock, status);
+}
+
+bool SnapshotManager::WriteSnapshotUpdateStatus(LockedFile* lock,
+ const SnapshotUpdateStatus& status) {
CHECK(lock);
CHECK(lock->lock_mode() == LOCK_EX);
- std::stringstream ss;
- ss << state;
- std::string contents = ss.str();
- if (contents.empty()) return false;
+ std::string contents;
+ if (!status.SerializeToString(&contents)) {
+ LOG(ERROR) << "Unable to serialize SnapshotUpdateStatus.";
+ return false;
+ }
#ifdef LIBSNAPSHOT_USE_HAL
auto merge_status = MergeStatus::UNKNOWN;
- switch (state) {
+ switch (status.state()) {
// The needs-reboot and completed cases imply that /data and /metadata
// can be safely wiped, so we don't report a merge status.
case UpdateState::None:
@@ -1724,7 +1769,7 @@
default:
// Note that Cancelled flows to here - it is never written, since
// it only communicates a transient state to the caller.
- LOG(ERROR) << "Unexpected update status: " << state;
+ LOG(ERROR) << "Unexpected update status: " << status.state();
break;
}
@@ -1845,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();
@@ -1953,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) {
@@ -2086,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/fs_mgr/libvbmeta/Android.bp b/fs_mgr/libvbmeta/Android.bp
index 937e0f3..bceabab 100644
--- a/fs_mgr/libvbmeta/Android.bp
+++ b/fs_mgr/libvbmeta/Android.bp
@@ -37,6 +37,7 @@
cc_test_host {
name: "libvbmeta_test",
static_libs: [
+ "liblog",
"libsparse",
"libvbmeta",
"libz",
diff --git a/init/builtins.cpp b/init/builtins.cpp
index 2a6df84..c877590 100644
--- a/init/builtins.cpp
+++ b/init/builtins.cpp
@@ -1119,19 +1119,28 @@
}
static Result<void> ExecVdcRebootOnFailure(const std::string& vdc_arg) {
+ bool should_reboot_into_recovery = true;
auto reboot_reason = vdc_arg + "_failed";
+ if (android::sysprop::InitProperties::userspace_reboot_in_progress().value_or(false)) {
+ should_reboot_into_recovery = false;
+ }
- auto reboot = [reboot_reason](const std::string& message) {
+ auto reboot = [reboot_reason, should_reboot_into_recovery](const std::string& message) {
// TODO (b/122850122): support this in gsi
- if (fscrypt_is_native() && !android::gsi::IsGsiRunning()) {
- LOG(ERROR) << message << ": Rebooting into recovery, reason: " << reboot_reason;
- if (auto result = reboot_into_recovery(
- {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
- !result) {
- LOG(FATAL) << "Could not reboot into recovery: " << result.error();
+ if (should_reboot_into_recovery) {
+ if (fscrypt_is_native() && !android::gsi::IsGsiRunning()) {
+ LOG(ERROR) << message << ": Rebooting into recovery, reason: " << reboot_reason;
+ if (auto result = reboot_into_recovery(
+ {"--prompt_and_wipe_data", "--reason="s + reboot_reason});
+ !result) {
+ LOG(FATAL) << "Could not reboot into recovery: " << result.error();
+ }
+ } else {
+ LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
}
} else {
- LOG(ERROR) << "Failure (reboot suppressed): " << reboot_reason;
+ LOG(ERROR) << message << ": rebooting, reason: " << reboot_reason;
+ trigger_shutdown("reboot," + reboot_reason);
}
};
@@ -1267,7 +1276,7 @@
if (strchr(name, '@') != nullptr) continue;
auto path = "/data/misc/apexdata/" + std::string(name);
- auto options = MkdirOptions{path, 0770, AID_ROOT, AID_SYSTEM, FscryptAction::kNone, "ref"};
+ auto options = MkdirOptions{path, 0771, AID_ROOT, AID_SYSTEM, FscryptAction::kNone, "ref"};
make_dir_with_options(options);
}
return {};
diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp
index 6d1259d..9da32e4 100644
--- a/init/first_stage_mount.cpp
+++ b/init/first_stage_mount.cpp
@@ -58,7 +58,6 @@
using android::fs_mgr::ReadFstabFromDt;
using android::fs_mgr::SkipMountingPartitions;
using android::fs_mgr::TransformFstabForDsu;
-using android::init::WriteFile;
using android::snapshot::SnapshotManager;
using namespace std::literals;
@@ -620,7 +619,13 @@
}
return InitRequiredDevices(std::move(devices));
};
- auto images = IImageManager::Open("dsu", 0ms);
+ std::string active_dsu;
+ if (!gsi::GetActiveDsu(&active_dsu)) {
+ LOG(ERROR) << "Failed to GetActiveDsu";
+ return;
+ }
+ LOG(INFO) << "DSU slot: " << active_dsu;
+ auto images = IImageManager::Open("dsu/" + active_dsu, 0ms);
if (!images || !images->MapAllImages(init_devices)) {
LOG(ERROR) << "DSU partition layout could not be instantiated";
return;
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/init/sysprop/InitProperties.sysprop b/init/sysprop/InitProperties.sysprop
index c856358..b876dc0 100644
--- a/init/sysprop/InitProperties.sysprop
+++ b/init/sysprop/InitProperties.sysprop
@@ -29,7 +29,7 @@
prop {
api_name: "is_userspace_reboot_supported"
type: Boolean
- scope: System
+ scope: Public
access: Readonly
prop_name: "ro.init.userspace_reboot.is_supported"
integer_as_bool: true
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/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp
index 340572c..8c232f0 100644
--- a/libcutils/ashmem-dev.cpp
+++ b/libcutils/ashmem-dev.cpp
@@ -203,19 +203,23 @@
{
static const std::string ashmem_device_path = get_ashmem_device_path();
- int ret;
- struct stat st;
-
if (ashmem_device_path.empty()) {
return -1;
}
int fd = TEMP_FAILURE_RETRY(open(ashmem_device_path.c_str(), O_RDWR | O_CLOEXEC));
+
+ // fallback for APEX w/ use_vendor on Q, which would have still used /dev/ashmem
+ if (fd < 0) {
+ fd = TEMP_FAILURE_RETRY(open("/dev/ashmem", O_RDWR | O_CLOEXEC));
+ }
+
if (fd < 0) {
return fd;
}
- ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
+ struct stat st;
+ int ret = TEMP_FAILURE_RETRY(fstat(fd, &st));
if (ret < 0) {
int save_errno = errno;
close(fd);
diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h
index e1e8230..f9a3df9 100644
--- a/libcutils/include/private/android_filesystem_config.h
+++ b/libcutils/include/private/android_filesystem_config.h
@@ -129,6 +129,7 @@
#define AID_NETWORK_STACK 1073 /* network stack service */
#define AID_GSID 1074 /* GSI service daemon */
#define AID_FSVERITY_CERT 1075 /* fs-verity key ownership in keystore */
+#define AID_CREDSTORE 1076 /* identity credential manager service */
/* Changes to this file must be made in AOSP, *not* in internal branches. */
#define AID_SHELL 2000 /* adb and debug shell user */
diff --git a/liblog/Android.bp b/liblog/Android.bp
index bab57c0..58c96b6 100644
--- a/liblog/Android.bp
+++ b/liblog/Android.bp
@@ -103,7 +103,7 @@
stubs: {
symbol_file: "liblog.map.txt",
- versions: ["10000"],
+ versions: ["29", "30"],
},
// TODO(tomcherry): Renable this before release branch is cut
diff --git a/liblog/event_tag_map.cpp b/liblog/event_tag_map.cpp
index 2886289..51c5e60 100644
--- a/liblog/event_tag_map.cpp
+++ b/liblog/event_tag_map.cpp
@@ -36,7 +36,6 @@
#include <utils/FastStrcmp.h>
#include <utils/RWLock.h>
-#include "log_portability.h"
#include "logd_reader.h"
#define OUT_TAG "EventTagMap"
diff --git a/liblog/fake_log_device.cpp b/liblog/fake_log_device.cpp
index af9f18b..2582cea 100644
--- a/liblog/fake_log_device.cpp
+++ b/liblog/fake_log_device.cpp
@@ -36,7 +36,6 @@
#include <log/log_id.h>
#include <log/logprint.h>
-#include "log_portability.h"
#include "logger.h"
#define kMaxTagLen 16 /* from the long-dead utils/Log.cpp */
diff --git a/liblog/fake_log_device.h b/liblog/fake_log_device.h
index a2b40e2..53f1b41 100644
--- a/liblog/fake_log_device.h
+++ b/liblog/fake_log_device.h
@@ -16,12 +16,11 @@
#pragma once
+#include <sys/cdefs.h>
#include <sys/types.h>
#include <android/log.h>
-#include "log_portability.h"
-
__BEGIN_DECLS
void FakeClose();
diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt
index 2dd8059..65194ce 100644
--- a/liblog/liblog.map.txt
+++ b/liblog/liblog.map.txt
@@ -54,18 +54,22 @@
__android_log_is_debuggable; # apex llndk
};
-LIBLOG_Q {
+LIBLOG_Q { # introduced=29
global:
__android_log_bswrite; # apex
__android_log_btwrite; # apex
__android_log_bwrite; # apex
__android_log_close; # apex
__android_log_security; # apex
- __android_log_security_bswrite; # apex
android_log_reset; # llndk
android_log_parser_reset; # llndk
};
+LIGLOG_R { # introduced=30
+ global:
+ __android_log_security_bswrite; # apex
+};
+
LIBLOG_PRIVATE {
global:
__android_log_pmsg_file_read;
diff --git a/liblog/log_event_list.cpp b/liblog/log_event_list.cpp
index e9f4a32..cb70d48 100644
--- a/liblog/log_event_list.cpp
+++ b/liblog/log_event_list.cpp
@@ -25,8 +25,6 @@
#include <log/log_event_list.h>
#include <private/android_logger.h>
-#include "log_portability.h"
-
#define MAX_EVENT_PAYLOAD (LOGGER_ENTRY_MAX_PAYLOAD - sizeof(int32_t))
enum ReadWriteFlag {
diff --git a/liblog/log_event_write.cpp b/liblog/log_event_write.cpp
index d04ba90..39afd0c 100644
--- a/liblog/log_event_write.cpp
+++ b/liblog/log_event_write.cpp
@@ -20,8 +20,6 @@
#include <log/log.h>
#include <log/log_event_list.h>
-#include "log_portability.h"
-
#define MAX_SUBTAG_LEN 32
int __android_log_error_write(int tag, const char* subTag, int32_t uid, const char* data,
diff --git a/liblog/log_portability.h b/liblog/log_portability.h
deleted file mode 100644
index b7279d1..0000000
--- a/liblog/log_portability.h
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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.
- */
-
-#pragma once
-
-#include <sys/cdefs.h>
-#include <unistd.h>
-
-/* possible missing definitions in sys/cdefs.h */
-
-/* DECLS */
-#ifndef __BEGIN_DECLS
-#if defined(__cplusplus)
-#define __BEGIN_DECLS extern "C" {
-#define __END_DECLS }
-#else
-#define __BEGIN_DECLS
-#define __END_DECLS
-#endif
-#endif
-
-/* possible missing definitions in unistd.h */
-
-#ifndef TEMP_FAILURE_RETRY
-/* Used to retry syscalls that can return EINTR. */
-#define TEMP_FAILURE_RETRY(exp) \
- ({ \
- __typeof__(exp) _rc; \
- do { \
- _rc = (exp); \
- } while (_rc == -1 && errno == EINTR); \
- _rc; \
- })
-#endif
diff --git a/liblog/log_time.cpp b/liblog/log_time.cpp
index 3ae250f..3fbe1cb 100644
--- a/liblog/log_time.cpp
+++ b/liblog/log_time.cpp
@@ -21,8 +21,6 @@
#include <private/android_logger.h>
-#include "log_portability.h"
-
const char log_time::default_format[] = "%m-%d %H:%M:%S.%q";
const timespec log_time::EPOCH = {0, 0};
diff --git a/liblog/logd_reader.h b/liblog/logd_reader.h
index 2d032fa..68eef02 100644
--- a/liblog/logd_reader.h
+++ b/liblog/logd_reader.h
@@ -16,10 +16,10 @@
#pragma once
+#include <sys/cdefs.h>
#include <unistd.h>
#include "log/log_read.h"
-#include "log_portability.h"
__BEGIN_DECLS
diff --git a/liblog/logd_writer.cpp b/liblog/logd_writer.cpp
index f49c59e..67376f4 100644
--- a/liblog/logd_writer.cpp
+++ b/liblog/logd_writer.cpp
@@ -37,7 +37,6 @@
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
-#include "log_portability.h"
#include "logger.h"
#include "rwlock.h"
#include "uio.h"
diff --git a/liblog/logger.h b/liblog/logger.h
index 078e778..ddff19d 100644
--- a/liblog/logger.h
+++ b/liblog/logger.h
@@ -17,10 +17,10 @@
#pragma once
#include <stdatomic.h>
+#include <sys/cdefs.h>
#include <log/log.h>
-#include "log_portability.h"
#include "uio.h"
__BEGIN_DECLS
diff --git a/liblog/logger_name.cpp b/liblog/logger_name.cpp
index ece0550..7d676f4 100644
--- a/liblog/logger_name.cpp
+++ b/liblog/logger_name.cpp
@@ -19,8 +19,6 @@
#include <log/log.h>
-#include "log_portability.h"
-
/* In the future, we would like to make this list extensible */
static const char* LOG_NAME[LOG_ID_MAX] = {
/* clang-format off */
diff --git a/liblog/logger_read.cpp b/liblog/logger_read.cpp
index a13ab36..e0598de 100644
--- a/liblog/logger_read.cpp
+++ b/liblog/logger_read.cpp
@@ -28,7 +28,6 @@
#include <android/log.h>
-#include "log_portability.h"
#include "logd_reader.h"
#include "logger.h"
#include "pmsg_reader.h"
diff --git a/liblog/logger_write.cpp b/liblog/logger_write.cpp
index 77be581..d6ef951 100644
--- a/liblog/logger_write.cpp
+++ b/liblog/logger_write.cpp
@@ -23,10 +23,10 @@
#include <android/set_abort_message.h>
#endif
+#include <android-base/macros.h>
#include <private/android_filesystem_config.h>
#include <private/android_logger.h>
-#include "log_portability.h"
#include "logger.h"
#include "uio.h"
diff --git a/liblog/logprint.cpp b/liblog/logprint.cpp
index 4b61828..0745a1e 100644
--- a/liblog/logprint.cpp
+++ b/liblog/logprint.cpp
@@ -40,8 +40,6 @@
#include <log/logprint.h>
#include <private/android_logger.h>
-#include "log_portability.h"
-
#define MS_PER_NSEC 1000000
#define US_PER_NSEC 1000
diff --git a/liblog/pmsg_reader.h b/liblog/pmsg_reader.h
index 53746d8..b784f9f 100644
--- a/liblog/pmsg_reader.h
+++ b/liblog/pmsg_reader.h
@@ -16,10 +16,10 @@
#pragma once
+#include <sys/cdefs.h>
#include <unistd.h>
#include "log/log_read.h"
-#include "log_portability.h"
__BEGIN_DECLS
diff --git a/liblog/pmsg_writer.cpp b/liblog/pmsg_writer.cpp
index 319360f..06e5e04 100644
--- a/liblog/pmsg_writer.cpp
+++ b/liblog/pmsg_writer.cpp
@@ -28,7 +28,6 @@
#include <log/log_properties.h>
#include <private/android_logger.h>
-#include "log_portability.h"
#include "logger.h"
#include "rwlock.h"
#include "uio.h"
diff --git a/liblog/properties.cpp b/liblog/properties.cpp
index 2e0a8c9..2b2327c 100644
--- a/liblog/properties.cpp
+++ b/liblog/properties.cpp
@@ -26,8 +26,6 @@
#include <private/android_logger.h>
-#include "log_portability.h"
-
static pthread_mutex_t lock_loggable = PTHREAD_MUTEX_INITIALIZER;
static int lock() {
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/libutils/StrongPointer_test.cpp b/libutils/StrongPointer_test.cpp
index 153cf96..7b2e37f 100644
--- a/libutils/StrongPointer_test.cpp
+++ b/libutils/StrongPointer_test.cpp
@@ -56,3 +56,18 @@
}
ASSERT_TRUE(isDeleted) << "foo was leaked!";
}
+
+TEST(StrongPointer, NullptrComparison) {
+ sp<SPFoo> foo;
+ ASSERT_EQ(foo, nullptr);
+ ASSERT_EQ(nullptr, foo);
+}
+
+TEST(StrongPointer, PointerComparison) {
+ bool isDeleted;
+ sp<SPFoo> foo = new SPFoo(&isDeleted);
+ ASSERT_EQ(foo.get(), foo);
+ ASSERT_EQ(foo, foo.get());
+ ASSERT_NE(nullptr, foo);
+ ASSERT_NE(foo, nullptr);
+}
diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h
index 100e507..6f4fb47 100644
--- a/libutils/include/utils/StrongPointer.h
+++ b/libutils/include/utils/StrongPointer.h
@@ -27,43 +27,6 @@
// ---------------------------------------------------------------------------
-// TODO: Maybe remove sp<> ? wp<> comparison? These are dangerous: If the wp<>
-// was created before the sp<>, and they point to different objects, they may
-// compare equal even if they are entirely unrelated. E.g. CameraService
-// currently performa such comparisons.
-
-#define COMPARE_STRONG(_op_) \
-template<typename U> \
-inline bool operator _op_ (const sp<U>& o) const { \
- return m_ptr _op_ o.m_ptr; \
-} \
-template<typename U> \
-inline bool operator _op_ (const U* o) const { \
- return m_ptr _op_ o; \
-} \
-/* Needed to handle type inference for nullptr: */ \
-inline bool operator _op_ (const T* o) const { \
- return m_ptr _op_ o; \
-}
-
-template<template<typename C> class comparator, typename T, typename U>
-static inline bool _sp_compare_(T* a, U* b) {
- return comparator<typename std::common_type<T*, U*>::type>()(a, b);
-}
-
-// Use std::less and friends to avoid undefined behavior when ordering pointers
-// to different objects.
-#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_) \
-template<typename U> \
-inline bool operator _op_ (const sp<U>& o) const { \
- return _sp_compare_<_compare_>(m_ptr, o.m_ptr); \
-} \
-template<typename U> \
-inline bool operator _op_ (const U* o) const { \
- return _sp_compare_<_compare_>(m_ptr, o); \
-}
-// ---------------------------------------------------------------------------
-
template<typename T>
class sp {
public:
@@ -102,15 +65,6 @@
inline T* get() const { return m_ptr; }
inline explicit operator bool () const { return m_ptr != nullptr; }
- // Operators
-
- COMPARE_STRONG(==)
- COMPARE_STRONG(!=)
- COMPARE_STRONG_FUNCTIONAL(>, std::greater)
- COMPARE_STRONG_FUNCTIONAL(<, std::less)
- COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
- COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
-
// Punt these to the wp<> implementation.
template<typename U>
inline bool operator == (const wp<U>& o) const {
@@ -130,13 +84,69 @@
T* m_ptr;
};
-// For code size reasons, we do not want these inlined or templated.
-void sp_report_race();
-void sp_report_stack_pointer();
+#define COMPARE_STRONG(_op_) \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
+ return t.get() _op_ u.get(); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const T* t, const sp<U>& u) { \
+ return t _op_ u.get(); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const U* u) { \
+ return t.get() _op_ u; \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
+ return t.get() _op_ nullptr; \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
+ return nullptr _op_ t.get(); \
+ }
+
+template <template <typename C> class comparator, typename T, typename U>
+static inline bool _sp_compare_(T* a, U* b) {
+ return comparator<typename std::common_type<T*, U*>::type>()(a, b);
+}
+
+#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_) \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const sp<U>& u) { \
+ return _sp_compare_<_compare_>(t.get(), u.get()); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const T* t, const sp<U>& u) { \
+ return _sp_compare_<_compare_>(t, u.get()); \
+ } \
+ template <typename T, typename U> \
+ static inline bool operator _op_(const sp<T>& t, const U* u) { \
+ return _sp_compare_<_compare_>(t.get(), u); \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(const sp<T>& t, std::nullptr_t) { \
+ return _sp_compare_<_compare_>(t.get(), nullptr); \
+ } \
+ template <typename T> \
+ static inline bool operator _op_(std::nullptr_t, const sp<T>& t) { \
+ return _sp_compare_<_compare_>(nullptr, t.get()); \
+ }
+
+COMPARE_STRONG(==)
+COMPARE_STRONG(!=)
+COMPARE_STRONG_FUNCTIONAL(>, std::greater)
+COMPARE_STRONG_FUNCTIONAL(<, std::less)
+COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal)
+COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal)
#undef COMPARE_STRONG
#undef COMPARE_STRONG_FUNCTIONAL
+// For code size reasons, we do not want these inlined or templated.
+void sp_report_race();
+void sp_report_stack_pointer();
+
// ---------------------------------------------------------------------------
// No user serviceable parts below here.
diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp
index f4544a1..b92c76c 100644
--- a/libvndksupport/Android.bp
+++ b/libvndksupport/Android.bp
@@ -1,5 +1,3 @@
-subdirs = ["tests"]
-
cc_library {
name: "libvndksupport",
native_bridge_supported: true,
diff --git a/llkd/libllkd.cpp b/llkd/libllkd.cpp
index b26ad4d..1c3acb8 100644
--- a/llkd/libllkd.cpp
+++ b/llkd/libllkd.cpp
@@ -304,10 +304,13 @@
bool cmdlineValid; // cmdline has been cached
bool updated; // cleared before monitoring pass.
bool killed; // sent a kill to this thread, next panic...
+ bool frozen; // process is in frozen cgroup.
void setComm(const char* _comm) { strncpy(comm + 1, _comm, sizeof(comm) - 2); }
- proc(pid_t tid, pid_t pid, pid_t ppid, const char* _comm, int time, char state)
+ void setFrozen(bool _frozen) { frozen = _frozen; }
+
+ proc(pid_t tid, pid_t pid, pid_t ppid, const char* _comm, int time, char state, bool frozen)
: tid(tid),
schedUpdate(0),
nrSwitches(0),
@@ -327,7 +330,8 @@
exeMissingValid(false),
cmdlineValid(false),
updated(true),
- killed(!llkTestWithKill) {
+ killed(!llkTestWithKill),
+ frozen(frozen) {
memset(comm, '\0', sizeof(comm));
setComm(_comm);
}
@@ -373,6 +377,8 @@
return uid;
}
+ bool isFrozen() { return frozen; }
+
void reset(void) { // reset cache, if we detected pid rollover
uid = -1;
state = '?';
@@ -592,8 +598,9 @@
tids.erase(tid);
}
-proc* llkTidAlloc(pid_t tid, pid_t pid, pid_t ppid, const char* comm, int time, char state) {
- auto it = tids.emplace(std::make_pair(tid, proc(tid, pid, ppid, comm, time, state)));
+proc* llkTidAlloc(pid_t tid, pid_t pid, pid_t ppid, const char* comm, int time, char state,
+ bool frozen) {
+ auto it = tids.emplace(std::make_pair(tid, proc(tid, pid, ppid, comm, time, state, frozen)));
return &it.first->second;
}
@@ -1039,12 +1046,18 @@
continue;
}
+ // Get the process cgroup
+ auto cgroup = ReadFile(piddir + "/cgroup");
+ auto frozen = cgroup.find(":freezer:/frozen") != std::string::npos;
+
auto procp = llkTidLookup(tid);
if (procp == nullptr) {
- procp = llkTidAlloc(tid, pid, ppid, pdir, utime + stime, state);
+ procp = llkTidAlloc(tid, pid, ppid, pdir, utime + stime, state, frozen);
} else {
// comm can change ...
procp->setComm(pdir);
+ // frozen can change, too...
+ procp->setFrozen(frozen);
procp->updated = true;
// pid/ppid/tid wrap?
if (((procp->update != prevUpdate) && (procp->update != llkUpdate)) ||
@@ -1084,6 +1097,9 @@
if ((tid == myTid) || llkSkipPid(tid)) {
continue;
}
+ if (procp->isFrozen()) {
+ break;
+ }
if (llkSkipPpid(ppid)) {
break;
}
@@ -1101,7 +1117,7 @@
auto pprocp = llkTidLookup(ppid);
if (pprocp == nullptr) {
- pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?');
+ pprocp = llkTidAlloc(ppid, ppid, 0, "", 0, '?', false);
}
if (pprocp) {
if (llkSkipPproc(pprocp, procp)) break;
diff --git a/llkd/llkd-debuggable.rc b/llkd/llkd-debuggable.rc
index 724cb5e..4b11b1c 100644
--- a/llkd/llkd-debuggable.rc
+++ b/llkd/llkd-debuggable.rc
@@ -13,7 +13,7 @@
disabled
user llkd
group llkd readproc
- capabilities KILL IPC_LOCK SYS_PTRACE DAC_OVERRIDE
+ capabilities KILL IPC_LOCK SYS_PTRACE DAC_OVERRIDE SYS_ADMIN
file /dev/kmsg w
file /proc/sysrq-trigger w
writepid /dev/cpuset/system-background/tasks
diff --git a/llkd/tests/llkd_test.cpp b/llkd/tests/llkd_test.cpp
index 96079cc..475512c 100644
--- a/llkd/tests/llkd_test.cpp
+++ b/llkd/tests/llkd_test.cpp
@@ -89,7 +89,8 @@
rest();
std::string setprop("setprop ");
// Manually check that SyS_openat is _added_ to the list when restarted
- execute((setprop + LLK_CHECK_STACK_PROPERTY + " ,SyS_openat").c_str());
+ // 4.19+ kernels report __arm64_sys_openat b/147486902
+ execute((setprop + LLK_CHECK_STACK_PROPERTY + " ,SyS_openat,__arm64_sys_openat").c_str());
rest();
execute((setprop + LLK_ENABLE_WRITEABLE_PROPERTY + " false").c_str());
rest();
diff --git a/property_service/Android.bp b/property_service/Android.bp
deleted file mode 100644
index b44c296..0000000
--- a/property_service/Android.bp
+++ /dev/null
@@ -1 +0,0 @@
-subdirs = ["*"]
diff --git a/property_service/property_info_checker/Android.bp b/property_service/property_info_checker/Android.bp
index 7d66199..65e660a 100644
--- a/property_service/property_info_checker/Android.bp
+++ b/property_service/property_info_checker/Android.bp
@@ -7,6 +7,7 @@
"libpropertyinfoserializer",
"libpropertyinfoparser",
"libbase",
+ "liblog",
"libsepol",
],
srcs: ["property_info_checker.cpp"],
diff --git a/rootdir/init.rc b/rootdir/init.rc
index 470c912..6a6169c 100644
--- a/rootdir/init.rc
+++ b/rootdir/init.rc
@@ -42,6 +42,10 @@
mkdir /linkerconfig/bootstrap 0755
mkdir /linkerconfig/default 0755
+ # Disable dm-verity hash prefetching, since it doesn't help performance
+ # Read more in b/136247322
+ write /sys/module/dm_verity/parameters/prefetch_cluster 0
+
# Generate ld.config.txt for early executed processes
exec -- /system/bin/linkerconfig --target /linkerconfig/bootstrap
chmod 644 /linkerconfig/bootstrap/ld.config.txt
@@ -547,6 +551,7 @@
chown bluetooth bluetooth /data/misc/bluedroid/bt_config.conf
mkdir /data/misc/bluetooth 0770 bluetooth bluetooth
mkdir /data/misc/bluetooth/logs 0770 bluetooth bluetooth
+ mkdir /data/misc/credstore 0700 credstore credstore
mkdir /data/misc/keystore 0700 keystore keystore
mkdir /data/misc/gatekeeper 0700 system system
mkdir /data/misc/keychain 0771 system system
@@ -584,11 +589,11 @@
# profile file layout
mkdir /data/misc/profiles 0771 system system
mkdir /data/misc/profiles/cur 0771 system system
- mkdir /data/misc/profiles/ref 0771 system system
+ mkdir /data/misc/profiles/ref 0770 system system
mkdir /data/misc/profman 0770 system shell
mkdir /data/misc/gcov 0770 root root
mkdir /data/misc/installd 0700 root root
- mkdir /data/misc/apexdata 0700 root root
+ mkdir /data/misc/apexdata 0711 root root
mkdir /data/misc/apexrollback 0700 root root
mkdir /data/preloads 0775 system system encryption=None
@@ -691,6 +696,10 @@
mount none /data/user /data_mirror/data_ce/null bind rec
mount none /data/user_de /data_mirror/data_de/null bind rec
+ # Create mirror directory for jit profiles
+ mkdir /data_mirror/cur_profiles 0700 root root
+ mount none /data/misc/profiles/cur /data_mirror/cur_profiles bind rec
+
mkdir /data/cache 0770 system cache encryption=Require
mkdir /data/cache/recovery 0770 system cache
mkdir /data/cache/backup_stage 0700 system system
@@ -701,7 +710,7 @@
mkdir /data/rollback-observer 0700 system system encryption=DeleteIfNecessary
# Create root dir for Incremental Service
- mkdir /data/incremental 0770 system system encryption=None
+ mkdir /data/incremental 0771 system system encryption=Require
# Wait for apexd to finish activating APEXes before starting more processes.
wait_for_prop apexd.status ready
diff --git a/trusty/Android.bp b/trusty/Android.bp
deleted file mode 100644
index 2fb2e19..0000000
--- a/trusty/Android.bp
+++ /dev/null
@@ -1,6 +0,0 @@
-subdirs = [
- "gatekeeper",
- "keymaster",
- "libtrusty",
- "storage/*",
-]
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;
+}
diff --git a/trusty/libtrusty/Android.bp b/trusty/libtrusty/Android.bp
index f6e9bee..8dba78d 100644
--- a/trusty/libtrusty/Android.bp
+++ b/trusty/libtrusty/Android.bp
@@ -12,10 +12,6 @@
// See the License for the specific language governing permissions and
// limitations under the License.
-subdirs = [
- "tipc-test",
-]
-
cc_library {
name: "libtrusty",
vendor: true,