Merge "Add core scoped storage host test to test mapping."
diff --git a/Android.bp b/Android.bp
index 593dd27..4852fe4 100644
--- a/Android.bp
+++ b/Android.bp
@@ -89,7 +89,7 @@
export_aidl_headers: true,
},
whole_static_libs: [
- "libincremental_aidl-cpp",
+ "libincremental_aidl-unstable-cpp",
],
}
diff --git a/EncryptInplace.cpp b/EncryptInplace.cpp
index 9d304da..bdb2da7 100644
--- a/EncryptInplace.cpp
+++ b/EncryptInplace.cpp
@@ -49,11 +49,7 @@
/* aligned 32K writes tends to make flash happy.
* SD card association recommends it.
*/
-#ifndef CONFIG_HW_DISK_ENCRYPTION
#define BLOCKS_AT_A_TIME 8
-#else
-#define BLOCKS_AT_A_TIME 1024
-#endif
struct encryptGroupsData {
int realfd;
@@ -205,9 +201,16 @@
data->count = 0;
for (block = 0; block < block_count; block++) {
- int used = (aux_info.bg_desc[i].bg_flags & EXT4_BG_BLOCK_UNINIT)
- ? 0
- : bitmap_get_bit(block_bitmap, block);
+ int used;
+
+ if (aux_info.bg_desc[i].bg_flags & EXT4_BG_BLOCK_UNINIT) {
+ // In block groups with an uninitialized block bitmap, we only
+ // need to encrypt the backup superblock (if one is present).
+ used = (ext4_bg_has_super_block(i) && block < 1 + aux_info.bg_desc_blocks);
+ } else {
+ used = bitmap_get_bit(block_bitmap, block);
+ }
+
update_progress(data, used);
if (used) {
if (data->count == 0) {
diff --git a/FsCrypt.cpp b/FsCrypt.cpp
index e21524a..45edc9d 100644
--- a/FsCrypt.cpp
+++ b/FsCrypt.cpp
@@ -269,10 +269,9 @@
// HEH as default was always a mistake. Use the libfscrypt default (CTS)
// for devices launching on versions above Android 10.
auto first_api_level = GetFirstApiLevel();
- constexpr uint64_t pre_gki_level = 29;
auto filenames_mode =
android::base::GetProperty("ro.crypto.volume.filenames_mode",
- first_api_level > pre_gki_level ? "" : "aes-256-heh");
+ first_api_level > __ANDROID_API_Q__ ? "" : "aes-256-heh");
auto options_string = android::base::GetProperty("ro.crypto.volume.options",
contents_mode + ":" + filenames_mode);
if (!ParseOptionsForApiLevel(first_api_level, options_string, options)) {
@@ -792,6 +791,11 @@
static bool prepare_subdirs(const std::string& action, const std::string& volume_uuid,
userid_t user_id, int flags) {
+ // TODO(b/141677108): Remove this & make it the default behavior
+ if (android::base::GetProperty("ro.vold.level_from_user", "0") == "1") {
+ flags |= android::os::IVold::STORAGE_FLAG_LEVEL_FROM_USER;
+ }
+
if (0 != android::vold::ForkExecvp(
std::vector<std::string>{prepare_subdirs_path, action, volume_uuid,
std::to_string(user_id), std::to_string(flags)})) {
diff --git a/MetadataCrypt.cpp b/MetadataCrypt.cpp
index ca2813d..c61132c 100644
--- a/MetadataCrypt.cpp
+++ b/MetadataCrypt.cpp
@@ -283,10 +283,9 @@
return false;
}
- constexpr unsigned int pre_gki_level = 29;
unsigned int options_format_version = android::base::GetUintProperty<unsigned int>(
"ro.crypto.dm_default_key.options_format.version",
- (GetFirstApiLevel() <= pre_gki_level ? 1 : 2));
+ (GetFirstApiLevel() <= __ANDROID_API_Q__ ? 1 : 2));
CryptoOptions options;
if (options_format_version == 1) {
diff --git a/NetlinkHandler.cpp b/NetlinkHandler.cpp
index d180a95..2231cd1 100644
--- a/NetlinkHandler.cpp
+++ b/NetlinkHandler.cpp
@@ -33,10 +33,6 @@
return this->startListener();
}
-int NetlinkHandler::stop() {
- return this->stopListener();
-}
-
void NetlinkHandler::onEvent(NetlinkEvent* evt) {
VolumeManager* vm = VolumeManager::Instance();
const char* subsys = evt->getSubsystem();
diff --git a/NetlinkHandler.h b/NetlinkHandler.h
index 8af7575..d779eae 100644
--- a/NetlinkHandler.h
+++ b/NetlinkHandler.h
@@ -25,7 +25,6 @@
virtual ~NetlinkHandler();
int start(void);
- int stop(void);
protected:
virtual void onEvent(NetlinkEvent* evt);
diff --git a/NetlinkManager.cpp b/NetlinkManager.cpp
index aacf4b9..56d9df6 100644
--- a/NetlinkManager.cpp
+++ b/NetlinkManager.cpp
@@ -90,19 +90,3 @@
close(mSock);
return -1;
}
-
-int NetlinkManager::stop() {
- int status = 0;
-
- if (mHandler->stop()) {
- PLOG(ERROR) << "Unable to stop NetlinkHandler";
- status = -1;
- }
- delete mHandler;
- mHandler = NULL;
-
- close(mSock);
- mSock = -1;
-
- return status;
-}
diff --git a/NetlinkManager.h b/NetlinkManager.h
index e31fc2e..c4f3ab5 100644
--- a/NetlinkManager.h
+++ b/NetlinkManager.h
@@ -35,7 +35,6 @@
virtual ~NetlinkManager();
int start();
- int stop();
void setBroadcaster(SocketListener* sl) { mBroadcaster = sl; }
SocketListener* getBroadcaster() { return mBroadcaster; }
diff --git a/OWNERS b/OWNERS
index bab0ef6..deeceb7 100644
--- a/OWNERS
+++ b/OWNERS
@@ -4,3 +4,4 @@
ebiggers@google.com
drosen@google.com
zezeozue@google.com
+maco@google.com
diff --git a/Utils.cpp b/Utils.cpp
index a9b7440..17921e8 100644
--- a/Utils.cpp
+++ b/Utils.cpp
@@ -416,7 +416,32 @@
return OK;
}
-status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid) {
+int SetAttrs(const std::string& path, unsigned int attrs) {
+ unsigned long flags;
+ android::base::unique_fd fd(
+ TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_NONBLOCK | O_CLOEXEC)));
+
+ if (fd == -1) {
+ PLOG(ERROR) << "Failed to open " << path;
+ return -1;
+ }
+
+ if (ioctl(fd, FS_IOC_GETFLAGS, (void*)&flags)) {
+ PLOG(ERROR) << "Failed to get flags for " << path;
+ return -1;
+ }
+
+ if ((flags & attrs) == attrs) return 0;
+ flags |= attrs;
+ if (ioctl(fd, FS_IOC_SETFLAGS, (void*)&flags)) {
+ PLOG(ERROR) << "Failed to set flags for " << path << "(0x" << std::hex << attrs << ")";
+ return -1;
+ }
+ return 0;
+}
+
+status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid,
+ unsigned int attrs) {
std::lock_guard<std::mutex> lock(kSecurityLock);
const char* cpath = path.c_str();
@@ -434,6 +459,9 @@
freecon(secontext);
}
+ if (res) return -errno;
+ if (attrs) res = SetAttrs(path, attrs);
+
if (res == 0) {
return OK;
} else {
diff --git a/Utils.h b/Utils.h
index 0def28b..769161a 100644
--- a/Utils.h
+++ b/Utils.h
@@ -66,7 +66,8 @@
bool fixupExisting);
/* fs_prepare_dir wrapper that creates with SELinux context */
-status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid);
+status_t PrepareDir(const std::string& path, mode_t mode, uid_t uid, gid_t gid,
+ unsigned int attrs = 0);
/* Really unmounts the path, killing active processes along the way */
status_t ForceUnmount(const std::string& path);
diff --git a/VolumeManager.cpp b/VolumeManager.cpp
index 8319b24..fca953e 100644
--- a/VolumeManager.cpp
+++ b/VolumeManager.cpp
@@ -198,16 +198,6 @@
return 0;
}
-int VolumeManager::stop() {
- CHECK(!mInternalEmulatedVolumes.empty());
- for (const auto& vol : mInternalEmulatedVolumes) {
- vol->destroy();
- }
- mInternalEmulatedVolumes.clear();
-
- return 0;
-}
-
void VolumeManager::handleBlockEvent(NetlinkEvent* evt) {
std::lock_guard<std::mutex> lock(mLock);
diff --git a/VolumeManager.h b/VolumeManager.h
index 23a7fe0..614a5f4 100644
--- a/VolumeManager.h
+++ b/VolumeManager.h
@@ -56,7 +56,6 @@
android::sp<android::os::IVoldListener> getListener() const { return mListener; }
int start();
- int stop();
void handleBlockEvent(NetlinkEvent* evt);
diff --git a/bench/inodeop_bench/Android.bp b/bench/inodeop_bench/Android.bp
new file mode 100644
index 0000000..a01ddd1
--- /dev/null
+++ b/bench/inodeop_bench/Android.bp
@@ -0,0 +1,19 @@
+/*
+ * 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.
+ */
+cc_binary {
+ name: "inodeop_bench",
+ srcs: ["inodeop_bench.cpp"],
+}
diff --git a/bench/inodeop_bench/OWNERS b/bench/inodeop_bench/OWNERS
new file mode 100644
index 0000000..3ced4a1
--- /dev/null
+++ b/bench/inodeop_bench/OWNERS
@@ -0,0 +1,3 @@
+balsini@google.com
+stefanoduo@google.com
+zezeozue@google.com
diff --git a/bench/inodeop_bench/inodeop_bench.cpp b/bench/inodeop_bench/inodeop_bench.cpp
new file mode 100644
index 0000000..cf38e4c
--- /dev/null
+++ b/bench/inodeop_bench/inodeop_bench.cpp
@@ -0,0 +1,424 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include <chrono>
+#include <functional>
+#include <iostream>
+#include <ratio>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <dirent.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+static constexpr char VERSION[] = "0";
+
+// Self-contained class for collecting and reporting benchmark metrics
+// (currently only execution time).
+class Collector {
+ using time_point = std::chrono::time_point<std::chrono::steady_clock>;
+ using time_unit = std::chrono::duration<double, std::milli>;
+
+ struct Metric {
+ std::string workload;
+ time_unit exec_time;
+ Metric(const std::string& workload, const time_unit& exec_time)
+ : workload(workload), exec_time(exec_time) {}
+ };
+
+ static constexpr char TIME_UNIT[] = "ms";
+ static constexpr char VERSION[] = "0";
+ std::vector<Metric> metrics;
+ time_point reset_time;
+
+ public:
+ Collector() { reset(); }
+
+ void reset() { reset_time = std::chrono::steady_clock::now(); }
+
+ void collect_metric(const std::string& workload) {
+ auto elapsed = std::chrono::steady_clock::now() - reset_time;
+ metrics.emplace_back(workload, std::chrono::duration_cast<time_unit>(elapsed));
+ }
+
+ void report_metrics() {
+ for (const Metric& metric : metrics)
+ std::cout << VERSION << ";" << metric.workload << ";" << metric.exec_time.count() << ";"
+ << TIME_UNIT << std::endl;
+ }
+};
+
+struct Command {
+ static constexpr char CREATE[] = "create";
+ static constexpr char DELETE[] = "delete";
+ static constexpr char MOVE[] = "move";
+ static constexpr char HARDLINK[] = "hardlink";
+ static constexpr char SYMLINK[] = "symlink";
+ static constexpr char READDIR[] = "readdir";
+ std::string workload;
+ std::string from_dir;
+ std::string from_basename;
+ std::string to_dir;
+ std::string to_basename;
+ bool drop_state;
+ int n_file;
+
+ Command() { reset(); }
+
+ std::string to_string() const {
+ std::stringstream string_repr;
+ string_repr << "Command {\n";
+ string_repr << "\t.workload = " << workload << ",\n";
+ string_repr << "\t.from_dir = " << from_dir << ",\n";
+ string_repr << "\t.from_basename = " << from_basename << ",\n";
+ string_repr << "\t.to_dir = " << to_dir << ",\n";
+ string_repr << "\t.to_basename = " << to_basename << ",\n";
+ string_repr << "\t.drop_state = " << drop_state << ",\n";
+ string_repr << "\t.n_file = " << n_file << "\n";
+ string_repr << "}\n";
+ return string_repr.str();
+ }
+
+ void reset() {
+ workload = "";
+ from_dir = to_dir = "./";
+ from_basename = "from_file";
+ to_basename = "to_file";
+ drop_state = true;
+ n_file = 0;
+ }
+};
+
+void print_version() {
+ std::cout << VERSION << std::endl;
+}
+
+void print_commands(const std::vector<Command>& commands) {
+ for (const Command& command : commands) std::cout << command.to_string();
+}
+
+void usage(std::ostream& ostr, const std::string& program_name) {
+ Command command;
+
+ ostr << "Usage: " << program_name << " [global_options] {[workload_options] -w WORKLOAD_T}\n";
+ ostr << "WORKLOAD_T = {" << Command::CREATE << ", " << Command::DELETE << ", " << Command::MOVE
+ << ", " << Command::HARDLINK << ", " << Command::SYMLINK << "}\n";
+ ostr << "Global options\n";
+ ostr << "\t-v: Print version.\n";
+ ostr << "\t-p: Print parsed workloads and exit.\n";
+ ostr << "Workload options\n";
+ ostr << "\t-d DIR\t\t: Work directory for " << Command::CREATE << "/" << Command::DELETE
+ << " (default '" << command.from_dir << "').\n";
+ ostr << "\t-f FROM-DIR\t: Source directory for " << Command::MOVE << "/" << Command::SYMLINK
+ << "/" << Command::HARDLINK << " (default '" << command.from_dir << "').\n";
+ ostr << "\t-t TO-DIR\t: Destination directory for " << Command::MOVE << "/" << Command::SYMLINK
+ << "/" << Command::HARDLINK << " (default '" << command.to_dir << "').\n";
+ ostr << "\t-n N_FILES\t: Number of files to create/delete etc. (default " << command.n_file
+ << ").\n";
+ ostr << "\t-s\t\t: Do not drop state (caches) before running the workload (default "
+ << !command.drop_state << ").\n";
+ ostr << "NOTE: -w WORKLOAD_T defines a new command and must come after its workload_options."
+ << std::endl;
+}
+
+void drop_state() {
+ // Drop inode/dentry/page caches.
+ std::system("sync; echo 3 > /proc/sys/vm/drop_caches");
+}
+
+static constexpr int OPEN_DIR_FLAGS = O_RDONLY | O_DIRECTORY | O_PATH | O_CLOEXEC;
+
+bool delete_files(const std::string& dir, int n_file, const std::string& basename) {
+ int dir_fd = open(dir.c_str(), OPEN_DIR_FLAGS);
+ if (dir_fd == -1) {
+ int error = errno;
+ std::cerr << "Failed to open work directory '" << dir << "', error '" << strerror(error)
+ << "'." << std::endl;
+ return false;
+ }
+
+ bool ret = true;
+ for (int i = 0; i < n_file; i++) {
+ std::string filename = basename + std::to_string(i);
+ ret = ret && (unlinkat(dir_fd, filename.c_str(), 0) == 0);
+ }
+
+ if (!ret) std::cerr << "Failed to delete at least one of the files" << std::endl;
+ close(dir_fd);
+ return ret;
+}
+
+bool create_files(const std::string& dir, int n_file, const std::string& basename) {
+ int dir_fd = open(dir.c_str(), OPEN_DIR_FLAGS);
+ if (dir_fd == -1) {
+ int error = errno;
+ std::cerr << "Failed to open work directory '" << dir << "', error '" << strerror(error)
+ << "'." << std::endl;
+ return false;
+ }
+
+ bool ret = true;
+ for (int i = 0; i < n_file; i++) {
+ std::string filename = basename + std::to_string(i);
+ int fd = openat(dir_fd, filename.c_str(), O_RDWR | O_CREAT | O_EXCL | O_CLOEXEC, 0777);
+ ret = ret && fd != -1;
+ close(fd);
+ }
+
+ close(dir_fd);
+ if (!ret) {
+ std::cerr << "Failed to open at least one of the files" << std::endl;
+ delete_files(dir, n_file, basename);
+ }
+ return ret;
+}
+
+bool move_files(const std::string& from_dir, const std::string& to_dir, int n_file,
+ const std::string& from_basename, const std::string& to_basename) {
+ int from_dir_fd = open(from_dir.c_str(), OPEN_DIR_FLAGS);
+ if (from_dir_fd == -1) {
+ int error = errno;
+ std::cerr << "Failed to open source directory '" << from_dir << "', error '"
+ << strerror(error) << "'." << std::endl;
+ return false;
+ }
+ int to_dir_fd = open(to_dir.c_str(), OPEN_DIR_FLAGS);
+ if (to_dir_fd == -1) {
+ int error = errno;
+ std::cerr << "Failed to open destination directory '" << to_dir << "', error '"
+ << strerror(error) << "'." << std::endl;
+ close(from_dir_fd);
+ return false;
+ }
+
+ bool ret = true;
+ for (int i = 0; i < n_file; i++) {
+ std::string from_filename = from_basename + std::to_string(i);
+ std::string to_filename = to_basename + std::to_string(i);
+ ret = ret &&
+ (renameat(from_dir_fd, from_filename.c_str(), to_dir_fd, to_filename.c_str()) == 0);
+ }
+
+ if (!ret) std::cerr << "Failed to move at least one of the files" << std::endl;
+ close(from_dir_fd);
+ close(from_dir_fd);
+ return ret;
+}
+
+bool hardlink_files(const std::string& from_dir, const std::string& to_dir, int n_file,
+ const std::string& from_basename, const std::string& to_basename) {
+ int from_dir_fd = open(from_dir.c_str(), OPEN_DIR_FLAGS);
+ if (from_dir_fd == -1) {
+ int error = errno;
+ std::cerr << "Failed to open source directory '" << from_dir << "', error '"
+ << strerror(error) << "'." << std::endl;
+ return false;
+ }
+ int to_dir_fd = open(to_dir.c_str(), OPEN_DIR_FLAGS);
+ if (to_dir_fd == -1) {
+ int error = errno;
+ std::cerr << "Failed to open destination directory '" << to_dir << "', error '"
+ << strerror(error) << "'." << std::endl;
+ close(from_dir_fd);
+ return false;
+ }
+
+ bool ret = true;
+ for (int i = 0; i < n_file; i++) {
+ std::string from_filename = from_basename + std::to_string(i);
+ std::string to_filename = to_basename + std::to_string(i);
+ ret = ret &&
+ (linkat(from_dir_fd, from_filename.c_str(), to_dir_fd, to_filename.c_str(), 0) == 0);
+ }
+
+ if (!ret) std::cerr << "Failed to hardlink at least one of the files" << std::endl;
+ close(from_dir_fd);
+ close(to_dir_fd);
+ return ret;
+}
+
+bool symlink_files(std::string from_dir, const std::string& to_dir, int n_file,
+ const std::string& from_basename, const std::string& to_basename) {
+ if (from_dir.back() != '/') from_dir.push_back('/');
+ int to_dir_fd = open(to_dir.c_str(), OPEN_DIR_FLAGS);
+ if (to_dir_fd == -1) {
+ int error = errno;
+ std::cerr << "Failed to open destination directory '" << to_dir << "', error '"
+ << strerror(error) << "'." << std::endl;
+ return false;
+ }
+
+ bool ret = true;
+ for (int i = 0; i < n_file; i++) {
+ std::string from_filepath = from_dir + from_basename + std::to_string(i);
+ std::string to_filename = to_basename + std::to_string(i);
+ ret = ret && (symlinkat(from_filepath.c_str(), to_dir_fd, to_filename.c_str()) == 0);
+ }
+
+ if (!ret) std::cerr << "Failed to symlink at least one of the files" << std::endl;
+ close(to_dir_fd);
+ return ret;
+}
+
+bool exhaustive_readdir(const std::string& from_dir) {
+ DIR* dir = opendir(from_dir.c_str());
+ if (dir == nullptr) {
+ int error = errno;
+ std::cerr << "Failed to open working directory '" << from_dir << "', error '"
+ << strerror(error) << "'." << std::endl;
+ return false;
+ }
+
+ errno = 0;
+ while (readdir(dir) != nullptr)
+ ;
+ // In case of failure readdir returns nullptr and sets errno accordingly (to
+ // something != 0).
+ // In case of success readdir != nullptr and errno is not changed.
+ // Source: man 3 readdir.
+ bool ret = errno == 0;
+ closedir(dir);
+ return ret;
+}
+
+void create_workload(Collector* collector, const Command& command) {
+ if (command.drop_state) drop_state();
+ collector->reset();
+ if (create_files(command.from_dir, command.n_file, command.from_basename))
+ collector->collect_metric(command.workload);
+
+ delete_files(command.from_dir, command.n_file, command.from_basename);
+}
+
+void delete_workload(Collector* collector, const Command& command) {
+ if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
+
+ if (command.drop_state) drop_state();
+ collector->reset();
+ if (delete_files(command.from_dir, command.n_file, command.from_basename))
+ collector->collect_metric(command.workload);
+}
+
+void move_workload(Collector* collector, const Command& command) {
+ if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
+
+ if (command.drop_state) drop_state();
+ collector->reset();
+ if (move_files(command.from_dir, command.to_dir, command.n_file, command.from_basename,
+ command.to_basename))
+ collector->collect_metric(command.workload);
+
+ delete_files(command.to_dir, command.n_file, command.to_basename);
+}
+
+void hardlink_workload(Collector* collector, const Command& command) {
+ if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
+
+ if (command.drop_state) drop_state();
+ collector->reset();
+ if (hardlink_files(command.from_dir, command.to_dir, command.n_file, command.from_basename,
+ command.to_basename))
+ collector->collect_metric(command.workload);
+
+ delete_files(command.from_dir, command.n_file, command.from_basename);
+ delete_files(command.to_dir, command.n_file, command.to_basename);
+}
+
+void symlink_workload(Collector* collector, const Command& command) {
+ if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
+
+ if (command.drop_state) drop_state();
+ collector->reset();
+ if (symlink_files(command.from_dir, command.to_dir, command.n_file, command.from_basename,
+ command.to_basename))
+ collector->collect_metric(command.workload);
+
+ delete_files(command.to_dir, command.n_file, command.to_basename);
+ delete_files(command.from_dir, command.n_file, command.from_basename);
+}
+
+void readdir_workload(Collector* collector, const Command& command) {
+ if (!create_files(command.from_dir, command.n_file, command.from_basename)) return;
+
+ if (command.drop_state) drop_state();
+ collector->reset();
+ if (exhaustive_readdir(command.from_dir)) collector->collect_metric(command.workload);
+
+ delete_files(command.from_dir, command.n_file, command.from_basename);
+}
+
+using workload_executor_t = std::function<void(Collector*, const Command&)>;
+
+std::unordered_map<std::string, workload_executor_t> executors = {
+ {Command::CREATE, create_workload}, {Command::DELETE, delete_workload},
+ {Command::MOVE, move_workload}, {Command::HARDLINK, hardlink_workload},
+ {Command::SYMLINK, symlink_workload}, {Command::READDIR, readdir_workload}};
+
+int main(int argc, char** argv) {
+ std::vector<Command> commands;
+ Command command;
+ int opt;
+
+ while ((opt = getopt(argc, argv, "hvpsw:d:f:t:n:")) != -1) {
+ switch (opt) {
+ case 'h':
+ usage(std::cout, argv[0]);
+ return EXIT_SUCCESS;
+ case 'v':
+ print_version();
+ return EXIT_SUCCESS;
+ case 'p':
+ print_commands(commands);
+ return EXIT_SUCCESS;
+ case 's':
+ command.drop_state = false;
+ break;
+ case 'w':
+ command.workload = optarg;
+ commands.push_back(command);
+ command.reset();
+ break;
+ case 'd':
+ case 'f':
+ command.from_dir = optarg;
+ break;
+ case 't':
+ command.to_dir = optarg;
+ break;
+ case 'n':
+ command.n_file = std::stoi(optarg);
+ break;
+ default:
+ usage(std::cerr, argv[0]);
+ return EXIT_FAILURE;
+ }
+ }
+
+ Collector collector;
+ for (const Command& command : commands) {
+ auto executor = executors.find(command.workload);
+ if (executor == executors.end()) continue;
+ executor->second(&collector, command);
+ }
+ collector.report_metrics();
+
+ return EXIT_SUCCESS;
+}
diff --git a/binder/android/os/IVold.aidl b/binder/android/os/IVold.aidl
index d0e753e..61e1e54 100644
--- a/binder/android/os/IVold.aidl
+++ b/binder/android/os/IVold.aidl
@@ -164,6 +164,7 @@
const int STORAGE_FLAG_DE = 1;
const int STORAGE_FLAG_CE = 2;
+ const int STORAGE_FLAG_LEVEL_FROM_USER = 4;
const int REMOUNT_MODE_NONE = 0;
const int REMOUNT_MODE_DEFAULT = 1;
diff --git a/model/PrivateVolume.cpp b/model/PrivateVolume.cpp
index 39a946c..1875b7b 100644
--- a/model/PrivateVolume.cpp
+++ b/model/PrivateVolume.cpp
@@ -166,11 +166,14 @@
RestoreconRecursive(mPath);
+ int attrs = 0;
+ if (!IsSdcardfsUsed()) attrs = FS_CASEFOLD_FL;
+
// Verify that common directories are ready to roll
if (PrepareDir(mPath + "/app", 0771, AID_SYSTEM, AID_SYSTEM) ||
PrepareDir(mPath + "/user", 0711, AID_SYSTEM, AID_SYSTEM) ||
PrepareDir(mPath + "/user_de", 0711, AID_SYSTEM, AID_SYSTEM) ||
- PrepareDir(mPath + "/media", 0770, AID_MEDIA_RW, AID_MEDIA_RW) ||
+ PrepareDir(mPath + "/media", 0770, AID_MEDIA_RW, AID_MEDIA_RW, attrs) ||
PrepareDir(mPath + "/media/0", 0770, AID_MEDIA_RW, AID_MEDIA_RW) ||
PrepareDir(mPath + "/local", 0751, AID_ROOT, AID_ROOT) ||
PrepareDir(mPath + "/local/tmp", 0771, AID_SHELL, AID_SHELL)) {
diff --git a/model/VolumeEncryption.cpp b/model/VolumeEncryption.cpp
index 5b0e73d..e6a55a9 100644
--- a/model/VolumeEncryption.cpp
+++ b/model/VolumeEncryption.cpp
@@ -32,16 +32,16 @@
enum class VolumeMethod { kFailed, kCrypt, kDefaultKey };
static VolumeMethod lookup_volume_method() {
- constexpr uint64_t pre_gki_level = 29;
auto first_api_level =
android::base::GetUintProperty<uint64_t>("ro.product.first_api_level", 0);
auto method = android::base::GetProperty("ro.crypto.volume.metadata.method", "default");
if (method == "default") {
- return first_api_level > pre_gki_level ? VolumeMethod::kDefaultKey : VolumeMethod::kCrypt;
+ return first_api_level > __ANDROID_API_Q__ ? VolumeMethod::kDefaultKey
+ : VolumeMethod::kCrypt;
} else if (method == "dm-default-key") {
return VolumeMethod::kDefaultKey;
} else if (method == "dm-crypt") {
- if (first_api_level > pre_gki_level) {
+ if (first_api_level > __ANDROID_API_Q__) {
LOG(ERROR) << "volume encryption method dm-crypt cannot be used, "
"ro.product.first_api_level = "
<< first_api_level;
diff --git a/secdiscard.cpp b/secdiscard.cpp
index 4659eed..b91f321 100644
--- a/secdiscard.cpp
+++ b/secdiscard.cpp
@@ -50,6 +50,27 @@
} // namespace
+#ifndef F2FS_IOCTL_MAGIC
+#define F2FS_IOCTL_MAGIC 0xf5
+#endif
+
+// F2FS-specific ioctl
+// It requires the below kernel commit merged in v5.9-rc1.
+// 9af846486d78 ("f2fs: add F2FS_IOC_SEC_TRIM_FILE ioctl")
+// In android12-5.4,
+// 7fc27297c44d ("Merge remote-tracking branch 'aosp/upstream-f2fs-stable-linux-5.4.y'
+// into android12-5.4")
+#ifndef F2FS_IOC_SEC_TRIM_FILE
+struct f2fs_sectrim_range {
+ __u64 start;
+ __u64 len;
+ __u64 flags;
+};
+#define F2FS_IOC_SEC_TRIM_FILE _IOW(F2FS_IOCTL_MAGIC, 20, struct f2fs_sectrim_range)
+#define F2FS_TRIM_FILE_DISCARD 0x1
+#define F2FS_TRIM_FILE_ZEROOUT 0x2
+#endif
+
int main(int argc, const char* const argv[]) {
android::base::InitLogging(const_cast<char**>(argv));
Options options;
@@ -69,9 +90,6 @@
// In android-4.14,
// ce767d9a55bc ("f2fs: updates on v4.16-rc1")
#ifndef F2FS_IOC_SET_PIN_FILE
-#ifndef F2FS_IOCTL_MAGIC
-#define F2FS_IOCTL_MAGIC 0xf5
-#endif
#define F2FS_IOC_SET_PIN_FILE _IOW(F2FS_IOCTL_MAGIC, 13, __u32)
#define F2FS_IOC_GET_PIN_FILE _IOR(F2FS_IOCTL_MAGIC, 14, __u32)
#endif
@@ -85,8 +103,31 @@
ioctl(fd, F2FS_IOC_SET_PIN_FILE, &set);
LOG(DEBUG) << "Securely discarding '" << target << "' unlink=" << options.unlink;
- if (!secdiscard_path(target)) {
- LOG(ERROR) << "Secure discard failed for: " << target;
+ struct f2fs_sectrim_range secRange;
+ secRange.start = 0;
+ secRange.len = -1; // until end of file
+ secRange.flags = F2FS_TRIM_FILE_DISCARD | F2FS_TRIM_FILE_ZEROOUT;
+ /*
+ * F2FS_IOC_SEC_TRIM_FILE is only supported by F2FS.
+ * 1. If device supports secure discard, it sends secure discard command on the file.
+ * 2. Otherwise, it sends discard command on the file.
+ * 3. Lastly, it overwrites zero data on it.
+ */
+ int ret = ioctl(fd, F2FS_IOC_SEC_TRIM_FILE, &secRange);
+ if (ret != 0) {
+ if (errno == EOPNOTSUPP) {
+ // If device doesn't support any type of discard, just overwrite zero data.
+ secRange.flags = F2FS_TRIM_FILE_ZEROOUT;
+ ret = ioctl(fd, F2FS_IOC_SEC_TRIM_FILE, &secRange);
+ }
+ if (ret != 0 && errno != ENOTTY) {
+ PLOG(WARNING) << "F2FS_IOC_SEC_TRIM_FILE failed on " << target;
+ }
+ }
+ if (ret != 0) {
+ if (!secdiscard_path(target)) {
+ LOG(ERROR) << "Secure discard failed for: " << target;
+ }
}
if (options.unlink) {
if (unlink(target.c_str()) != 0 && errno != ENOENT) {
diff --git a/vold_prepare_subdirs.cpp b/vold_prepare_subdirs.cpp
index d624d73..0283614 100644
--- a/vold_prepare_subdirs.cpp
+++ b/vold_prepare_subdirs.cpp
@@ -54,20 +54,33 @@
return s.size() < 40 && s.find_first_not_of("0123456789abcdefABCDEF-_") == std::string::npos;
}
-static bool prepare_dir(struct selabel_handle* sehandle, mode_t mode, uid_t uid, gid_t gid,
- const std::string& path) {
+static bool prepare_dir_for_user(struct selabel_handle* sehandle, mode_t mode, uid_t uid, gid_t gid,
+ const std::string& path, uid_t user_id) {
auto clearfscreatecon = android::base::make_scope_guard([] { setfscreatecon(nullptr); });
auto secontext = std::unique_ptr<char, void (*)(char*)>(nullptr, freecon);
- char* tmp_secontext;
- if (sehandle && selabel_lookup(sehandle, &tmp_secontext, path.c_str(), S_IFDIR) == 0) {
- secontext.reset(tmp_secontext);
+ if (sehandle) {
+ char* tmp_secontext;
+
+ if (selabel_lookup(sehandle, &tmp_secontext, path.c_str(), S_IFDIR) == 0) {
+ secontext.reset(tmp_secontext);
+
+ if (user_id != (uid_t)-1) {
+ if (selinux_android_context_with_level(secontext.get(), &tmp_secontext, user_id,
+ (uid_t)-1) != 0) {
+ PLOG(ERROR) << "Unable to create context with level for: " << path;
+ return false;
+ }
+ secontext.reset(tmp_secontext); // Free the context
+ }
+ }
}
+
LOG(DEBUG) << "Setting up mode " << std::oct << mode << std::dec << " uid " << uid << " gid "
<< gid << " context " << (secontext ? secontext.get() : "null")
<< " on path: " << path;
if (secontext) {
if (setfscreatecon(secontext.get()) != 0) {
- PLOG(ERROR) << "Unable to read setfscreatecon for: " << path;
+ PLOG(ERROR) << "Unable to setfscreatecon for: " << path;
return false;
}
}
@@ -93,6 +106,11 @@
return true;
}
+static bool prepare_dir(struct selabel_handle* sehandle, mode_t mode, uid_t uid, gid_t gid,
+ const std::string& path) {
+ return prepare_dir_for_user(sehandle, mode, uid, gid, path, (uid_t)-1);
+}
+
static bool rmrf_contents(const std::string& path) {
auto dirp = std::unique_ptr<DIR, int (*)(DIR*)>(opendir(path.c_str()), closedir);
if (!dirp) {
@@ -148,8 +166,17 @@
static bool prepare_subdirs(const std::string& volume_uuid, int user_id, int flags) {
struct selabel_handle* sehandle = selinux_android_file_context_handle();
- if (volume_uuid.empty()) {
- if (flags & android::os::IVold::STORAGE_FLAG_DE) {
+ const uid_t user_for_level =
+ (flags & android::os::IVold::STORAGE_FLAG_LEVEL_FROM_USER) ? user_id : -1;
+
+ if (flags & android::os::IVold::STORAGE_FLAG_DE) {
+ auto user_de_path = android::vold::BuildDataUserDePath(volume_uuid, user_id);
+ if (!prepare_dir_for_user(sehandle, 0771, AID_SYSTEM, AID_SYSTEM, user_de_path,
+ user_for_level)) {
+ return false;
+ }
+
+ if (volume_uuid.empty()) {
auto misc_de_path = android::vold::BuildDataMiscDePath(user_id);
if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/vold")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/storaged")) return false;
@@ -158,6 +185,12 @@
prepare_dir(sehandle, 0700, 0, 0, misc_de_path + "/apexrollback");
prepare_apex_subdirs(sehandle, misc_de_path);
+ auto profiles_de_path = android::vold::BuildDataProfilesDePath(user_id);
+ if (!prepare_dir_for_user(sehandle, 0771, AID_SYSTEM, AID_SYSTEM, profiles_de_path,
+ user_for_level)) {
+ return false;
+ }
+
auto vendor_de_path = android::vold::BuildDataVendorDePath(user_id);
if (!prepare_dir(sehandle, 0700, AID_SYSTEM, AID_SYSTEM, vendor_de_path + "/fpdata")) {
return false;
@@ -167,11 +200,20 @@
return false;
}
}
- if (flags & android::os::IVold::STORAGE_FLAG_CE) {
+ }
+ if (flags & android::os::IVold::STORAGE_FLAG_CE) {
+ auto user_ce_path = android::vold::BuildDataUserCePath(volume_uuid, user_id);
+ if (!prepare_dir_for_user(sehandle, 0771, AID_SYSTEM, AID_SYSTEM, user_ce_path,
+ user_for_level)) {
+ return false;
+ }
+
+ if (volume_uuid.empty()) {
auto misc_ce_path = android::vold::BuildDataMiscCePath(user_id);
if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/vold")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/storaged")) return false;
if (!prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/rollback")) return false;
+
// TODO: Return false if this returns false once sure this should succeed.
prepare_dir(sehandle, 0700, 0, 0, misc_ce_path + "/apexrollback");
prepare_apex_subdirs(sehandle, misc_ce_path);