Merge "Remove gettid declaration from cutils" into main
diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp
index 4e4d20e..87db98b 100644
--- a/fs_mgr/Android.bp
+++ b/fs_mgr/Android.bp
@@ -171,6 +171,25 @@
],
}
+cc_library_static {
+ name: "libfs_mgr_file_wait",
+ defaults: ["fs_mgr_defaults"],
+ export_include_dirs: ["include"],
+ cflags: [
+ "-D_FILE_OFFSET_BITS=64",
+ ],
+ srcs: [
+ "file_wait.cpp",
+ ],
+ shared_libs: [
+ "libbase",
+ ],
+ host_supported: true,
+ ramdisk_available: true,
+ vendor_ramdisk_available: true,
+ recovery_available: true,
+}
+
cc_binary {
name: "remount",
defaults: ["fs_mgr_defaults"],
diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp
index 4c45828..4b3a5d3 100644
--- a/fs_mgr/fs_mgr_remount.cpp
+++ b/fs_mgr/fs_mgr_remount.cpp
@@ -128,12 +128,11 @@
}
static android::sp<android::os::IVold> GetVold() {
+ auto sm = android::defaultServiceManager();
while (true) {
- if (auto sm = android::defaultServiceManager()) {
- if (auto binder = sm->getService(android::String16("vold"))) {
- if (auto vold = android::interface_cast<android::os::IVold>(binder)) {
- return vold;
- }
+ if (auto binder = sm->checkService(android::String16("vold"))) {
+ if (auto vold = android::interface_cast<android::os::IVold>(binder)) {
+ return vold;
}
}
std::this_thread::sleep_for(2s);
diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp
index ddda648..c8d5756 100644
--- a/fs_mgr/libfiemap/Android.bp
+++ b/fs_mgr/libfiemap/Android.bp
@@ -24,6 +24,7 @@
vendor_ramdisk_available: true,
recovery_available: true,
export_include_dirs: ["include"],
+ host_supported: true,
}
filegroup {
diff --git a/fs_mgr/libfstab/boot_config.cpp b/fs_mgr/libfstab/boot_config.cpp
index 53c843e..b21495e 100644
--- a/fs_mgr/libfstab/boot_config.cpp
+++ b/fs_mgr/libfstab/boot_config.cpp
@@ -17,11 +17,9 @@
#include <algorithm>
#include <iterator>
#include <string>
-#include <vector>
#include <android-base/file.h>
#include <android-base/properties.h>
-#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include "fstab_priv.h"
@@ -35,7 +33,7 @@
static const std::string kAndroidDtDir = [] {
std::string android_dt_dir;
if ((GetBootconfig("androidboot.android_dt_dir", &android_dt_dir) ||
- fs_mgr_get_boot_config_from_kernel_cmdline("android_dt_dir", &android_dt_dir)) &&
+ GetKernelCmdline("androidboot.android_dt_dir", &android_dt_dir)) &&
!android_dt_dir.empty()) {
// Ensure the returned path ends with a /
if (android_dt_dir.back() != '/') {
@@ -110,13 +108,10 @@
return GetBootconfigFromString(bootconfig, key, out);
}
-} // namespace fs_mgr
-} // namespace android
-
-std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline) {
+void ImportKernelCmdlineFromString(const std::string& cmdline,
+ const std::function<void(std::string, std::string)>& fn) {
static constexpr char quote = '"';
- std::vector<std::pair<std::string, std::string>> result;
size_t base = 0;
while (true) {
// skip quoted spans
@@ -127,56 +122,54 @@
if ((found = cmdline.find(quote, found + 1)) == cmdline.npos) break;
++found;
}
- std::string piece;
- auto source = cmdline.substr(base, found - base);
- std::remove_copy(source.begin(), source.end(),
- std::back_insert_iterator<std::string>(piece), quote);
+ std::string piece = cmdline.substr(base, found - base);
+ piece.erase(std::remove(piece.begin(), piece.end(), quote), piece.end());
auto equal_sign = piece.find('=');
if (equal_sign == piece.npos) {
if (!piece.empty()) {
// no difference between <key> and <key>=
- result.emplace_back(std::move(piece), "");
+ fn(std::move(piece), "");
}
} else {
- result.emplace_back(piece.substr(0, equal_sign), piece.substr(equal_sign + 1));
+ std::string value = piece.substr(equal_sign + 1);
+ piece.resize(equal_sign);
+ fn(std::move(piece), std::move(value));
}
if (found == cmdline.npos) break;
base = found + 1;
}
-
- return result;
}
-bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& android_key,
- std::string* out_val) {
- FSTAB_CHECK(out_val != nullptr);
-
- const std::string cmdline_key("androidboot." + android_key);
- for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
- if (key == cmdline_key) {
- *out_val = value;
- return true;
+bool GetKernelCmdlineFromString(const std::string& cmdline, const std::string& key,
+ std::string* out) {
+ bool found = false;
+ ImportKernelCmdlineFromString(cmdline, [&](std::string config_key, std::string value) {
+ if (!found && config_key == key) {
+ *out = std::move(value);
+ found = true;
}
- }
-
- *out_val = "";
- return false;
+ });
+ return found;
}
-// Tries to get the given boot config value from kernel cmdline.
-// Returns true if successfully found, false otherwise.
-bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val) {
+void ImportKernelCmdline(const std::function<void(std::string, std::string)>& fn) {
std::string cmdline;
- if (!android::base::ReadFileToString("/proc/cmdline", &cmdline)) return false;
- if (!cmdline.empty() && cmdline.back() == '\n') {
- cmdline.pop_back();
- }
- return fs_mgr_get_boot_config_from_kernel(cmdline, key, out_val);
+ android::base::ReadFileToString("/proc/cmdline", &cmdline);
+ ImportKernelCmdlineFromString(android::base::Trim(cmdline), fn);
}
-// Tries to get the boot config value in device tree, properties and
-// kernel cmdline (in that order). Returns 'true' if successfully
-// found, 'false' otherwise.
+bool GetKernelCmdline(const std::string& key, std::string* out) {
+ std::string cmdline;
+ android::base::ReadFileToString("/proc/cmdline", &cmdline);
+ return GetKernelCmdlineFromString(android::base::Trim(cmdline), key, out);
+}
+
+} // namespace fs_mgr
+} // namespace android
+
+// Tries to get the boot config value in device tree, properties, kernel bootconfig and kernel
+// cmdline (in that order).
+// Returns 'true' if successfully found, 'false' otherwise.
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val) {
FSTAB_CHECK(out_val != nullptr);
@@ -204,7 +197,7 @@
}
// finally, fallback to kernel cmdline, properties may not be ready yet
- if (fs_mgr_get_boot_config_from_kernel_cmdline(key, out_val)) {
+ if (android::fs_mgr::GetKernelCmdline(config_key, out_val)) {
return true;
}
diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp
index 3cbd8c8..32460b1 100644
--- a/fs_mgr/libfstab/fstab.cpp
+++ b/fs_mgr/libfstab/fstab.cpp
@@ -831,9 +831,8 @@
Fstab default_fstab;
const std::string default_fstab_path = GetFstabPath();
if (!default_fstab_path.empty() && ReadFstabFromFile(default_fstab_path, &default_fstab)) {
- for (auto&& entry : default_fstab) {
- fstab->emplace_back(std::move(entry));
- }
+ fstab->insert(fstab->end(), std::make_move_iterator(default_fstab.begin()),
+ std::make_move_iterator(default_fstab.end()));
} else {
LINFO << __FUNCTION__ << "(): failed to find device default fstab";
}
@@ -863,11 +862,11 @@
}
std::set<std::string> GetBootDevices() {
+ std::set<std::string> boot_devices;
// First check bootconfig, then kernel commandline, then the device tree
std::string value;
if (GetBootconfig("androidboot.boot_devices", &value) ||
GetBootconfig("androidboot.boot_device", &value)) {
- std::set<std::string> boot_devices;
// split by spaces and trim the trailing comma.
for (std::string_view device : android::base::Split(value, " ")) {
base::ConsumeSuffix(&device, ",");
@@ -876,25 +875,20 @@
return boot_devices;
}
- std::string dt_file_name = GetAndroidDtDir() + "boot_devices";
- if (fs_mgr_get_boot_config_from_kernel_cmdline("boot_devices", &value) ||
- ReadDtFile(dt_file_name, &value)) {
- auto boot_devices = Split(value, ",");
- return std::set<std::string>(boot_devices.begin(), boot_devices.end());
+ const std::string dt_file_name = GetAndroidDtDir() + "boot_devices";
+ if (GetKernelCmdline("androidboot.boot_devices", &value) || ReadDtFile(dt_file_name, &value)) {
+ auto boot_devices_list = Split(value, ",");
+ return {std::make_move_iterator(boot_devices_list.begin()),
+ std::make_move_iterator(boot_devices_list.end())};
}
- std::string cmdline;
- if (android::base::ReadFileToString("/proc/cmdline", &cmdline)) {
- std::set<std::string> boot_devices;
- const std::string cmdline_key = "androidboot.boot_device";
- for (const auto& [key, value] : fs_mgr_parse_cmdline(cmdline)) {
- if (key == cmdline_key) {
- boot_devices.emplace(value);
- }
+ ImportKernelCmdline([&](std::string key, std::string value) {
+ if (key == "androidboot.boot_device") {
+ boot_devices.emplace(std::move(value));
}
- if (!boot_devices.empty()) {
- return boot_devices;
- }
+ });
+ if (!boot_devices.empty()) {
+ return boot_devices;
}
// Fallback to extract boot devices from fstab.
diff --git a/fs_mgr/libfstab/fstab_priv.h b/fs_mgr/libfstab/fstab_priv.h
index cc56825..5105da0 100644
--- a/fs_mgr/libfstab/fstab_priv.h
+++ b/fs_mgr/libfstab/fstab_priv.h
@@ -18,17 +18,11 @@
#include <functional>
#include <string>
-#include <utility>
-#include <vector>
#include <fstab/fstab.h>
// Do not include logging_macros.h here as this header is used by fs_mgr, too.
-std::vector<std::pair<std::string, std::string>> fs_mgr_parse_cmdline(const std::string& cmdline);
-bool fs_mgr_get_boot_config_from_kernel(const std::string& cmdline, const std::string& key,
- std::string* out_val);
-bool fs_mgr_get_boot_config_from_kernel_cmdline(const std::string& key, std::string* out_val);
bool fs_mgr_get_boot_config(const std::string& key, std::string* out_val);
bool fs_mgr_update_for_slotselect(android::fs_mgr::Fstab* fstab);
@@ -48,5 +42,11 @@
bool GetBootconfigFromString(const std::string& bootconfig, const std::string& key,
std::string* out);
+void ImportKernelCmdlineFromString(const std::string& cmdline,
+ const std::function<void(std::string, std::string)>& fn);
+
+bool GetKernelCmdlineFromString(const std::string& cmdline, const std::string& key,
+ std::string* out);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h
index 79a07ee..150a47d 100644
--- a/fs_mgr/libfstab/include/fstab/fstab.h
+++ b/fs_mgr/libfstab/include/fstab/fstab.h
@@ -137,5 +137,13 @@
// Otherwise returns false and |*out| is not modified.
bool GetBootconfig(const std::string& key, std::string* out);
+// Import the kernel cmdline by calling the callback |fn| with each key-value pair.
+void ImportKernelCmdline(const std::function<void(std::string, std::string)>& fn);
+
+// Get the kernel cmdline value for |key|.
+// Returns true if |key| is found in the kernel cmdline.
+// Otherwise returns false and |*out| is not modified.
+bool GetKernelCmdline(const std::string& key, std::string* out);
+
} // namespace fs_mgr
} // namespace android
diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp
index bd017ff..04b5a02 100644
--- a/fs_mgr/libsnapshot/Android.bp
+++ b/fs_mgr/libsnapshot/Android.bp
@@ -44,7 +44,7 @@
"libext2_uuid",
"libext4_utils",
"libfstab",
- "libsnapshot_snapuserd",
+ "libsnapuserd_client",
"libz",
],
header_libs: [
diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp
index a9b96e2..f63579b 100644
--- a/fs_mgr/libsnapshot/snapuserd/Android.bp
+++ b/fs_mgr/libsnapshot/snapuserd/Android.bp
@@ -19,7 +19,7 @@
}
cc_defaults {
- name: "libsnapshot_snapuserd_defaults",
+ name: "libsnapuserd_client_defaults",
defaults: [
"fs_mgr_defaults",
],
@@ -33,15 +33,15 @@
}
cc_library_static {
- name: "libsnapshot_snapuserd",
+ name: "libsnapuserd_client",
defaults: [
"fs_mgr_defaults",
- "libsnapshot_snapuserd_defaults",
+ "libsnapuserd_client_defaults",
],
recovery_available: true,
static_libs: [
"libcutils_sockets",
- "libfs_mgr",
+ "libfs_mgr_file_wait",
],
shared_libs: [
"libbase",
@@ -75,11 +75,13 @@
static_libs: [
"libbase",
"libdm",
+ "libext2_uuid",
"libext4_utils",
"libsnapshot_cow",
"liburing",
],
include_dirs: ["bionic/libc/kernel"],
+ export_include_dirs: ["include"],
header_libs: [
"libstorage_literals_headers",
],
@@ -104,12 +106,13 @@
"libbrotli",
"libcutils_sockets",
"libdm",
- "libfs_mgr",
+ "libext2_uuid",
+ "libfs_mgr_file_wait",
"libgflags",
"liblog",
"libsnapshot_cow",
- "libsnapshot_snapuserd",
"libsnapuserd",
+ "libsnapuserd_client",
"libz",
"liblz4",
"libext4_utils",
@@ -144,6 +147,9 @@
init_rc: [
"snapuserd.rc",
],
+ static_libs: [
+ "libsnapuserd_client",
+ ],
ramdisk_available: false,
vendor_ramdisk_available: true,
}
@@ -186,12 +192,13 @@
"libbrotli",
"libgtest",
"libsnapshot_cow",
- "libsnapshot_snapuserd",
+ "libsnapuserd_client",
"libcutils_sockets",
"libz",
- "libfs_mgr",
"libdm",
+ "libext2_uuid",
"libext4_utils",
+ "libfs_mgr_file_wait",
],
header_libs: [
"libstorage_literals_headers",
@@ -221,17 +228,20 @@
"libbrotli",
"libcutils_sockets",
"libdm",
+ "libext2_uuid",
"libext4_utils",
- "libfs_mgr",
+ "libfs_mgr_file_wait",
"libgflags",
"libgtest",
"libsnapshot_cow",
- "libsnapshot_snapuserd",
"libsnapuserd",
"liburing",
"libz",
],
- include_dirs: ["bionic/libc/kernel"],
+ include_dirs: [
+ "bionic/libc/kernel",
+ ".",
+ ],
header_libs: [
"libstorage_literals_headers",
"libfiemap_headers",
diff --git a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
index 46952c4..0d83f47 100644
--- a/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
+++ b/fs_mgr/libsnapshot/snapuserd/include/snapuserd/snapuserd_kernel.h
@@ -40,6 +40,7 @@
* multiple of 512 bytes. Hence these two constants.
*/
static constexpr uint32_t SECTOR_SHIFT = 9;
+static constexpr uint64_t SECTOR_SIZE = (1ULL << SECTOR_SHIFT);
static constexpr size_t BLOCK_SZ = 4096;
static constexpr size_t BLOCK_SHIFT = (__builtin_ffs(BLOCK_SZ) - 1);
diff --git a/fs_mgr/libsnapshot/snapuserd/testing/temp_device.h b/fs_mgr/libsnapshot/snapuserd/testing/temp_device.h
new file mode 100644
index 0000000..2a6d3ea
--- /dev/null
+++ b/fs_mgr/libsnapshot/snapuserd/testing/temp_device.h
@@ -0,0 +1,72 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+#pragma once
+
+#include <chrono>
+#include <string>
+
+#include <libdm/dm.h>
+
+namespace android {
+namespace snapshot {
+
+using android::dm::DeviceMapper;
+using android::dm::DmTable;
+
+class Tempdevice {
+ public:
+ Tempdevice(const std::string& name, const DmTable& table)
+ : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
+ valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5));
+ }
+ Tempdevice(Tempdevice&& other) noexcept
+ : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
+ other.valid_ = false;
+ }
+ ~Tempdevice() {
+ if (valid_) {
+ dm_.DeleteDeviceIfExists(name_);
+ }
+ }
+ bool Destroy() {
+ if (!valid_) {
+ return true;
+ }
+ valid_ = false;
+ return dm_.DeleteDeviceIfExists(name_);
+ }
+ const std::string& path() const { return path_; }
+ const std::string& name() const { return name_; }
+ bool valid() const { return valid_; }
+
+ Tempdevice(const Tempdevice&) = delete;
+ Tempdevice& operator=(const Tempdevice&) = delete;
+
+ Tempdevice& operator=(Tempdevice&& other) noexcept {
+ name_ = other.name_;
+ valid_ = other.valid_;
+ other.valid_ = false;
+ return *this;
+ }
+
+ private:
+ DeviceMapper& dm_;
+ std::string name_;
+ std::string path_;
+ bool valid_;
+};
+
+} // namespace snapshot
+} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
index 2dd2ec0..12d095a 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.cpp
@@ -280,20 +280,6 @@
return false;
}
- unique_fd fd(TEMP_FAILURE_RETRY(open(base_path_merge_.c_str(), O_RDONLY | O_CLOEXEC)));
- if (fd < 0) {
- SNAP_LOG(ERROR) << "Cannot open block device";
- return false;
- }
-
- uint64_t dev_sz = get_block_device_size(fd.get());
- if (!dev_sz) {
- SNAP_LOG(ERROR) << "Failed to find block device size: " << base_path_merge_;
- return false;
- }
-
- num_sectors_ = dev_sz >> SECTOR_SHIFT;
-
return ReadMetadata();
}
@@ -460,5 +446,21 @@
merge_thread_ = nullptr;
}
+uint64_t SnapshotHandler::GetNumSectors() const {
+ unique_fd fd(TEMP_FAILURE_RETRY(open(base_path_merge_.c_str(), O_RDONLY | O_CLOEXEC)));
+ if (fd < 0) {
+ SNAP_LOG(ERROR) << "Cannot open base path: " << base_path_merge_;
+ return false;
+ }
+
+ uint64_t dev_sz = get_block_device_size(fd.get());
+ if (!dev_sz) {
+ SNAP_LOG(ERROR) << "Failed to find block device size: " << base_path_merge_;
+ return false;
+ }
+
+ return dev_sz / SECTOR_SIZE;
+}
+
} // namespace snapshot
} // namespace android
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
index cdc38c0..5fe0a70 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h
@@ -109,7 +109,7 @@
const std::string& GetControlDevicePath() { return control_device_; }
const std::string& GetMiscName() { return misc_name_; }
- const uint64_t& GetNumSectors() { return num_sectors_; }
+ uint64_t GetNumSectors() const;
const bool& IsAttached() const { return attached_; }
void AttachControlDevice() { attached_ = true; }
@@ -202,8 +202,6 @@
unique_fd cow_fd_;
- uint64_t num_sectors_;
-
std::unique_ptr<CowReader> reader_;
// chunk_vec stores the pseudo mapping of sector
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
index c953f1a..f2585ea 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp
@@ -130,7 +130,12 @@
return Sendmsg(fd, "fail");
}
- auto retval = "success," + std::to_string(handler->snapuserd()->GetNumSectors());
+ auto num_sectors = handler->snapuserd()->GetNumSectors();
+ if (!num_sectors) {
+ return Sendmsg(fd, "fail");
+ }
+
+ auto retval = "success," + std::to_string(num_sectors);
return Sendmsg(fd, retval);
} else if (cmd == "start") {
// Message format:
diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
index efe0c14..16f9ed8 100644
--- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
+++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp
@@ -41,6 +41,7 @@
#include "handler_manager.h"
#include "snapuserd_core.h"
+#include "testing/temp_device.h"
DEFINE_string(force_config, "", "Force testing mode with iouring disabled");
@@ -54,49 +55,6 @@
using namespace android::dm;
using namespace std;
-class Tempdevice {
- public:
- Tempdevice(const std::string& name, const DmTable& table)
- : dm_(DeviceMapper::Instance()), name_(name), valid_(false) {
- valid_ = dm_.CreateDevice(name, table, &path_, std::chrono::seconds(5));
- }
- Tempdevice(Tempdevice&& other) noexcept
- : dm_(other.dm_), name_(other.name_), path_(other.path_), valid_(other.valid_) {
- other.valid_ = false;
- }
- ~Tempdevice() {
- if (valid_) {
- dm_.DeleteDeviceIfExists(name_);
- }
- }
- bool Destroy() {
- if (!valid_) {
- return true;
- }
- valid_ = false;
- return dm_.DeleteDeviceIfExists(name_);
- }
- const std::string& path() const { return path_; }
- const std::string& name() const { return name_; }
- bool valid() const { return valid_; }
-
- Tempdevice(const Tempdevice&) = delete;
- Tempdevice& operator=(const Tempdevice&) = delete;
-
- Tempdevice& operator=(Tempdevice&& other) noexcept {
- name_ = other.name_;
- valid_ = other.valid_;
- other.valid_ = false;
- return *this;
- }
-
- private:
- DeviceMapper& dm_;
- std::string name_;
- std::string path_;
- bool valid_;
-};
-
class SnapuserdTest : public ::testing::Test {
public:
bool SetupDefault();
@@ -582,7 +540,9 @@
base_loop_->device(), 1, use_iouring, false);
ASSERT_NE(handler, nullptr);
ASSERT_NE(handler->snapuserd(), nullptr);
+#ifdef __ANDROID__
ASSERT_NE(handler->snapuserd()->GetNumSectors(), 0);
+#endif
}
void SnapuserdTest::SetDeviceControlName() {
diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp
index fbed371..322bf1b 100644
--- a/fs_mgr/tests/fs_mgr_test.cpp
+++ b/fs_mgr/tests/fs_mgr_test.cpp
@@ -224,23 +224,32 @@
} // namespace
-TEST(fs_mgr, fs_mgr_parse_cmdline) {
- EXPECT_EQ(result_space, fs_mgr_parse_cmdline(cmdline));
+TEST(fs_mgr, ImportKernelCmdline) {
+ std::vector<std::pair<std::string, std::string>> result;
+ ImportKernelCmdlineFromString(
+ cmdline, [&](std::string key, std::string value) { result.emplace_back(key, value); });
+ EXPECT_THAT(result, ContainerEq(result_space));
}
-TEST(fs_mgr, fs_mgr_get_boot_config_from_kernel_cmdline) {
+TEST(fs_mgr, GetKernelCmdline) {
std::string content;
- for (const auto& entry : result_space) {
- static constexpr char androidboot[] = "androidboot.";
- if (!android::base::StartsWith(entry.first, androidboot)) continue;
- auto key = entry.first.substr(strlen(androidboot));
- EXPECT_TRUE(fs_mgr_get_boot_config_from_kernel(cmdline, key, &content)) << " for " << key;
- EXPECT_EQ(entry.second, content);
+ for (const auto& [key, value] : result_space) {
+ EXPECT_TRUE(GetKernelCmdlineFromString(cmdline, key, &content)) << " for " << key;
+ EXPECT_EQ(content, value);
}
- EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "vbmeta.avb_versio", &content));
- EXPECT_TRUE(content.empty()) << content;
- EXPECT_FALSE(fs_mgr_get_boot_config_from_kernel(cmdline, "nospace", &content));
- EXPECT_TRUE(content.empty()) << content;
+
+ const std::string kUnmodifiedToken = "<UNMODIFIED>";
+ content = kUnmodifiedToken;
+ EXPECT_FALSE(GetKernelCmdlineFromString(cmdline, "", &content));
+ EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";
+
+ content = kUnmodifiedToken;
+ EXPECT_FALSE(GetKernelCmdlineFromString(cmdline, "androidboot.vbmeta.avb_versio", &content));
+ EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";
+
+ content = kUnmodifiedToken;
+ EXPECT_FALSE(GetKernelCmdlineFromString(bootconfig, "androidboot.nospace", &content));
+ EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";
}
TEST(fs_mgr, ImportBootconfig) {
@@ -260,17 +269,15 @@
const std::string kUnmodifiedToken = "<UNMODIFIED>";
content = kUnmodifiedToken;
- EXPECT_FALSE(android::fs_mgr::GetBootconfigFromString(bootconfig, "", &content));
+ EXPECT_FALSE(GetBootconfigFromString(bootconfig, "", &content));
EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";
content = kUnmodifiedToken;
- EXPECT_FALSE(android::fs_mgr::GetBootconfigFromString(
- bootconfig, "androidboot.vbmeta.avb_versio", &content));
+ EXPECT_FALSE(GetBootconfigFromString(bootconfig, "androidboot.vbmeta.avb_versio", &content));
EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";
content = kUnmodifiedToken;
- EXPECT_FALSE(
- android::fs_mgr::GetBootconfigFromString(bootconfig, "androidboot.nospace", &content));
+ EXPECT_FALSE(GetBootconfigFromString(bootconfig, "androidboot.nospace", &content));
EXPECT_EQ(content, kUnmodifiedToken) << "output parameter shouldn't be overridden";
}
diff --git a/init/devices.cpp b/init/devices.cpp
index 6b8474e..e76786a 100644
--- a/init/devices.cpp
+++ b/init/devices.cpp
@@ -204,7 +204,7 @@
partition_map.emplace_back(map_pieces[0], map_pieces[1]);
}
};
- ImportKernelCmdline(parser);
+ android::fs_mgr::ImportKernelCmdline(parser);
android::fs_mgr::ImportBootconfig(parser);
return partition_map;
}();
diff --git a/init/property_service.cpp b/init/property_service.cpp
index 3557787..f5de17d 100644
--- a/init/property_service.cpp
+++ b/init/property_service.cpp
@@ -1342,7 +1342,7 @@
constexpr auto ANDROIDBOOT_PREFIX = "androidboot."sv;
static void ProcessKernelCmdline() {
- ImportKernelCmdline([&](const std::string& key, const std::string& value) {
+ android::fs_mgr::ImportKernelCmdline([&](const std::string& key, const std::string& value) {
if (StartsWith(key, ANDROIDBOOT_PREFIX)) {
InitPropertySet("ro.boot." + key.substr(ANDROIDBOOT_PREFIX.size()), value);
}
diff --git a/init/selinux.cpp b/init/selinux.cpp
index 6fb028b..f34474f 100644
--- a/init/selinux.cpp
+++ b/init/selinux.cpp
@@ -101,23 +101,14 @@
enum EnforcingStatus { SELINUX_PERMISSIVE, SELINUX_ENFORCING };
EnforcingStatus StatusFromProperty() {
- EnforcingStatus status = SELINUX_ENFORCING;
-
- ImportKernelCmdline([&](const std::string& key, const std::string& value) {
- if (key == "androidboot.selinux" && value == "permissive") {
- status = SELINUX_PERMISSIVE;
- }
- });
-
- if (status == SELINUX_ENFORCING) {
- std::string value;
- if (android::fs_mgr::GetBootconfig("androidboot.selinux", &value) &&
- value == "permissive") {
- status = SELINUX_PERMISSIVE;
- }
+ std::string value;
+ if (android::fs_mgr::GetKernelCmdline("androidboot.selinux", &value) && value == "permissive") {
+ return SELINUX_PERMISSIVE;
}
-
- return status;
+ if (android::fs_mgr::GetBootconfig("androidboot.selinux", &value) && value == "permissive") {
+ return SELINUX_PERMISSIVE;
+ }
+ return SELINUX_ENFORCING;
}
bool IsEnforcing() {
diff --git a/init/util.cpp b/init/util.cpp
index b34d45d..e760a59 100644
--- a/init/util.cpp
+++ b/init/util.cpp
@@ -242,18 +242,6 @@
return -1;
}
-void ImportKernelCmdline(const std::function<void(const std::string&, const std::string&)>& fn) {
- std::string cmdline;
- android::base::ReadFileToString("/proc/cmdline", &cmdline);
-
- for (const auto& entry : android::base::Split(android::base::Trim(cmdline), " ")) {
- std::vector<std::string> pieces = android::base::Split(entry, "=");
- if (pieces.size() == 2) {
- fn(pieces[0], pieces[1]);
- }
- }
-}
-
bool make_dir(const std::string& path, mode_t mode) {
std::string secontext;
if (SelabelLookupFileContext(path, mode, &secontext) && !secontext.empty()) {
diff --git a/init/util.h b/init/util.h
index 0b0ef63..2d02182 100644
--- a/init/util.h
+++ b/init/util.h
@@ -53,8 +53,7 @@
Result<uid_t> DecodeUid(const std::string& name);
bool mkdir_recursive(const std::string& pathname, mode_t mode);
-int wait_for_file(const char *filename, std::chrono::nanoseconds timeout);
-void ImportKernelCmdline(const std::function<void(const std::string&, const std::string&)>&);
+int wait_for_file(const char* filename, std::chrono::nanoseconds timeout);
bool make_dir(const std::string& path, mode_t mode);
bool is_dir(const char* pathname);
Result<std::string> ExpandProps(const std::string& src);
diff --git a/trusty/line-coverage/Android.bp b/trusty/line-coverage/Android.bp
new file mode 100644
index 0000000..36a73aa
--- /dev/null
+++ b/trusty/line-coverage/Android.bp
@@ -0,0 +1,36 @@
+// Copyright (C) 2023 The Android Open-Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_library {
+ name: "libtrusty_line_coverage",
+ vendor_available: true,
+ srcs: [
+ "coverage.cpp",
+ ],
+ export_include_dirs: [
+ "include",
+ ],
+ shared_libs: [
+ "libbase",
+ "libext2_uuid",
+ "liblog",
+ "libdmabufheap",
+ "libtrusty",
+ ],
+}
+
diff --git a/trusty/line-coverage/coverage.cpp b/trusty/line-coverage/coverage.cpp
new file mode 100644
index 0000000..57b7025
--- /dev/null
+++ b/trusty/line-coverage/coverage.cpp
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2023 The Android Open Sourete 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.
+ */
+
+#define LOG_TAG "line-coverage"
+
+#include <BufferAllocator/BufferAllocator.h>
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/unique_fd.h>
+#include <assert.h>
+#include <log/log.h>
+#include <stdio.h>
+#include <sys/mman.h>
+#include <sys/uio.h>
+#include <trusty/line-coverage/coverage.h>
+#include <trusty/line-coverage/tipc.h>
+#include <trusty/tipc.h>
+#include <iostream>
+
+#define LINE_COVERAGE_CLIENT_PORT "com.android.trusty.linecoverage.client"
+
+struct control {
+ /* Written by controller, read by instrumented TA */
+ uint64_t cntrl_flags;
+
+ /* Written by instrumented TA, read by controller */
+ uint64_t oper_flags;
+ uint64_t write_buffer_start_count;
+ uint64_t write_buffer_complete_count;
+};
+
+namespace android {
+namespace trusty {
+namespace line_coverage {
+
+using ::android::base::ErrnoError;
+using ::android::base::Error;
+using ::std::string;
+
+static inline uintptr_t RoundPageUp(uintptr_t val) {
+ return (val + (PAGE_SIZE - 1)) & ~(PAGE_SIZE - 1);
+}
+
+CoverageRecord::CoverageRecord(string tipc_dev, struct uuid* uuid)
+ : tipc_dev_(std::move(tipc_dev)),
+ coverage_srv_fd_(-1),
+ uuid_(*uuid),
+ record_len_(0),
+ shm_(NULL),
+ shm_len_(0) {}
+
+CoverageRecord::~CoverageRecord() {
+ if (shm_) {
+ munmap((void*)shm_, shm_len_);
+ }
+}
+
+volatile void *CoverageRecord::getShm() {
+ if(!IsOpen()) {
+ fprintf(stderr, "Warning! SHM is NULL!\n");
+ }
+ return shm_;
+}
+
+Result<void> CoverageRecord::Rpc(struct line_coverage_client_req* req, \
+ int req_fd, \
+ struct line_coverage_client_resp* resp) {
+ int rc;
+
+ if (req_fd < 0) {
+ rc = write(coverage_srv_fd_, req, sizeof(*req));
+ } else {
+ iovec iov = {
+ .iov_base = req,
+ .iov_len = sizeof(*req),
+ };
+
+ trusty_shm shm = {
+ .fd = req_fd,
+ .transfer = TRUSTY_SHARE,
+ };
+
+ rc = tipc_send(coverage_srv_fd_, &iov, 1, &shm, 1);
+ }
+
+ if (rc != (int)sizeof(*req)) {
+ return ErrnoError() << "failed to send request to coverage server: ";
+ }
+
+ rc = read(coverage_srv_fd_, resp, sizeof(*resp));
+ if (rc != (int)sizeof(*resp)) {
+ return ErrnoError() << "failed to read reply from coverage server: ";
+ }
+
+ if (resp->hdr.cmd != (req->hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT)) {
+ return ErrnoError() << "unknown response cmd: " << resp->hdr.cmd;
+ }
+
+ return {};
+}
+
+Result<void> CoverageRecord::Open(int fd) {
+ struct line_coverage_client_req req;
+ struct line_coverage_client_resp resp;
+
+ if (shm_) {
+ return {}; /* already initialized */
+ }
+
+ coverage_srv_fd_= fd;
+
+ req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_OPEN;
+ req.open_args.uuid = uuid_;
+ auto ret = Rpc(&req, -1, &resp);
+ if (!ret.ok()) {
+ return Error() << "failed to open coverage client: " << ret.error();
+ }
+ record_len_ = resp.open_args.record_len;
+ shm_len_ = RoundPageUp(record_len_);
+
+ BufferAllocator allocator;
+
+ fd = allocator.Alloc("system", shm_len_);
+ if (fd < 0) {
+ return ErrnoError() << "failed to create dmabuf of size " << shm_len_
+ << " err code: " << fd;
+ }
+ unique_fd dma_buf(fd);
+
+ void* shm = mmap(0, shm_len_, PROT_READ | PROT_WRITE, MAP_SHARED, dma_buf, 0);
+ if (shm == MAP_FAILED) {
+ return ErrnoError() << "failed to map memfd: ";
+ }
+
+ req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD;
+ req.share_record_args.shm_len = shm_len_;
+ ret = Rpc(&req, dma_buf, &resp);
+ if (!ret.ok()) {
+ return Error() << "failed to send shared memory: " << ret.error();
+ }
+
+ shm_ = shm;
+
+ req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_OPEN;
+ req.open_args.uuid = uuid_;
+ ret = Rpc(&req, -1, &resp);
+ if (!ret.ok()) {
+ return Error() << "failed to open coverage client: " << ret.error();
+ }
+
+ return {};
+}
+
+bool CoverageRecord::IsOpen() {
+ return shm_;
+}
+
+Result<void> CoverageRecord::SaveFile(const std::string& filename) {
+ if(!IsOpen()) {
+ return ErrnoError() << "Warning! SHM is NULL!";
+ }
+ android::base::unique_fd output_fd(TEMP_FAILURE_RETRY(creat(filename.c_str(), 00644)));
+ if (!output_fd.ok()) {
+ return ErrnoError() << "Could not open output file";
+ }
+
+ uintptr_t* begin = (uintptr_t*)((char *)shm_ + sizeof(struct control));
+ bool ret = WriteFully(output_fd, begin, record_len_);
+ if(!ret) {
+ fprintf(stderr, "Coverage write to file failed\n");
+ }
+
+ return {};
+}
+
+} // namespace line_coverage
+} // namespace trusty
+} // namespace android
diff --git a/trusty/line-coverage/include/trusty/line-coverage/coverage.h b/trusty/line-coverage/include/trusty/line-coverage/coverage.h
new file mode 100644
index 0000000..53901be
--- /dev/null
+++ b/trusty/line-coverage/include/trusty/line-coverage/coverage.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <optional>
+#include <string>
+
+#include <android-base/result.h>
+#include <android-base/unique_fd.h>
+#include <stdint.h>
+#include <trusty/line-coverage/tipc.h>
+
+namespace android {
+namespace trusty {
+namespace line_coverage {
+
+using android::base::Result;
+using android::base::unique_fd;
+
+class CoverageRecord {
+ public:
+ CoverageRecord(std::string tipc_dev, struct uuid* uuid);
+
+ ~CoverageRecord();
+ Result<void> Open(int fd);
+ bool IsOpen();
+ Result<void> SaveFile(const std::string& filename);
+ volatile void* getShm();
+
+ private:
+ Result<void> Rpc(struct line_coverage_client_req* req, \
+ int req_fd, \
+ struct line_coverage_client_resp* resp);
+
+ Result<std::pair<size_t, size_t>> GetRegionBounds(uint32_t region_type);
+
+ std::string tipc_dev_;
+ int coverage_srv_fd_;
+ struct uuid uuid_;
+ size_t record_len_;
+ volatile void* shm_;
+ size_t shm_len_;
+};
+
+} // namespace line_coverage
+} // namespace trusty
+} // namespace android
diff --git a/trusty/line-coverage/include/trusty/line-coverage/tipc.h b/trusty/line-coverage/include/trusty/line-coverage/tipc.h
new file mode 100644
index 0000000..20e855c
--- /dev/null
+++ b/trusty/line-coverage/include/trusty/line-coverage/tipc.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* This file needs to be kept in-sync with its counterpart on Trusty side */
+
+#pragma once
+
+#include <stdint.h>
+#include <trusty/line-coverage/uuid.h>
+
+
+#define LINE_COVERAGE_CLIENT_PORT "com.android.trusty.linecoverage.client"
+
+/**
+ * enum line_coverage_client_cmd - command identifiers for coverage client interface
+ * @LINE_COVERAGE_CLIENT_CMD_RESP_BIT: response bit set as part of response
+ * @LINE_COVERAGE_CLIENT_CMD_SHIFT: number of bits used by response bit
+ * @LINE_COVERAGE_CLIENT_CMD_OPEN: command to open coverage record
+ * @LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD: command to register a shared memory region
+ * where coverage record will be written to
+ */
+enum line_coverage_client_cmd {
+ LINE_COVERAGE_CLIENT_CMD_RESP_BIT = 1U,
+ LINE_COVERAGE_CLIENT_CMD_SHIFT = 1U,
+ LINE_COVERAGE_CLIENT_CMD_OPEN = (1U << LINE_COVERAGE_CLIENT_CMD_SHIFT),
+ LINE_COVERAGE_CLIENT_CMD_SHARE_RECORD = (2U << LINE_COVERAGE_CLIENT_CMD_SHIFT),
+ LINE_COVERAGE_CLIENT_CMD_SEND_LIST = (3U << LINE_COVERAGE_CLIENT_CMD_SHIFT),
+};
+
+/**
+ * struct line_coverage_client_hdr - header for coverage client messages
+ * @cmd: command identifier
+ *
+ * Note that no messages return a status code. Any error on the server side
+ * results in the connection being closed. So, operations can be assumed to be
+ * successful if they return a response.
+ */
+struct line_coverage_client_hdr {
+ uint32_t cmd;
+};
+
+/**
+ * struct line_coverage_client_open_req - arguments for request to open coverage
+ * record
+ * @uuid: UUID of target TA
+ *
+ * There is one coverage record per TA. @uuid is used to identify both the TA
+ * and corresponding coverage record.
+ */
+struct line_coverage_client_open_req {
+ struct uuid uuid;
+};
+
+/**
+ * struct line_coverage_client_open_resp - arguments for response to open coverage
+ * record
+ * @record_len: length of coverage record that will be emitted by target TA
+ *
+ * Shared memory allocated for this coverage record must larger than
+ * @record_len.
+ */
+struct line_coverage_client_open_resp {
+ uint32_t record_len;
+};
+
+/**
+ * struct line_coverage_client_send_list_resp - arguments for response to send list
+ * record
+ * @uuid: UUID of TA that connected to aggregator
+ */
+struct line_coverage_client_send_list_resp {
+ struct uuid uuid;
+};
+
+/**
+ * struct line_coverage_client_send_list_resp - arguments for response to send list
+ * record
+ * @index: index of the list being requested
+ */
+struct line_coverage_client_send_list_req {
+ uint32_t index;
+};
+
+/**
+ * struct line_coverage_client_share_record_req - arguments for request to share
+ * memory for coverage record
+ * @shm_len: length of memory region being shared
+ *
+ * A handle to a memory region must be sent along with this message. This memory
+ * is used to store coverage record.
+ *
+ * Upon success, this memory region can be assumed to be shared between the
+ * client and target TA.
+ */
+struct line_coverage_client_share_record_req {
+ uint32_t shm_len;
+};
+
+/**
+ * struct line_coverage_client_req - structure for a coverage client request
+ * @hdr: message header
+ * @open_args: arguments for %COVERAGE_CLIENT_CMD_OPEN request
+ * @share_record_args: arguments for %COVERAGE_CLIENT_CMD_SHARE_RECORD request
+ * @index: arguments for %COVERAGE_CLIENT_CMD_SHARE_RECORD request
+ */
+struct line_coverage_client_req {
+ struct line_coverage_client_hdr hdr;
+ union {
+ struct line_coverage_client_open_req open_args;
+ struct line_coverage_client_share_record_req share_record_args;
+ struct line_coverage_client_send_list_req send_list_args;
+ };
+};
+
+/**
+ * struct line_coverage_client_resp - structure for a coverage client response
+ * @hdr: message header
+ * @open_args: arguments for %COVERAGE_CLIENT_CMD_OPEN response
+ * @send_list_args: arguments for %COVERAGE_CLIENT_CMD_SHARE_RECORD response
+ */
+struct line_coverage_client_resp {
+ struct line_coverage_client_hdr hdr;
+ union {
+ struct line_coverage_client_open_resp open_args;
+ struct line_coverage_client_send_list_resp send_list_args;
+ };
+};
diff --git a/trusty/line-coverage/include/trusty/line-coverage/uuid.h b/trusty/line-coverage/include/trusty/line-coverage/uuid.h
new file mode 100644
index 0000000..1873980
--- /dev/null
+++ b/trusty/line-coverage/include/trusty/line-coverage/uuid.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <stdint.h>
+#include <string.h>
+
+#define UUCMP(u1, u2) if (u1 != u2) return u1 < u2
+
+struct uuid {
+ uint32_t time_low;
+ uint16_t time_mid;
+ uint16_t time_hi_and_version;
+ uint8_t clock_seq_and_node[8];
+
+ bool operator<(const struct uuid& rhs) const
+ {
+ UUCMP(time_low, rhs.time_low);
+ UUCMP(time_mid, rhs.time_mid);
+ UUCMP(time_hi_and_version, rhs.time_hi_and_version);
+ return memcmp(clock_seq_and_node, rhs.clock_seq_and_node, 8);
+ }
+};
diff --git a/trusty/utils/coverage-controller/Android.bp b/trusty/utils/coverage-controller/Android.bp
new file mode 100644
index 0000000..1aa88cc
--- /dev/null
+++ b/trusty/utils/coverage-controller/Android.bp
@@ -0,0 +1,34 @@
+// Copyright (C) 2023 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+
+package {
+ default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+cc_binary {
+ name: "coverage-controller",
+ vendor: true,
+
+ srcs: ["controller.cpp"],
+ shared_libs: [
+ "libc",
+ "liblog",
+ "libbase",
+ "libdmabufheap",
+ ],
+ static_libs: [
+ "libtrusty",
+ "libtrusty_line_coverage",
+ ],
+}
diff --git a/trusty/utils/coverage-controller/controller.cpp b/trusty/utils/coverage-controller/controller.cpp
new file mode 100644
index 0000000..730c010
--- /dev/null
+++ b/trusty/utils/coverage-controller/controller.cpp
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <getopt.h>
+#include <trusty/line-coverage/coverage.h>
+#include <trusty/tipc.h>
+#include <array>
+#include <memory>
+#include <vector>
+
+#include "controller.h"
+
+#define READ_ONCE(x) (*((volatile __typeof__(x) *) &(x)))
+#define WRITE_ONCE(x, val) (*((volatile __typeof__(val) *) &(x)) = (val))
+
+namespace android {
+namespace trusty {
+namespace controller {
+
+using ::android::trusty::line_coverage::CoverageRecord;
+
+void Controller::run(std::string output_dir) {
+ connectCoverageServer();
+ struct control *control;
+ uint64_t complete_cnt = 0, start_cnt = 0, flags;
+
+ while(1) {
+ setUpShm();
+
+ for (int index = 0; index < record_list_.size(); index++) {
+ control = (struct control *)record_list_[index]->getShm();
+ start_cnt = READ_ONCE((control->write_buffer_start_count));
+ complete_cnt = READ_ONCE(control->write_buffer_complete_count);
+ flags = READ_ONCE(control->cntrl_flags);
+
+ if (complete_cnt != counters[index] && start_cnt == complete_cnt) {
+ WRITE_ONCE(control->cntrl_flags, FLAG_NONE);
+ std::string fmt = "/%d.%lu.profraw";
+ int sz = std::snprintf(nullptr, 0, fmt.c_str(), index, counters[index]);
+ std::string filename(sz+1, '.');
+ std::sprintf(filename.data(), fmt.c_str(), index, counters[index]);
+ filename.insert(0, output_dir);
+ android::base::Result<void> res = record_list_[index]->SaveFile(filename);
+ counters[index]++;
+ }
+ if(complete_cnt == counters[index] &&
+ !(flags & FLAG_RUN)) {
+ flags |= FLAG_RUN;
+ WRITE_ONCE(control->cntrl_flags, flags);
+ }
+ }
+ }
+}
+
+void Controller::connectCoverageServer() {
+ coverage_srv_fd = tipc_connect(TIPC_DEV, LINE_COVERAGE_CLIENT_PORT);
+ if (coverage_srv_fd < 0) {
+ fprintf(stderr, \
+ "Error: Failed to connect to Trusty coverage server: %d\n", coverage_srv_fd);
+ return;
+ }
+}
+
+void Controller::setUpShm() {
+ struct line_coverage_client_req req;
+ struct line_coverage_client_resp resp;
+ uint32_t cur_index = record_list_.size();
+ struct uuid zero_uuid = {0, 0, 0, { 0 }};
+ req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST;
+ int rc = write(coverage_srv_fd, &req, sizeof(req));
+ if (rc != (int)sizeof(req)) {
+ fprintf(stderr, "failed to send request to coverage server: %d\n", rc);
+ return;
+ }
+
+ while(1) {
+ rc = read(coverage_srv_fd, &resp, sizeof(resp));
+ if (rc != (int)sizeof(resp)) {
+ fprintf(stderr, "failed to read reply from coverage server:: %d\n", rc);
+ }
+
+ if (resp.hdr.cmd == (req.hdr.cmd | LINE_COVERAGE_CLIENT_CMD_RESP_BIT)) {
+ if (!memcmp(&resp.send_list_args.uuid, &zero_uuid, sizeof(struct uuid))) {
+ break;
+ }
+ if(uuid_set_.find(resp.send_list_args.uuid) == uuid_set_.end()) {
+ uuid_set_.insert(resp.send_list_args.uuid);
+ record_list_.push_back(std::make_unique<CoverageRecord>(TIPC_DEV,
+ &resp.send_list_args.uuid));
+ counters.push_back(0);
+ }
+ }
+ else {
+ fprintf(stderr, "Unknown response header\n");
+ }
+ cur_index++;
+ req.hdr.cmd = LINE_COVERAGE_CLIENT_CMD_SEND_LIST;
+ req.send_list_args.index = cur_index;
+ int rc = write(coverage_srv_fd, &req, sizeof(req));
+ if (rc != (int)sizeof(req)) {
+ fprintf(stderr, "failed to send request to coverage server: %d\n", rc);
+ }
+ }
+
+ for(int ind = 0 ; ind < record_list_.size() ; ind++) {
+ record_list_[ind]->Open(coverage_srv_fd);
+ }
+}
+
+
+} // namespace controller
+} // namespace trusty
+} // namespace android
+
+int main(int argc, char* argv[]) {
+
+ std::string optarg = "";
+ do {
+ int c;
+ c = getopt(argc, argv, "o");
+
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'o':
+ break;
+ default:
+ fprintf(stderr, "usage: %s -o [output_directory]\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+ } while (1);
+
+ if (argc > optind + 1) {
+ fprintf(stderr, "%s: too many arguments\n", argv[0]);
+ exit(EXIT_FAILURE);
+ }
+
+ if (argc > optind) {
+ optarg = argv[optind];
+ }
+ if (optarg.size()==0) {
+ optarg = "data/local/tmp";
+ }
+
+ android::trusty::controller::Controller cur;
+ cur.run(optarg);
+
+ return EXIT_SUCCESS;
+}
\ No newline at end of file
diff --git a/trusty/utils/coverage-controller/controller.h b/trusty/utils/coverage-controller/controller.h
new file mode 100644
index 0000000..b771c16
--- /dev/null
+++ b/trusty/utils/coverage-controller/controller.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <trusty/line-coverage/coverage.h>
+#include <array>
+#include <memory>
+#include <vector>
+#include <set>
+
+#define TIPC_DEV "/dev/trusty-ipc-dev0"
+#define TEST_SRV_PORT "com.android.trusty.sancov.test.srv"
+#define TEST_SRV_MODULE "srv.syms.elf"
+
+#define FLAG_NONE 0x0
+#define FLAG_RUN 0x1
+#define FLAG_TOGGLE_CLEAR 0x2
+
+struct control {
+ /* Written by controller, read by instrumented TA */
+ uint64_t cntrl_flags;
+
+ /* Written by instrumented TA, read by controller */
+ uint64_t oper_flags;
+ uint64_t write_buffer_start_count;
+ uint64_t write_buffer_complete_count;
+};
+
+namespace android {
+namespace trusty {
+namespace controller {
+
+class Controller {
+ public:
+ public:
+ void run(std::string output_dir);
+
+ private:
+ std::vector<std::unique_ptr<line_coverage::CoverageRecord>>record_list_;
+ std::set<struct uuid>uuid_set_;
+ std::vector<uint64_t> counters;
+ int coverage_srv_fd;
+
+ void connectCoverageServer();
+ void setUpShm();
+};
+
+} // namespace controller
+} // namespace trusty
+} // namespace android