diff options
32 files changed, 630 insertions, 121 deletions
diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 198e4defb..6b4071925 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -31,7 +31,6 @@ cc_defaults { cflags: [ "-Wall", "-Wextra", - "-Werror", "-Wno-unused-argument", "-Wno-unused-function", "-Wno-nullability-completeness", diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index b60739794..74b5c719e 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -553,9 +553,8 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c }; // Set PR_SET_DUMPABLE to 1, so that crash_dump can ptrace us. - int orig_dumpable = prctl(PR_GET_DUMPABLE); if (prctl(PR_SET_DUMPABLE, 1) != 0) { - fatal_errno("failed to set dumpable"); + fatal_errno("failed to set dumpable"); } // On kernels with yama_ptrace enabled, also allow any process to attach. @@ -585,9 +584,14 @@ static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* c // and then wait for it to terminate. futex_wait(&thread_info.pseudothread_tid, child_pid); - // Restore PR_SET_DUMPABLE to its original value. - if (prctl(PR_SET_DUMPABLE, orig_dumpable) != 0) { - fatal_errno("failed to restore dumpable"); + // Signals can either be fatal or nonfatal. + // For fatal signals, crash_dump will PTRACE_CONT us with the signal we + // crashed with, so that processes using waitpid on us will see that we + // exited with the correct exit status (e.g. so that sh will report + // "Segmentation fault" instead of "Killed"). For this to work, we need + // to deregister our signal handler for that signal before continuing. + if (signal_number != DEBUGGER_SIGNAL) { + signal(signal_number, SIG_DFL); } // Restore PR_SET_PTRACER to its original value. diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 21df8af8c..82f8ab485 100644..100755 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -185,7 +185,14 @@ static void check_fs(const std::string& blk_device, const std::string& fs_type, Timer t; /* Check for the types of filesystems we know how to check */ - if (is_extfs(fs_type)) { + if (fs_type == "vfat") { + const char* vfat_fsck_argv[] = {"/system/bin/fsck_msdos", "-y", blk_device.c_str()}; + ret = logwrap_fork_execvp(ARRAY_SIZE(vfat_fsck_argv), vfat_fsck_argv, &status, + false, LOG_KLOG | LOG_FILE, false, FSCK_LOG_FILE); + if (ret < 0) + LERROR << "Failed running '/system/bin/fsck_msdos' on '" << blk_device.c_str() + << "' - " << ret; + } else if (is_extfs(fs_type)) { /* * First try to mount and unmount the filesystem. We do this because * the kernel is more efficient than e2fsck in running the journal and @@ -1369,6 +1376,8 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) { int encryptable = FS_MGR_MNTALL_DEV_NOT_ENCRYPTABLE; int error_count = 0; CheckpointManager checkpoint_manager; + char propbuf[PROPERTY_VALUE_MAX]; + bool is_ffbm = false; AvbUniquePtr avb_handle(nullptr); bool wiped = false; @@ -1376,12 +1385,21 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) { if (fstab->empty()) { return {FS_MGR_MNTALL_FAIL, userdata_mounted}; } + /**get boot mode*/ + property_get("ro.bootmode", propbuf, ""); + if ((strncmp(propbuf, "ffbm-00", 7) == 0) || (strncmp(propbuf, "ffbm-01", 7) == 0)) + is_ffbm = true; // Keep i int to prevent unsigned integer overflow from (i = top_idx - 1), // where top_idx is 0. It will give SIGABRT for (int i = 0; i < static_cast<int>(fstab->size()); i++) { auto& current_entry = (*fstab)[i]; + /* Skip userdata partition in ffbm mode */ + if (is_ffbm && !strcmp(current_entry.mount_point.c_str(), "/data")){ + continue; + } + // If a filesystem should have been mounted in the first stage, we // ignore it here. With one exception, if the filesystem is // formattable, then it can only be formatted in the second stage, @@ -1391,7 +1409,6 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) { IsMountPointMounted(current_entry.mount_point))) { continue; } - // Don't mount entries that are managed by vold or not for the mount mode. if (current_entry.fs_mgr_flags.vold_managed || current_entry.fs_mgr_flags.recovery_only || ((mount_mode == MOUNT_MODE_LATE) && !current_entry.fs_mgr_flags.late_mount) || @@ -1605,11 +1622,18 @@ MountAllResult fs_mgr_mount_all(Fstab* fstab, int mount_mode) { if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.blk_device, attempted_entry.mount_point}, nullptr)) { - ++error_count; - } else if (current_entry.mount_point == "/data") { - userdata_mounted = true; + PERROR << android::base::StringPrintf( + "Failure while mounting metadata, setting flag to needing recovery " + "partition on %s at %s options: %s", + attempted_entry.blk_device.c_str(), attempted_entry.mount_point.c_str(), + attempted_entry.fs_options.c_str()); + encryptable = FS_MGR_MNTALL_DEV_NEEDS_RECOVERY_WIPE_PROMPT; + } else { + if (current_entry.mount_point == "/data") { + userdata_mounted = true; + } + encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED; } - encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED; continue; } else { // fs_options might be null so we cannot use PERROR << directly. diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp index 301c90755..7367dd54d 100644 --- a/fs_mgr/fs_mgr_format.cpp +++ b/fs_mgr/fs_mgr_format.cpp @@ -176,6 +176,10 @@ int fs_mgr_do_format(const FstabEntry& entry, bool crypt_footer) { } else if (entry.fs_type == "ext4") { return format_ext4(entry.blk_device, entry.mount_point, crypt_footer, needs_projid, entry.fs_mgr_flags.ext_meta_csum); + } else if (entry.fs_type == "vfat") { + std::vector<const char*> args = {"/system/bin/newfs_msdos", + entry.blk_device.c_str()}; + return logwrap_fork_execvp(args.size(), args.data(), nullptr, false, LOG_KLOG, false, nullptr); } else { LERROR << "File system type '" << entry.fs_type << "' is not supported"; return -EINVAL; diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index f5ab5571f..7fc73bdc5 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -181,6 +181,7 @@ void ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { CheckFlag("fsverity", fs_verity); CheckFlag("metadata_csum", ext_meta_csum); CheckFlag("fscompress", fs_compress); + CheckFlag("wrappedkey", wrapped_key); #undef CheckFlag diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 4d3ecc9dc..a825a63d9 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -51,6 +51,8 @@ enum mount_mode { MOUNT_MODE_ONLY_USERDATA = 3 }; + +#define FS_MGR_MNTALL_DEV_NEEDS_RECOVERY_WIPE_PROMPT 8 #define FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED 7 #define FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION 6 #define FS_MGR_MNTALL_DEV_FILE_ENCRYPTED 5 diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index f33768b9d..0d1e935c0 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -86,6 +86,7 @@ struct FstabEntry { bool fs_verity : 1; bool ext_meta_csum : 1; bool fs_compress : 1; + bool wrapped_key : 1; } fs_mgr_flags = {}; bool is_encryptable() const { diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index e43c00b44..b1d5b397a 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -170,19 +170,18 @@ static bool IsRecovery() { return access("/system/bin/recovery", F_OK) == 0; } -bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path, - const std::chrono::milliseconds& timeout_ms) { +bool DeviceMapper::CreateEmptyDevice(const std::string& name) { std::string uuid = GenerateUuid(); - if (!CreateDevice(name, uuid)) { - return false; - } + return CreateDevice(name, uuid); +} +bool DeviceMapper::WaitForDevice(const std::string& name, + const std::chrono::milliseconds& timeout_ms, std::string* path) { // We use the unique path for testing whether the device is ready. After // that, it's safe to use the dm-N path which is compatible with callers // that expect it to be formatted as such. std::string unique_path; - if (!LoadTableAndActivate(name, table) || !GetDeviceUniquePath(name, &unique_path) || - !GetDmDevicePathByName(name, path)) { + if (!GetDeviceUniquePath(name, &unique_path) || !GetDmDevicePathByName(name, path)) { DeleteDevice(name); return false; } @@ -208,6 +207,25 @@ bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, s return true; } +bool DeviceMapper::CreateDevice(const std::string& name, const DmTable& table, std::string* path, + const std::chrono::milliseconds& timeout_ms) { + if (!CreateEmptyDevice(name)) { + return false; + } + + if (!LoadTableAndActivate(name, table)) { + DeleteDevice(name); + return false; + } + + if (!WaitForDevice(name, timeout_ms, path)) { + DeleteDevice(name); + return false; + } + + return true; +} + bool DeviceMapper::GetDeviceUniquePath(const std::string& name, std::string* path) { struct dm_ioctl io; InitIo(&io, name); diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index 8006db220..8314ec596 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -29,6 +29,7 @@ #include <thread> #include <android-base/file.h> +#include <android-base/scopeguard.h> #include <android-base/strings.h> #include <android-base/unique_fd.h> #include <gtest/gtest.h> @@ -679,3 +680,17 @@ TEST(libdm, DeleteDeviceDeferredWaitsForLastReference) { ASSERT_NE(0, access(path.c_str(), F_OK)); ASSERT_EQ(ENOENT, errno); } + +TEST(libdm, CreateEmptyDevice) { + DeviceMapper& dm = DeviceMapper::Instance(); + ASSERT_TRUE(dm.CreateEmptyDevice("empty-device")); + auto guard = android::base::make_scope_guard([&]() { dm.DeleteDevice("empty-device", 5s); }); + + // Empty device should be in suspended state. + ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device")); + + std::string path; + ASSERT_TRUE(dm.WaitForDevice("empty-device", 5s, &path)); + // Path should exist. + ASSERT_EQ(0, access(path.c_str(), F_OK)); +} diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h index bdbbf9112..e6698ea38 100644 --- a/fs_mgr/libdm/include/libdm/dm.h +++ b/fs_mgr/libdm/include/libdm/dm.h @@ -119,6 +119,19 @@ class DeviceMapper final { // - ACTIVE: resumes the device. bool ChangeState(const std::string& name, DmDeviceState state); + // Creates empty device. + // This supports a use case when a caller doesn't need a device straight away, but instead + // asks kernel to create it beforehand, thus avoiding blocking itself from waiting for ueventd + // to create user space paths. + // Callers are expected to then activate their device by calling LoadTableAndActivate function. + // To avoid race conditions, callers must still synchronize with ueventd by calling + // WaitForDevice function. + bool CreateEmptyDevice(const std::string& name); + + // Waits for device paths to be created in the user space. + bool WaitForDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms, + std::string* path); + // Creates a device, loads the given table, and activates it. If the device // is not able to be activated, it is destroyed, and false is returned. // After creation, |path| contains the result of calling diff --git a/fs_mgr/libsnapshot/dm_snapshot_internals.h b/fs_mgr/libsnapshot/dm_snapshot_internals.h index ed77c1526..4a3625197 100644 --- a/fs_mgr/libsnapshot/dm_snapshot_internals.h +++ b/fs_mgr/libsnapshot/dm_snapshot_internals.h @@ -17,8 +17,9 @@ #include <android-base/logging.h> #include <stdint.h> +#include <limits> #include <optional> -#include <vector> +#include <unordered_set> namespace android { namespace snapshot { @@ -37,21 +38,16 @@ class DmSnapCowSizeCalculator { return; } - if (modified_chunks_.size() <= chunk_id) { - if (modified_chunks_.max_size() <= chunk_id) { - LOG(ERROR) << "Invalid COW size, chunk_id is too large."; - valid_ = false; - return; - } - modified_chunks_.resize(chunk_id + 1, false); - if (modified_chunks_.size() <= chunk_id) { - LOG(ERROR) << "Invalid COW size, chunk_id is too large."; - valid_ = false; - return; - } + if (chunk_id > std::numeric_limits<uint32_t>::max()) { + LOG(ERROR) << "Chunk exceeds maximum size: " << chunk_id; + valid_ = false; + return; + } + if (modified_chunks_.count(chunk_id) > 0) { + return; } - modified_chunks_[chunk_id] = true; + modified_chunks_.emplace(chunk_id); } std::optional<uint64_t> cow_size_bytes() const { @@ -91,23 +87,16 @@ class DmSnapCowSizeCalculator { return std::nullopt; } - uint64_t modified_chunks_count = 0; uint64_t cow_chunks = 0; - for (const auto& c : modified_chunks_) { - if (c) { - ++modified_chunks_count; - } - } - /* disk header + padding = 1 chunk */ cow_chunks += 1; /* snapshot modified chunks */ - cow_chunks += modified_chunks_count; + cow_chunks += modified_chunks_.size(); /* snapshot chunks index metadata */ - cow_chunks += 1 + modified_chunks_count / exceptions_per_chunk; + cow_chunks += 1 + modified_chunks_.size() / exceptions_per_chunk; return cow_chunks; } @@ -150,30 +139,8 @@ class DmSnapCowSizeCalculator { /* * |modified_chunks_| is a container that keeps trace of the modified * chunks. - * Multiple options were considered when choosing the most appropriate data - * structure for this container. Here follows a summary of why vector<bool> - * has been chosen, taking as a reference a snapshot partition of 4 GiB and - * chunk size of 4 KiB. - * - std::set<uint64_t> is very space-efficient for a small number of - * operations, but if the whole snapshot is changed, it would need to - * store - * 4 GiB / 4 KiB * (64 bit / 8) = 8 MiB - * just for the data, plus the additional data overhead for the red-black - * tree used for data sorting (if each rb-tree element stores 3 address - * and the word-aligne color, the total size grows to 32 MiB). - * - std::bitset<N> is not a good fit because requires a priori knowledge, - * at compile time, of the bitset size. - * - std::vector<bool> is a special case of vector, which uses a data - * compression that allows reducing the space utilization of each element - * to 1 bit. In detail, this data structure is composed of a resizable - * array of words, each of them representing a bitmap. On a 64 bit - * device, modifying the whole 4 GiB snapshot grows this container up to - * 4 * GiB / 4 KiB / 64 = 64 KiB - * that, even if is the same space requirement to change a single byte at - * the highest address of the snapshot, is a very affordable space - * requirement. */ - std::vector<bool> modified_chunks_; + std::unordered_set<uint32_t> modified_chunks_; }; } // namespace snapshot diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp index 50eee198f..9a47f6b2b 100644 --- a/healthd/healthd_draw.cpp +++ b/healthd/healthd_draw.cpp @@ -46,14 +46,6 @@ static int get_split_offset() { HealthdDraw::HealthdDraw(animation* anim) : kSplitScreen(get_split_screen()), kSplitOffset(get_split_offset()) { - int ret = gr_init(); - - if (ret < 0) { - LOGE("gr_init failed\n"); - graphics_available = false; - return; - } - graphics_available = true; sys_font = gr_sys_font(); if (sys_font == nullptr) { @@ -235,3 +227,11 @@ void HealthdDraw::draw_unknown(GRSurface* surf_unknown) { LOGW("Charging, level unknown\n"); } } + +std::unique_ptr<HealthdDraw> HealthdDraw::Create(animation *anim) { + if (gr_init() < 0) { + LOGE("gr_init failed\n"); + return nullptr; + } + return std::unique_ptr<HealthdDraw>(new HealthdDraw(anim)); +} diff --git a/healthd/healthd_draw.h b/healthd/healthd_draw.h index 7c847bdbf..0b48ce842 100644 --- a/healthd/healthd_draw.h +++ b/healthd/healthd_draw.h @@ -26,8 +26,6 @@ using namespace android; class HealthdDraw { public: - // Configures font using given animation. - HealthdDraw(animation* anim); virtual ~HealthdDraw(); // Redraws screen. @@ -36,6 +34,8 @@ class HealthdDraw { // Blanks screen if true, unblanks if false. virtual void blank_screen(bool blank); + static std::unique_ptr<HealthdDraw> Create(animation *anim); + protected: virtual void clear_screen(); @@ -76,6 +76,10 @@ class HealthdDraw { // true if minui init'ed OK, false if minui init failed bool graphics_available; + + private: + // Configures font using given animation. + HealthdDraw(animation* anim); }; #endif // HEALTHD_DRAW_H diff --git a/healthd/healthd_mode_charger.cpp b/healthd/healthd_mode_charger.cpp index e95efc04c..6b503f4a8 100644 --- a/healthd/healthd_mode_charger.cpp +++ b/healthd/healthd_mode_charger.cpp @@ -218,9 +218,7 @@ static void dump_last_kmsg(void) { char* ptr; size_t len; - LOGW("\n"); LOGW("*************** LAST KMSG ***************\n"); - LOGW("\n"); const char* kmsg[] = { // clang-format off "/sys/fs/pstore/console-ramoops-0", @@ -263,9 +261,7 @@ static void dump_last_kmsg(void) { } out: - LOGW("\n"); LOGW("************* END LAST KMSG *************\n"); - LOGW("\n"); } static int request_suspend(bool enable) { @@ -325,7 +321,8 @@ void Charger::UpdateScreenState(int64_t now) { } } - healthd_draw_.reset(new HealthdDraw(&batt_anim_)); + healthd_draw_ = HealthdDraw::Create(&batt_anim_); + if (healthd_draw_ == nullptr) return; if (android::sysprop::ChargerProperties::disable_init_blank().value_or(false)) { healthd_draw_->blank_screen(true); @@ -346,6 +343,9 @@ void Charger::UpdateScreenState(int64_t now) { disp_time = batt_anim_.frames[batt_anim_.cur_frame].disp_time; + /* unblank the screen on first cycle and first frame */ + if (batt_anim_.cur_cycle == 0 && batt_anim_.cur_frame == 0) healthd_draw_->blank_screen(false); + if (screen_blanked_) { healthd_draw_->blank_screen(false); screen_blanked_ = false; diff --git a/init/builtins.cpp b/init/builtins.cpp index 035038f32..058f84aa5 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -621,6 +621,13 @@ static Result<void> queue_fs_event(int code, bool userdata_remount) { PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery."; const std::vector<std::string> options = {"--wipe_data", "--reason=fs_mgr_mount_all" }; return reboot_into_recovery(options); + } else if (code == FS_MGR_MNTALL_DEV_NEEDS_RECOVERY_WIPE_PROMPT) { + /* Setup a wipe via recovery with prompt, and reboot into recovery if chosen */ + PLOG(ERROR) << "fs_mgr_mount_all suggested recovery, so wiping data via recovery " + "with prompt."; + const std::vector<std::string> options = {"--prompt_and_wipe_data", + "--reason=fs_mgr_mount_all" }; + return reboot_into_recovery(options); /* If reboot worked, there is no return. */ } else if (code == FS_MGR_MNTALL_DEV_FILE_ENCRYPTED) { if (!FscryptInstallKeyring()) { @@ -1114,6 +1121,19 @@ static Result<void> do_loglevel(const BuiltinArguments& args) { return {}; } +static int check_rlim_action() { + struct rlimit rl; + std::string value = android::base::GetProperty("persist.debug.trace", ""); + if(value == "1") { + rl.rlim_cur = RLIM_INFINITY; + rl.rlim_max = RLIM_INFINITY; + if (setrlimit(RLIMIT_CORE, &rl) < 0) { + PLOG(ERROR) << "could not enable core file generation"; + } + } + return 0; +} + static Result<void> do_load_persist_props(const BuiltinArguments& args) { // Devices with FDE have load_persist_props called twice; the first time when the temporary // /data partition is mounted and then again once /data is truly mounted. We do not want to @@ -1129,6 +1149,8 @@ static Result<void> do_load_persist_props(const BuiltinArguments& args) { SendLoadPersistentPropertiesMessage(); start_waiting_for_property("ro.persistent_properties.ready", "true"); + /*check for coredump*/ + check_rlim_action(); return {}; } diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index 78e5b60a1..a86e0733f 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -368,6 +368,7 @@ int FirstStageMain(int argc, char** argv) { setenv(kEnvFirstStageStartedAt, std::to_string(start_time.time_since_epoch().count()).c_str(), 1); + LOG(INFO) << "init first stage completed!"; const char* path = "/system/bin/init"; const char* args[] = {path, "selinux_setup", nullptr}; diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index f5c10bbd4..52b4aa24e 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -74,6 +74,16 @@ using namespace std::literals; namespace android { namespace init { +namespace { + +bool DeferOverlayfsMount() { + std::string cmdline; + android::base::ReadFileToString("/proc/cmdline", &cmdline); + return cmdline.find("androidboot.defer_overlayfs_mount=1") != std::string::npos; +} +} // namespace + + // Class Declarations // ------------------ class FirstStageMount { @@ -607,7 +617,9 @@ bool FirstStageMount::MountPartitions() { }; MapScratchPartitionIfNeeded(&fstab_, init_devices); - fs_mgr_overlayfs_mount_all(&fstab_); + if (!DeferOverlayfsMount()) { + fs_mgr_overlayfs_mount_all(&fstab_); + } return true; } diff --git a/init/init.cpp b/init/init.cpp index 942feb939..6dcf4a30b 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -50,11 +50,16 @@ #include <android-base/strings.h> #include <backtrace/Backtrace.h> #include <fs_avb/fs_avb.h> +#include <fs_mgr.h> +#include <fs_mgr_dm_linear.h> +#include <fs_mgr_overlayfs.h> #include <fs_mgr_vendor_overlay.h> + #include <keyutils.h> #include <libavb/libavb.h> #include <libgsi/libgsi.h> #include <libsnapshot/snapshot.h> +#include <private/android_filesystem_config.h> #include <processgroup/processgroup.h> #include <processgroup/setup.h> #include <selinux/android.h> @@ -98,10 +103,20 @@ using android::base::Timer; using android::base::Trim; using android::fs_mgr::AvbHandle; using android::snapshot::SnapshotManager; +using android::fs_mgr::Fstab; +using android::fs_mgr::ReadDefaultFstab; namespace android { namespace init { +namespace { +bool DeferOverlayfsMount() { + std::string cmdline; + android::base::ReadFileToString("/proc/cmdline", &cmdline); + return cmdline.find("androidboot.defer_overlayfs_mount=1") != std::string::npos; +} +} + static int property_triggers_enabled = 0; static int signal_fd = -1; @@ -768,6 +783,20 @@ int SecondStageMain(int argc, char** argv) { sigaction(SIGPIPE, &action, nullptr); } + if (DeferOverlayfsMount()) { + Fstab fstab; + if (ReadDefaultFstab(&fstab)) { + fstab.erase(std::remove_if(fstab.begin(), fstab.end(), + [](const auto& entry) { + return !entry.fs_mgr_flags.first_stage_mount; + }), + fstab.end()); + LOG(INFO) << "Running deferred mounting of overlayfs"; + fs_mgr_overlayfs_mount_all(&fstab); + } + + } + // Set init and its forked children's oom_adj. if (auto result = WriteFile("/proc/1/oom_score_adj", StringPrintf("%d", DEFAULT_OOM_SCORE_ADJUST)); @@ -790,6 +819,7 @@ int SecondStageMain(int argc, char** argv) { if (force_debuggable_env && AvbHandle::IsDeviceUnlocked()) { load_debug_prop = "true"s == force_debuggable_env; } + unsetenv("INIT_FORCE_DEBUGGABLE"); // Umount the debug ramdisk so property service doesn't read .prop files from there, when it diff --git a/init/property_service.cpp b/init/property_service.cpp index 2d67bf5d7..600f27919 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -954,6 +954,109 @@ static void property_derive_build_fingerprint() { } } +// Initialize ro.build.product property with the value of ro.product.device, if it has not been set. +static void property_derive_build_product() { + std::string build_product = GetProperty("ro.build.product", ""); + if (!build_product.empty()) { + return; + } + + const std::string UNKNOWN = "unknown"; + build_product = GetProperty("ro.product.device", UNKNOWN); + + LOG(INFO) << "Setting property 'ro.build.product' to '" << build_product << "'"; + + std::string error; + uint32_t res = PropertySet("ro.build.product", build_product, &error); + if (res != PROP_SUCCESS) { + LOG(ERROR) << "Error setting property 'ro.build.product': err=" << res << " (" << error + << ")"; + } +} + +// If the ro.build.description property has not been set, derive it from constituent pieces +static void property_derive_build_description() { + std::string build_description = GetProperty("ro.build.description", ""); + if (!build_description.empty()) { + return; + } + + const std::string UNKNOWN = "unknown"; + build_description = GetProperty("ro.product.name", UNKNOWN); + build_description += '-'; + build_description += GetProperty("ro.build.type", UNKNOWN); + build_description += ' '; + build_description += GetProperty("ro.build.version.release", UNKNOWN); + build_description += ' '; + build_description += GetProperty("ro.build.id", UNKNOWN); + build_description += ' '; + build_description += GetProperty("ro.build.version.incremental", UNKNOWN); + build_description += ' '; + build_description += GetProperty("ro.build.tags", UNKNOWN); + + LOG(INFO) << "Setting property 'ro.build.description' to '" << build_description << "'"; + + std::string error; + uint32_t res = PropertySet("ro.build.description", build_description, &error); + if (res != PROP_SUCCESS) { + LOG(ERROR) << "Error setting property 'ro.build.description': err=" << res << " (" << error + << ")"; + } +} + +// If the ro.build.display.id property has not been set, derive it from constituent pieces +static void property_derive_build_display_id() { + std::string build_display_id = GetProperty("ro.build.display.id", ""); + if (!build_display_id.empty()) { + return; + } + + const std::string UNKNOWN = "unknown"; + std::string build_type = GetProperty("ro.build.type", ""); + if (build_type == "user") { + std::string display_build_number = GetProperty("ro.build.display_build_number", ""); + if (display_build_number == "true") { + build_display_id = GetProperty("ro.build.id", UNKNOWN); + build_display_id += '.'; + build_display_id += GetProperty("ro.build.version.incremental", UNKNOWN); + build_display_id += ' '; + build_display_id += GetProperty("ro.build.keys", UNKNOWN); + } else { + build_display_id = GetProperty("ro.build.id", UNKNOWN); + build_display_id += ' '; + build_display_id += GetProperty("ro.build.keys", UNKNOWN); + } + } else { + build_display_id = GetProperty("ro.product.name", UNKNOWN); + build_display_id += '-'; + build_display_id += GetProperty("ro.build.type", UNKNOWN); + build_display_id += ' '; + build_display_id += GetProperty("ro.build.version.release", UNKNOWN); + build_display_id += ' '; + build_display_id += GetProperty("ro.build.id", UNKNOWN); + build_display_id += ' '; + build_display_id += GetProperty("ro.build.version.incremental", UNKNOWN); + build_display_id += ' '; + build_display_id += GetProperty("ro.build.tags", UNKNOWN); + } + + LOG(INFO) << "Setting property 'ro.build.display.id' to '" << build_display_id << "'"; + + std::string error; + uint32_t res = PropertySet("ro.build.display.id", build_display_id, &error); + if (res != PROP_SUCCESS) { + LOG(ERROR) << "Error setting property 'ro.build.display.id': err=" << res << " (" << error + << ")"; + } +} + +static void property_derive_build_props() { + property_derive_build_fingerprint(); + property_derive_build_product(); + property_derive_build_description(); + property_derive_build_display_id(); +} + // If the ro.product.cpu.abilist* properties have not been explicitly // set, derive them from ro.${partition}.product.cpu.abilist* properties. static void property_initialize_ro_cpu_abilist() { @@ -1099,7 +1202,7 @@ void PropertyLoadBootDefaults() { property_initialize_ro_product_props(); property_initialize_build_id(); - property_derive_build_fingerprint(); + property_derive_build_props(); property_derive_legacy_build_fingerprint(); property_initialize_ro_cpu_abilist(); diff --git a/init/reboot.cpp b/init/reboot.cpp index a0ae4b4d4..845bdb949 100644 --- a/init/reboot.cpp +++ b/init/reboot.cpp @@ -54,6 +54,8 @@ #include <private/android_filesystem_config.h> #include <selinux/selinux.h> +#include <cutils/properties.h> + #include "action.h" #include "action_manager.h" #include "builtin_arguments.h" @@ -425,11 +427,17 @@ static UmountStat TryUmountAndFsck(unsigned int cmd, bool run_fsck, UmountStat stat = UmountPartitions(timeout - t.duration()); if (stat != UMOUNT_STAT_SUCCESS) { LOG(INFO) << "umount timeout, last resort, kill all and try"; - if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(); + bool dumpUmountDebugInfo = property_get_bool("persist.sys.dumpUmountDebugInfo",false); + if (dumpUmountDebugInfo) { + if (DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(); + } KillAllProcesses(); // even if it succeeds, still it is timeout and do not run fsck with all processes killed UmountStat st = UmountPartitions(0ms); - if ((st != UMOUNT_STAT_SUCCESS) && DUMP_ON_UMOUNT_FAILURE) DumpUmountDebuggingInfo(); + if (dumpUmountDebugInfo) { + if ((st != UMOUNT_STAT_SUCCESS) && DUMP_ON_UMOUNT_FAILURE) + DumpUmountDebuggingInfo(); + } } if (stat == UMOUNT_STAT_SUCCESS && run_fsck) { diff --git a/libasyncio/Android.bp b/libasyncio/Android.bp index 692e223a1..694b0a3c9 100644 --- a/libasyncio/Android.bp +++ b/libasyncio/Android.bp @@ -20,11 +20,7 @@ package { cc_defaults { name: "libasyncio_defaults", - cflags: [ - "-Wall", - "-Werror", - "-Wextra", - ], + cflags: ["-Wall", "-Werror", "-Wextra"], } cc_library { diff --git a/libprocessgroup/profiles/cgroups.json b/libprocessgroup/profiles/cgroups.json index 063422091..23e4575cb 100644 --- a/libprocessgroup/profiles/cgroups.json +++ b/libprocessgroup/profiles/cgroups.json @@ -24,8 +24,8 @@ { "Controller": "memory", "Path": "/dev/memcg", - "Mode": "0700", - "UID": "root", + "Mode": "0755", + "UID": "system", "GID": "system", "Optional": true } diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index 449a50546..b133769a3 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -16,6 +16,12 @@ "File": "top-app/cpus" }, { + "Name": "AudioAppCapacityCPUs", + "Controller": "cpuset", + "File": "audio-app/cpus" + }, + + { "Name": "MemLimit", "Controller": "memory", "File": "memory.limit_in_bytes" @@ -171,6 +177,19 @@ ] }, { + "Name": "AudioAppPerformance", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "schedtune", + "Path": "audio-app" + } + } + ] + }, + { "Name": "NNApiHALPerformance", "Actions": [ { @@ -396,6 +415,46 @@ } ] }, + { + "Name": "AudioAppCapacity", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "audio-app" + } + } + ] + }, + + { + "Name": "BlkIOForeground", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "blkio", + "Path": "" + } + } + ] + }, + { + "Name": "BlkIOBackground", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "blkio", + "Path": "bg" + } + } + ] + }, { "Name": "LowIoPriority", diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp index 1a4196a4d..03d347973 100644 --- a/libprocessgroup/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -46,15 +46,16 @@ int set_cpuset_policy(int tid, SchedPolicy policy) { switch (policy) { case SP_BACKGROUND: - return SetTaskProfiles(tid, {"CPUSET_SP_BACKGROUND"}, true) ? 0 : -1; + return SetTaskProfiles(tid, {"CPUSET_SP_BACKGROUND", "BlkIOBackground"}, true) ? 0 : -1; case SP_FOREGROUND: + return SetTaskProfiles(tid, {"CPUSET_SP_FOREGROUND", "BlkIOForeground"}, true) ? 0 : -1; case SP_AUDIO_APP: case SP_AUDIO_SYS: - return SetTaskProfiles(tid, {"CPUSET_SP_FOREGROUND"}, true) ? 0 : -1; + return SetTaskProfiles(tid, {"CPUSET_SP_FOREGROUND", "AudioAppCapacity", "BlkIOForeground"}, true) ? 0 : -1; case SP_TOP_APP: - return SetTaskProfiles(tid, {"CPUSET_SP_TOP_APP"}, true) ? 0 : -1; + return SetTaskProfiles(tid, {"CPUSET_SP_TOP_APP", "BlkIOBackground"}, true) ? 0 : -1; case SP_SYSTEM: - return SetTaskProfiles(tid, {"CPUSET_SP_SYSTEM"}, true) ? 0 : -1; + return SetTaskProfiles(tid, {"CPUSET_SP_SYSTEM", "BlkIOForeground"}, true) ? 0 : -1; case SP_RESTRICTED: return SetTaskProfiles(tid, {"CPUSET_SP_RESTRICTED"}, true) ? 0 : -1; default: @@ -101,7 +102,7 @@ int set_sched_policy(int tid, SchedPolicy policy) { case SP_AUDIO_APP: case SP_AUDIO_SYS: case SP_TOP_APP: - SLOGD("^^^ tid %d (%s)", tid, thread_name); + SLOGD("^^^ tid %d policy %d (%s)", tid, policy, thread_name); break; case SP_SYSTEM: SLOGD("/// tid %d (%s)", tid, thread_name); @@ -117,17 +118,17 @@ int set_sched_policy(int tid, SchedPolicy policy) { switch (policy) { case SP_BACKGROUND: - return SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND"}, true) ? 0 : -1; + return SetTaskProfiles(tid, {"SCHED_SP_BACKGROUND", "BlkIOBackground"}, true) ? 0 : -1; case SP_FOREGROUND: case SP_AUDIO_APP: case SP_AUDIO_SYS: - return SetTaskProfiles(tid, {"SCHED_SP_FOREGROUND"}, true) ? 0 : -1; + return SetTaskProfiles(tid, {"SCHED_SP_FOREGROUND", "BlkIOForeground"}, true) ? 0 : -1; case SP_TOP_APP: - return SetTaskProfiles(tid, {"SCHED_SP_TOP_APP"}, true) ? 0 : -1; + return SetTaskProfiles(tid, {"SCHED_SP_TOP_APP", "BlkIOForeground"}, true) ? 0 : -1; case SP_SYSTEM: return SetTaskProfiles(tid, {"SCHED_SP_SYSTEM"}, true) ? 0 : -1; case SP_RT_APP: - return SetTaskProfiles(tid, {"SCHED_SP_RT_APP"}, true) ? 0 : -1; + return SetTaskProfiles(tid, {"SCHED_SP_RT_APP", "BlkIOForeground"}, true) ? 0 : -1; default: return SetTaskProfiles(tid, {"SCHED_SP_DEFAULT"}, true) ? 0 : -1; } @@ -198,6 +199,8 @@ int get_sched_policy(int tid, SchedPolicy* policy) { *policy = SP_TOP_APP; } else if (group == "restricted") { *policy = SP_RESTRICTED; + } else if (group == "audio-app") { + *policy = SP_AUDIO_APP; } else { errno = ERANGE; return -1; diff --git a/libsystem/include/system/camera.h b/libsystem/include/system/camera.h index 2ca90c395..990edcf32 100644 --- a/libsystem/include/system/camera.h +++ b/libsystem/include/system/camera.h @@ -88,9 +88,20 @@ enum { // Notify on autofocus start and stop. This is useful in continuous // autofocus - FOCUS_MODE_CONTINUOUS_VIDEO and FOCUS_MODE_CONTINUOUS_PICTURE. CAMERA_MSG_FOCUS_MOVE = 0x0800, // notifyCallback + CAMERA_MSG_VENDOR_START = 0x1000, + CAMERA_MSG_STATS_DATA = CAMERA_MSG_VENDOR_START, + CAMERA_MSG_META_DATA = 0x2000, + CAMERA_MSG_VENDOR_END = 0x8000, CAMERA_MSG_ALL_MSGS = 0xFFFF }; +/** meta data type in CameraMetaDataCallback */ +enum { + CAMERA_META_DATA_ASD = 0x001, //ASD data + CAMERA_META_DATA_FD = 0x002, //FD/FP data + CAMERA_META_DATA_HDR = 0x003, //Auto HDR data +}; + /** cmdType in sendCommand functions */ enum { CAMERA_CMD_START_SMOOTH_ZOOM = 1, @@ -189,7 +200,25 @@ enum { * IMPLEMENTATION_DEFINED, then HALv3 devices will use gralloc usage flags * of SW_READ_OFTEN. */ - CAMERA_CMD_SET_VIDEO_FORMAT = 11 + CAMERA_CMD_SET_VIDEO_FORMAT = 11, + + CAMERA_CMD_VENDOR_START = 20, + /** + * Commands to enable/disable preview histogram + * + * Based on user's input to enable/disable histogram from the camera + * UI, send the appropriate command to the HAL to turn on/off the histogram + * stats and start sending the data to the application. + */ + CAMERA_CMD_HISTOGRAM_ON = CAMERA_CMD_VENDOR_START, + CAMERA_CMD_HISTOGRAM_OFF = CAMERA_CMD_VENDOR_START + 1, + CAMERA_CMD_HISTOGRAM_SEND_DATA = CAMERA_CMD_VENDOR_START + 2, + CAMERA_CMD_LONGSHOT_ON = CAMERA_CMD_VENDOR_START + 3, + CAMERA_CMD_LONGSHOT_OFF = CAMERA_CMD_VENDOR_START + 4, + CAMERA_CMD_STOP_LONGSHOT = CAMERA_CMD_VENDOR_START + 5, + CAMERA_CMD_METADATA_ON = CAMERA_CMD_VENDOR_START + 6, + CAMERA_CMD_METADATA_OFF = CAMERA_CMD_VENDOR_START + 7, + CAMERA_CMD_VENDOR_END = 200, }; /** camera fatal errors */ @@ -284,10 +313,32 @@ typedef struct camera_face { * -2000, -2000 if this is not supported. */ int32_t mouth[2]; + int32_t smile_degree; + int32_t smile_score; + int32_t blink_detected; + int32_t face_recognised; + int32_t gaze_angle; + int32_t updown_dir; + int32_t leftright_dir; + int32_t roll_dir; + int32_t left_right_gaze; + int32_t top_bottom_gaze; + int32_t leye_blink; + int32_t reye_blink; } camera_face_t; /** + * The information of a data type received in a camera frame. + */ +typedef enum { + /** Data buffer */ + CAMERA_FRAME_DATA_BUF = 0x000, + /** File descriptor */ + CAMERA_FRAME_DATA_FD = 0x100 +} camera_frame_data_type_t; + +/** * The metadata of the frame data. */ typedef struct camera_frame_metadata { diff --git a/libutils/RefBase.cpp b/libutils/RefBase.cpp index b57e28741..9d359b805 100644 --- a/libutils/RefBase.cpp +++ b/libutils/RefBase.cpp @@ -549,7 +549,7 @@ void RefBase::weakref_type::decWeak(const void* id) weakref_impl* const impl = static_cast<weakref_impl*>(this); impl->removeWeakRef(id); const int32_t c = impl->mWeak.fetch_sub(1, std::memory_order_release); - LOG_ALWAYS_FATAL_IF(BAD_WEAK(c), "decWeak called on %p too many times", + ALOGW_IF(BAD_WEAK(c), "decWeak called on %p too many times", this); if (c != 1) return; atomic_thread_fence(std::memory_order_acquire); diff --git a/rootdir/init.rc b/rootdir/init.rc index d10689a01..8272654c7 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -32,10 +32,14 @@ on early-init # memory.pressure_level used by lmkd chown root system /dev/memcg/memory.pressure_level chmod 0040 /dev/memcg/memory.pressure_level + # app mem cgroups, used by activity manager, lmkd and zygote mkdir /dev/memcg/apps/ 0755 system system + write /dev/memcg/apps/memory.swappiness 100 + # cgroup for system_server and surfaceflinger mkdir /dev/memcg/system 0550 system system + write /dev/memcg/system/memory.swappiness 100 # symlink the Android specific /dev/tun to Linux expected /dev/net/tun mkdir /dev/net 0755 root root @@ -132,21 +136,25 @@ on init mkdir /dev/stune/background mkdir /dev/stune/top-app mkdir /dev/stune/rt + mkdir /dev/stune/audio-app chown system system /dev/stune chown system system /dev/stune/foreground chown system system /dev/stune/background chown system system /dev/stune/top-app chown system system /dev/stune/rt + chown system system /dev/stune/audio-app chown system system /dev/stune/tasks chown system system /dev/stune/foreground/tasks chown system system /dev/stune/background/tasks chown system system /dev/stune/top-app/tasks chown system system /dev/stune/rt/tasks + chown system system /dev/stune/audio-app/tasks chmod 0664 /dev/stune/tasks chmod 0664 /dev/stune/foreground/tasks chmod 0664 /dev/stune/background/tasks chmod 0664 /dev/stune/top-app/tasks chmod 0664 /dev/stune/rt/tasks + chmod 0664 /dev/stune/audio-app/tasks # cpuctl hierarchy for devices using utilclamp mkdir /dev/cpuctl/foreground @@ -348,12 +356,17 @@ on init copy /dev/cpuset/cpus /dev/cpuset/camera-daemon/cpus copy /dev/cpuset/mems /dev/cpuset/camera-daemon/mems + mkdir /dev/cpuset/audio-app + copy /dev/cpuset/cpus /dev/cpuset/audio-app/cpus + copy /dev/cpuset/mems /dev/cpuset/audio-app/mems + # change permissions for all cpusets we'll touch at runtime chown system system /dev/cpuset chown system system /dev/cpuset/foreground chown system system /dev/cpuset/background chown system system /dev/cpuset/system-background chown system system /dev/cpuset/top-app + chown system system /dev/cpuset/audio-app chown system system /dev/cpuset/restricted chown system system /dev/cpuset/camera-daemon chown system system /dev/cpuset/tasks @@ -361,6 +374,7 @@ on init chown system system /dev/cpuset/background/tasks chown system system /dev/cpuset/system-background/tasks chown system system /dev/cpuset/top-app/tasks + chown system system /dev/cpuset/audio-app/tasks chown system system /dev/cpuset/restricted/tasks chown system system /dev/cpuset/camera-daemon/tasks @@ -371,6 +385,7 @@ on init chmod 0664 /dev/cpuset/background/tasks chmod 0664 /dev/cpuset/system-background/tasks chmod 0664 /dev/cpuset/top-app/tasks + chmod 0664 /dev/cpuset/audio-app/tasks chmod 0664 /dev/cpuset/restricted/tasks chmod 0664 /dev/cpuset/tasks chmod 0664 /dev/cpuset/camera-daemon/tasks @@ -472,6 +487,7 @@ on late-init # '--early' can be specified to skip entries with 'latemount'. # /system and /vendor must be mounted by the end of the fs stage, # while /data is optional. + trigger factory-fs trigger fs trigger post-fs @@ -500,6 +516,7 @@ on late-init trigger early-boot trigger boot + trigger mmi on early-fs # Once metadata has been mounted, we'll need vold to deal with userdata checkpointing @@ -590,7 +607,20 @@ on late-fs # Load trusted keys from dm-verity protected partitions exec -- /system/bin/fsverity_init --load-verified-keys -on late-fs && property:ro.product.cpu.abilist64=* +# Only enable the bootreceiver tracing instance for kernels 5.10 and above. +on late-fs && property:ro.kernel.version=4.9 + setprop bootreceiver.enable 0 +on late-fs && property:ro.kernel.version=4.14 + setprop bootreceiver.enable 0 +on late-fs && property:ro.kernel.version=4.19 + setprop bootreceiver.enable 0 +on late-fs && property:ro.kernel.version=5.4 + setprop bootreceiver.enable 0 +on late-fs + # Bootreceiver tracing instance is enabled by default. + setprop bootreceiver.enable ${bootreceiver.enable:-1} + +on property:ro.product.cpu.abilist64=* && property:bootreceiver.enable=1 # Set up a tracing instance for system_server to monitor error_report_end events. # These are sent by kernel tools like KASAN and KFENCE when a memory corruption # is detected. This is only needed for 64-bit systems. @@ -1099,6 +1129,11 @@ on property:vold.decrypt=trigger_load_persist_props start logd start logd-reinit +# corefile limit +on property:persist.debug.trace=1 + mkdir /data/core 0777 root root + write /proc/sys/kernel/core_pattern "/data/core/%E.%p.%e" + on property:vold.decrypt=trigger_post_fs_data trigger post-fs-data trigger zygote-start diff --git a/trusty/storage/interface/include/trusty/interface/storage.h b/trusty/storage/interface/include/trusty/interface/storage.h index b196d88b3..3f1dcb8c6 100644 --- a/trusty/storage/interface/include/trusty/interface/storage.h +++ b/trusty/storage/interface/include/trusty/interface/storage.h @@ -112,26 +112,30 @@ enum storage_file_open_flag { /** * enum storage_msg_flag - protocol-level flags in struct storage_msg - * @STORAGE_MSG_FLAG_BATCH: if set, command belongs to a batch transaction. - * No response will be sent by the server until - * it receives a command with this flag unset, at - * which point a cummulative result for all messages - * sent with STORAGE_MSG_FLAG_BATCH will be sent. - * This is only supported by the non-secure disk proxy - * server. - * @STORAGE_MSG_FLAG_PRE_COMMIT: if set, indicates that server need to commit - * pending changes before processing this message. - * @STORAGE_MSG_FLAG_POST_COMMIT: if set, indicates that server need to commit - * pending changes after processing this message. - * @STORAGE_MSG_FLAG_TRANSACT_COMPLETE: if set, indicates that server need to commit - * current transaction after processing this message. - * It is an alias for STORAGE_MSG_FLAG_POST_COMMIT. + * @STORAGE_MSG_FLAG_BATCH: if set, command belongs to a batch transaction. + * No response will be sent by the server until + * it receives a command with this flag unset, at + * which point a cumulative result for all messages + * sent with STORAGE_MSG_FLAG_BATCH will be sent. + * This is only supported by the non-secure disk proxy + * server. + * @STORAGE_MSG_FLAG_PRE_COMMIT: if set, indicates that server need to commit + * pending changes before processing this message. + * @STORAGE_MSG_FLAG_POST_COMMIT: if set, indicates that server need to commit + * pending changes after processing this message. + * @STORAGE_MSG_FLAG_TRANSACT_COMPLETE: if set, indicates that server need to commit + * current transaction after processing this message. + * It is an alias for STORAGE_MSG_FLAG_POST_COMMIT. + * @STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT: if set, indicates that server needs to ensure + * that there is not a pending checkpoint for + * userdata before processing this message. */ enum storage_msg_flag { - STORAGE_MSG_FLAG_BATCH = 0x1, - STORAGE_MSG_FLAG_PRE_COMMIT = 0x2, - STORAGE_MSG_FLAG_POST_COMMIT = 0x4, - STORAGE_MSG_FLAG_TRANSACT_COMPLETE = STORAGE_MSG_FLAG_POST_COMMIT, + STORAGE_MSG_FLAG_BATCH = 0x1, + STORAGE_MSG_FLAG_PRE_COMMIT = 0x2, + STORAGE_MSG_FLAG_POST_COMMIT = 0x4, + STORAGE_MSG_FLAG_TRANSACT_COMPLETE = STORAGE_MSG_FLAG_POST_COMMIT, + STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT = 0x8, }; /* diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp index d67089fb2..38d868508 100644 --- a/trusty/storage/proxy/Android.bp +++ b/trusty/storage/proxy/Android.bp @@ -23,6 +23,7 @@ cc_binary { vendor: true, srcs: [ + "checkpoint_handling.cpp", "ipc.c", "rpmb.c", "storage.c", @@ -30,12 +31,14 @@ cc_binary { ], shared_libs: [ + "libbase", "liblog", "libhardware_legacy", ], header_libs: ["libcutils_headers"], static_libs: [ + "libfstab", "libtrustystorageinterface", "libtrusty", ], diff --git a/trusty/storage/proxy/checkpoint_handling.cpp b/trusty/storage/proxy/checkpoint_handling.cpp new file mode 100644 index 000000000..6c2fd363e --- /dev/null +++ b/trusty/storage/proxy/checkpoint_handling.cpp @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "checkpoint_handling.h" +#include "log.h" + +#include <fstab/fstab.h> +#include <cstring> +#include <string> + +namespace { + +bool checkpointingDoneForever = false; + +} // namespace + +int is_data_checkpoint_active(bool* active) { + if (!active) { + ALOGE("active out parameter is null"); + return 0; + } + + *active = false; + + if (checkpointingDoneForever) { + return 0; + } + + android::fs_mgr::Fstab procMounts; + bool success = android::fs_mgr::ReadFstabFromFile("/proc/mounts", &procMounts); + if (!success) { + ALOGE("Could not parse /proc/mounts\n"); + /* Really bad. Tell the caller to abort the write. */ + return -1; + } + + android::fs_mgr::FstabEntry* dataEntry = + android::fs_mgr::GetEntryForMountPoint(&procMounts, "/data"); + if (dataEntry == NULL) { + ALOGE("/data is not mounted yet\n"); + return 0; + } + + /* We can't handle e.g., ext4. Nothing we can do about it for now. */ + if (dataEntry->fs_type != "f2fs") { + ALOGW("Checkpoint status not supported for filesystem %s\n", dataEntry->fs_type.c_str()); + checkpointingDoneForever = true; + return 0; + } + + /* + * The data entry looks like "... blah,checkpoint=disable:0,blah ...". + * checkpoint=disable means checkpointing is on (yes, arguably reversed). + */ + size_t checkpointPos = dataEntry->fs_options.find("checkpoint=disable"); + if (checkpointPos == std::string::npos) { + /* Assumption is that once checkpointing turns off, it stays off */ + checkpointingDoneForever = true; + } else { + *active = true; + } + + return 0; +} diff --git a/trusty/storage/proxy/checkpoint_handling.h b/trusty/storage/proxy/checkpoint_handling.h new file mode 100644 index 000000000..f1bf27c8d --- /dev/null +++ b/trusty/storage/proxy/checkpoint_handling.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include <stdbool.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * is_data_checkpoint_active() - Check for an active, uncommitted checkpoint of + * /data. If a checkpoint is active, storage should not commit any + * rollback-protected writes to /data. + * @active: Out parameter that will be set to the result of the check. + * + * Return: 0 if active was set and is valid, non-zero otherwise. + */ +int is_data_checkpoint_active(bool* active); + +#ifdef __cplusplus +} +#endif diff --git a/trusty/storage/proxy/proxy.c b/trusty/storage/proxy/proxy.c index e23094183..c690a2876 100644 --- a/trusty/storage/proxy/proxy.c +++ b/trusty/storage/proxy/proxy.c @@ -26,6 +26,7 @@ #include <cutils/android_filesystem_config.h> +#include "checkpoint_handling.h" #include "ipc.h" #include "log.h" #include "rpmb.h" @@ -130,6 +131,21 @@ static int handle_req(struct storage_msg* msg, const void* req, size_t req_len) } } + if (msg->flags & STORAGE_MSG_FLAG_PRE_COMMIT_CHECKPOINT) { + bool is_checkpoint_active = false; + + rc = is_data_checkpoint_active(&is_checkpoint_active); + if (rc != 0) { + ALOGE("is_data_checkpoint_active failed in an unexpected way. Aborting.\n"); + msg->result = STORAGE_ERR_GENERIC; + return ipc_respond(msg, NULL, 0); + } else if (is_checkpoint_active) { + ALOGE("Checkpoint in progress, dropping write ...\n"); + msg->result = STORAGE_ERR_GENERIC; + return ipc_respond(msg, NULL, 0); + } + } + switch (msg->cmd) { case STORAGE_FILE_DELETE: rc = storage_file_delete(msg, req, req_len); |