From f3f3845b444608e982015c95ae50c8de3aad3820 Mon Sep 17 00:00:00 2001 From: Snehal Date: Fri, 19 Jul 2024 13:13:19 +0000 Subject: [PATCH 001/183] Update struct to include far and elr on the NS side Bug: 354119614 Change-Id: I88a5f08ead9a536e12bc4a3e8d701e01aa8b8f29 --- trusty/metrics/include/trusty/metrics/tipc.h | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/trusty/metrics/include/trusty/metrics/tipc.h b/trusty/metrics/include/trusty/metrics/tipc.h index b4428d576..4c4d37df1 100644 --- a/trusty/metrics/include/trusty/metrics/tipc.h +++ b/trusty/metrics/include/trusty/metrics/tipc.h @@ -43,6 +43,8 @@ #define UUID_STR_SIZE (37) +#define HASH_SIZE_BYTES 64 + /** * enum metrics_cmd - command identifiers for metrics interface * @METRICS_CMD_RESP_BIT: message is a response @@ -112,10 +114,22 @@ struct metrics_report_exit_req { * "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" * @crash_reason: architecture-specific code representing the reason for the * crash + * @far: Fault Address Register corresponding to the crash. It is set to 0 and + * not always revealed + * @far_hash: Fault Address Register obfuscated, always revealed + * @elr: Exception Link Register corresponding to the crash. It is set to 0 and + * not always revealed + * @elr_hash: Exception Link Register obfuscated, always revealed + * @is_hash: Boolean value indicating whether far and elr have been ob */ struct metrics_report_crash_req { char app_id[UUID_STR_SIZE]; uint32_t crash_reason; + uint64_t far; + uint8_t far_hash[HASH_SIZE_BYTES]; + uint64_t elr; + uint8_t elr_hash[HASH_SIZE_BYTES]; + bool is_hash; } __attribute__((__packed__)); enum TrustyStorageErrorType { From 34083b7151101cd2ed0e865eb4e40a54fd2f1131 Mon Sep 17 00:00:00 2001 From: Andrew Walbran Date: Fri, 20 Sep 2024 15:20:41 +0100 Subject: [PATCH 002/183] Use std::sync::LazyLock rather than once_cell. This was recently stabilised in Rust 1.80. Test: Treehugger Change-Id: I33a16bb1ad6c868c5d32ab72d08ce4e7f910300f --- libstats/pull_rust/Android.bp | 1 - libstats/pull_rust/stats_pull.rs | 7 +++---- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/libstats/pull_rust/Android.bp b/libstats/pull_rust/Android.bp index 69020267d..2a8939edb 100644 --- a/libstats/pull_rust/Android.bp +++ b/libstats/pull_rust/Android.bp @@ -61,7 +61,6 @@ rust_library { srcs: ["stats_pull.rs"], rustlibs: [ "liblog_rust", - "libonce_cell", "libstatslog_rust_header", "libstatspull_bindgen", ], diff --git a/libstats/pull_rust/stats_pull.rs b/libstats/pull_rust/stats_pull.rs index b2bebcc4e..03929e3b2 100644 --- a/libstats/pull_rust/stats_pull.rs +++ b/libstats/pull_rust/stats_pull.rs @@ -14,13 +14,12 @@ //! A Rust interface for the StatsD pull API. -use once_cell::sync::Lazy; use statslog_rust_header::{Atoms, Stat, StatsError}; use statspull_bindgen::*; use std::collections::HashMap; use std::convert::TryInto; use std::os::raw::c_void; -use std::sync::Mutex; +use std::sync::{LazyLock, Mutex}; /// The return value of callbacks. pub type StatsPullResult = Vec>; @@ -107,8 +106,8 @@ impl Default for Metadata { } } -static COOKIES: Lazy StatsPullResult>>> = - Lazy::new(|| Mutex::new(HashMap::new())); +static COOKIES: LazyLock StatsPullResult>>> = + LazyLock::new(|| Mutex::new(HashMap::new())); /// # Safety /// From 47718268d4537ea5db1228ab9aa18a176f0c7b92 Mon Sep 17 00:00:00 2001 From: Han Wang Date: Sun, 31 Dec 2023 02:46:38 +0000 Subject: [PATCH 003/183] Remove OEM_UNLOCK_PROP usage * It was only used for adb host scripts, but after commit "Remove sys.oem_unlock_allowed check for Android device" in 2016, there is no usage for it. Remove it because this prop is now exposed to untrusted apps, which is not desirable. Change-Id: Ic1c2f4e06b3a07ecf3f724fe5085974c626cb3fc --- .../libpropertyinfoserializer/property_info_serializer_test.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp index a484441c9..bed4a73bd 100644 --- a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp +++ b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp @@ -729,7 +729,6 @@ TEST(propertyinfoserializer, RealProperties) { {"sys.ims.QMI_DAEMON_STATUS", "u:object_r:qcom_ims_prop:s0"}, {"sys.listeners.registered", "u:object_r:qseecomtee_prop:s0"}, {"sys.logbootcomplete", "u:object_r:system_prop:s0"}, - {"sys.oem_unlock_allowed", "u:object_r:system_prop:s0"}, {"sys.qcom.devup", "u:object_r:system_prop:s0"}, {"sys.sysctl.extra_free_kbytes", "u:object_r:system_prop:s0"}, {"sys.usb.config", "u:object_r:system_radio_prop:s0"}, From a3b9e560bdd6b7676cb41ab0293a777b65754063 Mon Sep 17 00:00:00 2001 From: Pawan Wagh Date: Mon, 23 Sep 2024 20:32:48 +0000 Subject: [PATCH 004/183] Replace ANDROID_VENDOR with ANDROID_VNDK in versioning API_LEVEL_AT_LEAST Check doesn't work on product modules Bug: 368559337 Test: Boot device Change-Id: I8b37b39caa642afc4d8c2b7adf6eed0b08efb40c --- libvendorsupport/include_llndk/android/llndk-versioning.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/libvendorsupport/include_llndk/android/llndk-versioning.h b/libvendorsupport/include_llndk/android/llndk-versioning.h index cf82fb712..0402c2880 100644 --- a/libvendorsupport/include_llndk/android/llndk-versioning.h +++ b/libvendorsupport/include_llndk/android/llndk-versioning.h @@ -25,7 +25,7 @@ __attribute__((annotate("introduced_in_llndk=" #vendor_api_level))) #endif -#if defined(__ANDROID_VENDOR__) +#if defined(__ANDROID_VNDK__) // Use this macro as an `if` statement to call an API that are available to both NDK and LLNDK. // This returns true for the vendor modules if the vendor_api_level is less than or equal to the @@ -33,7 +33,7 @@ #define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ constexpr(__ANDROID_VENDOR_API__ >= vendor_api_level) -#else // __ANDROID_VENDOR__ +#else // __ANDROID_VNDK__ // For non-vendor modules, API_LEVEL_AT_LEAST is replaced with __builtin_available(sdk_api_level) to // guard the API for __INTRODUCED_IN. @@ -42,4 +42,4 @@ (__builtin_available(android sdk_api_level, *)) #endif -#endif // __ANDROID_VENDOR__ +#endif // __ANDROID_VNDK__ From 4f0e3eb6f2eec51f688001e13da673106eec8dd1 Mon Sep 17 00:00:00 2001 From: Armelle Laine Date: Wed, 18 Sep 2024 05:55:47 +0000 Subject: [PATCH 005/183] trusty: utils: trusty-ut-ctrl: add to system_ext Bug: 367423387 Test: atest VtsHalSecureStorageTargetTest Change-Id: I70a8a9108c7399f99bfdf26b00c5fbd1fcb039c6 --- trusty/utils/trusty-ut-ctrl/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/trusty/utils/trusty-ut-ctrl/Android.bp b/trusty/utils/trusty-ut-ctrl/Android.bp index 6fc2a48d7..b76e55fb8 100644 --- a/trusty/utils/trusty-ut-ctrl/Android.bp +++ b/trusty/utils/trusty-ut-ctrl/Android.bp @@ -18,7 +18,8 @@ package { cc_binary { name: "trusty-ut-ctrl", - vendor: true, + vendor_available: true, + system_ext_specific: true, srcs: ["ut-ctrl.c"], shared_libs: [ From 16f94816dbdc4747036eb1933ee39c5602253571 Mon Sep 17 00:00:00 2001 From: "Pechetty Sravani (xWF)" Date: Tue, 24 Sep 2024 15:27:48 +0000 Subject: [PATCH 006/183] Revert "Support vendor partition in non-debuggable pVMs" Revert submission 3236797-b/340506965 Reason for revert: DroidMonitor created revert due to b/366178299. Reverted changes: /q/submissionid:3236797-b/340506965 Tracking bug: b/369390218 Change-Id: I0ec7fe89a7a0ca3a9981cd80222d03a785e9b28f --- init/first_stage_mount.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index c26b31e93..ece430b70 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -156,13 +156,6 @@ static Result ReadFirstStageFstabAndroid() { return fstab; } -static bool IsRequestingMicrodroidVendorPartition(const std::string& cmdline) { - if (virtualization::IsEnableTpuAssignableDeviceFlagEnabled()) { - return access("/proc/device-tree/avf/vendor_hashtree_descriptor_root_digest", F_OK) == 0; - } - return cmdline.find("androidboot.microdroid.mount_vendor=1") != std::string::npos; -} - // Note: this is a temporary solution to avoid blocking devs that depend on /vendor partition in // Microdroid. For the proper solution the /vendor fstab should probably be defined in the DT. // TODO(b/285855430): refactor this @@ -173,7 +166,7 @@ static Result ReadFirstStageFstabMicrodroid(const std::string& cmdline) { if (!ReadDefaultFstab(&fstab)) { return Error() << "failed to read fstab"; } - if (!IsRequestingMicrodroidVendorPartition(cmdline)) { + if (cmdline.find("androidboot.microdroid.mount_vendor=1") == std::string::npos) { // We weren't asked to mount /vendor partition, filter it out from the fstab. auto predicate = [](const auto& entry) { return entry.mount_point == "/vendor"; }; fstab.erase(std::remove_if(fstab.begin(), fstab.end(), predicate), fstab.end()); From 69f3da832fb080b1e2db2270e26b16c84d7b194e Mon Sep 17 00:00:00 2001 From: Armelle Laine Date: Wed, 28 Aug 2024 06:51:35 +0000 Subject: [PATCH 007/183] trusty: support secure storage in system-ext Bug: 355194622 Test: CF gets booted with KeyMint TA in VM Change-Id: I3708ac572068162ca57c0e9b287296cea73215a7 --- trusty/storage/interface/Android.bp | 3 +- trusty/storage/proxy/Android.bp | 26 ++++++---- trusty/trusty-storage-cf.mk | 25 +++++++++ trusty/utils/rpmb_dev/Android.bp | 23 +++++++-- trusty/utils/rpmb_dev/rpmb_dev.system.rc | 64 ++++++++++++++++++++++++ 5 files changed, 125 insertions(+), 16 deletions(-) create mode 100644 trusty/trusty-storage-cf.mk create mode 100644 trusty/utils/rpmb_dev/rpmb_dev.system.rc diff --git a/trusty/storage/interface/Android.bp b/trusty/storage/interface/Android.bp index d031b0c1e..769f53d8e 100644 --- a/trusty/storage/interface/Android.bp +++ b/trusty/storage/interface/Android.bp @@ -20,6 +20,7 @@ package { cc_library_static { name: "libtrustystorageinterface", - vendor: true, + vendor_available: true, + system_ext_specific: true, export_include_dirs: ["include"], } diff --git a/trusty/storage/proxy/Android.bp b/trusty/storage/proxy/Android.bp index 7ef0e6f83..f32188a22 100644 --- a/trusty/storage/proxy/Android.bp +++ b/trusty/storage/proxy/Android.bp @@ -18,10 +18,8 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } -cc_binary { - name: "storageproxyd", - vendor: true, - +cc_defaults { + name: "storageproxyd.defaults", srcs: [ "checkpoint_handling.cpp", "ipc.c", @@ -47,14 +45,22 @@ cc_binary { "libtrustystorageinterface", "libtrusty", ], - target: { - vendor: { - // vendor variant requires this flag - cflags: ["-DVENDOR_FS_READY_PROPERTY"], - }, - }, cflags: [ "-Wall", "-Werror", ], } + +cc_binary { + name: "storageproxyd", + defaults: ["storageproxyd.defaults"], + vendor: true, + // vendor variant requires this flag + cflags: ["-DVENDOR_FS_READY_PROPERTY"], +} + +cc_binary { + name: "storageproxyd.system", + defaults: ["storageproxyd.defaults"], + system_ext_specific: true, +} diff --git a/trusty/trusty-storage-cf.mk b/trusty/trusty-storage-cf.mk new file mode 100644 index 000000000..3b46445da --- /dev/null +++ b/trusty/trusty-storage-cf.mk @@ -0,0 +1,25 @@ +# +# Copyright (C) 2024 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 makefile should be included by the cuttlefish device +# when enabling the Trusty VM to pull in the baseline set +# of storage specific modules + +PRODUCT_PACKAGES += \ + storageproxyd.system \ + rpmb_dev.system \ + diff --git a/trusty/utils/rpmb_dev/Android.bp b/trusty/utils/rpmb_dev/Android.bp index 603a1a80a..13f151d2e 100644 --- a/trusty/utils/rpmb_dev/Android.bp +++ b/trusty/utils/rpmb_dev/Android.bp @@ -15,11 +15,8 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } -cc_binary { - name: "rpmb_dev", - vendor: true, - host_supported: true, - +cc_defaults { + name: "rpmb_dev.cc_defaults", srcs: [ "rpmb_dev.c", ], @@ -32,7 +29,23 @@ cc_binary { "-Wall", "-Werror", ], +} + +cc_binary { + name: "rpmb_dev", + defaults: ["rpmb_dev.cc_defaults"], + vendor: true, + host_supported: true, init_rc: [ "rpmb_dev.rc", ], } + +cc_binary { + name: "rpmb_dev.system", + defaults: ["rpmb_dev.cc_defaults"], + system_ext_specific: true, + init_rc: [ + "rpmb_dev.system.rc", + ], +} diff --git a/trusty/utils/rpmb_dev/rpmb_dev.system.rc b/trusty/utils/rpmb_dev/rpmb_dev.system.rc new file mode 100644 index 000000000..b78c4e2a1 --- /dev/null +++ b/trusty/utils/rpmb_dev/rpmb_dev.system.rc @@ -0,0 +1,64 @@ +service storageproxyd_system /system_ext/bin/storageproxyd.system \ + -d ${storageproxyd_system.trusty_ipc_dev:-/dev/trusty-ipc-dev0} \ + -r /dev/socket/rpmb_mock_system \ + -p /data/secure_storage_system \ + -t sock + disabled + user system + group system + +service rpmb_mock_init_system /system_ext/bin/rpmb_dev.system \ + --dev /mnt/secure_storage_rpmb_system/persist/RPMB_DATA --init --size 2048 + disabled + user system + group system + oneshot + +service rpmb_mock_system /system_ext/bin/rpmb_dev.system \ + --dev /mnt/secure_storage_rpmb_system/persist/RPMB_DATA \ + --sock rpmb_mock_system + disabled + user system + group system + socket rpmb_mock_system stream 660 system system + +# storageproxyd +on late-fs && \ + property:trusty_vm_system_nonsecure.ready=1 && \ + property:storageproxyd_system.trusty_ipc_dev=* + wait /dev/socket/rpmb_mock_system + start storageproxyd_system + + +# RPMB Mock +on post-fs && \ + property:trusty_vm_system_nonsecure.ready=1 && \ + property:trusty_vm_system.vm_cid=* + # Create a persistent location for the RPMB data + # (work around lack of RPMb block device on CF). + # file contexts secure_storage_rpmb_system_file + # (only used on Cuttlefish as this is non secure) + mkdir /metadata/secure_storage_rpmb_system 0770 system system + mkdir /mnt/secure_storage_rpmb_system 0770 system system + symlink /metadata/secure_storage_rpmb_system \ + /mnt/secure_storage_rpmb_system/persist + # Create a system persist directory in /metadata + # (work around lack of dedicated system persist partition). + # file contexts secure_storage_persist_system_file + mkdir /metadata/secure_storage_persist_system 0770 system system + mkdir /mnt/secure_storage_persist_system 0770 system system + symlink /metadata/secure_storage_persist_system \ + /mnt/secure_storage_persist_system/persist + setprop storageproxyd_system.trusty_ipc_dev VSOCK:${trusty_vm_system.vm_cid}:1 + exec_start rpmb_mock_init_system + start rpmb_mock_system + +on post-fs-data && \ + property:trusty_vm_system_nonsecure.ready=1 && \ + property:storageproxyd_system.trusty_ipc_dev=* + # file contexts secure_storage_system_file + mkdir /data/secure_storage_system 0770 root system + symlink /mnt/secure_storage_persist_system/persist \ + /data/secure_storage_system/persist + chown root system /data/secure_storage_system/persist + restart storageproxyd_system From 3d90ed0ceab2937f72183281aca1120619cadf1b Mon Sep 17 00:00:00 2001 From: Armelle Laine Date: Wed, 25 Sep 2024 06:32:25 +0000 Subject: [PATCH 008/183] trusty: utils: trusty-ut-ctrl: fix the vendor target Bug: 369492636 Test: trusty-ut-ctl -D Change-Id: I9d8a298941caa4e3c5a424269577580be0ba79c8 --- trusty/utils/trusty-ut-ctrl/Android.bp | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/trusty/utils/trusty-ut-ctrl/Android.bp b/trusty/utils/trusty-ut-ctrl/Android.bp index b76e55fb8..c255614b0 100644 --- a/trusty/utils/trusty-ut-ctrl/Android.bp +++ b/trusty/utils/trusty-ut-ctrl/Android.bp @@ -16,10 +16,8 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } -cc_binary { - name: "trusty-ut-ctrl", - vendor_available: true, - system_ext_specific: true, +cc_defaults { + name: "trusty-ut-ctrl.defaults", srcs: ["ut-ctrl.c"], shared_libs: [ @@ -34,3 +32,15 @@ cc_binary { "-Werror", ], } + +cc_binary { + name: "trusty-ut-ctrl", + defaults: ["trusty-ut-ctrl.defaults"], + vendor: true, +} + +cc_binary { + name: "trusty-ut-ctrl.system", + defaults: ["trusty-ut-ctrl.defaults"], + system_ext_specific: true, +} From 1396f9d3bb43ea44aa6b0a67fe44570828f9f668 Mon Sep 17 00:00:00 2001 From: Vova Sharaienko Date: Thu, 26 Sep 2024 00:10:31 +0000 Subject: [PATCH 009/183] Add host support to libexpresslog - change to a set of build artifacts Flag: EXEMPT Refactor Ignore-AOSP-First: will cp to aosp after Bug: n/a Test: build Change-Id: I8b565a9237319da0b24fed2c802f0e03a15bcd57 --- libstats/expresslog/Android.bp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libstats/expresslog/Android.bp b/libstats/expresslog/Android.bp index 96ab59b10..b4413e12d 100644 --- a/libstats/expresslog/Android.bp +++ b/libstats/expresslog/Android.bp @@ -1,4 +1,3 @@ - // // Copyright (C) 2023 The Android Open Source Project // @@ -28,6 +27,7 @@ cc_defaults { cc_library { name: "libexpresslog", + host_supported: true, defaults: ["expresslog_defaults"], cflags: [ "-DNAMESPACE_FOR_HASH_FUNCTIONS=farmhash", @@ -74,6 +74,7 @@ genrule { cc_library_static { name: "libstatslog_express", + host_supported: true, generated_sources: ["statslog_express.cpp"], generated_headers: ["statslog_express.h"], export_generated_headers: ["statslog_express.h"], @@ -119,5 +120,5 @@ cc_test { ], shared_libs: [ "libstatssocket", - ] + ], } From 8a32d828847a989523ebee8d21d084cf1d55a605 Mon Sep 17 00:00:00 2001 From: Vova Sharaienko Date: Thu, 26 Sep 2024 17:59:38 +0000 Subject: [PATCH 010/183] Added ownership attribution for test targets Flag: NONE Docs Bug: n/a Test: build Ignore-AOSP-First: will cp to aosp after Change-Id: I6ca6e48ea1ec704216833c2c04177b0022e7b659 --- libstats/expresslog/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/libstats/expresslog/Android.bp b/libstats/expresslog/Android.bp index b4413e12d..f70252afc 100644 --- a/libstats/expresslog/Android.bp +++ b/libstats/expresslog/Android.bp @@ -15,6 +15,7 @@ // package { default_applicable_licenses: ["Android-Apache-2.0"], + default_team: "trendy_team_android_telemetry_client_infra", } cc_defaults { From 1ec5290872b1bd120e44ebffddd47b2a62bc90d1 Mon Sep 17 00:00:00 2001 From: Hans Boehm Date: Thu, 26 Sep 2024 12:59:37 -0700 Subject: [PATCH 011/183] Remove unnecessary getpriority() system call This was introduced for a valid reason in aosp/1224543, but that reason was later removed. This code wasn't. It is not worth making a system call in order to possibly avoid a second one, which I expect is no more expensive in that, particularly easy, case. Test: Treehugger Change-Id: I346f9b641c6feb791247b16fb900a4ad97e646d2 --- libutils/Threads.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp index d8d75acf4..111d46af9 100644 --- a/libutils/Threads.cpp +++ b/libutils/Threads.cpp @@ -313,11 +313,6 @@ void androidSetCreateThreadFunc(android_create_thread_fn func) int androidSetThreadPriority(pid_t tid, int pri) { int rc = 0; - int curr_pri = getpriority(PRIO_PROCESS, tid); - - if (curr_pri == pri) { - return rc; - } if (setpriority(PRIO_PROCESS, tid, pri) < 0) { rc = INVALID_OPERATION; From 717b4a7187c5ff89d293432b0f5f22a34b1b4710 Mon Sep 17 00:00:00 2001 From: Vova Sharaienko Date: Thu, 26 Sep 2024 21:11:51 +0000 Subject: [PATCH 012/183] Add host support to libexpresslog - change to a set of build artifacts Flag: EXEMPT Refactor Ignore-AOSP-First: will cp to aosp after Bug: n/a Test: build (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:1396f9d3bb43ea44aa6b0a67fe44570828f9f668) Merged-In: I8b565a9237319da0b24fed2c802f0e03a15bcd57 Change-Id: I8b565a9237319da0b24fed2c802f0e03a15bcd57 --- libstats/expresslog/Android.bp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libstats/expresslog/Android.bp b/libstats/expresslog/Android.bp index 96ab59b10..b4413e12d 100644 --- a/libstats/expresslog/Android.bp +++ b/libstats/expresslog/Android.bp @@ -1,4 +1,3 @@ - // // Copyright (C) 2023 The Android Open Source Project // @@ -28,6 +27,7 @@ cc_defaults { cc_library { name: "libexpresslog", + host_supported: true, defaults: ["expresslog_defaults"], cflags: [ "-DNAMESPACE_FOR_HASH_FUNCTIONS=farmhash", @@ -74,6 +74,7 @@ genrule { cc_library_static { name: "libstatslog_express", + host_supported: true, generated_sources: ["statslog_express.cpp"], generated_headers: ["statslog_express.h"], export_generated_headers: ["statslog_express.h"], @@ -119,5 +120,5 @@ cc_test { ], shared_libs: [ "libstatssocket", - ] + ], } From 78d5f7c6f5712560c83dd64ab69addbb16bec4aa Mon Sep 17 00:00:00 2001 From: Vova Sharaienko Date: Thu, 26 Sep 2024 21:12:01 +0000 Subject: [PATCH 013/183] Added ownership attribution for test targets Flag: NONE Docs Bug: n/a Test: build Ignore-AOSP-First: will cp to aosp after (cherry picked from https://googleplex-android-review.googlesource.com/q/commit:8a32d828847a989523ebee8d21d084cf1d55a605) Merged-In: I6ca6e48ea1ec704216833c2c04177b0022e7b659 Change-Id: I6ca6e48ea1ec704216833c2c04177b0022e7b659 --- libstats/expresslog/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/libstats/expresslog/Android.bp b/libstats/expresslog/Android.bp index 96ab59b10..f8fc88f7e 100644 --- a/libstats/expresslog/Android.bp +++ b/libstats/expresslog/Android.bp @@ -16,6 +16,7 @@ // package { default_applicable_licenses: ["Android-Apache-2.0"], + default_team: "trendy_team_android_telemetry_client_infra", } cc_defaults { From 6f0ebcb5260a8e769e0e029596d21c0efabe361b Mon Sep 17 00:00:00 2001 From: Jan Dabros Date: Thu, 19 Oct 2023 11:36:37 +0000 Subject: [PATCH 014/183] init: Look for super partition only on a boot device Init code is bailing out as soon as `super` partition was found in the system, ignoring rest of uevents. In case given device contains multiple boot sources, `super` partition as well as all other partitions shall be taken from the same boot source, instead of relying on `which uevent came first`. Bug: 309244873, 349144493 Test: Plug secondary USB boot device to device that supports multiple boot sources. Select boot from USB. Device boots properly. Signed-off-by: Jan Dabros Signed-off-by: Konrad Adamczyk Change-Id: I70eb7d4223258ec273faa523cb67ddab0b7c32a0 --- init/block_dev_initializer.cpp | 6 +++++- init/devices.cpp | 22 ++++++++++++++++++++++ init/devices.h | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index 8f5215856..cabeb0109 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -98,7 +98,11 @@ ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent, LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name; - devices->erase(iter); + // Remove partition from the list only if it was found on boot device + if (device_handler_->IsBootDevice(uevent)) { + devices->erase(iter); + } + device_handler_->HandleUevent(uevent); return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue; } diff --git a/init/devices.cpp b/init/devices.cpp index f2bb9d276..6a3a64dd8 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -188,6 +188,28 @@ void SysfsPermissions::SetPermissions(const std::string& path) const { } } +bool DeviceHandler::IsBootDevice(const Uevent& uevent) const { + std::string device; + + if (FindPlatformDevice(uevent.path, &device)) { + // Skip /devices/platform or /devices/ if present + static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; + static constexpr std::string_view devices_prefix = "/devices/"; + + if (StartsWith(device, devices_platform_prefix)) { + device = device.substr(devices_platform_prefix.length()); + } else if (StartsWith(device, devices_prefix)) { + device = device.substr(devices_prefix.length()); + } + } else if (FindPciDevicePrefix(uevent.path, &device)) { + } else if (FindVbdDevicePrefix(uevent.path, &device)) { + } else { + return false; + } + + return boot_devices_.find(device) != boot_devices_.end(); +} + std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) { static const auto partition_map = [] { std::vector> partition_map; diff --git a/init/devices.h b/init/devices.h index 6da123259..4df604d00 100644 --- a/init/devices.h +++ b/init/devices.h @@ -133,6 +133,7 @@ class DeviceHandler : public UeventHandler { // `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to // `userdata`. static std::string GetPartitionNameForDevice(const std::string& device); + bool IsBootDevice(const Uevent& uevent) const; private: void ColdbootDone() override; From 0d84909d667bf3ebd49db2ba87af759d1f326aba Mon Sep 17 00:00:00 2001 From: Sandeep Dhavale Date: Fri, 27 Sep 2024 13:37:18 -0700 Subject: [PATCH 015/183] libsnapshot: Use words for xor ops Use words instead of doing xor byte-by-byte for the entire buffer. Profiling this with unittest, I can see the xor ops is much faster. Also handle the word size appropriately for 32bit and 64bit platforms. simpleperf shows that ProcessXorOp() is atleast 30% faster. Similar improvement is seen for ProcessXorData(). Test: snapuserd_test Bug: 369905394 Change-Id: I0bd8586f7fc1bf184f19320667b8195b07f9cdf2 Signed-off-by: Sandeep Dhavale --- .../snapuserd/user-space-merge/read_worker.cpp | 11 ++++++++--- .../user-space-merge/snapuserd_readahead.cpp | 12 +++++++----- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp index ef311d475..33767d654 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/read_worker.cpp @@ -104,6 +104,8 @@ bool ReadWorker::ProcessCopyOp(const CowOperation* cow_op, void* buffer) { } bool ReadWorker::ProcessXorOp(const CowOperation* cow_op, void* buffer) { + using WordType = std::conditional_t; + if (!ReadFromSourceDevice(cow_op, buffer)) { return false; } @@ -120,9 +122,12 @@ bool ReadWorker::ProcessXorOp(const CowOperation* cow_op, void* buffer) { return false; } - auto xor_out = reinterpret_cast(buffer); - for (size_t i = 0; i < BLOCK_SZ; i++) { - xor_out[i] ^= xor_buffer_[i]; + auto xor_in = reinterpret_cast(xor_buffer_.data()); + auto xor_out = reinterpret_cast(buffer); + auto num_words = BLOCK_SZ / sizeof(WordType); + + for (auto i = 0; i < num_words; i++) { + xor_out[i] ^= xor_in[i]; } return true; } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index 6b1ed0cd7..9a1d441c4 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -458,6 +458,7 @@ bool ReadAhead::ReapIoCompletions(int pending_ios_to_complete) { void ReadAhead::ProcessXorData(size_t& block_xor_index, size_t& xor_index, std::vector& xor_op_vec, void* buffer, loff_t& buffer_offset) { + using WordType = std::conditional_t; loff_t xor_buf_offset = 0; while (block_xor_index < blocks_.size()) { @@ -470,13 +471,14 @@ void ReadAhead::ProcessXorData(size_t& block_xor_index, size_t& xor_index, // Check if this block is an XOR op if (xor_op->new_block == new_block) { // Pointer to the data read from base device - uint8_t* buffer = reinterpret_cast(bufptr); + auto buffer_words = reinterpret_cast(bufptr); // Get the xor'ed data read from COW device - uint8_t* xor_data = reinterpret_cast((char*)bufsink_.GetPayloadBufPtr() + - xor_buf_offset); + auto xor_data_words = reinterpret_cast( + (char*)bufsink_.GetPayloadBufPtr() + xor_buf_offset); + auto num_words = BLOCK_SZ / sizeof(WordType); - for (size_t byte_offset = 0; byte_offset < BLOCK_SZ; byte_offset++) { - buffer[byte_offset] ^= xor_data[byte_offset]; + for (auto i = 0; i < num_words; i++) { + buffer_words[i] ^= xor_data_words[i]; } // Move to next XOR op From bc067ef9f0408f3b7c4f5dcae3b6aec51f386e4d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Oct 2024 11:01:08 -0700 Subject: [PATCH 016/183] libdm: Redact keys from dm-crypt targets when calling GetTable. Ignore-AOSP-First: security fix Bug: 368069390 Test: libdm_test Change-Id: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d --- fs_mgr/libdm/dm.cpp | 14 ++++++++++++++ fs_mgr/libdm/dm_test.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index a9633226f..94c320ac4 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -551,6 +551,17 @@ bool DeviceMapper::GetTableInfo(const std::string& name, std::vector return GetTable(name, DM_STATUS_TABLE_FLAG, table); } +void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) { + if (DeviceMapper::GetTargetType(spec) == "crypt") { + auto parts = android::base::Split(*data, " "); + if (parts.size() < 2) { + return; + } + parts[1] = "redacted"; + *data = android::base::Join(parts, " "); + } +} + // private methods of DeviceMapper bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, std::vector* table) { @@ -589,6 +600,9 @@ bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, // Note: we use c_str() to eliminate any extra trailing 0s. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str(); } + if (flags & DM_STATUS_TABLE_FLAG) { + RedactTableInfo(*spec, &data); + } table->emplace_back(*spec, data); cursor = next_cursor; } diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index b890f4715..5eddb513c 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -814,3 +814,31 @@ TEST_F(DmTest, ThinProvisioning) { TempDevice thin("thin", thinTable); ASSERT_TRUE(thin.valid()); } + +TEST_F(DmTest, RedactDmCrypt) { + static constexpr uint64_t kImageSize = 65536; + unique_fd temp_file(CreateTempFile("file_1", kImageSize)); + ASSERT_GE(temp_file, 0); + + LoopDevice loop(temp_file, 10s); + ASSERT_TRUE(loop.valid()); + + static constexpr const char* kAlgorithm = "aes-cbc-essiv:sha256"; + static constexpr const char* kKey = "0e64ef514e6a1315b1f6390cb57c9e6a"; + + auto target = std::make_unique(0, kImageSize / 512, kAlgorithm, kKey, 0, + loop.device(), 0); + target->AllowDiscards(); + + DmTable table; + table.AddTarget(std::move(target)); + + auto& dm = DeviceMapper::Instance(); + std::string crypt_path; + ASSERT_TRUE(dm.CreateDevice(test_name_, table, &crypt_path, 10s)); + + std::vector targets; + ASSERT_TRUE(dm.GetTableInfo(test_name_, &targets)); + ASSERT_EQ(targets.size(), 1); + EXPECT_EQ(targets[0].data.find(kKey), std::string::npos); +} From 981664df08619b66ad51daf52356ff02f98a2b77 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 27 Aug 2024 16:50:10 +0000 Subject: [PATCH 017/183] libprocessgroup: Remove schedtune support Schedtune was an out of tree cgroup controller present in Android kernels up to 4.19. It was replaced with uclamp and the cpu controller. Now that 4.19 is EOL and unsupported, and schedtune is not present in any supported Android kernels, remove the userspace support for schedtune. Bug: 362504801 Change-Id: If8baaf1a616984c5dbaac1bbd03e23ad001bc29c --- libcutils/sched_policy_test.cpp | 7 - .../include/processgroup/sched_policy.h | 8 - libprocessgroup/profiles/Android.bp | 46 ----- libprocessgroup/profiles/cgroups_28.json | 11 -- libprocessgroup/profiles/cgroups_29.json | 11 -- libprocessgroup/profiles/cgroups_30.json | 12 -- .../profiles/task_profiles_28.json | 160 ------------------ .../profiles/task_profiles_29.json | 160 ------------------ .../profiles/task_profiles_30.json | 160 ------------------ libprocessgroup/sched_policy.cpp | 15 +- 10 files changed, 2 insertions(+), 588 deletions(-) delete mode 100644 libprocessgroup/profiles/cgroups_28.json delete mode 100644 libprocessgroup/profiles/cgroups_29.json delete mode 100644 libprocessgroup/profiles/cgroups_30.json delete mode 100644 libprocessgroup/profiles/task_profiles_28.json delete mode 100644 libprocessgroup/profiles/task_profiles_29.json delete mode 100644 libprocessgroup/profiles/task_profiles_30.json diff --git a/libcutils/sched_policy_test.cpp b/libcutils/sched_policy_test.cpp index 50bd6d0b8..264174309 100644 --- a/libcutils/sched_policy_test.cpp +++ b/libcutils/sched_policy_test.cpp @@ -67,13 +67,6 @@ static void AssertPolicy(SchedPolicy expected_policy) { } TEST(SchedPolicy, set_sched_policy) { - if (!schedboost_enabled()) { - // schedboost_enabled() (i.e. CONFIG_CGROUP_SCHEDTUNE) is optional; - // it's only needed on devices using energy-aware scheduler. - GTEST_LOG_(INFO) << "skipping test that requires CONFIG_CGROUP_SCHEDTUNE"; - return; - } - ASSERT_EQ(0, set_sched_policy(0, SP_BACKGROUND)); ASSERT_EQ(0, set_cpuset_policy(0, SP_BACKGROUND)); AssertPolicy(SP_BACKGROUND); diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h index 1b6ea669d..92cd367bf 100644 --- a/libprocessgroup/include/processgroup/sched_policy.h +++ b/libprocessgroup/include/processgroup/sched_policy.h @@ -29,14 +29,6 @@ extern "C" { */ extern bool cpusets_enabled(); -/* - * Check if Linux kernel enables SCHEDTUNE feature (only available in Android - * common kernel or Linaro LSK, not in mainline Linux as of v4.9) - * - * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise. - */ -extern bool schedboost_enabled(); - /* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */ typedef enum { SP_DEFAULT = -1, diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp index 885971a7a..1ec9f7f3b 100644 --- a/libprocessgroup/profiles/Android.bp +++ b/libprocessgroup/profiles/Android.bp @@ -19,11 +19,6 @@ package { prebuilt_etc { name: "cgroups.json", src: "cgroups.json", - required: [ - "cgroups_28.json", - "cgroups_29.json", - "cgroups_30.json", - ], } prebuilt_etc { @@ -33,50 +28,9 @@ prebuilt_etc { src: "cgroups.recovery.json", } -prebuilt_etc { - name: "cgroups_28.json", - src: "cgroups_28.json", - sub_dir: "task_profiles", -} - -prebuilt_etc { - name: "cgroups_29.json", - src: "cgroups_29.json", - sub_dir: "task_profiles", -} - -prebuilt_etc { - name: "cgroups_30.json", - src: "cgroups_30.json", - sub_dir: "task_profiles", -} - prebuilt_etc { name: "task_profiles.json", src: "task_profiles.json", - required: [ - "task_profiles_28.json", - "task_profiles_29.json", - "task_profiles_30.json", - ], -} - -prebuilt_etc { - name: "task_profiles_28.json", - src: "task_profiles_28.json", - sub_dir: "task_profiles", -} - -prebuilt_etc { - name: "task_profiles_29.json", - src: "task_profiles_29.json", - sub_dir: "task_profiles", -} - -prebuilt_etc { - name: "task_profiles_30.json", - src: "task_profiles_30.json", - sub_dir: "task_profiles", } cc_defaults { diff --git a/libprocessgroup/profiles/cgroups_28.json b/libprocessgroup/profiles/cgroups_28.json deleted file mode 100644 index 17d492949..000000000 --- a/libprocessgroup/profiles/cgroups_28.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "Cgroups": [ - { - "Controller": "schedtune", - "Path": "/dev/stune", - "Mode": "0755", - "UID": "system", - "GID": "system" - } - ] -} diff --git a/libprocessgroup/profiles/cgroups_29.json b/libprocessgroup/profiles/cgroups_29.json deleted file mode 100644 index 17d492949..000000000 --- a/libprocessgroup/profiles/cgroups_29.json +++ /dev/null @@ -1,11 +0,0 @@ -{ - "Cgroups": [ - { - "Controller": "schedtune", - "Path": "/dev/stune", - "Mode": "0755", - "UID": "system", - "GID": "system" - } - ] -} diff --git a/libprocessgroup/profiles/cgroups_30.json b/libprocessgroup/profiles/cgroups_30.json deleted file mode 100644 index 80a074bf1..000000000 --- a/libprocessgroup/profiles/cgroups_30.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "Cgroups": [ - { - "Controller": "schedtune", - "Path": "/dev/stune", - "Mode": "0755", - "UID": "system", - "GID": "system", - "Optional": true - } - ] -} diff --git a/libprocessgroup/profiles/task_profiles_28.json b/libprocessgroup/profiles/task_profiles_28.json deleted file mode 100644 index e7be5487d..000000000 --- a/libprocessgroup/profiles/task_profiles_28.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "Attributes": [ - { - "Name": "STuneBoost", - "Controller": "schedtune", - "File": "schedtune.boost" - }, - { - "Name": "STunePreferIdle", - "Controller": "schedtune", - "File": "schedtune.prefer_idle" - } - ], - - "Profiles": [ - { - "Name": "HighEnergySaving", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "NormalPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "" - } - } - ] - }, - { - "Name": "ServicePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "HighPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "foreground" - } - } - ] - }, - { - "Name": "MaxPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "top-app" - } - } - ] - }, - { - "Name": "RealtimePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "rt" - } - } - ] - }, - { - "Name": "CameraServicePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "camera-daemon" - } - } - ] - }, - { - "Name": "NNApiHALPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "nnapi-hal" - } - } - ] - }, - { - "Name": "Dex2oatPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "CpuPolicySpread", - "Actions": [ - { - "Name": "SetAttribute", - "Params": - { - "Name": "STunePreferIdle", - "Value": "1" - } - } - ] - }, - { - "Name": "CpuPolicyPack", - "Actions": [ - { - "Name": "SetAttribute", - "Params": - { - "Name": "STunePreferIdle", - "Value": "0" - } - } - ] - } - ] -} diff --git a/libprocessgroup/profiles/task_profiles_29.json b/libprocessgroup/profiles/task_profiles_29.json deleted file mode 100644 index 6174c8d0f..000000000 --- a/libprocessgroup/profiles/task_profiles_29.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "Attributes": [ - { - "Name": "STuneBoost", - "Controller": "schedtune", - "File": "schedtune.boost" - }, - { - "Name": "STunePreferIdle", - "Controller": "schedtune", - "File": "schedtune.prefer_idle" - } - ], - - "Profiles": [ - { - "Name": "HighEnergySaving", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "NormalPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "" - } - } - ] - }, - { - "Name": "HighPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "foreground" - } - } - ] - }, - { - "Name": "ServicePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "MaxPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "top-app" - } - } - ] - }, - { - "Name": "RealtimePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "rt" - } - } - ] - }, - { - "Name": "CameraServicePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "camera-daemon" - } - } - ] - }, - { - "Name": "NNApiHALPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "nnapi-hal" - } - } - ] - }, - { - "Name": "Dex2oatPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "CpuPolicySpread", - "Actions": [ - { - "Name": "SetAttribute", - "Params": - { - "Name": "STunePreferIdle", - "Value": "1" - } - } - ] - }, - { - "Name": "CpuPolicyPack", - "Actions": [ - { - "Name": "SetAttribute", - "Params": - { - "Name": "STunePreferIdle", - "Value": "0" - } - } - ] - } - ] -} diff --git a/libprocessgroup/profiles/task_profiles_30.json b/libprocessgroup/profiles/task_profiles_30.json deleted file mode 100644 index e7be5487d..000000000 --- a/libprocessgroup/profiles/task_profiles_30.json +++ /dev/null @@ -1,160 +0,0 @@ -{ - "Attributes": [ - { - "Name": "STuneBoost", - "Controller": "schedtune", - "File": "schedtune.boost" - }, - { - "Name": "STunePreferIdle", - "Controller": "schedtune", - "File": "schedtune.prefer_idle" - } - ], - - "Profiles": [ - { - "Name": "HighEnergySaving", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "NormalPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "" - } - } - ] - }, - { - "Name": "ServicePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "HighPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "foreground" - } - } - ] - }, - { - "Name": "MaxPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "top-app" - } - } - ] - }, - { - "Name": "RealtimePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "rt" - } - } - ] - }, - { - "Name": "CameraServicePerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "camera-daemon" - } - } - ] - }, - { - "Name": "NNApiHALPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "nnapi-hal" - } - } - ] - }, - { - "Name": "Dex2oatPerformance", - "Actions": [ - { - "Name": "JoinCgroup", - "Params": - { - "Controller": "schedtune", - "Path": "background" - } - } - ] - }, - { - "Name": "CpuPolicySpread", - "Actions": [ - { - "Name": "SetAttribute", - "Params": - { - "Name": "STunePreferIdle", - "Value": "1" - } - } - ] - }, - { - "Name": "CpuPolicyPack", - "Actions": [ - { - "Name": "SetAttribute", - "Params": - { - "Name": "STunePreferIdle", - "Value": "0" - } - } - ] - } - ] -} diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp index 042bcd24c..5a53c35de 100644 --- a/libprocessgroup/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -148,20 +148,10 @@ bool cpusets_enabled() { return enabled; } -static bool schedtune_enabled() { - return (CgroupMap::GetInstance().FindController("schedtune").IsUsable()); -} - static bool cpuctl_enabled() { return (CgroupMap::GetInstance().FindController("cpu").IsUsable()); } -bool schedboost_enabled() { - static bool enabled = schedtune_enabled() || cpuctl_enabled(); - - return enabled; -} - static int getCGroupSubsys(pid_t tid, const char* subsys, std::string& subgroup) { auto controller = CgroupMap::GetInstance().FindController(subsys); @@ -201,9 +191,8 @@ int get_sched_policy(pid_t tid, SchedPolicy* policy) { } std::string group; - if (schedboost_enabled()) { - if ((getCGroupSubsys(tid, "schedtune", group) < 0) && - (getCGroupSubsys(tid, "cpu", group) < 0)) { + if (cpuctl_enabled()) { + if (getCGroupSubsys(tid, "cpu", group) < 0) { LOG(ERROR) << "Failed to find cpu cgroup for tid " << tid; return -1; } From a23013dd4ba9d9de8a2eec75c5e0d4f406cf8a58 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Mon, 23 Sep 2024 14:46:11 -0700 Subject: [PATCH 018/183] libsnapshot: configure num worker threads Forward number of worker threads build configuration to snapuserd. these are the threads that will be used to serve i/o requests to dm-user. Bug: 361438985 Test: OTA with print logs post OTA reboot Change-Id: Ib70a3cb8766b96232ea6f97effece041534dc922 --- .../android/snapshot/snapshot.proto | 2 ++ .../include/libsnapshot/snapshot.h | 4 ++++ fs_mgr/libsnapshot/snapshot.cpp | 21 +++++++++++++++---- .../snapuserd/snapuserd_daemon.cpp | 6 ++++-- .../user-space-merge/snapuserd_server.cpp | 20 ++++++++++-------- .../user-space-merge/snapuserd_server.h | 1 + 6 files changed, 39 insertions(+), 15 deletions(-) diff --git a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto index 62f99013e..5fb71a37b 100644 --- a/fs_mgr/libsnapshot/android/snapshot/snapshot.proto +++ b/fs_mgr/libsnapshot/android/snapshot/snapshot.proto @@ -233,6 +233,8 @@ message SnapshotUpdateStatus { // Number of cow operations to be merged at once uint32 cow_op_merge_size = 13; + // Number of worker threads to serve I/O from dm-user + uint32 num_worker_threads = 14; } // Next: 10 diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index 7ae55db31..8ff41dbcb 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -838,6 +838,10 @@ class SnapshotManager final : public ISnapshotManager { // Get value of maximum cow op merge size uint32_t GetUpdateCowOpMergeSize(LockedFile* lock); + + // Get number of threads to perform post OTA boot verification + uint32_t GetUpdateWorkerCount(LockedFile* lock); + // Wrapper around libdm, with diagnostics. bool DeleteDeviceIfExists(const std::string& name, const std::chrono::milliseconds& timeout_ms = {}); diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 6c3bedd86..05dec68d5 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -1235,8 +1235,8 @@ auto SnapshotManager::CheckMergeState(LockedFile* lock, wrong_phase = true; break; default: - LOG(ERROR) << "Unknown merge status for \"" << snapshot << "\": " - << "\"" << result.state << "\""; + LOG(ERROR) << "Unknown merge status for \"" << snapshot << "\": " << "\"" + << result.state << "\""; if (failure_code == MergeFailureCode::Ok) { failure_code = MergeFailureCode::UnexpectedMergeState; } @@ -1725,6 +1725,10 @@ bool SnapshotManager::PerformInitTransition(InitTransition transition, if (cow_op_merge_size != 0) { snapuserd_argv->emplace_back("-cow_op_merge_size=" + std::to_string(cow_op_merge_size)); } + uint32_t worker_count = GetUpdateWorkerCount(lock.get()); + if (worker_count != 0) { + snapuserd_argv->emplace_back("-worker_count=" + std::to_string(worker_count)); + } } size_t num_cows = 0; @@ -2152,6 +2156,11 @@ uint32_t SnapshotManager::GetUpdateCowOpMergeSize(LockedFile* lock) { return update_status.cow_op_merge_size(); } +uint32_t SnapshotManager::GetUpdateWorkerCount(LockedFile* lock) { + SnapshotUpdateStatus update_status = ReadSnapshotUpdateStatus(lock); + return update_status.num_worker_threads(); +} + bool SnapshotManager::MarkSnapuserdFromSystem() { auto path = GetSnapuserdFromSystemPath(); @@ -3140,6 +3149,7 @@ bool SnapshotManager::WriteUpdateState(LockedFile* lock, UpdateState state, status.set_legacy_snapuserd(old_status.legacy_snapuserd()); status.set_o_direct(old_status.o_direct()); status.set_cow_op_merge_size(old_status.cow_op_merge_size()); + status.set_num_worker_threads(old_status.num_worker_threads()); } return WriteSnapshotUpdateStatus(lock, status); } @@ -3524,6 +3534,9 @@ Return SnapshotManager::CreateUpdateSnapshots(const DeltaArchiveManifest& manife } status.set_cow_op_merge_size( android::base::GetUintProperty("ro.virtual_ab.cow_op_merge_size", 0)); + status.set_num_worker_threads( + android::base::GetUintProperty("ro.virtual_ab.num_worker_threads", 0)); + } else if (legacy_compression) { LOG(INFO) << "Virtual A/B using legacy snapuserd"; } else { @@ -3960,6 +3973,7 @@ bool SnapshotManager::Dump(std::ostream& os) { ss << "Using io_uring: " << update_status.io_uring_enabled() << std::endl; ss << "Using o_direct: " << update_status.o_direct() << std::endl; ss << "Cow op merge size (0 for uncapped): " << update_status.cow_op_merge_size() << std::endl; + ss << "Worker thread count: " << update_status.num_worker_threads() << std::endl; ss << "Using XOR compression: " << GetXorCompressionEnabledProperty() << std::endl; ss << "Current slot: " << device_->GetSlotSuffix() << std::endl; ss << "Boot indicator: booting from " << GetCurrentSlot() << " slot" << std::endl; @@ -4576,8 +4590,7 @@ bool SnapshotManager::DeleteDeviceIfExists(const std::string& name, } } - LOG(ERROR) << "Device-mapper device " << name << "(" << full_path << ")" - << " still in use." + LOG(ERROR) << "Device-mapper device " << name << "(" << full_path << ")" << " still in use." << " Probably a file descriptor was leaked or held open, or a loop device is" << " attached."; return false; diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp index dd2dd5659..32e16cc80 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_daemon.cpp @@ -31,6 +31,7 @@ DEFINE_bool(user_snapshot, false, "If true, user-space snapshots are used"); DEFINE_bool(io_uring, false, "If true, io_uring feature is enabled"); DEFINE_bool(o_direct, false, "If true, enable direct reads on source device"); DEFINE_int32(cow_op_merge_size, 0, "number of operations to be processed at once"); +DEFINE_int32(worker_count, 4, "number of worker threads used to serve I/O requests to dm-user"); namespace android { namespace snapshot { @@ -114,8 +115,9 @@ bool Daemon::StartServerForUserspaceSnapshots(int arg_start, int argc, char** ar LOG(ERROR) << "Malformed message, expected at least four sub-arguments."; return false; } - auto handler = user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3], - FLAGS_o_direct, FLAGS_cow_op_merge_size); + auto handler = + user_server_.AddHandler(parts[0], parts[1], parts[2], parts[3], FLAGS_worker_count, + FLAGS_o_direct, FLAGS_cow_op_merge_size); if (!handler || !user_server_.StartHandler(parts[0])) { return false; } 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 013df350b..3bb8a3037 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.cpp @@ -35,6 +35,7 @@ #include #include #include "snapuserd_server.h" +#include "user-space-merge/snapuserd_core.h" namespace android { namespace snapshot { @@ -125,7 +126,7 @@ bool UserSnapshotServer::Receivemsg(android::base::borrowed_fd fd, const std::st return Sendmsg(fd, "fail"); } - auto handler = AddHandler(out[1], out[2], out[3], out[4]); + auto handler = AddHandler(out[1], out[2], out[3], out[4], std::nullopt); if (!handler) { return Sendmsg(fd, "fail"); } @@ -341,12 +342,11 @@ void UserSnapshotServer::Interrupt() { SetTerminating(); } -std::shared_ptr UserSnapshotServer::AddHandler(const std::string& misc_name, - const std::string& cow_device_path, - const std::string& backing_device, - const std::string& base_path_merge, - const bool o_direct, - uint32_t cow_op_merge_size) { +std::shared_ptr UserSnapshotServer::AddHandler( + const std::string& misc_name, const std::string& cow_device_path, + const std::string& backing_device, const std::string& base_path_merge, + std::optional num_worker_threads, const bool o_direct, + uint32_t cow_op_merge_size) { // We will need multiple worker threads only during // device boot after OTA. For all other purposes, // one thread is sufficient. We don't want to consume @@ -355,7 +355,9 @@ std::shared_ptr UserSnapshotServer::AddHandler(const std::string& // // During boot up, we need multiple threads primarily for // update-verification. - int num_worker_threads = kNumWorkerThreads; + if (!num_worker_threads.has_value()) { + num_worker_threads = kNumWorkerThreads; + } if (is_socket_present_) { num_worker_threads = 1; } @@ -368,7 +370,7 @@ std::shared_ptr UserSnapshotServer::AddHandler(const std::string& auto opener = block_server_factory_->CreateOpener(misc_name); return handlers_->AddHandler(misc_name, cow_device_path, backing_device, base_path_merge, - opener, num_worker_threads, io_uring_enabled_, o_direct, + opener, num_worker_threads.value(), io_uring_enabled_, o_direct, cow_op_merge_size); } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h index ceea36ae4..f002e8d9a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_server.h @@ -87,6 +87,7 @@ class UserSnapshotServer { const std::string& cow_device_path, const std::string& backing_device, const std::string& base_path_merge, + std::optional num_worker_threads, bool o_direct = false, uint32_t cow_op_merge_size = 0); bool StartHandler(const std::string& misc_name); From 6f451a9c8ceec473745bf7e6b67c9776cbb5e1a1 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 2 Oct 2024 19:35:21 -0700 Subject: [PATCH 019/183] init: Issue a wipe on boot if trade-in mode was active. This modifies first-stage init to check for /metadata/tradeinmode/wipe as soon as /metadata is mounted. If the file exists, we issue a request to the bootloader to reboot to recovery and wipe /data. Since this also wipes /metadata, the wipe indicator will be removed too. In case some kind of failure happens in recovery, this also implements a quick-and-dirty counter mechanism to fallback to the recovery menu. Bug: 307713521 Test: touch /metadata/tradeinmode/wipe && adb reboot Change-Id: I2d05903cadcdadf9c05f6736454db790a9e6b5bb --- init/Android.bp | 1 + init/first_stage_mount.cpp | 57 ++++++++++++++++++++++++++++++++++++++ rootdir/init.rc | 1 + 3 files changed, 59 insertions(+) diff --git a/init/Android.bp b/init/Android.bp index 18a79d6c4..5e06000a4 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -390,6 +390,7 @@ init_first_stage_cc_defaults { "libsnapshot_init", "update_metadata-protos", "libprocinfo", + "libbootloader_message", ], static_executable: true, diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index ece430b70..f303815b0 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -32,9 +32,12 @@ #include #include #include +#include #include #include #include +#include +#include #include #include #include @@ -46,6 +49,7 @@ #include "block_dev_initializer.h" #include "devices.h" +#include "reboot_utils.h" #include "result.h" #include "snapuserd_transition.h" #include "switch_root.h" @@ -111,6 +115,8 @@ class FirstStageMountVBootV2 : public FirstStageMount { bool GetDmVerityDevices(std::set* devices); bool SetUpDmVerity(FstabEntry* fstab_entry); + void RequestTradeInModeWipeIfNeeded(); + bool InitAvbHandle(); bool need_dm_verity_; @@ -263,6 +269,8 @@ bool FirstStageMountVBootV2::DoCreateDevices() { } bool FirstStageMountVBootV2::DoFirstStageMount() { + RequestTradeInModeWipeIfNeeded(); + if (!IsDmLinearEnabled() && fstab_.empty()) { // Nothing to mount. LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)"; @@ -883,6 +891,55 @@ bool FirstStageMountVBootV2::InitAvbHandle() { return true; } +void FirstStageMountVBootV2::RequestTradeInModeWipeIfNeeded() { + static constexpr const char* kWipeIndicator = "/metadata/tradeinmode/wipe"; + static constexpr size_t kWipeAttempts = 3; + + if (access(kWipeIndicator, R_OK) == -1) { + return; + } + + // Write a counter to the wipe indicator, to try and prevent boot loops if + // recovery fails to wipe data. + uint32_t counter = 0; + std::string contents; + if (ReadFileToString(kWipeIndicator, &contents)) { + android::base::ParseUint(contents, &counter); + contents = std::to_string(++counter); + if (android::base::WriteStringToFile(contents, kWipeIndicator)) { + sync(); + } else { + PLOG(ERROR) << "Failed to update " << kWipeIndicator; + } + } else { + PLOG(ERROR) << "Failed to read " << kWipeIndicator; + } + + std::string err; + auto misc_device = get_misc_blk_device(&err); + if (misc_device.empty()) { + LOG(FATAL) << "Could not find misc device: " << err; + } + + auto misc_name = android::base::Basename(misc_device); + if (!block_dev_init_.InitDevices({misc_name})) { + LOG(FATAL) << "Could not find misc device: " << misc_device; + } + + // If we've failed to wipe three times, don't include the wipe command. This + // will force us to boot into the recovery menu instead where a manual wipe + // can be attempted. + std::vector options; + if (counter <= kWipeAttempts) { + options.emplace_back("--wipe_data"); + options.emplace_back("--reason=tradeinmode"); + } + if (!write_bootloader_message(options, &err)) { + LOG(FATAL) << "Could not issue wipe: " << err; + } + RebootSystem(ANDROID_RB_RESTART2, "recovery", "reboot,tradeinmode,wipe"); +} + void SetInitAvbVersionInRecovery() { if (!IsRecoveryMode()) { LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)"; diff --git a/rootdir/init.rc b/rootdir/init.rc index 1acd63774..f43c71855 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -644,6 +644,7 @@ on post-fs mkdir /metadata/ota 0750 root system mkdir /metadata/ota/snapshots 0750 root system mkdir /metadata/watchdog 0770 root system + mkdir /metadata/tradeinmode 0770 root system mkdir /metadata/apex 0700 root system mkdir /metadata/apex/sessions 0700 root system From f29f1a2a3832aa33863e30c851e6f6565e78ad73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Arve=20Hj=C3=B8nnev=C3=A5g?= Date: Wed, 25 Sep 2024 16:21:50 -0700 Subject: [PATCH 020/183] trusty-ut-ctrl: Allow stream mode When using vsock in stream mode (or any other stream mode connection) message boundaries are not preserved, so the original messages can get both split and merged. The TEST_MESSAGE and TEST_TEXT messages don't have a length field which makes it imposible to support every possible message that can be sent over a channel that preserves message boundaries. Since the current message header types don't contain any printable character, we assume any of these characters in a message payload means that two messages got merged, so we split them back up. Additionally, if we receive a message that does not start with a valid message header, we assume it is a continuation of the previous message. Test: trusty-ut-ctrl -D VSOCK:2:1 com.android.libctest ^Z fg Bug: 298705967 Change-Id: I0e470a23664268f86e4defd824c47be3479c8f25 --- trusty/utils/trusty-ut-ctrl/ut-ctrl.c | 57 +++++++++++++++++++++------ 1 file changed, 44 insertions(+), 13 deletions(-) diff --git a/trusty/utils/trusty-ut-ctrl/ut-ctrl.c b/trusty/utils/trusty-ut-ctrl/ut-ctrl.c index 6cc66707e..31cfd4c79 100644 --- a/trusty/utils/trusty-ut-ctrl/ut-ctrl.c +++ b/trusty/utils/trusty-ut-ctrl/ut-ctrl.c @@ -95,12 +95,26 @@ enum test_message_header { TEST_FAILED = 1, TEST_MESSAGE = 2, TEST_TEXT = 3, + TEST_OPCODE_COUNT, }; +static int get_msg_len(const char* buf, int max_buf_len) { + int buf_len; + for (buf_len = 0; buf_len < max_buf_len; buf_len++) { + if ((unsigned char)buf[buf_len] < TEST_OPCODE_COUNT) { + break; + } + } + return buf_len; +} + static int run_trusty_unitest(const char* utapp) { int fd; - int rc; - char rx_buf[1024]; + char read_buf[1024]; + int read_len; + char* rx_buf; + int rx_buf_len; + int cmd = -1; /* connect to unitest app */ fd = tipc_connect(dev_name, utapp); @@ -110,22 +124,39 @@ static int run_trusty_unitest(const char* utapp) { } /* wait for test to complete */ + rx_buf_len = 0; for (;;) { - rc = read(fd, rx_buf, sizeof(rx_buf)); - if (rc <= 0 || rc >= (int)sizeof(rx_buf)) { - fprintf(stderr, "%s: Read failed: %d\n", __func__, rc); - tipc_close(fd); - return -1; + if (rx_buf_len == 0) { + read_len = read(fd, read_buf, sizeof(read_buf)); + if (read_len <= 0 || read_len > (int)sizeof(read_buf)) { + fprintf(stderr, "%s: Read failed: %d, %s\n", __func__, read_len, + read_len < 0 ? strerror(errno) : ""); + tipc_close(fd); + return -1; + } + rx_buf = read_buf; + rx_buf_len = read_len; } - if (rx_buf[0] == TEST_PASSED) { + int msg_len = get_msg_len(rx_buf, rx_buf_len); + if (msg_len == 0) { + cmd = rx_buf[0]; + rx_buf++; + rx_buf_len--; + } + + if (cmd == TEST_PASSED) { break; - } else if (rx_buf[0] == TEST_FAILED) { + } else if (cmd == TEST_FAILED) { break; - } else if (rx_buf[0] == TEST_MESSAGE || rx_buf[0] == TEST_TEXT) { - write(STDOUT_FILENO, rx_buf + 1, rc - 1); + } else if (cmd == TEST_MESSAGE || cmd == TEST_TEXT) { + if (msg_len) { + write(STDOUT_FILENO, rx_buf, msg_len); + rx_buf += msg_len; + rx_buf_len -= msg_len; + } } else { - fprintf(stderr, "%s: Bad message header: %d\n", __func__, rx_buf[0]); + fprintf(stderr, "%s: Bad message header: %d\n", __func__, cmd); break; } } @@ -133,7 +164,7 @@ static int run_trusty_unitest(const char* utapp) { /* close connection to unitest app */ tipc_close(fd); - return rx_buf[0] == TEST_PASSED ? 0 : -1; + return cmd == TEST_PASSED ? 0 : -1; } int main(int argc, char** argv) { From da77c2e1dc762a8d4930260ec6ec19447cce828c Mon Sep 17 00:00:00 2001 From: Rob Barnes Date: Wed, 18 Sep 2024 01:29:15 +0000 Subject: [PATCH 021/183] Change owner of ACPI BERT tables to system Changes the owner of the following files to system:system: * /sys/firmware/acpi/tables * /sys/firmware/acpi/tables/BERT * /sys/firmware/acpi/tables/data/BERT This allows the bert_collector deamon to read these files for error reporting. Bug: 357626966 Test: m && atest bert_collector_test Change-Id: Iba3a169f1851566ee6fed6d41b538dae448bf811 --- rootdir/init.rc | 3 +++ 1 file changed, 3 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index 1acd63774..339f1beba 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1243,6 +1243,9 @@ on boot chown system system /sys/kernel/ipv4/tcp_rmem_min chown system system /sys/kernel/ipv4/tcp_rmem_def chown system system /sys/kernel/ipv4/tcp_rmem_max + chown system system /sys/firmware/acpi/tables + chown system system /sys/firmware/acpi/tables/BERT + chown system system /sys/firmware/acpi/tables/data/BERT chown root radio /proc/cmdline chown root system /proc/bootconfig From ae4ce8ccc5933c8d1d557930021a0715bdaacf64 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Thu, 8 Aug 2024 16:11:21 +0000 Subject: [PATCH 022/183] libprocessgroup: Remove cgroup.rc file The cgroup.rc file was introduced in 192aee782 ("libprocessgroup: Add support for task profiles") back with the initial support for task profiles. It was intended to optimize performance associated with cgroup operations. However over time, supporting this file led to making libprocessgroup code more complicated (such as the cgrouprc LLNDK interface), and the file ended up getting mmaped into nearly every process on Android even though only a handful of them actually use it. Replacing this file with reading and parsing of cgroup information on demand allows us to simplify and shrink libprocessgroup, and eliminates thousands of unused mappings without negatively affecting boot time or other performance metrics. Bug: 349105928 Test: Verified with memcg v2 and MaxActivationDepth 1 on Cuttlefish, Raven, and Mokey Change-Id: Ic3f01fdf7fda89a56ab80657e1cf4573156273e6 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 7 +- init/Android.bp | 1 - init/init.cpp | 3 - libcutils/Android.bp | 2 +- libprocessgroup/Android.bp | 3 +- libprocessgroup/cgroup_map.cpp | 4 +- libprocessgroup/cgrouprc/Android.bp | 3 +- libprocessgroup/cgrouprc/a_cgroup_file.cpp | 88 ++---- libprocessgroup/cgrouprc/cgrouprc_internal.h | 7 +- libprocessgroup/cgrouprc_format/Android.bp | 13 - .../include/processgroup/processgroup.h | 2 +- .../format/cgroup_file.h => internal.h} | 23 +- libprocessgroup/setup/Android.bp | 1 - libprocessgroup/setup/cgroup_descriptor.h | 12 +- libprocessgroup/setup/cgroup_map_write.cpp | 259 ++---------------- libprocessgroup/util/Android.bp | 8 + .../cgroup_controller.cpp | 12 +- libprocessgroup/util/cgroup_descriptor.cpp | 38 +++ .../include/processgroup}/cgroup_controller.h | 12 +- .../include/processgroup/cgroup_descriptor.h | 45 +++ .../util/include/processgroup/util.h | 12 +- libprocessgroup/util/tests/util.cpp | 2 - libprocessgroup/util/util.cpp | 197 ++++++++++++- 23 files changed, 365 insertions(+), 389 deletions(-) rename libprocessgroup/{cgrouprc_format/include/processgroup/format/cgroup_file.h => internal.h} (54%) rename libprocessgroup/{cgrouprc_format => util}/cgroup_controller.cpp (90%) create mode 100644 libprocessgroup/util/cgroup_descriptor.cpp rename libprocessgroup/{cgrouprc_format/include/processgroup/format => util/include/processgroup}/cgroup_controller.h (87%) create mode 100644 libprocessgroup/util/include/processgroup/cgroup_descriptor.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 298fd9f30..083068b54 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -85,9 +85,9 @@ cc_library_static { "libsnapshot_cow", "liburing", "libprocessgroup", + "libprocessgroup_util", "libjsoncpp", "libcgrouprc", - "libcgrouprc_format", ], include_dirs: ["bionic/libc/kernel"], export_include_dirs: ["include"], @@ -129,9 +129,9 @@ cc_defaults { "libsnapshot_cow", "libsnapuserd", "libprocessgroup", + "libprocessgroup_util", "libjsoncpp", "libcgrouprc", - "libcgrouprc_format", "libsnapuserd_client", "libz", "liblz4", @@ -221,9 +221,9 @@ cc_defaults { "libsnapshot_cow", "libsnapuserd", "libprocessgroup", + "libprocessgroup_util", "libjsoncpp", "libcgrouprc", - "libcgrouprc_format", "liburing", "libz", ], @@ -319,7 +319,6 @@ cc_binary_host { "libprocessgroup", "libjsoncpp", "libcgrouprc", - "libcgrouprc_format", "liburing", "libz", ], diff --git a/init/Android.bp b/init/Android.bp index 18a79d6c4..8da2e7c2e 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -163,7 +163,6 @@ libinit_cc_defaults { "libavb", "libavf_cc_flags", "libbootloader_message", - "libcgrouprc_format", "liblmkd_utils", "liblz4", "libzstd", diff --git a/init/init.cpp b/init/init.cpp index 6c8089926..17498da6d 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -636,9 +636,6 @@ static Result SetupCgroupsAction(const BuiltinArguments&) { LOG(INFO) << "Cgroups support in kernel is not enabled"; return {}; } - // Have to create using make_dir function - // for appropriate sepolicy to be set for it - make_dir(android::base::Dirname(CGROUPS_RC_PATH), 0711); if (!CgroupSetup()) { return ErrnoError() << "Failed to setup cgroups"; } diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 3c3eeb663..fc4c571b7 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -301,7 +301,7 @@ cc_defaults { android: { static_executable: true, static_libs: [ - "libcgrouprc_format", + "libprocessgroup_util", ] + test_libraries + always_static_test_libraries, }, not_windows: { diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index a60bfe973..d623a1152 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -17,7 +17,7 @@ soong_config_module_type { libprocessgroup_flag_aware_cc_defaults { name: "libprocessgroup_build_flags_cc", - cpp_std: "gnu++20", + cpp_std: "gnu++23", soong_config_variables: { memcg_v2_force_enabled: { cflags: [ @@ -116,5 +116,6 @@ cc_test { ], static_libs: [ "libgmock", + "libprocessgroup_util", ], } diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index fb01cfda9..aeccfe89b 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -151,7 +151,7 @@ bool CgroupMap::LoadRcFile() { void CgroupMap::Print() const { if (!loaded_) { LOG(ERROR) << "CgroupMap::Print called for [" << getpid() - << "] failed, RC file was not initialized properly"; + << "] failed, cgroups were not initialized properly"; return; } LOG(INFO) << "File version = " << ACgroupFile_getVersion(); @@ -221,7 +221,7 @@ int CgroupMap::ActivateControllers(const std::string& path) const { if (__builtin_available(android 36, *)) { max_activation_depth = ACgroupController_getMaxActivationDepth(controller); } - const int depth = util::GetCgroupDepth(ACgroupController_getPath(controller), path); + const int depth = GetCgroupDepth(ACgroupController_getPath(controller), path); if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { std::string str("+"); diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index cb912476e..38b2fa31d 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -49,7 +49,8 @@ cc_library { "libbase", ], static_libs: [ - "libcgrouprc_format", + "libjsoncpp", + "libprocessgroup_util", ], stubs: { symbol_file: "libcgrouprc.map.txt", diff --git a/libprocessgroup/cgrouprc/a_cgroup_file.cpp b/libprocessgroup/cgrouprc/a_cgroup_file.cpp index e26d84114..33c8376f4 100644 --- a/libprocessgroup/cgrouprc/a_cgroup_file.cpp +++ b/libprocessgroup/cgrouprc/a_cgroup_file.cpp @@ -14,93 +14,51 @@ * limitations under the License. */ -#include -#include - -#include +#include #include -#include -#include #include -#include +#include #include "cgrouprc_internal.h" -using android::base::StringPrintf; -using android::base::unique_fd; - -using android::cgrouprc::format::CgroupController; -using android::cgrouprc::format::CgroupFile; - -static CgroupFile* LoadRcFile() { - struct stat sb; - - unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_RDONLY | O_CLOEXEC))); - if (fd < 0) { - PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; +static CgroupDescriptorMap* LoadDescriptors() { + CgroupDescriptorMap* descriptors = new CgroupDescriptorMap; + if (!ReadDescriptors(descriptors)) { + LOG(ERROR) << "Failed to load cgroup description file"; return nullptr; } - - if (fstat(fd, &sb) < 0) { - PLOG(ERROR) << "fstat() failed for " << CGROUPS_RC_PATH; - return nullptr; - } - - size_t file_size = sb.st_size; - if (file_size < sizeof(CgroupFile)) { - LOG(ERROR) << "Invalid file format " << CGROUPS_RC_PATH; - return nullptr; - } - - CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0); - if (file_data == MAP_FAILED) { - PLOG(ERROR) << "Failed to mmap " << CGROUPS_RC_PATH; - return nullptr; - } - - if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) { - LOG(ERROR) << CGROUPS_RC_PATH << " file version mismatch"; - munmap(file_data, file_size); - return nullptr; - } - - auto expected = sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController); - if (file_size != expected) { - LOG(ERROR) << CGROUPS_RC_PATH << " file has invalid size, expected " << expected - << ", actual " << file_size; - munmap(file_data, file_size); - return nullptr; - } - - return file_data; + return descriptors; } -static CgroupFile* GetInstance() { +static const CgroupDescriptorMap* GetInstance() { // Deliberately leak this object (not munmap) to avoid a race between destruction on // process exit and concurrent access from another thread. - static auto* file = LoadRcFile(); - return file; + static const CgroupDescriptorMap* descriptors = LoadDescriptors(); + return descriptors; } uint32_t ACgroupFile_getVersion() { - auto file = GetInstance(); - if (file == nullptr) return 0; - return file->version_; + static constexpr uint32_t FILE_VERSION_1 = 1; + auto descriptors = GetInstance(); + if (descriptors == nullptr) return 0; + // There has only ever been one version, and there will be no more since cgroup.rc is no more + return FILE_VERSION_1; } uint32_t ACgroupFile_getControllerCount() { - auto file = GetInstance(); - if (file == nullptr) return 0; - return file->controller_count_; + auto descriptors = GetInstance(); + if (descriptors == nullptr) return 0; + return descriptors->size(); } const ACgroupController* ACgroupFile_getController(uint32_t index) { - auto file = GetInstance(); - if (file == nullptr) return nullptr; - CHECK(index < file->controller_count_); + auto descriptors = GetInstance(); + if (descriptors == nullptr) return nullptr; + CHECK(index < descriptors->size()); // Although the object is not actually an ACgroupController object, all ACgroupController_* // functions implicitly convert ACgroupController* back to CgroupController* before invoking // member functions. - return static_cast(&file->controllers_[index]); + const CgroupController* p = std::next(descriptors->begin(), index)->second.controller(); + return static_cast(p); } diff --git a/libprocessgroup/cgrouprc/cgrouprc_internal.h b/libprocessgroup/cgrouprc/cgrouprc_internal.h index cd02f0304..d51770346 100644 --- a/libprocessgroup/cgrouprc/cgrouprc_internal.h +++ b/libprocessgroup/cgrouprc/cgrouprc_internal.h @@ -16,9 +16,6 @@ #pragma once -#include +#include -#include -#include - -struct ACgroupController : android::cgrouprc::format::CgroupController {}; +struct ACgroupController : CgroupController {}; diff --git a/libprocessgroup/cgrouprc_format/Android.bp b/libprocessgroup/cgrouprc_format/Android.bp index 059092419..6f9ab3e73 100644 --- a/libprocessgroup/cgrouprc_format/Android.bp +++ b/libprocessgroup/cgrouprc_format/Android.bp @@ -23,17 +23,4 @@ cc_library_static { vendor_ramdisk_available: true, recovery_available: true, native_bridge_supported: true, - srcs: [ - "cgroup_controller.cpp", - ], - cflags: [ - "-Wall", - "-Werror", - ], - export_include_dirs: [ - "include", - ], - shared_libs: [ - "libbase", - ], } diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index ffffeb48b..805775744 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -57,7 +57,7 @@ __BEGIN_DECLS bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector& profiles); -static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; +[[deprecated]] static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; bool UsePerAppMemcg(); diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h b/libprocessgroup/internal.h similarity index 54% rename from libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h rename to libprocessgroup/internal.h index 2d9786fe6..ef855790d 100644 --- a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h +++ b/libprocessgroup/internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2024 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. @@ -16,23 +16,6 @@ #pragma once -#include +#include -#include - -namespace android { -namespace cgrouprc { -namespace format { - -struct CgroupFile { - uint32_t version_; - uint32_t controller_count_; - CgroupController controllers_[]; - - static constexpr uint32_t FILE_VERSION_1 = 1; - static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1; -}; - -} // namespace format -} // namespace cgrouprc -} // namespace android +static const std::string CGROUP_V2_ROOT_DEFAULT = "/sys/fs/cgroup"; \ No newline at end of file diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp index 1a4ad0118..cc6c67cf4 100644 --- a/libprocessgroup/setup/Android.bp +++ b/libprocessgroup/setup/Android.bp @@ -33,7 +33,6 @@ cc_library_shared { "libjsoncpp", ], static_libs: [ - "libcgrouprc_format", "libprocessgroup_util", ], header_libs: [ diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h index 06ce186fd..1afd2ee9c 100644 --- a/libprocessgroup/setup/cgroup_descriptor.h +++ b/libprocessgroup/setup/cgroup_descriptor.h @@ -21,10 +21,7 @@ #include -#include - -namespace android { -namespace cgrouprc { +#include // Complete controller description for mounting cgroups class CgroupDescriptor { @@ -33,7 +30,7 @@ class CgroupDescriptor { mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, uint32_t max_activation_depth); - const format::CgroupController* controller() const { return &controller_; } + const CgroupController* controller() const { return &controller_; } mode_t mode() const { return mode_; } std::string uid() const { return uid_; } std::string gid() const { return gid_; } @@ -41,11 +38,8 @@ class CgroupDescriptor { void set_mounted(bool mounted); private: - format::CgroupController controller_; + CgroupController controller_; mode_t mode_ = 0; std::string uid_; std::string gid_; }; - -} // namespace cgrouprc -} // namespace android diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index bd4187475..821168008 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -22,45 +22,28 @@ #include #include #include -#include #include #include #include -#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include #include #include #include #include "../build_flags.h" -#include "cgroup_descriptor.h" - -using android::base::GetUintProperty; -using android::base::StringPrintf; -using android::base::unique_fd; - -namespace android { -namespace cgrouprc { +#include "../internal.h" static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; static constexpr const char* TEMPLATE_CGROUPS_DESC_API_FILE = "/etc/task_profiles/cgroups_%u.json"; -static const std::string CGROUP_V2_ROOT_DEFAULT = "/sys/fs/cgroup"; - static bool ChangeDirModeAndOwner(const std::string& path, mode_t mode, const std::string& uid, const std::string& gid, bool permissive_mode = false) { uid_t pw_uid = -1; @@ -148,149 +131,15 @@ static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid, return true; } -static void MergeCgroupToDescriptors(std::map* descriptors, - const Json::Value& cgroup, const std::string& name, - const std::string& root_path, int cgroups_version) { - const std::string cgroup_path = cgroup["Path"].asString(); - std::string path; - - if (!root_path.empty()) { - path = root_path; - if (cgroup_path != ".") { - path += "/"; - path += cgroup_path; - } - } else { - path = cgroup_path; - } - - uint32_t controller_flags = 0; - - if (cgroup["NeedsActivation"].isBool() && cgroup["NeedsActivation"].asBool()) { - controller_flags |= CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION; - } - - if (cgroup["Optional"].isBool() && cgroup["Optional"].asBool()) { - controller_flags |= CGROUPRC_CONTROLLER_FLAG_OPTIONAL; - } - - uint32_t max_activation_depth = UINT32_MAX; - if (cgroup.isMember("MaxActivationDepth")) { - max_activation_depth = cgroup["MaxActivationDepth"].asUInt(); - } - - CgroupDescriptor descriptor( - cgroups_version, name, path, std::strtoul(cgroup["Mode"].asString().c_str(), 0, 8), - cgroup["UID"].asString(), cgroup["GID"].asString(), controller_flags, - max_activation_depth); - - auto iter = descriptors->find(name); - if (iter == descriptors->end()) { - descriptors->emplace(name, descriptor); - } else { - iter->second = descriptor; - } -} - -static const bool force_memcg_v2 = android::libprocessgroup_flags::force_memcg_v2(); - -static bool ReadDescriptorsFromFile(const std::string& file_name, - std::map* descriptors) { - std::vector result; - std::string json_doc; - - if (!android::base::ReadFileToString(file_name, &json_doc)) { - PLOG(ERROR) << "Failed to read task profiles from " << file_name; - return false; - } - - Json::CharReaderBuilder builder; - std::unique_ptr reader(builder.newCharReader()); - Json::Value root; - std::string errorMessage; - if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) { - LOG(ERROR) << "Failed to parse cgroups description: " << errorMessage; - return false; - } - - if (root.isMember("Cgroups")) { - const Json::Value& cgroups = root["Cgroups"]; - for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { - std::string name = cgroups[i]["Controller"].asString(); - - if (force_memcg_v2 && name == "memory") continue; - - MergeCgroupToDescriptors(descriptors, cgroups[i], name, "", 1); - } - } - - bool memcgv2_present = false; - std::string root_path; - if (root.isMember("Cgroups2")) { - const Json::Value& cgroups2 = root["Cgroups2"]; - root_path = cgroups2["Path"].asString(); - MergeCgroupToDescriptors(descriptors, cgroups2, CGROUPV2_HIERARCHY_NAME, "", 2); - - const Json::Value& childGroups = cgroups2["Controllers"]; - for (Json::Value::ArrayIndex i = 0; i < childGroups.size(); ++i) { - std::string name = childGroups[i]["Controller"].asString(); - - if (force_memcg_v2 && name == "memory") memcgv2_present = true; - - MergeCgroupToDescriptors(descriptors, childGroups[i], name, root_path, 2); - } - } - - if (force_memcg_v2 && !memcgv2_present) { - LOG(INFO) << "Forcing memcg to v2 hierarchy"; - Json::Value memcgv2; - memcgv2["Controller"] = "memory"; - memcgv2["NeedsActivation"] = true; - memcgv2["Path"] = "."; - memcgv2["Optional"] = true; // In case of cgroup_disabled=memory, so we can still boot - MergeCgroupToDescriptors(descriptors, memcgv2, "memory", - root_path.empty() ? CGROUP_V2_ROOT_DEFAULT : root_path, 2); - } - - return true; -} - -static bool ReadDescriptors(std::map* descriptors) { - // load system cgroup descriptors - if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) { - return false; - } - - // load API-level specific system cgroups descriptors if available - unsigned int api_level = GetUintProperty("ro.product.first_api_level", 0); - if (api_level > 0) { - std::string api_cgroups_path = - android::base::StringPrintf(TEMPLATE_CGROUPS_DESC_API_FILE, api_level); - if (!access(api_cgroups_path.c_str(), F_OK) || errno != ENOENT) { - if (!ReadDescriptorsFromFile(api_cgroups_path, descriptors)) { - return false; - } - } - } - - // load vendor cgroup descriptors if the file exists - if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) && - !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) { - return false; - } - - return true; -} - // To avoid issues in sdk_mac build #if defined(__ANDROID__) -static bool IsOptionalController(const format::CgroupController* controller) { +static bool IsOptionalController(const CgroupController* controller) { return controller->flags() & CGROUPRC_CONTROLLER_FLAG_OPTIONAL; } static bool MountV2CgroupController(const CgroupDescriptor& descriptor) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); // /sys/fs/cgroup is created by cgroup2 with specific selinux permissions, // try to create again in case the mount point is changed @@ -324,7 +173,7 @@ static bool MountV2CgroupController(const CgroupDescriptor& descriptor) { } static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup"; @@ -338,7 +187,7 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { std::string path = controller->path(); path += "/cgroup.subtree_control"; - if (!base::WriteStringToFile(str, path)) { + if (!android::base::WriteStringToFile(str, path)) { if (IsOptionalController(controller)) { PLOG(INFO) << "Failed to activate optional controller " << controller->name() << " at " << path; @@ -353,7 +202,7 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { } static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); // mkdir [mode] [owner] [group] if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { @@ -388,7 +237,7 @@ static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { } static bool SetupCgroup(const CgroupDescriptor& descriptor) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); if (controller->version() == 2) { if (!strcmp(controller->name(), CGROUPV2_HIERARCHY_NAME)) { @@ -410,35 +259,6 @@ static bool SetupCgroup(const CgroupDescriptor&) { #endif -static bool WriteRcFile(const std::map& descriptors) { - unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, - S_IRUSR | S_IRGRP | S_IROTH))); - if (fd < 0) { - PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; - return false; - } - - format::CgroupFile fl; - fl.version_ = format::CgroupFile::FILE_CURR_VERSION; - fl.controller_count_ = descriptors.size(); - int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl))); - if (ret < 0) { - PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; - return false; - } - - for (const auto& [name, descriptor] : descriptors) { - ret = TEMP_FAILURE_RETRY( - write(fd, descriptor.controller(), sizeof(format::CgroupController))); - if (ret < 0) { - PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; - return false; - } - } - - return true; -} - CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, @@ -458,9 +278,6 @@ void CgroupDescriptor::set_mounted(bool mounted) { controller_.set_flags(flags); } -} // namespace cgrouprc -} // namespace android - static std::optional MGLRUDisabled() { const std::string file_name = "/sys/kernel/mm/lru_gen/enabled"; std::string content; @@ -472,9 +289,8 @@ static std::optional MGLRUDisabled() { return content == "0x0000"; } -static std::optional MEMCGDisabled( - const std::map& descriptors) { - std::string cgroup_v2_root = android::cgrouprc::CGROUP_V2_ROOT_DEFAULT; +static std::optional MEMCGDisabled(const CgroupDescriptorMap& descriptors) { + std::string cgroup_v2_root = CGROUP_V2_ROOT_DEFAULT; const auto it = descriptors.find(CGROUPV2_HIERARCHY_NAME); if (it == descriptors.end()) { LOG(WARNING) << "No Cgroups2 path found in cgroups.json. Vendor has modified Android, and " @@ -495,14 +311,10 @@ static std::optional MEMCGDisabled( return content.find("memory") == std::string::npos; } -static bool CreateV2SubHierarchy( - const std::string& path, - const std::map& descriptors) { - using namespace android::cgrouprc; - +static bool CreateV2SubHierarchy(const std::string& path, const CgroupDescriptorMap& descriptors) { const auto cgv2_iter = descriptors.find(CGROUPV2_HIERARCHY_NAME); if (cgv2_iter == descriptors.end()) return false; - const android::cgrouprc::CgroupDescriptor cgv2_descriptor = cgv2_iter->second; + const CgroupDescriptor cgv2_descriptor = cgv2_iter->second; if (!Mkdir(path, cgv2_descriptor.mode(), cgv2_descriptor.uid(), cgv2_descriptor.gid())) { PLOG(ERROR) << "Failed to create directory for " << path; @@ -512,10 +324,10 @@ static bool CreateV2SubHierarchy( // Activate all v2 controllers in path so they can be activated in // children as they are created. for (const auto& [name, descriptor] : descriptors) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); std::uint32_t flags = controller->flags(); std::uint32_t max_activation_depth = controller->max_activation_depth(); - const int depth = util::GetCgroupDepth(controller->path(), path); + const int depth = GetCgroupDepth(controller->path(), path); if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME && flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { @@ -535,22 +347,13 @@ static bool CreateV2SubHierarchy( } bool CgroupSetup() { - using namespace android::cgrouprc; - - std::map descriptors; + CgroupDescriptorMap descriptors; if (getpid() != 1) { LOG(ERROR) << "Cgroup setup can be done only by init process"; return false; } - // Make sure we do this only one time. No need for std::call_once because - // init is a single-threaded process - if (access(CGROUPS_RC_PATH, F_OK) == 0) { - LOG(WARNING) << "Attempt to call CgroupSetup() more than once"; - return true; - } - // load cgroups.json file if (!ReadDescriptors(&descriptors)) { LOG(ERROR) << "Failed to load cgroup description file"; @@ -559,15 +362,18 @@ bool CgroupSetup() { // setup cgroups for (auto& [name, descriptor] : descriptors) { - if (SetupCgroup(descriptor)) { - descriptor.set_mounted(true); - } else { + if (descriptor.controller()->flags() & CGROUPRC_CONTROLLER_FLAG_MOUNTED) { + LOG(WARNING) << "Attempt to call CgroupSetup() more than once"; + return true; + } + + if (!SetupCgroup(descriptor)) { // issue a warning and proceed with the next cgroup LOG(WARNING) << "Failed to setup " << name << " cgroup"; } } - if (force_memcg_v2) { + if (android::libprocessgroup_flags::force_memcg_v2()) { if (MGLRUDisabled().value_or(false)) { LOG(WARNING) << "Memcg forced to v2 hierarchy with MGLRU disabled! " << "Global reclaim performance will suffer."; @@ -593,26 +399,5 @@ bool CgroupSetup() { } } - // mkdir 0711 system system - if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) { - LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file"; - return false; - } - - // Generate file which can be directly mmapped into - // process memory. This optimizes performance, memory usage - // and limits infrormation shared with unprivileged processes - // to the minimum subset of information from cgroups.json - if (!WriteRcFile(descriptors)) { - LOG(ERROR) << "Failed to write " << CGROUPS_RC_PATH << " file"; - return false; - } - - // chmod 0644 - if (fchmodat(AT_FDCWD, CGROUPS_RC_PATH, 0644, AT_SYMLINK_NOFOLLOW) < 0) { - PLOG(ERROR) << "fchmodat() failed"; - return false; - } - return true; } diff --git a/libprocessgroup/util/Android.bp b/libprocessgroup/util/Android.bp index 54ba69b4e..1c74d4ed5 100644 --- a/libprocessgroup/util/Android.bp +++ b/libprocessgroup/util/Android.bp @@ -37,8 +37,16 @@ cc_library_static { "include", ], srcs: [ + "cgroup_controller.cpp", + "cgroup_descriptor.cpp", "util.cpp", ], + shared_libs: [ + "libbase", + ], + static_libs: [ + "libjsoncpp", + ], defaults: ["libprocessgroup_build_flags_cc"], } diff --git a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp b/libprocessgroup/util/cgroup_controller.cpp similarity index 90% rename from libprocessgroup/cgrouprc_format/cgroup_controller.cpp rename to libprocessgroup/util/cgroup_controller.cpp index 0dd909a29..fb4168075 100644 --- a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp +++ b/libprocessgroup/util/cgroup_controller.cpp @@ -14,11 +14,9 @@ * limitations under the License. */ -#include +#include -namespace android { -namespace cgrouprc { -namespace format { +#include CgroupController::CgroupController(uint32_t version, uint32_t flags, const std::string& name, const std::string& path, uint32_t max_activation_depth) @@ -54,8 +52,4 @@ const char* CgroupController::path() const { void CgroupController::set_flags(uint32_t flags) { flags_ = flags; -} - -} // namespace format -} // namespace cgrouprc -} // namespace android +} \ No newline at end of file diff --git a/libprocessgroup/util/cgroup_descriptor.cpp b/libprocessgroup/util/cgroup_descriptor.cpp new file mode 100644 index 000000000..4d3347f34 --- /dev/null +++ b/libprocessgroup/util/cgroup_descriptor.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 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 + +#include // For flag values + +CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, + const std::string& path, mode_t mode, const std::string& uid, + const std::string& gid, uint32_t flags, + uint32_t max_activation_depth) + : controller_(version, flags, name, path, max_activation_depth), + mode_(mode), + uid_(uid), + gid_(gid) {} + +void CgroupDescriptor::set_mounted(bool mounted) { + uint32_t flags = controller_.flags(); + if (mounted) { + flags |= CGROUPRC_CONTROLLER_FLAG_MOUNTED; + } else { + flags &= ~CGROUPRC_CONTROLLER_FLAG_MOUNTED; + } + controller_.set_flags(flags); +} diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h b/libprocessgroup/util/include/processgroup/cgroup_controller.h similarity index 87% rename from libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h rename to libprocessgroup/util/include/processgroup/cgroup_controller.h index c0c1f6034..fe6a829a0 100644 --- a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h +++ b/libprocessgroup/util/include/processgroup/cgroup_controller.h @@ -20,11 +20,7 @@ #include #include -namespace android { -namespace cgrouprc { -namespace format { - -// Minimal controller description to be mmapped into process address space +// Minimal controller description struct CgroupController { public: CgroupController() = default; @@ -48,8 +44,4 @@ struct CgroupController { uint32_t max_activation_depth_ = UINT32_MAX; char name_[CGROUP_NAME_BUF_SZ] = {}; char path_[CGROUP_PATH_BUF_SZ] = {}; -}; - -} // namespace format -} // namespace cgrouprc -} // namespace android +}; \ No newline at end of file diff --git a/libprocessgroup/util/include/processgroup/cgroup_descriptor.h b/libprocessgroup/util/include/processgroup/cgroup_descriptor.h new file mode 100644 index 000000000..1afd2ee9c --- /dev/null +++ b/libprocessgroup/util/include/processgroup/cgroup_descriptor.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include + +// Complete controller description for mounting cgroups +class CgroupDescriptor { + public: + CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, + mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, + uint32_t max_activation_depth); + + const CgroupController* controller() const { return &controller_; } + mode_t mode() const { return mode_; } + std::string uid() const { return uid_; } + std::string gid() const { return gid_; } + + void set_mounted(bool mounted); + + private: + CgroupController controller_; + mode_t mode_ = 0; + std::string uid_; + std::string gid_; +}; diff --git a/libprocessgroup/util/include/processgroup/util.h b/libprocessgroup/util/include/processgroup/util.h index 8d013af55..d592a6347 100644 --- a/libprocessgroup/util/include/processgroup/util.h +++ b/libprocessgroup/util/include/processgroup/util.h @@ -16,10 +16,18 @@ #pragma once +#include #include -namespace util { +#include "cgroup_descriptor.h" + +// Duplicated from cgrouprc.h. Don't depend on libcgrouprc here. +#define CGROUPRC_CONTROLLER_FLAG_MOUNTED 0x1 +#define CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION 0x2 +#define CGROUPRC_CONTROLLER_FLAG_OPTIONAL 0x4 unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path); -} // namespace util +using CgroupControllerName = std::string; +using CgroupDescriptorMap = std::map; +bool ReadDescriptors(CgroupDescriptorMap* descriptors); diff --git a/libprocessgroup/util/tests/util.cpp b/libprocessgroup/util/tests/util.cpp index 1de7d6f3f..6caef8ee3 100644 --- a/libprocessgroup/util/tests/util.cpp +++ b/libprocessgroup/util/tests/util.cpp @@ -18,8 +18,6 @@ #include "gtest/gtest.h" -using util::GetCgroupDepth; - TEST(EmptyInputs, bothEmpty) { EXPECT_EQ(GetCgroupDepth({}, {}), 0); } diff --git a/libprocessgroup/util/util.cpp b/libprocessgroup/util/util.cpp index 9b88a223a..bff4c6f1a 100644 --- a/libprocessgroup/util/util.cpp +++ b/libprocessgroup/util/util.cpp @@ -18,9 +18,33 @@ #include #include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "../build_flags.h" +#include "../internal.h" + +using android::base::GetUintProperty; namespace { +constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; +constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; +constexpr const char* TEMPLATE_CGROUPS_DESC_API_FILE = "/etc/task_profiles/cgroups_%u.json"; + +// This should match the publicly declared value in processgroup.h, +// but we don't want this library to depend on libprocessgroup. +constexpr std::string CGROUPV2_HIERARCHY_NAME_INTERNAL = "cgroup2"; + const char SEP = '/'; std::string DeduplicateAndTrimSeparators(const std::string& path) { @@ -42,9 +66,135 @@ std::string DeduplicateAndTrimSeparators(const std::string& path) { return ret; } +void MergeCgroupToDescriptors(CgroupDescriptorMap* descriptors, const Json::Value& cgroup, + const std::string& name, const std::string& root_path, + int cgroups_version) { + const std::string cgroup_path = cgroup["Path"].asString(); + std::string path; + + if (!root_path.empty()) { + path = root_path; + if (cgroup_path != ".") { + path += "/"; + path += cgroup_path; + } + } else { + path = cgroup_path; + } + + uint32_t controller_flags = 0; + + if (cgroup["NeedsActivation"].isBool() && cgroup["NeedsActivation"].asBool()) { + controller_flags |= CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION; + } + + if (cgroup["Optional"].isBool() && cgroup["Optional"].asBool()) { + controller_flags |= CGROUPRC_CONTROLLER_FLAG_OPTIONAL; + } + + uint32_t max_activation_depth = UINT32_MAX; + if (cgroup.isMember("MaxActivationDepth")) { + max_activation_depth = cgroup["MaxActivationDepth"].asUInt(); + } + + CgroupDescriptor descriptor( + cgroups_version, name, path, std::strtoul(cgroup["Mode"].asString().c_str(), 0, 8), + cgroup["UID"].asString(), cgroup["GID"].asString(), controller_flags, + max_activation_depth); + + auto iter = descriptors->find(name); + if (iter == descriptors->end()) { + descriptors->emplace(name, descriptor); + } else { + iter->second = descriptor; + } +} + +bool ReadDescriptorsFromFile(const std::string& file_name, CgroupDescriptorMap* descriptors) { + static constexpr bool force_memcg_v2 = android::libprocessgroup_flags::force_memcg_v2(); + std::vector result; + std::string json_doc; + + if (!android::base::ReadFileToString(file_name, &json_doc)) { + PLOG(ERROR) << "Failed to read task profiles from " << file_name; + return false; + } + + Json::CharReaderBuilder builder; + std::unique_ptr reader(builder.newCharReader()); + Json::Value root; + std::string errorMessage; + if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) { + LOG(ERROR) << "Failed to parse cgroups description: " << errorMessage; + return false; + } + + if (root.isMember("Cgroups")) { + const Json::Value& cgroups = root["Cgroups"]; + for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { + std::string name = cgroups[i]["Controller"].asString(); + + if (force_memcg_v2 && name == "memory") continue; + + MergeCgroupToDescriptors(descriptors, cgroups[i], name, "", 1); + } + } + + bool memcgv2_present = false; + std::string root_path; + if (root.isMember("Cgroups2")) { + const Json::Value& cgroups2 = root["Cgroups2"]; + root_path = cgroups2["Path"].asString(); + MergeCgroupToDescriptors(descriptors, cgroups2, CGROUPV2_HIERARCHY_NAME_INTERNAL, "", 2); + + const Json::Value& childGroups = cgroups2["Controllers"]; + for (Json::Value::ArrayIndex i = 0; i < childGroups.size(); ++i) { + std::string name = childGroups[i]["Controller"].asString(); + + if (force_memcg_v2 && name == "memory") memcgv2_present = true; + + MergeCgroupToDescriptors(descriptors, childGroups[i], name, root_path, 2); + } + } + + if (force_memcg_v2 && !memcgv2_present) { + LOG(INFO) << "Forcing memcg to v2 hierarchy"; + Json::Value memcgv2; + memcgv2["Controller"] = "memory"; + memcgv2["NeedsActivation"] = true; + memcgv2["Path"] = "."; + memcgv2["Optional"] = true; // In case of cgroup_disabled=memory, so we can still boot + MergeCgroupToDescriptors(descriptors, memcgv2, "memory", + root_path.empty() ? CGROUP_V2_ROOT_DEFAULT : root_path, 2); + } + + return true; +} + +using MountDir = std::string; +using MountOpts = std::string; +static std::optional> ReadCgroupV1Mounts() { + FILE* fp = setmntent("/proc/mounts", "r"); + if (fp == nullptr) { + PLOG(ERROR) << "Failed to read mounts"; + return std::nullopt; + } + + std::map mounts; + const std::string_view CGROUP_V1_TYPE = "cgroup"; + for (mntent* mentry = getmntent(fp); mentry != nullptr; mentry = getmntent(fp)) { + if (mentry->mnt_type && CGROUP_V1_TYPE == mentry->mnt_type && + mentry->mnt_dir && mentry->mnt_opts) { + mounts[mentry->mnt_dir] = mentry->mnt_opts; + } + } + endmntent(fp); + + return mounts; +} + } // anonymous namespace -namespace util { unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path) { const std::string deduped_root = DeduplicateAndTrimSeparators(controller_root); @@ -56,4 +206,47 @@ unsigned int GetCgroupDepth(const std::string& controller_root, const std::strin return std::count(deduped_path.begin() + deduped_root.size(), deduped_path.end(), SEP); } -} // namespace util +bool ReadDescriptors(CgroupDescriptorMap* descriptors) { + // load system cgroup descriptors + if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) { + return false; + } + + // load API-level specific system cgroups descriptors if available + unsigned int api_level = GetUintProperty("ro.product.first_api_level", 0); + if (api_level > 0) { + std::string api_cgroups_path = + android::base::StringPrintf(TEMPLATE_CGROUPS_DESC_API_FILE, api_level); + if (!access(api_cgroups_path.c_str(), F_OK) || errno != ENOENT) { + if (!ReadDescriptorsFromFile(api_cgroups_path, descriptors)) { + return false; + } + } + } + + // load vendor cgroup descriptors if the file exists + if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) && + !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) { + return false; + } + + // check for v1 mount/usability status + std::optional> v1Mounts; + for (auto& [name, descriptor] : *descriptors) { + const CgroupController* const controller = descriptor.controller(); + + if (controller->version() != 1) continue; + + // Read only once, and only if we have at least one v1 controller + if (!v1Mounts) { + v1Mounts = ReadCgroupV1Mounts(); + if (!v1Mounts) return false; + } + + if (const auto it = v1Mounts->find(controller->path()); it != v1Mounts->end()) { + if (it->second.contains(controller->name())) descriptor.set_mounted(true); + } + } + + return true; +} From 9d84103bdd07ef471362f815b53303e7ae008138 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Thu, 8 Aug 2024 16:27:00 +0000 Subject: [PATCH 023/183] libprocessgroup: Remove dependency on libcgrouprc Read cgroup descriptors ourselves instead of going through the LLNDK interface which performs the same thing. Bug: 349105928 Change-Id: I94625ffd0d884d619eb3449e63a305ad5e1d77e3 --- libprocessgroup/Android.bp | 1 - libprocessgroup/cgroup_map.cpp | 95 +++++++++++++--------------------- libprocessgroup/cgroup_map.h | 13 +++-- 3 files changed, 43 insertions(+), 66 deletions(-) diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index d623a1152..8448a39a4 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -75,7 +75,6 @@ cc_library { double_loadable: true, shared_libs: [ "libbase", - "libcgrouprc", ], static_libs: [ "libjsoncpp", diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index aeccfe89b..8180ccf3f 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -25,12 +25,10 @@ #include #include #include -#include #include #include #include -using android::base::StartsWith; using android::base::StringPrintf; using android::base::WriteStringToFile; @@ -40,17 +38,17 @@ static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.threads"; uint32_t CgroupControllerWrapper::version() const { CHECK(HasValue()); - return ACgroupController_getVersion(controller_); + return controller_->version(); } const char* CgroupControllerWrapper::name() const { CHECK(HasValue()); - return ACgroupController_getName(controller_); + return controller_->name(); } const char* CgroupControllerWrapper::path() const { CHECK(HasValue()); - return ACgroupController_getPath(controller_); + return controller_->path(); } bool CgroupControllerWrapper::HasValue() const { @@ -62,7 +60,7 @@ bool CgroupControllerWrapper::IsUsable() { if (state_ == UNKNOWN) { if (__builtin_available(android 30, *)) { - uint32_t flags = ACgroupController_getFlags(controller_); + uint32_t flags = controller_->flags(); state_ = (flags & CGROUPRC_CONTROLLER_FLAG_MOUNTED) != 0 ? USABLE : MISSING; } else { state_ = access(GetProcsFilePath("", 0, 0).c_str(), F_OK) == 0 ? USABLE : MISSING; @@ -129,8 +127,8 @@ bool CgroupControllerWrapper::GetTaskGroup(pid_t tid, std::string* group) const } CgroupMap::CgroupMap() { - if (!LoadRcFile()) { - LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed"; + if (!LoadDescriptors()) { + LOG(ERROR) << "CgroupMap::LoadDescriptors called for [" << getpid() << "] failed"; } } @@ -141,9 +139,9 @@ CgroupMap& CgroupMap::GetInstance() { return *instance; } -bool CgroupMap::LoadRcFile() { +bool CgroupMap::LoadDescriptors() { if (!loaded_) { - loaded_ = (ACgroupFile_getVersion() != 0); + loaded_ = ReadDescriptors(&descriptors_); } return loaded_; } @@ -154,40 +152,27 @@ void CgroupMap::Print() const { << "] failed, cgroups were not initialized properly"; return; } - LOG(INFO) << "File version = " << ACgroupFile_getVersion(); - LOG(INFO) << "File controller count = " << ACgroupFile_getControllerCount(); + LOG(INFO) << "Controller count = " << descriptors_.size(); LOG(INFO) << "Mounted cgroups:"; - auto controller_count = ACgroupFile_getControllerCount(); - for (uint32_t i = 0; i < controller_count; ++i) { - const ACgroupController* controller = ACgroupFile_getController(i); - if (__builtin_available(android 30, *)) { - LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver " - << ACgroupController_getVersion(controller) << " path " - << ACgroupController_getPath(controller) << " flags " - << ACgroupController_getFlags(controller); - } else { - LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver " - << ACgroupController_getVersion(controller) << " path " - << ACgroupController_getPath(controller); - } + for (const auto& [name, descriptor] : descriptors_) { + LOG(INFO) << "\t" << descriptor.controller()->name() << " ver " + << descriptor.controller()->version() << " path " + << descriptor.controller()->path() << " flags " + << descriptor.controller()->flags(); } } CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const { if (!loaded_) { LOG(ERROR) << "CgroupMap::FindController called for [" << getpid() - << "] failed, RC file was not initialized properly"; + << "] failed, cgroups were not initialized properly"; return CgroupControllerWrapper(nullptr); } - auto controller_count = ACgroupFile_getControllerCount(); - for (uint32_t i = 0; i < controller_count; ++i) { - const ACgroupController* controller = ACgroupFile_getController(i); - if (name == ACgroupController_getName(controller)) { - return CgroupControllerWrapper(controller); - } + if (const auto it = descriptors_.find(name); it != descriptors_.end()) { + return CgroupControllerWrapper(it->second.controller()); } return CgroupControllerWrapper(nullptr); @@ -196,15 +181,13 @@ CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) const { if (!loaded_) { LOG(ERROR) << "CgroupMap::FindControllerByPath called for [" << getpid() - << "] failed, RC file was not initialized properly"; + << "] failed, cgroups were not initialized properly"; return CgroupControllerWrapper(nullptr); } - auto controller_count = ACgroupFile_getControllerCount(); - for (uint32_t i = 0; i < controller_count; ++i) { - const ACgroupController* controller = ACgroupFile_getController(i); - if (StartsWith(path, ACgroupController_getPath(controller))) { - return CgroupControllerWrapper(controller); + for (const auto& [name, descriptor] : descriptors_) { + if (path.starts_with(descriptor.controller()->path())) { + return CgroupControllerWrapper(descriptor.controller()); } } @@ -212,31 +195,23 @@ CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) } int CgroupMap::ActivateControllers(const std::string& path) const { - if (__builtin_available(android 30, *)) { - auto controller_count = ACgroupFile_getControllerCount(); - for (uint32_t i = 0; i < controller_count; ++i) { - const ACgroupController* controller = ACgroupFile_getController(i); - const uint32_t flags = ACgroupController_getFlags(controller); - uint32_t max_activation_depth = UINT32_MAX; - if (__builtin_available(android 36, *)) { - max_activation_depth = ACgroupController_getMaxActivationDepth(controller); - } - const int depth = GetCgroupDepth(ACgroupController_getPath(controller), path); + for (const auto& [name, descriptor] : descriptors_) { + const uint32_t flags = descriptor.controller()->flags(); + const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); + const int depth = GetCgroupDepth(descriptor.controller()->path(), path); - if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { - std::string str("+"); - str.append(ACgroupController_getName(controller)); - if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { - if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { - PLOG(WARNING) << "Activation of cgroup controller " << str - << " failed in path " << path; - } else { - return -errno; - } + if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { + std::string str("+"); + str.append(descriptor.controller()->name()); + if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { + if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { + PLOG(WARNING) << "Activation of cgroup controller " << str + << " failed in path " << path; + } else { + return -errno; } } } - return 0; } - return -ENOSYS; + return 0; } diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index 364279414..5ad59bddf 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -18,15 +18,17 @@ #include +#include #include -#include +#include +#include -// Convenient wrapper of an ACgroupController pointer. +// Convenient wrapper of a CgroupController pointer. class CgroupControllerWrapper { public: // Does not own controller - explicit CgroupControllerWrapper(const ACgroupController* controller) + explicit CgroupControllerWrapper(const CgroupController* controller) : controller_(controller) {} uint32_t version() const; @@ -47,7 +49,7 @@ class CgroupControllerWrapper { MISSING = 2, }; - const ACgroupController* controller_ = nullptr; + const CgroupController* controller_ = nullptr; // CgroupMap owns the object behind this pointer ControllerState state_ = ControllerState::UNKNOWN; }; @@ -60,7 +62,8 @@ class CgroupMap { private: bool loaded_ = false; + CgroupDescriptorMap descriptors_; CgroupMap(); - bool LoadRcFile(); + bool LoadDescriptors(); void Print() const; }; From c31c5a75c8c275ca33bb44ba1faaf0e1f327a692 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 13 Aug 2024 21:09:30 +0000 Subject: [PATCH 024/183] libprocessgroup: Remove ACgroupController_getMaxActivationDepth This was targeted for API 36 which doesn't exist yet, so this was never released. Now that libprocessgroup does not use the libcgrouprc interfaces, this can be removed. Bug: 349105928 Bug: 359609093 Change-Id: I2ea466c9e8bc54bf9178fa74b45e88f26d3e4c69 --- libprocessgroup/cgrouprc/a_cgroup_controller.cpp | 5 ----- libprocessgroup/cgrouprc/include/android/cgrouprc.h | 8 -------- libprocessgroup/cgrouprc/libcgrouprc.map.txt | 7 ------- 3 files changed, 20 deletions(-) diff --git a/libprocessgroup/cgrouprc/a_cgroup_controller.cpp b/libprocessgroup/cgrouprc/a_cgroup_controller.cpp index 889b3becf..5a326e55d 100644 --- a/libprocessgroup/cgrouprc/a_cgroup_controller.cpp +++ b/libprocessgroup/cgrouprc/a_cgroup_controller.cpp @@ -32,11 +32,6 @@ uint32_t ACgroupController_getFlags(const ACgroupController* controller) { return controller->flags(); } -uint32_t ACgroupController_getMaxActivationDepth(const ACgroupController* controller) { - CHECK(controller != nullptr); - return controller->max_activation_depth(); -} - const char* ACgroupController_getName(const ACgroupController* controller) { CHECK(controller != nullptr); return controller->name(); diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h index 3a57df547..e704a36aa 100644 --- a/libprocessgroup/cgrouprc/include/android/cgrouprc.h +++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h @@ -78,14 +78,6 @@ __attribute__((warn_unused_result)) uint32_t ACgroupController_getVersion(const __attribute__((warn_unused_result, weak)) uint32_t ACgroupController_getFlags( const ACgroupController*) __INTRODUCED_IN(30); -/** - * Returns the maximum activation depth of the given controller. - * Only applicable to cgroup v2 controllers. - * Returns UINT32_MAX if no maximum activation depth is set. - */ -__attribute__((warn_unused_result, weak)) uint32_t ACgroupController_getMaxActivationDepth( - const ACgroupController* controller) __INTRODUCED_IN(36); - /** * Returns the name of the given controller. * If the given controller is null, return nullptr. diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.map.txt index 30bd25f18..b62b10f3b 100644 --- a/libprocessgroup/cgrouprc/libcgrouprc.map.txt +++ b/libprocessgroup/cgrouprc/libcgrouprc.map.txt @@ -16,10 +16,3 @@ LIBCGROUPRC_30 { # introduced=30 local: *; }; - -LIBCGROUPRC_36 { # introduced=36 - global: - ACgroupController_getMaxActivationDepth; # llndk=202504 systemapi - local: - *; -}; From 5161033f660250858ac0088a70ec57f7b9b26745 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Thu, 8 Aug 2024 16:32:05 +0000 Subject: [PATCH 025/183] libprocessgroup: Combine all 3 ActivateControllers implementations into one Remove this code duplication and use just one interface. Bug: 349105928 Change-Id: Id8c7186d9665e9087a654f5781b7593b06349160 --- libprocessgroup/cgroup_map.cpp | 22 +--------- libprocessgroup/cgroup_map.h | 2 +- libprocessgroup/processgroup.cpp | 7 ++-- libprocessgroup/setup/cgroup_map_write.cpp | 42 +------------------ .../util/include/processgroup/util.h | 2 + libprocessgroup/util/util.cpp | 23 ++++++++++ 6 files changed, 33 insertions(+), 65 deletions(-) diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index 8180ccf3f..32bef13a1 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -194,24 +194,6 @@ CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) return CgroupControllerWrapper(nullptr); } -int CgroupMap::ActivateControllers(const std::string& path) const { - for (const auto& [name, descriptor] : descriptors_) { - const uint32_t flags = descriptor.controller()->flags(); - const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); - const int depth = GetCgroupDepth(descriptor.controller()->path(), path); - - if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { - std::string str("+"); - str.append(descriptor.controller()->name()); - if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { - if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { - PLOG(WARNING) << "Activation of cgroup controller " << str - << " failed in path " << path; - } else { - return -errno; - } - } - } - } - return 0; +bool CgroupMap::ActivateControllers(const std::string& path) const { + return ::ActivateControllers(path, descriptors_); } diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index 5ad59bddf..fb9907645 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -58,7 +58,7 @@ class CgroupMap { static CgroupMap& GetInstance(); CgroupControllerWrapper FindController(const std::string& name) const; CgroupControllerWrapper FindControllerByPath(const std::string& path) const; - int ActivateControllers(const std::string& path) const; + bool ActivateControllers(const std::string& path) const; private: bool loaded_ = false; diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 83a2258bf..d3719eea3 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -662,10 +662,9 @@ static int createProcessGroupInternal(uid_t uid, pid_t initialPid, std::string c return -errno; } if (activate_controllers) { - ret = CgroupMap::GetInstance().ActivateControllers(uid_path); - if (ret) { - LOG(ERROR) << "Failed to activate controllers in " << uid_path; - return ret; + if (!CgroupMap::GetInstance().ActivateControllers(uid_path)) { + PLOG(ERROR) << "Failed to activate controllers in " << uid_path; + return -errno; } } diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index 821168008..d05bf2408 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -180,25 +180,7 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { return false; } - if (controller->flags() & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && - controller->max_activation_depth() > 0) { - std::string str = "+"; - str += controller->name(); - std::string path = controller->path(); - path += "/cgroup.subtree_control"; - - if (!android::base::WriteStringToFile(str, path)) { - if (IsOptionalController(controller)) { - PLOG(INFO) << "Failed to activate optional controller " << controller->name() - << " at " << path; - return true; - } - PLOG(ERROR) << "Failed to activate controller " << controller->name(); - return false; - } - } - - return true; + return ::ActivateControllers(controller->path(), {{controller->name(), descriptor}}); } static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { @@ -323,27 +305,7 @@ static bool CreateV2SubHierarchy(const std::string& path, const CgroupDescriptor // Activate all v2 controllers in path so they can be activated in // children as they are created. - for (const auto& [name, descriptor] : descriptors) { - const CgroupController* controller = descriptor.controller(); - std::uint32_t flags = controller->flags(); - std::uint32_t max_activation_depth = controller->max_activation_depth(); - const int depth = GetCgroupDepth(controller->path(), path); - - if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME && - flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { - std::string str("+"); - str += controller->name(); - if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) { - if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { - PLOG(WARNING) << "Activation of cgroup controller " << str << " failed in path " - << path; - } else { - return false; - } - } - } - } - return true; + return ::ActivateControllers(path, descriptors); } bool CgroupSetup() { diff --git a/libprocessgroup/util/include/processgroup/util.h b/libprocessgroup/util/include/processgroup/util.h index d592a6347..2c7b32926 100644 --- a/libprocessgroup/util/include/processgroup/util.h +++ b/libprocessgroup/util/include/processgroup/util.h @@ -31,3 +31,5 @@ unsigned int GetCgroupDepth(const std::string& controller_root, const std::strin using CgroupControllerName = std::string; using CgroupDescriptorMap = std::map; bool ReadDescriptors(CgroupDescriptorMap* descriptors); + +bool ActivateControllers(const std::string& path, const CgroupDescriptorMap& descriptors); diff --git a/libprocessgroup/util/util.cpp b/libprocessgroup/util/util.cpp index bff4c6f1a..14016751c 100644 --- a/libprocessgroup/util/util.cpp +++ b/libprocessgroup/util/util.cpp @@ -250,3 +250,26 @@ bool ReadDescriptors(CgroupDescriptorMap* descriptors) { return true; } + +bool ActivateControllers(const std::string& path, const CgroupDescriptorMap& descriptors) { + for (const auto& [name, descriptor] : descriptors) { + const uint32_t flags = descriptor.controller()->flags(); + const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); + const unsigned int depth = GetCgroupDepth(descriptor.controller()->path(), path); + + if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { + std::string str("+"); + str.append(descriptor.controller()->name()); + if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) { + if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { + PLOG(WARNING) << "Activation of cgroup controller " << str + << " failed in path " << path; + } else { + return false; + } + } + } + } + return true; +} + From 36ea62f1fd9dda7c733c229e84ab1da37db370c2 Mon Sep 17 00:00:00 2001 From: Tiffany Yang Date: Thu, 3 Oct 2024 23:52:54 +0000 Subject: [PATCH 026/183] Revert "init: Wait for /dev/hvc1 during ARCVM first-stage mount" This reverts commit b885e4ad533ea4d12e18a0147d298be0cd8cec72. Reason for revert: No longer needed (using virtio-blk instead) Change-Id: I667f0d4f58060e781a5e9b21c778cd568b92971a --- init/first_stage_mount.cpp | 5 ----- init/selinux.cpp | 2 -- init/util.h | 5 ----- 3 files changed, 12 deletions(-) diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index 927b45f22..55cce6eaa 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -305,11 +305,6 @@ bool FirstStageMountVBootV2::InitDevices() { return false; } } - - if (IsArcvm() && !block_dev_init_.InitHvcDevice("hvc1")) { - return false; - } - return true; } diff --git a/init/selinux.cpp b/init/selinux.cpp index 01af2b64d..c2d9b8d28 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -474,8 +474,6 @@ void SelinuxRestoreContext() { RestoreconIfExists(SnapshotManager::GetGlobalRollbackIndicatorPath().c_str(), 0); RestoreconIfExists("/metadata/gsi", SELINUX_ANDROID_RESTORECON_RECURSE | SELINUX_ANDROID_RESTORECON_SKIP_SEHASH); - - RestoreconIfExists("/dev/hvc1", 0); } int SelinuxKlogCallback(int type, const char* fmt, ...) { diff --git a/init/util.h b/init/util.h index 056539181..aa24123df 100644 --- a/init/util.h +++ b/init/util.h @@ -18,7 +18,6 @@ #include #include -#include #include #include @@ -109,10 +108,6 @@ inline constexpr bool IsMicrodroid() { #endif } -inline bool IsArcvm() { - return !access("/is_arcvm", F_OK); -} - bool Has32BitAbi(); std::string GetApexNameFromFileName(const std::string& path); From 8d71220df28851a7dce351f86601958fdbc3e5ae Mon Sep 17 00:00:00 2001 From: Jusik Chung Date: Fri, 4 Oct 2024 02:21:37 +0000 Subject: [PATCH 027/183] Revert "init: Look for super partition only on a boot device" This reverts commit 6f0ebcb5260a8e769e0e029596d21c0efabe361b. Reason for revert: b/371393845 boot up failure of gcar emulator Change-Id: I15e5bea609938cf5a1e347666b9a2abb287cb086 --- init/block_dev_initializer.cpp | 6 +----- init/devices.cpp | 22 ---------------------- init/devices.h | 1 - 3 files changed, 1 insertion(+), 28 deletions(-) diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index cabeb0109..8f5215856 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -98,11 +98,7 @@ ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent, LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name; - // Remove partition from the list only if it was found on boot device - if (device_handler_->IsBootDevice(uevent)) { - devices->erase(iter); - } - + devices->erase(iter); device_handler_->HandleUevent(uevent); return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue; } diff --git a/init/devices.cpp b/init/devices.cpp index 6a3a64dd8..f2bb9d276 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -188,28 +188,6 @@ void SysfsPermissions::SetPermissions(const std::string& path) const { } } -bool DeviceHandler::IsBootDevice(const Uevent& uevent) const { - std::string device; - - if (FindPlatformDevice(uevent.path, &device)) { - // Skip /devices/platform or /devices/ if present - static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; - static constexpr std::string_view devices_prefix = "/devices/"; - - if (StartsWith(device, devices_platform_prefix)) { - device = device.substr(devices_platform_prefix.length()); - } else if (StartsWith(device, devices_prefix)) { - device = device.substr(devices_prefix.length()); - } - } else if (FindPciDevicePrefix(uevent.path, &device)) { - } else if (FindVbdDevicePrefix(uevent.path, &device)) { - } else { - return false; - } - - return boot_devices_.find(device) != boot_devices_.end(); -} - std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) { static const auto partition_map = [] { std::vector> partition_map; diff --git a/init/devices.h b/init/devices.h index 4df604d00..6da123259 100644 --- a/init/devices.h +++ b/init/devices.h @@ -133,7 +133,6 @@ class DeviceHandler : public UeventHandler { // `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to // `userdata`. static std::string GetPartitionNameForDevice(const std::string& device); - bool IsBootDevice(const Uevent& uevent) const; private: void ColdbootDone() override; From 50fd822149d305b8fb53f2d9f650bb246acaf0ae Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Fri, 4 Oct 2024 14:53:27 +0000 Subject: [PATCH 028/183] init: Remove schedtune support Schedtune was an out of tree cgroup controller present in Android kernels up to 4.19. It was replaced with uclamp and the cpu controller. Now that 4.19 is EOL and unsupported, and schedtune is not present in any supported Android kernels, remove the userspace support for schedtune. Bug: 362504801 Change-Id: Iab7b7295d1fb443209d5868ac5c65dca0aabfbab --- init/service_parser.cpp | 3 --- rootdir/init.rc | 49 ----------------------------------------- 2 files changed, 52 deletions(-) diff --git a/init/service_parser.cpp b/init/service_parser.cpp index e6f3af617..ec3b176d4 100644 --- a/init/service_parser.cpp +++ b/init/service_parser.cpp @@ -538,12 +538,9 @@ Result ServiceParser::ParseUser(std::vector&& args) { // when we migrate to cgroups v2 while these hardcoded paths stay the same. static std::optional ConvertTaskFileToProfile(const std::string& file) { static const std::map map = { - {"/dev/stune/top-app/tasks", "MaxPerformance"}, - {"/dev/stune/foreground/tasks", "HighPerformance"}, {"/dev/cpuset/camera-daemon/tasks", "CameraServiceCapacity"}, {"/dev/cpuset/foreground/tasks", "ProcessCapacityHigh"}, {"/dev/cpuset/system-background/tasks", "ServiceCapacityLow"}, - {"/dev/stune/nnapi-hal/tasks", "NNApiHALPerformance"}, {"/dev/blkio/background/tasks", "LowIoPriority"}, }; auto iter = map.find(file); diff --git a/rootdir/init.rc b/rootdir/init.rc index 1acd63774..c8b725d1e 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -112,37 +112,6 @@ on init # Create socket dir for ot-daemon mkdir /dev/socket/ot-daemon 0770 thread_network thread_network - # Create energy-aware scheduler tuning nodes - mkdir /dev/stune/foreground - mkdir /dev/stune/background - mkdir /dev/stune/top-app - mkdir /dev/stune/rt - 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/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/cgroup.procs - chown system system /dev/stune/foreground/cgroup.procs - chown system system /dev/stune/background/cgroup.procs - chown system system /dev/stune/top-app/cgroup.procs - chown system system /dev/stune/rt/cgroup.procs - 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/cgroup.procs - chmod 0664 /dev/stune/foreground/cgroup.procs - chmod 0664 /dev/stune/background/cgroup.procs - chmod 0664 /dev/stune/top-app/cgroup.procs - chmod 0664 /dev/stune/rt/cgroup.procs - # cpuctl hierarchy for devices using utilclamp mkdir /dev/cpuctl/foreground mkdir /dev/cpuctl/foreground_window @@ -216,24 +185,6 @@ on init chmod 0664 /dev/cpuctl/camera-daemon/tasks chmod 0664 /dev/cpuctl/camera-daemon/cgroup.procs - # Create an stune group for camera-specific processes - mkdir /dev/stune/camera-daemon - chown system system /dev/stune/camera-daemon - chown system system /dev/stune/camera-daemon/tasks - chown system system /dev/stune/camera-daemon/cgroup.procs - chmod 0664 /dev/stune/camera-daemon/tasks - chmod 0664 /dev/stune/camera-daemon/cgroup.procs - - # Create an stune group for NNAPI HAL processes - mkdir /dev/stune/nnapi-hal - chown system system /dev/stune/nnapi-hal - chown system system /dev/stune/nnapi-hal/tasks - chown system system /dev/stune/nnapi-hal/cgroup.procs - chmod 0664 /dev/stune/nnapi-hal/tasks - chmod 0664 /dev/stune/nnapi-hal/cgroup.procs - write /dev/stune/nnapi-hal/schedtune.boost 1 - write /dev/stune/nnapi-hal/schedtune.prefer_idle 1 - # Create blkio group and apply initial settings. # This feature needs kernel to support it, and the # device's init.rc must actually set the correct values. From 551c6018c84dc68716167b998da34651eab6aa3a Mon Sep 17 00:00:00 2001 From: Neill Kapron Date: Fri, 4 Oct 2024 15:54:26 +0000 Subject: [PATCH 029/183] init/epoll: clean up reorder-init-list warning This change cleans up the following build warning: warning: ISO C++ requires field designators to be specified in declaration order; field 'events' will be initialized after field 'handler' [-Wreorder-init-list] Bug: none Test: TH Change-Id: I9fe566b452438dc9f00f782fc4435905227a60c9 Signed-off-by: Neill Kapron --- init/epoll.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init/epoll.cpp b/init/epoll.cpp index cd73a0c3d..719a53271 100644 --- a/init/epoll.cpp +++ b/init/epoll.cpp @@ -47,8 +47,8 @@ Result Epoll::RegisterHandler(int fd, Handler handler, uint32_t events) { auto [it, inserted] = epoll_handlers_.emplace( fd, Info{ - .events = events, .handler = std::move(handler), + .events = events, }); if (!inserted) { return Error() << "Cannot specify two epoll handlers for a given FD"; From 623682af2f7cd0052a157f459d74b5ebc9cfb2fe Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Sun, 6 Oct 2024 13:06:16 -0700 Subject: [PATCH 030/183] fiemap_writer_test: add block truncation and sync for safety There is a delay to get inode evicted whic requires to deallocate blocks used by the previous test. Let's secure the pinned space as much as possible. Bug: 371822983 Change-Id: I4cc69fc61e348511bb027ca0a9dd277fffb20f7f Signed-off-by: Jaegeuk Kim --- fs_mgr/libfiemap/fiemap_writer_test.cpp | 6 +++++- fs_mgr/libfiemap/split_fiemap_writer.cpp | 3 +++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/fs_mgr/libfiemap/fiemap_writer_test.cpp b/fs_mgr/libfiemap/fiemap_writer_test.cpp index c37329c36..115f53e8e 100644 --- a/fs_mgr/libfiemap/fiemap_writer_test.cpp +++ b/fs_mgr/libfiemap/fiemap_writer_test.cpp @@ -66,7 +66,11 @@ class FiemapWriterTest : public ::testing::Test { testfile = gTestDir + "/"s + tinfo->name(); } - void TearDown() override { unlink(testfile.c_str()); } + void TearDown() override { + truncate(testfile.c_str(), 0); + unlink(testfile.c_str()); + sync(); + } // name of the file we use for testing std::string testfile; diff --git a/fs_mgr/libfiemap/split_fiemap_writer.cpp b/fs_mgr/libfiemap/split_fiemap_writer.cpp index 0df61253c..1f32d2f99 100644 --- a/fs_mgr/libfiemap/split_fiemap_writer.cpp +++ b/fs_mgr/libfiemap/split_fiemap_writer.cpp @@ -196,10 +196,13 @@ bool SplitFiemap::RemoveSplitFiles(const std::string& file_path, std::string* me if (access(file.c_str(), F_OK) != 0 && (errno == ENOENT || errno == ENAMETOOLONG)) { continue; } + truncate(file.c_str(), 0); ok &= android::base::RemoveFileIfExists(file, message); } } + truncate(file_path.c_str(), 0); ok &= android::base::RemoveFileIfExists(file_path, message); + sync(); return ok; } From 3a7cb4c637afdb6084f2f9eecdaedd49e2c02cc2 Mon Sep 17 00:00:00 2001 From: Justin Yun Date: Sun, 6 Oct 2024 13:43:59 +0900 Subject: [PATCH 031/183] Use __ANDROID_VENDOR_API__ for vendor API surface Build system defines __ANDROID_VENDOR_API__ for non-system modules. Use this flag to provide vendor API surface for vendor or product variant modules. Bug: 368559337 Test: atest AImageReaderWindowTest Change-Id: I7da3d4ca9f92255a426af8d66b4391f3c1426759 --- .../include_llndk/android/llndk-versioning.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/libvendorsupport/include_llndk/android/llndk-versioning.h b/libvendorsupport/include_llndk/android/llndk-versioning.h index 0402c2880..81d165f47 100644 --- a/libvendorsupport/include_llndk/android/llndk-versioning.h +++ b/libvendorsupport/include_llndk/android/llndk-versioning.h @@ -25,15 +25,15 @@ __attribute__((annotate("introduced_in_llndk=" #vendor_api_level))) #endif -#if defined(__ANDROID_VNDK__) - +#if defined(__ANDROID_VENDOR_API__) +// __ANDROID_VENDOR_API__ is defined only for vendor or product variant modules. // Use this macro as an `if` statement to call an API that are available to both NDK and LLNDK. -// This returns true for the vendor modules if the vendor_api_level is less than or equal to the -// ro.board.api_level. +// This returns true for vendor or product modules if the vendor_api_level is less than or equal to +// the ro.board.api_level. #define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ constexpr(__ANDROID_VENDOR_API__ >= vendor_api_level) -#else // __ANDROID_VNDK__ +#else // __ANDROID_VENDOR_API__ // For non-vendor modules, API_LEVEL_AT_LEAST is replaced with __builtin_available(sdk_api_level) to // guard the API for __INTRODUCED_IN. @@ -42,4 +42,4 @@ (__builtin_available(android sdk_api_level, *)) #endif -#endif // __ANDROID_VNDK__ +#endif // __ANDROID_VENDOR_API__ From 42dbd2de872ffff2167723ae02a261d085c1c1ce Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Mon, 7 Oct 2024 18:14:22 -0700 Subject: [PATCH 032/183] Remove libstats*_lazy tests from MTS libstatssocket_lazy_test and libstatspull_lazy_test test primaryly the lazy libs that ship from the platform. As a result, they shouldn't be in MTS Bug: 363078348 Test: TH Change-Id: Iac7e2797d9f8c432f00688a49d53aa2691a52789 --- libstats/pull_lazy/Android.bp | 2 +- libstats/socket_lazy/Android.bp | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/libstats/pull_lazy/Android.bp b/libstats/pull_lazy/Android.bp index 65dce26a0..71af17068 100644 --- a/libstats/pull_lazy/Android.bp +++ b/libstats/pull_lazy/Android.bp @@ -32,7 +32,7 @@ cc_test { "-Wall", "-Werror", ], - test_suites: ["device-tests", "mts-statsd"], + test_suites: ["device-tests"], test_config: "libstatspull_lazy_test.xml", // TODO(b/153588990): Remove when the build system properly separates. // 32bit and 64bit architectures. diff --git a/libstats/socket_lazy/Android.bp b/libstats/socket_lazy/Android.bp index 241e87af3..945a7c494 100644 --- a/libstats/socket_lazy/Android.bp +++ b/libstats/socket_lazy/Android.bp @@ -36,7 +36,6 @@ cc_test { ], test_suites: [ "device-tests", - "mts-statsd", ], test_config: "libstatssocket_lazy_test.xml", // TODO(b/153588990): Remove when the build system properly separates. From e0ec952bae15d296006de86b80782551c144afa4 Mon Sep 17 00:00:00 2001 From: Shai Barack Date: Mon, 7 Oct 2024 15:25:28 +0000 Subject: [PATCH 033/183] Avoid unnecessary allocation in VectorImpl When shrinking a vector, we might reallocate the buffer if the current capacity is too large, or we might reuse the existing buffer. Never reallocate the buffer if the current capacity is already at the minimum (i.e. we won't actually shrink by reallocating). Bug: 370649413 Change-Id: I665037ed2a8621a82f2b58bcc834934de0761f34 Flag: EXEMPT bugfix Tested: see b/370649413#comment6 --- libutils/binder/VectorImpl.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libutils/binder/VectorImpl.cpp b/libutils/binder/VectorImpl.cpp index d951b8bbb..a62664f7b 100644 --- a/libutils/binder/VectorImpl.cpp +++ b/libutils/binder/VectorImpl.cpp @@ -463,7 +463,8 @@ void VectorImpl::_shrink(size_t where, size_t amount) size_t new_size; LOG_ALWAYS_FATAL_IF(__builtin_sub_overflow(mCount, amount, &new_size)); - if (new_size < (capacity() / 2)) { + const size_t prev_capacity = capacity(); + if (new_size < (prev_capacity / 2) && prev_capacity > kMinVectorCapacity) { // NOTE: (new_size * 2) is safe because capacity didn't overflow and // new_size < (capacity / 2)). const size_t new_capacity = max(kMinVectorCapacity, new_size * 2); From 972a2d30f8a3f260967b747592f4e8cdc560e01c Mon Sep 17 00:00:00 2001 From: "Priyanka Advani (xWF)" Date: Tue, 8 Oct 2024 18:54:37 +0000 Subject: [PATCH 034/183] Revert "libprocessgroup: Remove cgroup.rc file" Revert submission 3212512 Reason for revert: Droidmonitor created revert due to b/372273614. Will be verifying through ABTD before submission. Reverted changes: /q/submissionid:3212512 Change-Id: I37568516e973cb940f1229d52f94b8dc801da2ab --- fs_mgr/libsnapshot/snapuserd/Android.bp | 7 +- init/Android.bp | 1 + init/init.cpp | 3 + libcutils/Android.bp | 2 +- libprocessgroup/Android.bp | 3 +- libprocessgroup/cgroup_map.cpp | 4 +- libprocessgroup/cgrouprc/Android.bp | 3 +- libprocessgroup/cgrouprc/a_cgroup_file.cpp | 88 ++++-- libprocessgroup/cgrouprc/cgrouprc_internal.h | 7 +- libprocessgroup/cgrouprc_format/Android.bp | 13 + .../cgroup_controller.cpp | 12 +- .../processgroup/format}/cgroup_controller.h | 12 +- .../processgroup/format/cgroup_file.h} | 23 +- .../include/processgroup/processgroup.h | 2 +- libprocessgroup/setup/Android.bp | 1 + libprocessgroup/setup/cgroup_descriptor.h | 12 +- libprocessgroup/setup/cgroup_map_write.cpp | 259 ++++++++++++++++-- libprocessgroup/util/Android.bp | 8 - libprocessgroup/util/cgroup_descriptor.cpp | 38 --- .../include/processgroup/cgroup_descriptor.h | 45 --- .../util/include/processgroup/util.h | 12 +- libprocessgroup/util/tests/util.cpp | 2 + libprocessgroup/util/util.cpp | 197 +------------ 23 files changed, 389 insertions(+), 365 deletions(-) rename libprocessgroup/{util => cgrouprc_format}/cgroup_controller.cpp (90%) rename libprocessgroup/{util/include/processgroup => cgrouprc_format/include/processgroup/format}/cgroup_controller.h (87%) rename libprocessgroup/{internal.h => cgrouprc_format/include/processgroup/format/cgroup_file.h} (54%) delete mode 100644 libprocessgroup/util/cgroup_descriptor.cpp delete mode 100644 libprocessgroup/util/include/processgroup/cgroup_descriptor.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 083068b54..298fd9f30 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -85,9 +85,9 @@ cc_library_static { "libsnapshot_cow", "liburing", "libprocessgroup", - "libprocessgroup_util", "libjsoncpp", "libcgrouprc", + "libcgrouprc_format", ], include_dirs: ["bionic/libc/kernel"], export_include_dirs: ["include"], @@ -129,9 +129,9 @@ cc_defaults { "libsnapshot_cow", "libsnapuserd", "libprocessgroup", - "libprocessgroup_util", "libjsoncpp", "libcgrouprc", + "libcgrouprc_format", "libsnapuserd_client", "libz", "liblz4", @@ -221,9 +221,9 @@ cc_defaults { "libsnapshot_cow", "libsnapuserd", "libprocessgroup", - "libprocessgroup_util", "libjsoncpp", "libcgrouprc", + "libcgrouprc_format", "liburing", "libz", ], @@ -319,6 +319,7 @@ cc_binary_host { "libprocessgroup", "libjsoncpp", "libcgrouprc", + "libcgrouprc_format", "liburing", "libz", ], diff --git a/init/Android.bp b/init/Android.bp index 8da2e7c2e..18a79d6c4 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -163,6 +163,7 @@ libinit_cc_defaults { "libavb", "libavf_cc_flags", "libbootloader_message", + "libcgrouprc_format", "liblmkd_utils", "liblz4", "libzstd", diff --git a/init/init.cpp b/init/init.cpp index 17498da6d..6c8089926 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -636,6 +636,9 @@ static Result SetupCgroupsAction(const BuiltinArguments&) { LOG(INFO) << "Cgroups support in kernel is not enabled"; return {}; } + // Have to create using make_dir function + // for appropriate sepolicy to be set for it + make_dir(android::base::Dirname(CGROUPS_RC_PATH), 0711); if (!CgroupSetup()) { return ErrnoError() << "Failed to setup cgroups"; } diff --git a/libcutils/Android.bp b/libcutils/Android.bp index fc4c571b7..3c3eeb663 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -301,7 +301,7 @@ cc_defaults { android: { static_executable: true, static_libs: [ - "libprocessgroup_util", + "libcgrouprc_format", ] + test_libraries + always_static_test_libraries, }, not_windows: { diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index d623a1152..a60bfe973 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -17,7 +17,7 @@ soong_config_module_type { libprocessgroup_flag_aware_cc_defaults { name: "libprocessgroup_build_flags_cc", - cpp_std: "gnu++23", + cpp_std: "gnu++20", soong_config_variables: { memcg_v2_force_enabled: { cflags: [ @@ -116,6 +116,5 @@ cc_test { ], static_libs: [ "libgmock", - "libprocessgroup_util", ], } diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index aeccfe89b..fb01cfda9 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -151,7 +151,7 @@ bool CgroupMap::LoadRcFile() { void CgroupMap::Print() const { if (!loaded_) { LOG(ERROR) << "CgroupMap::Print called for [" << getpid() - << "] failed, cgroups were not initialized properly"; + << "] failed, RC file was not initialized properly"; return; } LOG(INFO) << "File version = " << ACgroupFile_getVersion(); @@ -221,7 +221,7 @@ int CgroupMap::ActivateControllers(const std::string& path) const { if (__builtin_available(android 36, *)) { max_activation_depth = ACgroupController_getMaxActivationDepth(controller); } - const int depth = GetCgroupDepth(ACgroupController_getPath(controller), path); + const int depth = util::GetCgroupDepth(ACgroupController_getPath(controller), path); if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { std::string str("+"); diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index 38b2fa31d..cb912476e 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -49,8 +49,7 @@ cc_library { "libbase", ], static_libs: [ - "libjsoncpp", - "libprocessgroup_util", + "libcgrouprc_format", ], stubs: { symbol_file: "libcgrouprc.map.txt", diff --git a/libprocessgroup/cgrouprc/a_cgroup_file.cpp b/libprocessgroup/cgrouprc/a_cgroup_file.cpp index 33c8376f4..e26d84114 100644 --- a/libprocessgroup/cgrouprc/a_cgroup_file.cpp +++ b/libprocessgroup/cgrouprc/a_cgroup_file.cpp @@ -14,51 +14,93 @@ * limitations under the License. */ -#include +#include +#include + +#include #include +#include +#include #include -#include +#include #include "cgrouprc_internal.h" -static CgroupDescriptorMap* LoadDescriptors() { - CgroupDescriptorMap* descriptors = new CgroupDescriptorMap; - if (!ReadDescriptors(descriptors)) { - LOG(ERROR) << "Failed to load cgroup description file"; +using android::base::StringPrintf; +using android::base::unique_fd; + +using android::cgrouprc::format::CgroupController; +using android::cgrouprc::format::CgroupFile; + +static CgroupFile* LoadRcFile() { + struct stat sb; + + unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_RDONLY | O_CLOEXEC))); + if (fd < 0) { + PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; return nullptr; } - return descriptors; + + if (fstat(fd, &sb) < 0) { + PLOG(ERROR) << "fstat() failed for " << CGROUPS_RC_PATH; + return nullptr; + } + + size_t file_size = sb.st_size; + if (file_size < sizeof(CgroupFile)) { + LOG(ERROR) << "Invalid file format " << CGROUPS_RC_PATH; + return nullptr; + } + + CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0); + if (file_data == MAP_FAILED) { + PLOG(ERROR) << "Failed to mmap " << CGROUPS_RC_PATH; + return nullptr; + } + + if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) { + LOG(ERROR) << CGROUPS_RC_PATH << " file version mismatch"; + munmap(file_data, file_size); + return nullptr; + } + + auto expected = sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController); + if (file_size != expected) { + LOG(ERROR) << CGROUPS_RC_PATH << " file has invalid size, expected " << expected + << ", actual " << file_size; + munmap(file_data, file_size); + return nullptr; + } + + return file_data; } -static const CgroupDescriptorMap* GetInstance() { +static CgroupFile* GetInstance() { // Deliberately leak this object (not munmap) to avoid a race between destruction on // process exit and concurrent access from another thread. - static const CgroupDescriptorMap* descriptors = LoadDescriptors(); - return descriptors; + static auto* file = LoadRcFile(); + return file; } uint32_t ACgroupFile_getVersion() { - static constexpr uint32_t FILE_VERSION_1 = 1; - auto descriptors = GetInstance(); - if (descriptors == nullptr) return 0; - // There has only ever been one version, and there will be no more since cgroup.rc is no more - return FILE_VERSION_1; + auto file = GetInstance(); + if (file == nullptr) return 0; + return file->version_; } uint32_t ACgroupFile_getControllerCount() { - auto descriptors = GetInstance(); - if (descriptors == nullptr) return 0; - return descriptors->size(); + auto file = GetInstance(); + if (file == nullptr) return 0; + return file->controller_count_; } const ACgroupController* ACgroupFile_getController(uint32_t index) { - auto descriptors = GetInstance(); - if (descriptors == nullptr) return nullptr; - CHECK(index < descriptors->size()); + auto file = GetInstance(); + if (file == nullptr) return nullptr; + CHECK(index < file->controller_count_); // Although the object is not actually an ACgroupController object, all ACgroupController_* // functions implicitly convert ACgroupController* back to CgroupController* before invoking // member functions. - const CgroupController* p = std::next(descriptors->begin(), index)->second.controller(); - return static_cast(p); + return static_cast(&file->controllers_[index]); } diff --git a/libprocessgroup/cgrouprc/cgrouprc_internal.h b/libprocessgroup/cgrouprc/cgrouprc_internal.h index d51770346..cd02f0304 100644 --- a/libprocessgroup/cgrouprc/cgrouprc_internal.h +++ b/libprocessgroup/cgrouprc/cgrouprc_internal.h @@ -16,6 +16,9 @@ #pragma once -#include +#include -struct ACgroupController : CgroupController {}; +#include +#include + +struct ACgroupController : android::cgrouprc::format::CgroupController {}; diff --git a/libprocessgroup/cgrouprc_format/Android.bp b/libprocessgroup/cgrouprc_format/Android.bp index 6f9ab3e73..059092419 100644 --- a/libprocessgroup/cgrouprc_format/Android.bp +++ b/libprocessgroup/cgrouprc_format/Android.bp @@ -23,4 +23,17 @@ cc_library_static { vendor_ramdisk_available: true, recovery_available: true, native_bridge_supported: true, + srcs: [ + "cgroup_controller.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "libbase", + ], } diff --git a/libprocessgroup/util/cgroup_controller.cpp b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp similarity index 90% rename from libprocessgroup/util/cgroup_controller.cpp rename to libprocessgroup/cgrouprc_format/cgroup_controller.cpp index fb4168075..0dd909a29 100644 --- a/libprocessgroup/util/cgroup_controller.cpp +++ b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp @@ -14,9 +14,11 @@ * limitations under the License. */ -#include +#include -#include +namespace android { +namespace cgrouprc { +namespace format { CgroupController::CgroupController(uint32_t version, uint32_t flags, const std::string& name, const std::string& path, uint32_t max_activation_depth) @@ -52,4 +54,8 @@ const char* CgroupController::path() const { void CgroupController::set_flags(uint32_t flags) { flags_ = flags; -} \ No newline at end of file +} + +} // namespace format +} // namespace cgrouprc +} // namespace android diff --git a/libprocessgroup/util/include/processgroup/cgroup_controller.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h similarity index 87% rename from libprocessgroup/util/include/processgroup/cgroup_controller.h rename to libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h index fe6a829a0..c0c1f6034 100644 --- a/libprocessgroup/util/include/processgroup/cgroup_controller.h +++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h @@ -20,7 +20,11 @@ #include #include -// Minimal controller description +namespace android { +namespace cgrouprc { +namespace format { + +// Minimal controller description to be mmapped into process address space struct CgroupController { public: CgroupController() = default; @@ -44,4 +48,8 @@ struct CgroupController { uint32_t max_activation_depth_ = UINT32_MAX; char name_[CGROUP_NAME_BUF_SZ] = {}; char path_[CGROUP_PATH_BUF_SZ] = {}; -}; \ No newline at end of file +}; + +} // namespace format +} // namespace cgrouprc +} // namespace android diff --git a/libprocessgroup/internal.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h similarity index 54% rename from libprocessgroup/internal.h rename to libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h index ef855790d..2d9786fe6 100644 --- a/libprocessgroup/internal.h +++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,6 +16,23 @@ #pragma once -#include +#include -static const std::string CGROUP_V2_ROOT_DEFAULT = "/sys/fs/cgroup"; \ No newline at end of file +#include + +namespace android { +namespace cgrouprc { +namespace format { + +struct CgroupFile { + uint32_t version_; + uint32_t controller_count_; + CgroupController controllers_[]; + + static constexpr uint32_t FILE_VERSION_1 = 1; + static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1; +}; + +} // namespace format +} // namespace cgrouprc +} // namespace android diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 805775744..ffffeb48b 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -57,7 +57,7 @@ __BEGIN_DECLS bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector& profiles); -[[deprecated]] static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; +static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; bool UsePerAppMemcg(); diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp index cc6c67cf4..1a4ad0118 100644 --- a/libprocessgroup/setup/Android.bp +++ b/libprocessgroup/setup/Android.bp @@ -33,6 +33,7 @@ cc_library_shared { "libjsoncpp", ], static_libs: [ + "libcgrouprc_format", "libprocessgroup_util", ], header_libs: [ diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h index 1afd2ee9c..06ce186fd 100644 --- a/libprocessgroup/setup/cgroup_descriptor.h +++ b/libprocessgroup/setup/cgroup_descriptor.h @@ -21,7 +21,10 @@ #include -#include +#include + +namespace android { +namespace cgrouprc { // Complete controller description for mounting cgroups class CgroupDescriptor { @@ -30,7 +33,7 @@ class CgroupDescriptor { mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, uint32_t max_activation_depth); - const CgroupController* controller() const { return &controller_; } + const format::CgroupController* controller() const { return &controller_; } mode_t mode() const { return mode_; } std::string uid() const { return uid_; } std::string gid() const { return gid_; } @@ -38,8 +41,11 @@ class CgroupDescriptor { void set_mounted(bool mounted); private: - CgroupController controller_; + format::CgroupController controller_; mode_t mode_ = 0; std::string uid_; std::string gid_; }; + +} // namespace cgrouprc +} // namespace android diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index 821168008..bd4187475 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -22,28 +22,45 @@ #include #include #include +#include #include #include #include +#include #include #include #include #include -#include +#include +#include +#include +#include +#include +#include +#include #include #include #include #include "../build_flags.h" -#include "../internal.h" +#include "cgroup_descriptor.h" + +using android::base::GetUintProperty; +using android::base::StringPrintf; +using android::base::unique_fd; + +namespace android { +namespace cgrouprc { static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; static constexpr const char* TEMPLATE_CGROUPS_DESC_API_FILE = "/etc/task_profiles/cgroups_%u.json"; +static const std::string CGROUP_V2_ROOT_DEFAULT = "/sys/fs/cgroup"; + static bool ChangeDirModeAndOwner(const std::string& path, mode_t mode, const std::string& uid, const std::string& gid, bool permissive_mode = false) { uid_t pw_uid = -1; @@ -131,15 +148,149 @@ static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid, return true; } +static void MergeCgroupToDescriptors(std::map* descriptors, + const Json::Value& cgroup, const std::string& name, + const std::string& root_path, int cgroups_version) { + const std::string cgroup_path = cgroup["Path"].asString(); + std::string path; + + if (!root_path.empty()) { + path = root_path; + if (cgroup_path != ".") { + path += "/"; + path += cgroup_path; + } + } else { + path = cgroup_path; + } + + uint32_t controller_flags = 0; + + if (cgroup["NeedsActivation"].isBool() && cgroup["NeedsActivation"].asBool()) { + controller_flags |= CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION; + } + + if (cgroup["Optional"].isBool() && cgroup["Optional"].asBool()) { + controller_flags |= CGROUPRC_CONTROLLER_FLAG_OPTIONAL; + } + + uint32_t max_activation_depth = UINT32_MAX; + if (cgroup.isMember("MaxActivationDepth")) { + max_activation_depth = cgroup["MaxActivationDepth"].asUInt(); + } + + CgroupDescriptor descriptor( + cgroups_version, name, path, std::strtoul(cgroup["Mode"].asString().c_str(), 0, 8), + cgroup["UID"].asString(), cgroup["GID"].asString(), controller_flags, + max_activation_depth); + + auto iter = descriptors->find(name); + if (iter == descriptors->end()) { + descriptors->emplace(name, descriptor); + } else { + iter->second = descriptor; + } +} + +static const bool force_memcg_v2 = android::libprocessgroup_flags::force_memcg_v2(); + +static bool ReadDescriptorsFromFile(const std::string& file_name, + std::map* descriptors) { + std::vector result; + std::string json_doc; + + if (!android::base::ReadFileToString(file_name, &json_doc)) { + PLOG(ERROR) << "Failed to read task profiles from " << file_name; + return false; + } + + Json::CharReaderBuilder builder; + std::unique_ptr reader(builder.newCharReader()); + Json::Value root; + std::string errorMessage; + if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) { + LOG(ERROR) << "Failed to parse cgroups description: " << errorMessage; + return false; + } + + if (root.isMember("Cgroups")) { + const Json::Value& cgroups = root["Cgroups"]; + for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { + std::string name = cgroups[i]["Controller"].asString(); + + if (force_memcg_v2 && name == "memory") continue; + + MergeCgroupToDescriptors(descriptors, cgroups[i], name, "", 1); + } + } + + bool memcgv2_present = false; + std::string root_path; + if (root.isMember("Cgroups2")) { + const Json::Value& cgroups2 = root["Cgroups2"]; + root_path = cgroups2["Path"].asString(); + MergeCgroupToDescriptors(descriptors, cgroups2, CGROUPV2_HIERARCHY_NAME, "", 2); + + const Json::Value& childGroups = cgroups2["Controllers"]; + for (Json::Value::ArrayIndex i = 0; i < childGroups.size(); ++i) { + std::string name = childGroups[i]["Controller"].asString(); + + if (force_memcg_v2 && name == "memory") memcgv2_present = true; + + MergeCgroupToDescriptors(descriptors, childGroups[i], name, root_path, 2); + } + } + + if (force_memcg_v2 && !memcgv2_present) { + LOG(INFO) << "Forcing memcg to v2 hierarchy"; + Json::Value memcgv2; + memcgv2["Controller"] = "memory"; + memcgv2["NeedsActivation"] = true; + memcgv2["Path"] = "."; + memcgv2["Optional"] = true; // In case of cgroup_disabled=memory, so we can still boot + MergeCgroupToDescriptors(descriptors, memcgv2, "memory", + root_path.empty() ? CGROUP_V2_ROOT_DEFAULT : root_path, 2); + } + + return true; +} + +static bool ReadDescriptors(std::map* descriptors) { + // load system cgroup descriptors + if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) { + return false; + } + + // load API-level specific system cgroups descriptors if available + unsigned int api_level = GetUintProperty("ro.product.first_api_level", 0); + if (api_level > 0) { + std::string api_cgroups_path = + android::base::StringPrintf(TEMPLATE_CGROUPS_DESC_API_FILE, api_level); + if (!access(api_cgroups_path.c_str(), F_OK) || errno != ENOENT) { + if (!ReadDescriptorsFromFile(api_cgroups_path, descriptors)) { + return false; + } + } + } + + // load vendor cgroup descriptors if the file exists + if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) && + !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) { + return false; + } + + return true; +} + // To avoid issues in sdk_mac build #if defined(__ANDROID__) -static bool IsOptionalController(const CgroupController* controller) { +static bool IsOptionalController(const format::CgroupController* controller) { return controller->flags() & CGROUPRC_CONTROLLER_FLAG_OPTIONAL; } static bool MountV2CgroupController(const CgroupDescriptor& descriptor) { - const CgroupController* controller = descriptor.controller(); + const format::CgroupController* controller = descriptor.controller(); // /sys/fs/cgroup is created by cgroup2 with specific selinux permissions, // try to create again in case the mount point is changed @@ -173,7 +324,7 @@ static bool MountV2CgroupController(const CgroupDescriptor& descriptor) { } static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { - const CgroupController* controller = descriptor.controller(); + const format::CgroupController* controller = descriptor.controller(); if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup"; @@ -187,7 +338,7 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { std::string path = controller->path(); path += "/cgroup.subtree_control"; - if (!android::base::WriteStringToFile(str, path)) { + if (!base::WriteStringToFile(str, path)) { if (IsOptionalController(controller)) { PLOG(INFO) << "Failed to activate optional controller " << controller->name() << " at " << path; @@ -202,7 +353,7 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { } static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { - const CgroupController* controller = descriptor.controller(); + const format::CgroupController* controller = descriptor.controller(); // mkdir [mode] [owner] [group] if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { @@ -237,7 +388,7 @@ static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { } static bool SetupCgroup(const CgroupDescriptor& descriptor) { - const CgroupController* controller = descriptor.controller(); + const format::CgroupController* controller = descriptor.controller(); if (controller->version() == 2) { if (!strcmp(controller->name(), CGROUPV2_HIERARCHY_NAME)) { @@ -259,6 +410,35 @@ static bool SetupCgroup(const CgroupDescriptor&) { #endif +static bool WriteRcFile(const std::map& descriptors) { + unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, + S_IRUSR | S_IRGRP | S_IROTH))); + if (fd < 0) { + PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; + return false; + } + + format::CgroupFile fl; + fl.version_ = format::CgroupFile::FILE_CURR_VERSION; + fl.controller_count_ = descriptors.size(); + int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl))); + if (ret < 0) { + PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; + return false; + } + + for (const auto& [name, descriptor] : descriptors) { + ret = TEMP_FAILURE_RETRY( + write(fd, descriptor.controller(), sizeof(format::CgroupController))); + if (ret < 0) { + PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; + return false; + } + } + + return true; +} + CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, @@ -278,6 +458,9 @@ void CgroupDescriptor::set_mounted(bool mounted) { controller_.set_flags(flags); } +} // namespace cgrouprc +} // namespace android + static std::optional MGLRUDisabled() { const std::string file_name = "/sys/kernel/mm/lru_gen/enabled"; std::string content; @@ -289,8 +472,9 @@ static std::optional MGLRUDisabled() { return content == "0x0000"; } -static std::optional MEMCGDisabled(const CgroupDescriptorMap& descriptors) { - std::string cgroup_v2_root = CGROUP_V2_ROOT_DEFAULT; +static std::optional MEMCGDisabled( + const std::map& descriptors) { + std::string cgroup_v2_root = android::cgrouprc::CGROUP_V2_ROOT_DEFAULT; const auto it = descriptors.find(CGROUPV2_HIERARCHY_NAME); if (it == descriptors.end()) { LOG(WARNING) << "No Cgroups2 path found in cgroups.json. Vendor has modified Android, and " @@ -311,10 +495,14 @@ static std::optional MEMCGDisabled(const CgroupDescriptorMap& descriptors) return content.find("memory") == std::string::npos; } -static bool CreateV2SubHierarchy(const std::string& path, const CgroupDescriptorMap& descriptors) { +static bool CreateV2SubHierarchy( + const std::string& path, + const std::map& descriptors) { + using namespace android::cgrouprc; + const auto cgv2_iter = descriptors.find(CGROUPV2_HIERARCHY_NAME); if (cgv2_iter == descriptors.end()) return false; - const CgroupDescriptor cgv2_descriptor = cgv2_iter->second; + const android::cgrouprc::CgroupDescriptor cgv2_descriptor = cgv2_iter->second; if (!Mkdir(path, cgv2_descriptor.mode(), cgv2_descriptor.uid(), cgv2_descriptor.gid())) { PLOG(ERROR) << "Failed to create directory for " << path; @@ -324,10 +512,10 @@ static bool CreateV2SubHierarchy(const std::string& path, const CgroupDescriptor // Activate all v2 controllers in path so they can be activated in // children as they are created. for (const auto& [name, descriptor] : descriptors) { - const CgroupController* controller = descriptor.controller(); + const format::CgroupController* controller = descriptor.controller(); std::uint32_t flags = controller->flags(); std::uint32_t max_activation_depth = controller->max_activation_depth(); - const int depth = GetCgroupDepth(controller->path(), path); + const int depth = util::GetCgroupDepth(controller->path(), path); if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME && flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { @@ -347,13 +535,22 @@ static bool CreateV2SubHierarchy(const std::string& path, const CgroupDescriptor } bool CgroupSetup() { - CgroupDescriptorMap descriptors; + using namespace android::cgrouprc; + + std::map descriptors; if (getpid() != 1) { LOG(ERROR) << "Cgroup setup can be done only by init process"; return false; } + // Make sure we do this only one time. No need for std::call_once because + // init is a single-threaded process + if (access(CGROUPS_RC_PATH, F_OK) == 0) { + LOG(WARNING) << "Attempt to call CgroupSetup() more than once"; + return true; + } + // load cgroups.json file if (!ReadDescriptors(&descriptors)) { LOG(ERROR) << "Failed to load cgroup description file"; @@ -362,18 +559,15 @@ bool CgroupSetup() { // setup cgroups for (auto& [name, descriptor] : descriptors) { - if (descriptor.controller()->flags() & CGROUPRC_CONTROLLER_FLAG_MOUNTED) { - LOG(WARNING) << "Attempt to call CgroupSetup() more than once"; - return true; - } - - if (!SetupCgroup(descriptor)) { + if (SetupCgroup(descriptor)) { + descriptor.set_mounted(true); + } else { // issue a warning and proceed with the next cgroup LOG(WARNING) << "Failed to setup " << name << " cgroup"; } } - if (android::libprocessgroup_flags::force_memcg_v2()) { + if (force_memcg_v2) { if (MGLRUDisabled().value_or(false)) { LOG(WARNING) << "Memcg forced to v2 hierarchy with MGLRU disabled! " << "Global reclaim performance will suffer."; @@ -399,5 +593,26 @@ bool CgroupSetup() { } } + // mkdir 0711 system system + if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) { + LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file"; + return false; + } + + // Generate file which can be directly mmapped into + // process memory. This optimizes performance, memory usage + // and limits infrormation shared with unprivileged processes + // to the minimum subset of information from cgroups.json + if (!WriteRcFile(descriptors)) { + LOG(ERROR) << "Failed to write " << CGROUPS_RC_PATH << " file"; + return false; + } + + // chmod 0644 + if (fchmodat(AT_FDCWD, CGROUPS_RC_PATH, 0644, AT_SYMLINK_NOFOLLOW) < 0) { + PLOG(ERROR) << "fchmodat() failed"; + return false; + } + return true; } diff --git a/libprocessgroup/util/Android.bp b/libprocessgroup/util/Android.bp index 1c74d4ed5..54ba69b4e 100644 --- a/libprocessgroup/util/Android.bp +++ b/libprocessgroup/util/Android.bp @@ -37,16 +37,8 @@ cc_library_static { "include", ], srcs: [ - "cgroup_controller.cpp", - "cgroup_descriptor.cpp", "util.cpp", ], - shared_libs: [ - "libbase", - ], - static_libs: [ - "libjsoncpp", - ], defaults: ["libprocessgroup_build_flags_cc"], } diff --git a/libprocessgroup/util/cgroup_descriptor.cpp b/libprocessgroup/util/cgroup_descriptor.cpp deleted file mode 100644 index 4d3347f34..000000000 --- a/libprocessgroup/util/cgroup_descriptor.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright (C) 2024 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 - -#include // For flag values - -CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, - const std::string& path, mode_t mode, const std::string& uid, - const std::string& gid, uint32_t flags, - uint32_t max_activation_depth) - : controller_(version, flags, name, path, max_activation_depth), - mode_(mode), - uid_(uid), - gid_(gid) {} - -void CgroupDescriptor::set_mounted(bool mounted) { - uint32_t flags = controller_.flags(); - if (mounted) { - flags |= CGROUPRC_CONTROLLER_FLAG_MOUNTED; - } else { - flags &= ~CGROUPRC_CONTROLLER_FLAG_MOUNTED; - } - controller_.set_flags(flags); -} diff --git a/libprocessgroup/util/include/processgroup/cgroup_descriptor.h b/libprocessgroup/util/include/processgroup/cgroup_descriptor.h deleted file mode 100644 index 1afd2ee9c..000000000 --- a/libprocessgroup/util/include/processgroup/cgroup_descriptor.h +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Copyright (C) 2019 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#pragma once - -#include -#include - -#include - -#include - -// Complete controller description for mounting cgroups -class CgroupDescriptor { - public: - CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, - mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, - uint32_t max_activation_depth); - - const CgroupController* controller() const { return &controller_; } - mode_t mode() const { return mode_; } - std::string uid() const { return uid_; } - std::string gid() const { return gid_; } - - void set_mounted(bool mounted); - - private: - CgroupController controller_; - mode_t mode_ = 0; - std::string uid_; - std::string gid_; -}; diff --git a/libprocessgroup/util/include/processgroup/util.h b/libprocessgroup/util/include/processgroup/util.h index d592a6347..8d013af55 100644 --- a/libprocessgroup/util/include/processgroup/util.h +++ b/libprocessgroup/util/include/processgroup/util.h @@ -16,18 +16,10 @@ #pragma once -#include #include -#include "cgroup_descriptor.h" - -// Duplicated from cgrouprc.h. Don't depend on libcgrouprc here. -#define CGROUPRC_CONTROLLER_FLAG_MOUNTED 0x1 -#define CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION 0x2 -#define CGROUPRC_CONTROLLER_FLAG_OPTIONAL 0x4 +namespace util { unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path); -using CgroupControllerName = std::string; -using CgroupDescriptorMap = std::map; -bool ReadDescriptors(CgroupDescriptorMap* descriptors); +} // namespace util diff --git a/libprocessgroup/util/tests/util.cpp b/libprocessgroup/util/tests/util.cpp index 6caef8ee3..1de7d6f3f 100644 --- a/libprocessgroup/util/tests/util.cpp +++ b/libprocessgroup/util/tests/util.cpp @@ -18,6 +18,8 @@ #include "gtest/gtest.h" +using util::GetCgroupDepth; + TEST(EmptyInputs, bothEmpty) { EXPECT_EQ(GetCgroupDepth({}, {}), 0); } diff --git a/libprocessgroup/util/util.cpp b/libprocessgroup/util/util.cpp index bff4c6f1a..9b88a223a 100644 --- a/libprocessgroup/util/util.cpp +++ b/libprocessgroup/util/util.cpp @@ -18,33 +18,9 @@ #include #include -#include -#include - -#include - -#include -#include -#include -#include -#include -#include - -#include "../build_flags.h" -#include "../internal.h" - -using android::base::GetUintProperty; namespace { -constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; -constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; -constexpr const char* TEMPLATE_CGROUPS_DESC_API_FILE = "/etc/task_profiles/cgroups_%u.json"; - -// This should match the publicly declared value in processgroup.h, -// but we don't want this library to depend on libprocessgroup. -constexpr std::string CGROUPV2_HIERARCHY_NAME_INTERNAL = "cgroup2"; - const char SEP = '/'; std::string DeduplicateAndTrimSeparators(const std::string& path) { @@ -66,135 +42,9 @@ std::string DeduplicateAndTrimSeparators(const std::string& path) { return ret; } -void MergeCgroupToDescriptors(CgroupDescriptorMap* descriptors, const Json::Value& cgroup, - const std::string& name, const std::string& root_path, - int cgroups_version) { - const std::string cgroup_path = cgroup["Path"].asString(); - std::string path; - - if (!root_path.empty()) { - path = root_path; - if (cgroup_path != ".") { - path += "/"; - path += cgroup_path; - } - } else { - path = cgroup_path; - } - - uint32_t controller_flags = 0; - - if (cgroup["NeedsActivation"].isBool() && cgroup["NeedsActivation"].asBool()) { - controller_flags |= CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION; - } - - if (cgroup["Optional"].isBool() && cgroup["Optional"].asBool()) { - controller_flags |= CGROUPRC_CONTROLLER_FLAG_OPTIONAL; - } - - uint32_t max_activation_depth = UINT32_MAX; - if (cgroup.isMember("MaxActivationDepth")) { - max_activation_depth = cgroup["MaxActivationDepth"].asUInt(); - } - - CgroupDescriptor descriptor( - cgroups_version, name, path, std::strtoul(cgroup["Mode"].asString().c_str(), 0, 8), - cgroup["UID"].asString(), cgroup["GID"].asString(), controller_flags, - max_activation_depth); - - auto iter = descriptors->find(name); - if (iter == descriptors->end()) { - descriptors->emplace(name, descriptor); - } else { - iter->second = descriptor; - } -} - -bool ReadDescriptorsFromFile(const std::string& file_name, CgroupDescriptorMap* descriptors) { - static constexpr bool force_memcg_v2 = android::libprocessgroup_flags::force_memcg_v2(); - std::vector result; - std::string json_doc; - - if (!android::base::ReadFileToString(file_name, &json_doc)) { - PLOG(ERROR) << "Failed to read task profiles from " << file_name; - return false; - } - - Json::CharReaderBuilder builder; - std::unique_ptr reader(builder.newCharReader()); - Json::Value root; - std::string errorMessage; - if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) { - LOG(ERROR) << "Failed to parse cgroups description: " << errorMessage; - return false; - } - - if (root.isMember("Cgroups")) { - const Json::Value& cgroups = root["Cgroups"]; - for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { - std::string name = cgroups[i]["Controller"].asString(); - - if (force_memcg_v2 && name == "memory") continue; - - MergeCgroupToDescriptors(descriptors, cgroups[i], name, "", 1); - } - } - - bool memcgv2_present = false; - std::string root_path; - if (root.isMember("Cgroups2")) { - const Json::Value& cgroups2 = root["Cgroups2"]; - root_path = cgroups2["Path"].asString(); - MergeCgroupToDescriptors(descriptors, cgroups2, CGROUPV2_HIERARCHY_NAME_INTERNAL, "", 2); - - const Json::Value& childGroups = cgroups2["Controllers"]; - for (Json::Value::ArrayIndex i = 0; i < childGroups.size(); ++i) { - std::string name = childGroups[i]["Controller"].asString(); - - if (force_memcg_v2 && name == "memory") memcgv2_present = true; - - MergeCgroupToDescriptors(descriptors, childGroups[i], name, root_path, 2); - } - } - - if (force_memcg_v2 && !memcgv2_present) { - LOG(INFO) << "Forcing memcg to v2 hierarchy"; - Json::Value memcgv2; - memcgv2["Controller"] = "memory"; - memcgv2["NeedsActivation"] = true; - memcgv2["Path"] = "."; - memcgv2["Optional"] = true; // In case of cgroup_disabled=memory, so we can still boot - MergeCgroupToDescriptors(descriptors, memcgv2, "memory", - root_path.empty() ? CGROUP_V2_ROOT_DEFAULT : root_path, 2); - } - - return true; -} - -using MountDir = std::string; -using MountOpts = std::string; -static std::optional> ReadCgroupV1Mounts() { - FILE* fp = setmntent("/proc/mounts", "r"); - if (fp == nullptr) { - PLOG(ERROR) << "Failed to read mounts"; - return std::nullopt; - } - - std::map mounts; - const std::string_view CGROUP_V1_TYPE = "cgroup"; - for (mntent* mentry = getmntent(fp); mentry != nullptr; mentry = getmntent(fp)) { - if (mentry->mnt_type && CGROUP_V1_TYPE == mentry->mnt_type && - mentry->mnt_dir && mentry->mnt_opts) { - mounts[mentry->mnt_dir] = mentry->mnt_opts; - } - } - endmntent(fp); - - return mounts; -} - } // anonymous namespace +namespace util { unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path) { const std::string deduped_root = DeduplicateAndTrimSeparators(controller_root); @@ -206,47 +56,4 @@ unsigned int GetCgroupDepth(const std::string& controller_root, const std::strin return std::count(deduped_path.begin() + deduped_root.size(), deduped_path.end(), SEP); } -bool ReadDescriptors(CgroupDescriptorMap* descriptors) { - // load system cgroup descriptors - if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) { - return false; - } - - // load API-level specific system cgroups descriptors if available - unsigned int api_level = GetUintProperty("ro.product.first_api_level", 0); - if (api_level > 0) { - std::string api_cgroups_path = - android::base::StringPrintf(TEMPLATE_CGROUPS_DESC_API_FILE, api_level); - if (!access(api_cgroups_path.c_str(), F_OK) || errno != ENOENT) { - if (!ReadDescriptorsFromFile(api_cgroups_path, descriptors)) { - return false; - } - } - } - - // load vendor cgroup descriptors if the file exists - if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) && - !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) { - return false; - } - - // check for v1 mount/usability status - std::optional> v1Mounts; - for (auto& [name, descriptor] : *descriptors) { - const CgroupController* const controller = descriptor.controller(); - - if (controller->version() != 1) continue; - - // Read only once, and only if we have at least one v1 controller - if (!v1Mounts) { - v1Mounts = ReadCgroupV1Mounts(); - if (!v1Mounts) return false; - } - - if (const auto it = v1Mounts->find(controller->path()); it != v1Mounts->end()) { - if (it->second.contains(controller->name())) descriptor.set_mounted(true); - } - } - - return true; -} +} // namespace util From aeca8793f533c243d0f9353bce5e276f48e01363 Mon Sep 17 00:00:00 2001 From: "Priyanka Advani (xWF)" Date: Tue, 8 Oct 2024 18:54:37 +0000 Subject: [PATCH 035/183] Revert "libprocessgroup: Remove ACgroupController_getMaxActivati..." Revert submission 3212512 Reason for revert: Droidmonitor created revert due to b/372273614. Will be verifying through ABTD before submission. Reverted changes: /q/submissionid:3212512 Change-Id: I0964d1300791334cdc9e98220324d934f7ba113e --- libprocessgroup/cgrouprc/a_cgroup_controller.cpp | 5 +++++ libprocessgroup/cgrouprc/include/android/cgrouprc.h | 8 ++++++++ libprocessgroup/cgrouprc/libcgrouprc.map.txt | 7 +++++++ 3 files changed, 20 insertions(+) diff --git a/libprocessgroup/cgrouprc/a_cgroup_controller.cpp b/libprocessgroup/cgrouprc/a_cgroup_controller.cpp index 5a326e55d..889b3becf 100644 --- a/libprocessgroup/cgrouprc/a_cgroup_controller.cpp +++ b/libprocessgroup/cgrouprc/a_cgroup_controller.cpp @@ -32,6 +32,11 @@ uint32_t ACgroupController_getFlags(const ACgroupController* controller) { return controller->flags(); } +uint32_t ACgroupController_getMaxActivationDepth(const ACgroupController* controller) { + CHECK(controller != nullptr); + return controller->max_activation_depth(); +} + const char* ACgroupController_getName(const ACgroupController* controller) { CHECK(controller != nullptr); return controller->name(); diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h index e704a36aa..3a57df547 100644 --- a/libprocessgroup/cgrouprc/include/android/cgrouprc.h +++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h @@ -78,6 +78,14 @@ __attribute__((warn_unused_result)) uint32_t ACgroupController_getVersion(const __attribute__((warn_unused_result, weak)) uint32_t ACgroupController_getFlags( const ACgroupController*) __INTRODUCED_IN(30); +/** + * Returns the maximum activation depth of the given controller. + * Only applicable to cgroup v2 controllers. + * Returns UINT32_MAX if no maximum activation depth is set. + */ +__attribute__((warn_unused_result, weak)) uint32_t ACgroupController_getMaxActivationDepth( + const ACgroupController* controller) __INTRODUCED_IN(36); + /** * Returns the name of the given controller. * If the given controller is null, return nullptr. diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.map.txt index b62b10f3b..30bd25f18 100644 --- a/libprocessgroup/cgrouprc/libcgrouprc.map.txt +++ b/libprocessgroup/cgrouprc/libcgrouprc.map.txt @@ -16,3 +16,10 @@ LIBCGROUPRC_30 { # introduced=30 local: *; }; + +LIBCGROUPRC_36 { # introduced=36 + global: + ACgroupController_getMaxActivationDepth; # llndk=202504 systemapi + local: + *; +}; From 691ad736bb4088a634e2766334c17ae8a2bfbe79 Mon Sep 17 00:00:00 2001 From: "Priyanka Advani (xWF)" Date: Tue, 8 Oct 2024 18:54:37 +0000 Subject: [PATCH 036/183] Revert "libprocessgroup: Remove dependency on libcgrouprc" Revert submission 3212512 Reason for revert: Droidmonitor created revert due to b/372273614. Will be verifying through ABTD before submission. Reverted changes: /q/submissionid:3212512 Change-Id: I15c7763467cd9f65d4b389b2d4ccaff92012f21f --- libprocessgroup/Android.bp | 1 + libprocessgroup/cgroup_map.cpp | 95 +++++++++++++++++++++------------- libprocessgroup/cgroup_map.h | 13 ++--- 3 files changed, 66 insertions(+), 43 deletions(-) diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index 8448a39a4..d623a1152 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -75,6 +75,7 @@ cc_library { double_loadable: true, shared_libs: [ "libbase", + "libcgrouprc", ], static_libs: [ "libjsoncpp", diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index 8180ccf3f..aeccfe89b 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -25,10 +25,12 @@ #include #include #include +#include #include #include #include +using android::base::StartsWith; using android::base::StringPrintf; using android::base::WriteStringToFile; @@ -38,17 +40,17 @@ static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.threads"; uint32_t CgroupControllerWrapper::version() const { CHECK(HasValue()); - return controller_->version(); + return ACgroupController_getVersion(controller_); } const char* CgroupControllerWrapper::name() const { CHECK(HasValue()); - return controller_->name(); + return ACgroupController_getName(controller_); } const char* CgroupControllerWrapper::path() const { CHECK(HasValue()); - return controller_->path(); + return ACgroupController_getPath(controller_); } bool CgroupControllerWrapper::HasValue() const { @@ -60,7 +62,7 @@ bool CgroupControllerWrapper::IsUsable() { if (state_ == UNKNOWN) { if (__builtin_available(android 30, *)) { - uint32_t flags = controller_->flags(); + uint32_t flags = ACgroupController_getFlags(controller_); state_ = (flags & CGROUPRC_CONTROLLER_FLAG_MOUNTED) != 0 ? USABLE : MISSING; } else { state_ = access(GetProcsFilePath("", 0, 0).c_str(), F_OK) == 0 ? USABLE : MISSING; @@ -127,8 +129,8 @@ bool CgroupControllerWrapper::GetTaskGroup(pid_t tid, std::string* group) const } CgroupMap::CgroupMap() { - if (!LoadDescriptors()) { - LOG(ERROR) << "CgroupMap::LoadDescriptors called for [" << getpid() << "] failed"; + if (!LoadRcFile()) { + LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed"; } } @@ -139,9 +141,9 @@ CgroupMap& CgroupMap::GetInstance() { return *instance; } -bool CgroupMap::LoadDescriptors() { +bool CgroupMap::LoadRcFile() { if (!loaded_) { - loaded_ = ReadDescriptors(&descriptors_); + loaded_ = (ACgroupFile_getVersion() != 0); } return loaded_; } @@ -152,27 +154,40 @@ void CgroupMap::Print() const { << "] failed, cgroups were not initialized properly"; return; } - LOG(INFO) << "Controller count = " << descriptors_.size(); + LOG(INFO) << "File version = " << ACgroupFile_getVersion(); + LOG(INFO) << "File controller count = " << ACgroupFile_getControllerCount(); LOG(INFO) << "Mounted cgroups:"; - for (const auto& [name, descriptor] : descriptors_) { - LOG(INFO) << "\t" << descriptor.controller()->name() << " ver " - << descriptor.controller()->version() << " path " - << descriptor.controller()->path() << " flags " - << descriptor.controller()->flags(); + auto controller_count = ACgroupFile_getControllerCount(); + for (uint32_t i = 0; i < controller_count; ++i) { + const ACgroupController* controller = ACgroupFile_getController(i); + if (__builtin_available(android 30, *)) { + LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver " + << ACgroupController_getVersion(controller) << " path " + << ACgroupController_getPath(controller) << " flags " + << ACgroupController_getFlags(controller); + } else { + LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver " + << ACgroupController_getVersion(controller) << " path " + << ACgroupController_getPath(controller); + } } } CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const { if (!loaded_) { LOG(ERROR) << "CgroupMap::FindController called for [" << getpid() - << "] failed, cgroups were not initialized properly"; + << "] failed, RC file was not initialized properly"; return CgroupControllerWrapper(nullptr); } - if (const auto it = descriptors_.find(name); it != descriptors_.end()) { - return CgroupControllerWrapper(it->second.controller()); + auto controller_count = ACgroupFile_getControllerCount(); + for (uint32_t i = 0; i < controller_count; ++i) { + const ACgroupController* controller = ACgroupFile_getController(i); + if (name == ACgroupController_getName(controller)) { + return CgroupControllerWrapper(controller); + } } return CgroupControllerWrapper(nullptr); @@ -181,13 +196,15 @@ CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) const { if (!loaded_) { LOG(ERROR) << "CgroupMap::FindControllerByPath called for [" << getpid() - << "] failed, cgroups were not initialized properly"; + << "] failed, RC file was not initialized properly"; return CgroupControllerWrapper(nullptr); } - for (const auto& [name, descriptor] : descriptors_) { - if (path.starts_with(descriptor.controller()->path())) { - return CgroupControllerWrapper(descriptor.controller()); + auto controller_count = ACgroupFile_getControllerCount(); + for (uint32_t i = 0; i < controller_count; ++i) { + const ACgroupController* controller = ACgroupFile_getController(i); + if (StartsWith(path, ACgroupController_getPath(controller))) { + return CgroupControllerWrapper(controller); } } @@ -195,23 +212,31 @@ CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) } int CgroupMap::ActivateControllers(const std::string& path) const { - for (const auto& [name, descriptor] : descriptors_) { - const uint32_t flags = descriptor.controller()->flags(); - const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); - const int depth = GetCgroupDepth(descriptor.controller()->path(), path); + if (__builtin_available(android 30, *)) { + auto controller_count = ACgroupFile_getControllerCount(); + for (uint32_t i = 0; i < controller_count; ++i) { + const ACgroupController* controller = ACgroupFile_getController(i); + const uint32_t flags = ACgroupController_getFlags(controller); + uint32_t max_activation_depth = UINT32_MAX; + if (__builtin_available(android 36, *)) { + max_activation_depth = ACgroupController_getMaxActivationDepth(controller); + } + const int depth = GetCgroupDepth(ACgroupController_getPath(controller), path); - if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { - std::string str("+"); - str.append(descriptor.controller()->name()); - if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { - if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { - PLOG(WARNING) << "Activation of cgroup controller " << str - << " failed in path " << path; - } else { - return -errno; + if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { + std::string str("+"); + str.append(ACgroupController_getName(controller)); + if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { + if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { + PLOG(WARNING) << "Activation of cgroup controller " << str + << " failed in path " << path; + } else { + return -errno; + } } } } + return 0; } - return 0; + return -ENOSYS; } diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index 5ad59bddf..364279414 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -18,17 +18,15 @@ #include -#include #include -#include -#include +#include -// Convenient wrapper of a CgroupController pointer. +// Convenient wrapper of an ACgroupController pointer. class CgroupControllerWrapper { public: // Does not own controller - explicit CgroupControllerWrapper(const CgroupController* controller) + explicit CgroupControllerWrapper(const ACgroupController* controller) : controller_(controller) {} uint32_t version() const; @@ -49,7 +47,7 @@ class CgroupControllerWrapper { MISSING = 2, }; - const CgroupController* controller_ = nullptr; // CgroupMap owns the object behind this pointer + const ACgroupController* controller_ = nullptr; ControllerState state_ = ControllerState::UNKNOWN; }; @@ -62,8 +60,7 @@ class CgroupMap { private: bool loaded_ = false; - CgroupDescriptorMap descriptors_; CgroupMap(); - bool LoadDescriptors(); + bool LoadRcFile(); void Print() const; }; From 0fa49253a484fc0c99d067ade57a4978059b3a95 Mon Sep 17 00:00:00 2001 From: "Priyanka Advani (xWF)" Date: Tue, 8 Oct 2024 18:54:37 +0000 Subject: [PATCH 037/183] Revert "libprocessgroup: Combine all 3 ActivateControllers imple..." Revert submission 3212512 Reason for revert: Droidmonitor created revert due to b/372273614. Will be verifying through ABTD before submission. Reverted changes: /q/submissionid:3212512 Change-Id: I3dadc0b7bccfe28bb067a93df2acf2c3ea0f9920 --- libprocessgroup/cgroup_map.cpp | 22 +++++++++- libprocessgroup/cgroup_map.h | 2 +- libprocessgroup/processgroup.cpp | 7 ++-- libprocessgroup/setup/cgroup_map_write.cpp | 42 ++++++++++++++++++- .../util/include/processgroup/util.h | 2 - libprocessgroup/util/util.cpp | 23 ---------- 6 files changed, 65 insertions(+), 33 deletions(-) diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index 32bef13a1..8180ccf3f 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -194,6 +194,24 @@ CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) return CgroupControllerWrapper(nullptr); } -bool CgroupMap::ActivateControllers(const std::string& path) const { - return ::ActivateControllers(path, descriptors_); +int CgroupMap::ActivateControllers(const std::string& path) const { + for (const auto& [name, descriptor] : descriptors_) { + const uint32_t flags = descriptor.controller()->flags(); + const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); + const int depth = GetCgroupDepth(descriptor.controller()->path(), path); + + if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { + std::string str("+"); + str.append(descriptor.controller()->name()); + if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { + if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { + PLOG(WARNING) << "Activation of cgroup controller " << str + << " failed in path " << path; + } else { + return -errno; + } + } + } + } + return 0; } diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index fb9907645..5ad59bddf 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -58,7 +58,7 @@ class CgroupMap { static CgroupMap& GetInstance(); CgroupControllerWrapper FindController(const std::string& name) const; CgroupControllerWrapper FindControllerByPath(const std::string& path) const; - bool ActivateControllers(const std::string& path) const; + int ActivateControllers(const std::string& path) const; private: bool loaded_ = false; diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index d3719eea3..83a2258bf 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -662,9 +662,10 @@ static int createProcessGroupInternal(uid_t uid, pid_t initialPid, std::string c return -errno; } if (activate_controllers) { - if (!CgroupMap::GetInstance().ActivateControllers(uid_path)) { - PLOG(ERROR) << "Failed to activate controllers in " << uid_path; - return -errno; + ret = CgroupMap::GetInstance().ActivateControllers(uid_path); + if (ret) { + LOG(ERROR) << "Failed to activate controllers in " << uid_path; + return ret; } } diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index d05bf2408..821168008 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -180,7 +180,25 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { return false; } - return ::ActivateControllers(controller->path(), {{controller->name(), descriptor}}); + if (controller->flags() & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && + controller->max_activation_depth() > 0) { + std::string str = "+"; + str += controller->name(); + std::string path = controller->path(); + path += "/cgroup.subtree_control"; + + if (!android::base::WriteStringToFile(str, path)) { + if (IsOptionalController(controller)) { + PLOG(INFO) << "Failed to activate optional controller " << controller->name() + << " at " << path; + return true; + } + PLOG(ERROR) << "Failed to activate controller " << controller->name(); + return false; + } + } + + return true; } static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { @@ -305,7 +323,27 @@ static bool CreateV2SubHierarchy(const std::string& path, const CgroupDescriptor // Activate all v2 controllers in path so they can be activated in // children as they are created. - return ::ActivateControllers(path, descriptors); + for (const auto& [name, descriptor] : descriptors) { + const CgroupController* controller = descriptor.controller(); + std::uint32_t flags = controller->flags(); + std::uint32_t max_activation_depth = controller->max_activation_depth(); + const int depth = GetCgroupDepth(controller->path(), path); + + if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME && + flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { + std::string str("+"); + str += controller->name(); + if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) { + if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { + PLOG(WARNING) << "Activation of cgroup controller " << str << " failed in path " + << path; + } else { + return false; + } + } + } + } + return true; } bool CgroupSetup() { diff --git a/libprocessgroup/util/include/processgroup/util.h b/libprocessgroup/util/include/processgroup/util.h index 2c7b32926..d592a6347 100644 --- a/libprocessgroup/util/include/processgroup/util.h +++ b/libprocessgroup/util/include/processgroup/util.h @@ -31,5 +31,3 @@ unsigned int GetCgroupDepth(const std::string& controller_root, const std::strin using CgroupControllerName = std::string; using CgroupDescriptorMap = std::map; bool ReadDescriptors(CgroupDescriptorMap* descriptors); - -bool ActivateControllers(const std::string& path, const CgroupDescriptorMap& descriptors); diff --git a/libprocessgroup/util/util.cpp b/libprocessgroup/util/util.cpp index 14016751c..bff4c6f1a 100644 --- a/libprocessgroup/util/util.cpp +++ b/libprocessgroup/util/util.cpp @@ -250,26 +250,3 @@ bool ReadDescriptors(CgroupDescriptorMap* descriptors) { return true; } - -bool ActivateControllers(const std::string& path, const CgroupDescriptorMap& descriptors) { - for (const auto& [name, descriptor] : descriptors) { - const uint32_t flags = descriptor.controller()->flags(); - const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); - const unsigned int depth = GetCgroupDepth(descriptor.controller()->path(), path); - - if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { - std::string str("+"); - str.append(descriptor.controller()->name()); - if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) { - if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { - PLOG(WARNING) << "Activation of cgroup controller " << str - << " failed in path " << path; - } else { - return false; - } - } - } - } - return true; -} - From a09ee8ece68376835e7dc96e439ec4854b90e46c Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 8 Oct 2024 23:41:27 +0000 Subject: [PATCH 038/183] Reapply "libprocessgroup: Remove cgroup.rc file" This reverts commit 972a2d30f8a3f260967b747592f4e8cdc560e01c. Change-Id: Icdf2824675e515ea3656b1c58ac55160ecc337df --- fs_mgr/libsnapshot/snapuserd/Android.bp | 7 +- init/Android.bp | 1 - init/init.cpp | 3 - libcutils/Android.bp | 2 +- libprocessgroup/Android.bp | 3 +- libprocessgroup/cgroup_map.cpp | 4 +- libprocessgroup/cgrouprc/Android.bp | 3 +- libprocessgroup/cgrouprc/a_cgroup_file.cpp | 88 ++---- libprocessgroup/cgrouprc/cgrouprc_internal.h | 7 +- libprocessgroup/cgrouprc_format/Android.bp | 13 - .../include/processgroup/processgroup.h | 2 +- .../format/cgroup_file.h => internal.h} | 23 +- libprocessgroup/setup/Android.bp | 1 - libprocessgroup/setup/cgroup_descriptor.h | 12 +- libprocessgroup/setup/cgroup_map_write.cpp | 259 ++---------------- libprocessgroup/util/Android.bp | 8 + .../cgroup_controller.cpp | 12 +- libprocessgroup/util/cgroup_descriptor.cpp | 38 +++ .../include/processgroup}/cgroup_controller.h | 12 +- .../include/processgroup/cgroup_descriptor.h | 45 +++ .../util/include/processgroup/util.h | 12 +- libprocessgroup/util/tests/util.cpp | 2 - libprocessgroup/util/util.cpp | 197 ++++++++++++- 23 files changed, 365 insertions(+), 389 deletions(-) rename libprocessgroup/{cgrouprc_format/include/processgroup/format/cgroup_file.h => internal.h} (54%) rename libprocessgroup/{cgrouprc_format => util}/cgroup_controller.cpp (90%) create mode 100644 libprocessgroup/util/cgroup_descriptor.cpp rename libprocessgroup/{cgrouprc_format/include/processgroup/format => util/include/processgroup}/cgroup_controller.h (87%) create mode 100644 libprocessgroup/util/include/processgroup/cgroup_descriptor.h diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 298fd9f30..083068b54 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -85,9 +85,9 @@ cc_library_static { "libsnapshot_cow", "liburing", "libprocessgroup", + "libprocessgroup_util", "libjsoncpp", "libcgrouprc", - "libcgrouprc_format", ], include_dirs: ["bionic/libc/kernel"], export_include_dirs: ["include"], @@ -129,9 +129,9 @@ cc_defaults { "libsnapshot_cow", "libsnapuserd", "libprocessgroup", + "libprocessgroup_util", "libjsoncpp", "libcgrouprc", - "libcgrouprc_format", "libsnapuserd_client", "libz", "liblz4", @@ -221,9 +221,9 @@ cc_defaults { "libsnapshot_cow", "libsnapuserd", "libprocessgroup", + "libprocessgroup_util", "libjsoncpp", "libcgrouprc", - "libcgrouprc_format", "liburing", "libz", ], @@ -319,7 +319,6 @@ cc_binary_host { "libprocessgroup", "libjsoncpp", "libcgrouprc", - "libcgrouprc_format", "liburing", "libz", ], diff --git a/init/Android.bp b/init/Android.bp index 18a79d6c4..8da2e7c2e 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -163,7 +163,6 @@ libinit_cc_defaults { "libavb", "libavf_cc_flags", "libbootloader_message", - "libcgrouprc_format", "liblmkd_utils", "liblz4", "libzstd", diff --git a/init/init.cpp b/init/init.cpp index 6c8089926..17498da6d 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -636,9 +636,6 @@ static Result SetupCgroupsAction(const BuiltinArguments&) { LOG(INFO) << "Cgroups support in kernel is not enabled"; return {}; } - // Have to create using make_dir function - // for appropriate sepolicy to be set for it - make_dir(android::base::Dirname(CGROUPS_RC_PATH), 0711); if (!CgroupSetup()) { return ErrnoError() << "Failed to setup cgroups"; } diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 3c3eeb663..fc4c571b7 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -301,7 +301,7 @@ cc_defaults { android: { static_executable: true, static_libs: [ - "libcgrouprc_format", + "libprocessgroup_util", ] + test_libraries + always_static_test_libraries, }, not_windows: { diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index a60bfe973..d623a1152 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -17,7 +17,7 @@ soong_config_module_type { libprocessgroup_flag_aware_cc_defaults { name: "libprocessgroup_build_flags_cc", - cpp_std: "gnu++20", + cpp_std: "gnu++23", soong_config_variables: { memcg_v2_force_enabled: { cflags: [ @@ -116,5 +116,6 @@ cc_test { ], static_libs: [ "libgmock", + "libprocessgroup_util", ], } diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index fb01cfda9..aeccfe89b 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -151,7 +151,7 @@ bool CgroupMap::LoadRcFile() { void CgroupMap::Print() const { if (!loaded_) { LOG(ERROR) << "CgroupMap::Print called for [" << getpid() - << "] failed, RC file was not initialized properly"; + << "] failed, cgroups were not initialized properly"; return; } LOG(INFO) << "File version = " << ACgroupFile_getVersion(); @@ -221,7 +221,7 @@ int CgroupMap::ActivateControllers(const std::string& path) const { if (__builtin_available(android 36, *)) { max_activation_depth = ACgroupController_getMaxActivationDepth(controller); } - const int depth = util::GetCgroupDepth(ACgroupController_getPath(controller), path); + const int depth = GetCgroupDepth(ACgroupController_getPath(controller), path); if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { std::string str("+"); diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index cb912476e..38b2fa31d 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -49,7 +49,8 @@ cc_library { "libbase", ], static_libs: [ - "libcgrouprc_format", + "libjsoncpp", + "libprocessgroup_util", ], stubs: { symbol_file: "libcgrouprc.map.txt", diff --git a/libprocessgroup/cgrouprc/a_cgroup_file.cpp b/libprocessgroup/cgrouprc/a_cgroup_file.cpp index e26d84114..33c8376f4 100644 --- a/libprocessgroup/cgrouprc/a_cgroup_file.cpp +++ b/libprocessgroup/cgrouprc/a_cgroup_file.cpp @@ -14,93 +14,51 @@ * limitations under the License. */ -#include -#include - -#include +#include #include -#include -#include #include -#include +#include #include "cgrouprc_internal.h" -using android::base::StringPrintf; -using android::base::unique_fd; - -using android::cgrouprc::format::CgroupController; -using android::cgrouprc::format::CgroupFile; - -static CgroupFile* LoadRcFile() { - struct stat sb; - - unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_RDONLY | O_CLOEXEC))); - if (fd < 0) { - PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; +static CgroupDescriptorMap* LoadDescriptors() { + CgroupDescriptorMap* descriptors = new CgroupDescriptorMap; + if (!ReadDescriptors(descriptors)) { + LOG(ERROR) << "Failed to load cgroup description file"; return nullptr; } - - if (fstat(fd, &sb) < 0) { - PLOG(ERROR) << "fstat() failed for " << CGROUPS_RC_PATH; - return nullptr; - } - - size_t file_size = sb.st_size; - if (file_size < sizeof(CgroupFile)) { - LOG(ERROR) << "Invalid file format " << CGROUPS_RC_PATH; - return nullptr; - } - - CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0); - if (file_data == MAP_FAILED) { - PLOG(ERROR) << "Failed to mmap " << CGROUPS_RC_PATH; - return nullptr; - } - - if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) { - LOG(ERROR) << CGROUPS_RC_PATH << " file version mismatch"; - munmap(file_data, file_size); - return nullptr; - } - - auto expected = sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController); - if (file_size != expected) { - LOG(ERROR) << CGROUPS_RC_PATH << " file has invalid size, expected " << expected - << ", actual " << file_size; - munmap(file_data, file_size); - return nullptr; - } - - return file_data; + return descriptors; } -static CgroupFile* GetInstance() { +static const CgroupDescriptorMap* GetInstance() { // Deliberately leak this object (not munmap) to avoid a race between destruction on // process exit and concurrent access from another thread. - static auto* file = LoadRcFile(); - return file; + static const CgroupDescriptorMap* descriptors = LoadDescriptors(); + return descriptors; } uint32_t ACgroupFile_getVersion() { - auto file = GetInstance(); - if (file == nullptr) return 0; - return file->version_; + static constexpr uint32_t FILE_VERSION_1 = 1; + auto descriptors = GetInstance(); + if (descriptors == nullptr) return 0; + // There has only ever been one version, and there will be no more since cgroup.rc is no more + return FILE_VERSION_1; } uint32_t ACgroupFile_getControllerCount() { - auto file = GetInstance(); - if (file == nullptr) return 0; - return file->controller_count_; + auto descriptors = GetInstance(); + if (descriptors == nullptr) return 0; + return descriptors->size(); } const ACgroupController* ACgroupFile_getController(uint32_t index) { - auto file = GetInstance(); - if (file == nullptr) return nullptr; - CHECK(index < file->controller_count_); + auto descriptors = GetInstance(); + if (descriptors == nullptr) return nullptr; + CHECK(index < descriptors->size()); // Although the object is not actually an ACgroupController object, all ACgroupController_* // functions implicitly convert ACgroupController* back to CgroupController* before invoking // member functions. - return static_cast(&file->controllers_[index]); + const CgroupController* p = std::next(descriptors->begin(), index)->second.controller(); + return static_cast(p); } diff --git a/libprocessgroup/cgrouprc/cgrouprc_internal.h b/libprocessgroup/cgrouprc/cgrouprc_internal.h index cd02f0304..d51770346 100644 --- a/libprocessgroup/cgrouprc/cgrouprc_internal.h +++ b/libprocessgroup/cgrouprc/cgrouprc_internal.h @@ -16,9 +16,6 @@ #pragma once -#include +#include -#include -#include - -struct ACgroupController : android::cgrouprc::format::CgroupController {}; +struct ACgroupController : CgroupController {}; diff --git a/libprocessgroup/cgrouprc_format/Android.bp b/libprocessgroup/cgrouprc_format/Android.bp index 059092419..6f9ab3e73 100644 --- a/libprocessgroup/cgrouprc_format/Android.bp +++ b/libprocessgroup/cgrouprc_format/Android.bp @@ -23,17 +23,4 @@ cc_library_static { vendor_ramdisk_available: true, recovery_available: true, native_bridge_supported: true, - srcs: [ - "cgroup_controller.cpp", - ], - cflags: [ - "-Wall", - "-Werror", - ], - export_include_dirs: [ - "include", - ], - shared_libs: [ - "libbase", - ], } diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index ffffeb48b..805775744 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -57,7 +57,7 @@ __BEGIN_DECLS bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector& profiles); -static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; +[[deprecated]] static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; bool UsePerAppMemcg(); diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h b/libprocessgroup/internal.h similarity index 54% rename from libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h rename to libprocessgroup/internal.h index 2d9786fe6..ef855790d 100644 --- a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h +++ b/libprocessgroup/internal.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2019 The Android Open Source Project + * Copyright (C) 2024 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. @@ -16,23 +16,6 @@ #pragma once -#include +#include -#include - -namespace android { -namespace cgrouprc { -namespace format { - -struct CgroupFile { - uint32_t version_; - uint32_t controller_count_; - CgroupController controllers_[]; - - static constexpr uint32_t FILE_VERSION_1 = 1; - static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1; -}; - -} // namespace format -} // namespace cgrouprc -} // namespace android +static const std::string CGROUP_V2_ROOT_DEFAULT = "/sys/fs/cgroup"; \ No newline at end of file diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp index 1a4ad0118..cc6c67cf4 100644 --- a/libprocessgroup/setup/Android.bp +++ b/libprocessgroup/setup/Android.bp @@ -33,7 +33,6 @@ cc_library_shared { "libjsoncpp", ], static_libs: [ - "libcgrouprc_format", "libprocessgroup_util", ], header_libs: [ diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h index 06ce186fd..1afd2ee9c 100644 --- a/libprocessgroup/setup/cgroup_descriptor.h +++ b/libprocessgroup/setup/cgroup_descriptor.h @@ -21,10 +21,7 @@ #include -#include - -namespace android { -namespace cgrouprc { +#include // Complete controller description for mounting cgroups class CgroupDescriptor { @@ -33,7 +30,7 @@ class CgroupDescriptor { mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, uint32_t max_activation_depth); - const format::CgroupController* controller() const { return &controller_; } + const CgroupController* controller() const { return &controller_; } mode_t mode() const { return mode_; } std::string uid() const { return uid_; } std::string gid() const { return gid_; } @@ -41,11 +38,8 @@ class CgroupDescriptor { void set_mounted(bool mounted); private: - format::CgroupController controller_; + CgroupController controller_; mode_t mode_ = 0; std::string uid_; std::string gid_; }; - -} // namespace cgrouprc -} // namespace android diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index bd4187475..821168008 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -22,45 +22,28 @@ #include #include #include -#include #include #include #include -#include #include #include #include #include -#include -#include -#include -#include -#include -#include -#include +#include #include #include #include #include "../build_flags.h" -#include "cgroup_descriptor.h" - -using android::base::GetUintProperty; -using android::base::StringPrintf; -using android::base::unique_fd; - -namespace android { -namespace cgrouprc { +#include "../internal.h" static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; static constexpr const char* TEMPLATE_CGROUPS_DESC_API_FILE = "/etc/task_profiles/cgroups_%u.json"; -static const std::string CGROUP_V2_ROOT_DEFAULT = "/sys/fs/cgroup"; - static bool ChangeDirModeAndOwner(const std::string& path, mode_t mode, const std::string& uid, const std::string& gid, bool permissive_mode = false) { uid_t pw_uid = -1; @@ -148,149 +131,15 @@ static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid, return true; } -static void MergeCgroupToDescriptors(std::map* descriptors, - const Json::Value& cgroup, const std::string& name, - const std::string& root_path, int cgroups_version) { - const std::string cgroup_path = cgroup["Path"].asString(); - std::string path; - - if (!root_path.empty()) { - path = root_path; - if (cgroup_path != ".") { - path += "/"; - path += cgroup_path; - } - } else { - path = cgroup_path; - } - - uint32_t controller_flags = 0; - - if (cgroup["NeedsActivation"].isBool() && cgroup["NeedsActivation"].asBool()) { - controller_flags |= CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION; - } - - if (cgroup["Optional"].isBool() && cgroup["Optional"].asBool()) { - controller_flags |= CGROUPRC_CONTROLLER_FLAG_OPTIONAL; - } - - uint32_t max_activation_depth = UINT32_MAX; - if (cgroup.isMember("MaxActivationDepth")) { - max_activation_depth = cgroup["MaxActivationDepth"].asUInt(); - } - - CgroupDescriptor descriptor( - cgroups_version, name, path, std::strtoul(cgroup["Mode"].asString().c_str(), 0, 8), - cgroup["UID"].asString(), cgroup["GID"].asString(), controller_flags, - max_activation_depth); - - auto iter = descriptors->find(name); - if (iter == descriptors->end()) { - descriptors->emplace(name, descriptor); - } else { - iter->second = descriptor; - } -} - -static const bool force_memcg_v2 = android::libprocessgroup_flags::force_memcg_v2(); - -static bool ReadDescriptorsFromFile(const std::string& file_name, - std::map* descriptors) { - std::vector result; - std::string json_doc; - - if (!android::base::ReadFileToString(file_name, &json_doc)) { - PLOG(ERROR) << "Failed to read task profiles from " << file_name; - return false; - } - - Json::CharReaderBuilder builder; - std::unique_ptr reader(builder.newCharReader()); - Json::Value root; - std::string errorMessage; - if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) { - LOG(ERROR) << "Failed to parse cgroups description: " << errorMessage; - return false; - } - - if (root.isMember("Cgroups")) { - const Json::Value& cgroups = root["Cgroups"]; - for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { - std::string name = cgroups[i]["Controller"].asString(); - - if (force_memcg_v2 && name == "memory") continue; - - MergeCgroupToDescriptors(descriptors, cgroups[i], name, "", 1); - } - } - - bool memcgv2_present = false; - std::string root_path; - if (root.isMember("Cgroups2")) { - const Json::Value& cgroups2 = root["Cgroups2"]; - root_path = cgroups2["Path"].asString(); - MergeCgroupToDescriptors(descriptors, cgroups2, CGROUPV2_HIERARCHY_NAME, "", 2); - - const Json::Value& childGroups = cgroups2["Controllers"]; - for (Json::Value::ArrayIndex i = 0; i < childGroups.size(); ++i) { - std::string name = childGroups[i]["Controller"].asString(); - - if (force_memcg_v2 && name == "memory") memcgv2_present = true; - - MergeCgroupToDescriptors(descriptors, childGroups[i], name, root_path, 2); - } - } - - if (force_memcg_v2 && !memcgv2_present) { - LOG(INFO) << "Forcing memcg to v2 hierarchy"; - Json::Value memcgv2; - memcgv2["Controller"] = "memory"; - memcgv2["NeedsActivation"] = true; - memcgv2["Path"] = "."; - memcgv2["Optional"] = true; // In case of cgroup_disabled=memory, so we can still boot - MergeCgroupToDescriptors(descriptors, memcgv2, "memory", - root_path.empty() ? CGROUP_V2_ROOT_DEFAULT : root_path, 2); - } - - return true; -} - -static bool ReadDescriptors(std::map* descriptors) { - // load system cgroup descriptors - if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) { - return false; - } - - // load API-level specific system cgroups descriptors if available - unsigned int api_level = GetUintProperty("ro.product.first_api_level", 0); - if (api_level > 0) { - std::string api_cgroups_path = - android::base::StringPrintf(TEMPLATE_CGROUPS_DESC_API_FILE, api_level); - if (!access(api_cgroups_path.c_str(), F_OK) || errno != ENOENT) { - if (!ReadDescriptorsFromFile(api_cgroups_path, descriptors)) { - return false; - } - } - } - - // load vendor cgroup descriptors if the file exists - if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) && - !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) { - return false; - } - - return true; -} - // To avoid issues in sdk_mac build #if defined(__ANDROID__) -static bool IsOptionalController(const format::CgroupController* controller) { +static bool IsOptionalController(const CgroupController* controller) { return controller->flags() & CGROUPRC_CONTROLLER_FLAG_OPTIONAL; } static bool MountV2CgroupController(const CgroupDescriptor& descriptor) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); // /sys/fs/cgroup is created by cgroup2 with specific selinux permissions, // try to create again in case the mount point is changed @@ -324,7 +173,7 @@ static bool MountV2CgroupController(const CgroupDescriptor& descriptor) { } static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup"; @@ -338,7 +187,7 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { std::string path = controller->path(); path += "/cgroup.subtree_control"; - if (!base::WriteStringToFile(str, path)) { + if (!android::base::WriteStringToFile(str, path)) { if (IsOptionalController(controller)) { PLOG(INFO) << "Failed to activate optional controller " << controller->name() << " at " << path; @@ -353,7 +202,7 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { } static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); // mkdir [mode] [owner] [group] if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { @@ -388,7 +237,7 @@ static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { } static bool SetupCgroup(const CgroupDescriptor& descriptor) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); if (controller->version() == 2) { if (!strcmp(controller->name(), CGROUPV2_HIERARCHY_NAME)) { @@ -410,35 +259,6 @@ static bool SetupCgroup(const CgroupDescriptor&) { #endif -static bool WriteRcFile(const std::map& descriptors) { - unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, - S_IRUSR | S_IRGRP | S_IROTH))); - if (fd < 0) { - PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; - return false; - } - - format::CgroupFile fl; - fl.version_ = format::CgroupFile::FILE_CURR_VERSION; - fl.controller_count_ = descriptors.size(); - int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl))); - if (ret < 0) { - PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; - return false; - } - - for (const auto& [name, descriptor] : descriptors) { - ret = TEMP_FAILURE_RETRY( - write(fd, descriptor.controller(), sizeof(format::CgroupController))); - if (ret < 0) { - PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; - return false; - } - } - - return true; -} - CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, @@ -458,9 +278,6 @@ void CgroupDescriptor::set_mounted(bool mounted) { controller_.set_flags(flags); } -} // namespace cgrouprc -} // namespace android - static std::optional MGLRUDisabled() { const std::string file_name = "/sys/kernel/mm/lru_gen/enabled"; std::string content; @@ -472,9 +289,8 @@ static std::optional MGLRUDisabled() { return content == "0x0000"; } -static std::optional MEMCGDisabled( - const std::map& descriptors) { - std::string cgroup_v2_root = android::cgrouprc::CGROUP_V2_ROOT_DEFAULT; +static std::optional MEMCGDisabled(const CgroupDescriptorMap& descriptors) { + std::string cgroup_v2_root = CGROUP_V2_ROOT_DEFAULT; const auto it = descriptors.find(CGROUPV2_HIERARCHY_NAME); if (it == descriptors.end()) { LOG(WARNING) << "No Cgroups2 path found in cgroups.json. Vendor has modified Android, and " @@ -495,14 +311,10 @@ static std::optional MEMCGDisabled( return content.find("memory") == std::string::npos; } -static bool CreateV2SubHierarchy( - const std::string& path, - const std::map& descriptors) { - using namespace android::cgrouprc; - +static bool CreateV2SubHierarchy(const std::string& path, const CgroupDescriptorMap& descriptors) { const auto cgv2_iter = descriptors.find(CGROUPV2_HIERARCHY_NAME); if (cgv2_iter == descriptors.end()) return false; - const android::cgrouprc::CgroupDescriptor cgv2_descriptor = cgv2_iter->second; + const CgroupDescriptor cgv2_descriptor = cgv2_iter->second; if (!Mkdir(path, cgv2_descriptor.mode(), cgv2_descriptor.uid(), cgv2_descriptor.gid())) { PLOG(ERROR) << "Failed to create directory for " << path; @@ -512,10 +324,10 @@ static bool CreateV2SubHierarchy( // Activate all v2 controllers in path so they can be activated in // children as they are created. for (const auto& [name, descriptor] : descriptors) { - const format::CgroupController* controller = descriptor.controller(); + const CgroupController* controller = descriptor.controller(); std::uint32_t flags = controller->flags(); std::uint32_t max_activation_depth = controller->max_activation_depth(); - const int depth = util::GetCgroupDepth(controller->path(), path); + const int depth = GetCgroupDepth(controller->path(), path); if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME && flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { @@ -535,22 +347,13 @@ static bool CreateV2SubHierarchy( } bool CgroupSetup() { - using namespace android::cgrouprc; - - std::map descriptors; + CgroupDescriptorMap descriptors; if (getpid() != 1) { LOG(ERROR) << "Cgroup setup can be done only by init process"; return false; } - // Make sure we do this only one time. No need for std::call_once because - // init is a single-threaded process - if (access(CGROUPS_RC_PATH, F_OK) == 0) { - LOG(WARNING) << "Attempt to call CgroupSetup() more than once"; - return true; - } - // load cgroups.json file if (!ReadDescriptors(&descriptors)) { LOG(ERROR) << "Failed to load cgroup description file"; @@ -559,15 +362,18 @@ bool CgroupSetup() { // setup cgroups for (auto& [name, descriptor] : descriptors) { - if (SetupCgroup(descriptor)) { - descriptor.set_mounted(true); - } else { + if (descriptor.controller()->flags() & CGROUPRC_CONTROLLER_FLAG_MOUNTED) { + LOG(WARNING) << "Attempt to call CgroupSetup() more than once"; + return true; + } + + if (!SetupCgroup(descriptor)) { // issue a warning and proceed with the next cgroup LOG(WARNING) << "Failed to setup " << name << " cgroup"; } } - if (force_memcg_v2) { + if (android::libprocessgroup_flags::force_memcg_v2()) { if (MGLRUDisabled().value_or(false)) { LOG(WARNING) << "Memcg forced to v2 hierarchy with MGLRU disabled! " << "Global reclaim performance will suffer."; @@ -593,26 +399,5 @@ bool CgroupSetup() { } } - // mkdir 0711 system system - if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) { - LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file"; - return false; - } - - // Generate file which can be directly mmapped into - // process memory. This optimizes performance, memory usage - // and limits infrormation shared with unprivileged processes - // to the minimum subset of information from cgroups.json - if (!WriteRcFile(descriptors)) { - LOG(ERROR) << "Failed to write " << CGROUPS_RC_PATH << " file"; - return false; - } - - // chmod 0644 - if (fchmodat(AT_FDCWD, CGROUPS_RC_PATH, 0644, AT_SYMLINK_NOFOLLOW) < 0) { - PLOG(ERROR) << "fchmodat() failed"; - return false; - } - return true; } diff --git a/libprocessgroup/util/Android.bp b/libprocessgroup/util/Android.bp index 54ba69b4e..1c74d4ed5 100644 --- a/libprocessgroup/util/Android.bp +++ b/libprocessgroup/util/Android.bp @@ -37,8 +37,16 @@ cc_library_static { "include", ], srcs: [ + "cgroup_controller.cpp", + "cgroup_descriptor.cpp", "util.cpp", ], + shared_libs: [ + "libbase", + ], + static_libs: [ + "libjsoncpp", + ], defaults: ["libprocessgroup_build_flags_cc"], } diff --git a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp b/libprocessgroup/util/cgroup_controller.cpp similarity index 90% rename from libprocessgroup/cgrouprc_format/cgroup_controller.cpp rename to libprocessgroup/util/cgroup_controller.cpp index 0dd909a29..fb4168075 100644 --- a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp +++ b/libprocessgroup/util/cgroup_controller.cpp @@ -14,11 +14,9 @@ * limitations under the License. */ -#include +#include -namespace android { -namespace cgrouprc { -namespace format { +#include CgroupController::CgroupController(uint32_t version, uint32_t flags, const std::string& name, const std::string& path, uint32_t max_activation_depth) @@ -54,8 +52,4 @@ const char* CgroupController::path() const { void CgroupController::set_flags(uint32_t flags) { flags_ = flags; -} - -} // namespace format -} // namespace cgrouprc -} // namespace android +} \ No newline at end of file diff --git a/libprocessgroup/util/cgroup_descriptor.cpp b/libprocessgroup/util/cgroup_descriptor.cpp new file mode 100644 index 000000000..4d3347f34 --- /dev/null +++ b/libprocessgroup/util/cgroup_descriptor.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2024 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 + +#include // For flag values + +CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, + const std::string& path, mode_t mode, const std::string& uid, + const std::string& gid, uint32_t flags, + uint32_t max_activation_depth) + : controller_(version, flags, name, path, max_activation_depth), + mode_(mode), + uid_(uid), + gid_(gid) {} + +void CgroupDescriptor::set_mounted(bool mounted) { + uint32_t flags = controller_.flags(); + if (mounted) { + flags |= CGROUPRC_CONTROLLER_FLAG_MOUNTED; + } else { + flags &= ~CGROUPRC_CONTROLLER_FLAG_MOUNTED; + } + controller_.set_flags(flags); +} diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h b/libprocessgroup/util/include/processgroup/cgroup_controller.h similarity index 87% rename from libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h rename to libprocessgroup/util/include/processgroup/cgroup_controller.h index c0c1f6034..fe6a829a0 100644 --- a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h +++ b/libprocessgroup/util/include/processgroup/cgroup_controller.h @@ -20,11 +20,7 @@ #include #include -namespace android { -namespace cgrouprc { -namespace format { - -// Minimal controller description to be mmapped into process address space +// Minimal controller description struct CgroupController { public: CgroupController() = default; @@ -48,8 +44,4 @@ struct CgroupController { uint32_t max_activation_depth_ = UINT32_MAX; char name_[CGROUP_NAME_BUF_SZ] = {}; char path_[CGROUP_PATH_BUF_SZ] = {}; -}; - -} // namespace format -} // namespace cgrouprc -} // namespace android +}; \ No newline at end of file diff --git a/libprocessgroup/util/include/processgroup/cgroup_descriptor.h b/libprocessgroup/util/include/processgroup/cgroup_descriptor.h new file mode 100644 index 000000000..1afd2ee9c --- /dev/null +++ b/libprocessgroup/util/include/processgroup/cgroup_descriptor.h @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include + +#include + +// Complete controller description for mounting cgroups +class CgroupDescriptor { + public: + CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, + mode_t mode, const std::string& uid, const std::string& gid, uint32_t flags, + uint32_t max_activation_depth); + + const CgroupController* controller() const { return &controller_; } + mode_t mode() const { return mode_; } + std::string uid() const { return uid_; } + std::string gid() const { return gid_; } + + void set_mounted(bool mounted); + + private: + CgroupController controller_; + mode_t mode_ = 0; + std::string uid_; + std::string gid_; +}; diff --git a/libprocessgroup/util/include/processgroup/util.h b/libprocessgroup/util/include/processgroup/util.h index 8d013af55..d592a6347 100644 --- a/libprocessgroup/util/include/processgroup/util.h +++ b/libprocessgroup/util/include/processgroup/util.h @@ -16,10 +16,18 @@ #pragma once +#include #include -namespace util { +#include "cgroup_descriptor.h" + +// Duplicated from cgrouprc.h. Don't depend on libcgrouprc here. +#define CGROUPRC_CONTROLLER_FLAG_MOUNTED 0x1 +#define CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION 0x2 +#define CGROUPRC_CONTROLLER_FLAG_OPTIONAL 0x4 unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path); -} // namespace util +using CgroupControllerName = std::string; +using CgroupDescriptorMap = std::map; +bool ReadDescriptors(CgroupDescriptorMap* descriptors); diff --git a/libprocessgroup/util/tests/util.cpp b/libprocessgroup/util/tests/util.cpp index 1de7d6f3f..6caef8ee3 100644 --- a/libprocessgroup/util/tests/util.cpp +++ b/libprocessgroup/util/tests/util.cpp @@ -18,8 +18,6 @@ #include "gtest/gtest.h" -using util::GetCgroupDepth; - TEST(EmptyInputs, bothEmpty) { EXPECT_EQ(GetCgroupDepth({}, {}), 0); } diff --git a/libprocessgroup/util/util.cpp b/libprocessgroup/util/util.cpp index 9b88a223a..bff4c6f1a 100644 --- a/libprocessgroup/util/util.cpp +++ b/libprocessgroup/util/util.cpp @@ -18,9 +18,33 @@ #include #include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include + +#include "../build_flags.h" +#include "../internal.h" + +using android::base::GetUintProperty; namespace { +constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; +constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; +constexpr const char* TEMPLATE_CGROUPS_DESC_API_FILE = "/etc/task_profiles/cgroups_%u.json"; + +// This should match the publicly declared value in processgroup.h, +// but we don't want this library to depend on libprocessgroup. +constexpr std::string CGROUPV2_HIERARCHY_NAME_INTERNAL = "cgroup2"; + const char SEP = '/'; std::string DeduplicateAndTrimSeparators(const std::string& path) { @@ -42,9 +66,135 @@ std::string DeduplicateAndTrimSeparators(const std::string& path) { return ret; } +void MergeCgroupToDescriptors(CgroupDescriptorMap* descriptors, const Json::Value& cgroup, + const std::string& name, const std::string& root_path, + int cgroups_version) { + const std::string cgroup_path = cgroup["Path"].asString(); + std::string path; + + if (!root_path.empty()) { + path = root_path; + if (cgroup_path != ".") { + path += "/"; + path += cgroup_path; + } + } else { + path = cgroup_path; + } + + uint32_t controller_flags = 0; + + if (cgroup["NeedsActivation"].isBool() && cgroup["NeedsActivation"].asBool()) { + controller_flags |= CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION; + } + + if (cgroup["Optional"].isBool() && cgroup["Optional"].asBool()) { + controller_flags |= CGROUPRC_CONTROLLER_FLAG_OPTIONAL; + } + + uint32_t max_activation_depth = UINT32_MAX; + if (cgroup.isMember("MaxActivationDepth")) { + max_activation_depth = cgroup["MaxActivationDepth"].asUInt(); + } + + CgroupDescriptor descriptor( + cgroups_version, name, path, std::strtoul(cgroup["Mode"].asString().c_str(), 0, 8), + cgroup["UID"].asString(), cgroup["GID"].asString(), controller_flags, + max_activation_depth); + + auto iter = descriptors->find(name); + if (iter == descriptors->end()) { + descriptors->emplace(name, descriptor); + } else { + iter->second = descriptor; + } +} + +bool ReadDescriptorsFromFile(const std::string& file_name, CgroupDescriptorMap* descriptors) { + static constexpr bool force_memcg_v2 = android::libprocessgroup_flags::force_memcg_v2(); + std::vector result; + std::string json_doc; + + if (!android::base::ReadFileToString(file_name, &json_doc)) { + PLOG(ERROR) << "Failed to read task profiles from " << file_name; + return false; + } + + Json::CharReaderBuilder builder; + std::unique_ptr reader(builder.newCharReader()); + Json::Value root; + std::string errorMessage; + if (!reader->parse(&*json_doc.begin(), &*json_doc.end(), &root, &errorMessage)) { + LOG(ERROR) << "Failed to parse cgroups description: " << errorMessage; + return false; + } + + if (root.isMember("Cgroups")) { + const Json::Value& cgroups = root["Cgroups"]; + for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { + std::string name = cgroups[i]["Controller"].asString(); + + if (force_memcg_v2 && name == "memory") continue; + + MergeCgroupToDescriptors(descriptors, cgroups[i], name, "", 1); + } + } + + bool memcgv2_present = false; + std::string root_path; + if (root.isMember("Cgroups2")) { + const Json::Value& cgroups2 = root["Cgroups2"]; + root_path = cgroups2["Path"].asString(); + MergeCgroupToDescriptors(descriptors, cgroups2, CGROUPV2_HIERARCHY_NAME_INTERNAL, "", 2); + + const Json::Value& childGroups = cgroups2["Controllers"]; + for (Json::Value::ArrayIndex i = 0; i < childGroups.size(); ++i) { + std::string name = childGroups[i]["Controller"].asString(); + + if (force_memcg_v2 && name == "memory") memcgv2_present = true; + + MergeCgroupToDescriptors(descriptors, childGroups[i], name, root_path, 2); + } + } + + if (force_memcg_v2 && !memcgv2_present) { + LOG(INFO) << "Forcing memcg to v2 hierarchy"; + Json::Value memcgv2; + memcgv2["Controller"] = "memory"; + memcgv2["NeedsActivation"] = true; + memcgv2["Path"] = "."; + memcgv2["Optional"] = true; // In case of cgroup_disabled=memory, so we can still boot + MergeCgroupToDescriptors(descriptors, memcgv2, "memory", + root_path.empty() ? CGROUP_V2_ROOT_DEFAULT : root_path, 2); + } + + return true; +} + +using MountDir = std::string; +using MountOpts = std::string; +static std::optional> ReadCgroupV1Mounts() { + FILE* fp = setmntent("/proc/mounts", "r"); + if (fp == nullptr) { + PLOG(ERROR) << "Failed to read mounts"; + return std::nullopt; + } + + std::map mounts; + const std::string_view CGROUP_V1_TYPE = "cgroup"; + for (mntent* mentry = getmntent(fp); mentry != nullptr; mentry = getmntent(fp)) { + if (mentry->mnt_type && CGROUP_V1_TYPE == mentry->mnt_type && + mentry->mnt_dir && mentry->mnt_opts) { + mounts[mentry->mnt_dir] = mentry->mnt_opts; + } + } + endmntent(fp); + + return mounts; +} + } // anonymous namespace -namespace util { unsigned int GetCgroupDepth(const std::string& controller_root, const std::string& cgroup_path) { const std::string deduped_root = DeduplicateAndTrimSeparators(controller_root); @@ -56,4 +206,47 @@ unsigned int GetCgroupDepth(const std::string& controller_root, const std::strin return std::count(deduped_path.begin() + deduped_root.size(), deduped_path.end(), SEP); } -} // namespace util +bool ReadDescriptors(CgroupDescriptorMap* descriptors) { + // load system cgroup descriptors + if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) { + return false; + } + + // load API-level specific system cgroups descriptors if available + unsigned int api_level = GetUintProperty("ro.product.first_api_level", 0); + if (api_level > 0) { + std::string api_cgroups_path = + android::base::StringPrintf(TEMPLATE_CGROUPS_DESC_API_FILE, api_level); + if (!access(api_cgroups_path.c_str(), F_OK) || errno != ENOENT) { + if (!ReadDescriptorsFromFile(api_cgroups_path, descriptors)) { + return false; + } + } + } + + // load vendor cgroup descriptors if the file exists + if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) && + !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) { + return false; + } + + // check for v1 mount/usability status + std::optional> v1Mounts; + for (auto& [name, descriptor] : *descriptors) { + const CgroupController* const controller = descriptor.controller(); + + if (controller->version() != 1) continue; + + // Read only once, and only if we have at least one v1 controller + if (!v1Mounts) { + v1Mounts = ReadCgroupV1Mounts(); + if (!v1Mounts) return false; + } + + if (const auto it = v1Mounts->find(controller->path()); it != v1Mounts->end()) { + if (it->second.contains(controller->name())) descriptor.set_mounted(true); + } + } + + return true; +} From c76b6ada233ccc8ab83e054177df49791896765b Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 8 Oct 2024 23:41:31 +0000 Subject: [PATCH 039/183] Reapply "libprocessgroup: Remove dependency on libcgrouprc" This reverts commit 691ad736bb4088a634e2766334c17ae8a2bfbe79. Change-Id: I6615792c24b5c3151ba789248cfbdfefaf57a1e4 --- libprocessgroup/Android.bp | 1 - libprocessgroup/cgroup_map.cpp | 95 +++++++++++++--------------------- libprocessgroup/cgroup_map.h | 13 +++-- 3 files changed, 43 insertions(+), 66 deletions(-) diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index d623a1152..8448a39a4 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -75,7 +75,6 @@ cc_library { double_loadable: true, shared_libs: [ "libbase", - "libcgrouprc", ], static_libs: [ "libjsoncpp", diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index aeccfe89b..8180ccf3f 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -25,12 +25,10 @@ #include #include #include -#include #include #include #include -using android::base::StartsWith; using android::base::StringPrintf; using android::base::WriteStringToFile; @@ -40,17 +38,17 @@ static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.threads"; uint32_t CgroupControllerWrapper::version() const { CHECK(HasValue()); - return ACgroupController_getVersion(controller_); + return controller_->version(); } const char* CgroupControllerWrapper::name() const { CHECK(HasValue()); - return ACgroupController_getName(controller_); + return controller_->name(); } const char* CgroupControllerWrapper::path() const { CHECK(HasValue()); - return ACgroupController_getPath(controller_); + return controller_->path(); } bool CgroupControllerWrapper::HasValue() const { @@ -62,7 +60,7 @@ bool CgroupControllerWrapper::IsUsable() { if (state_ == UNKNOWN) { if (__builtin_available(android 30, *)) { - uint32_t flags = ACgroupController_getFlags(controller_); + uint32_t flags = controller_->flags(); state_ = (flags & CGROUPRC_CONTROLLER_FLAG_MOUNTED) != 0 ? USABLE : MISSING; } else { state_ = access(GetProcsFilePath("", 0, 0).c_str(), F_OK) == 0 ? USABLE : MISSING; @@ -129,8 +127,8 @@ bool CgroupControllerWrapper::GetTaskGroup(pid_t tid, std::string* group) const } CgroupMap::CgroupMap() { - if (!LoadRcFile()) { - LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed"; + if (!LoadDescriptors()) { + LOG(ERROR) << "CgroupMap::LoadDescriptors called for [" << getpid() << "] failed"; } } @@ -141,9 +139,9 @@ CgroupMap& CgroupMap::GetInstance() { return *instance; } -bool CgroupMap::LoadRcFile() { +bool CgroupMap::LoadDescriptors() { if (!loaded_) { - loaded_ = (ACgroupFile_getVersion() != 0); + loaded_ = ReadDescriptors(&descriptors_); } return loaded_; } @@ -154,40 +152,27 @@ void CgroupMap::Print() const { << "] failed, cgroups were not initialized properly"; return; } - LOG(INFO) << "File version = " << ACgroupFile_getVersion(); - LOG(INFO) << "File controller count = " << ACgroupFile_getControllerCount(); + LOG(INFO) << "Controller count = " << descriptors_.size(); LOG(INFO) << "Mounted cgroups:"; - auto controller_count = ACgroupFile_getControllerCount(); - for (uint32_t i = 0; i < controller_count; ++i) { - const ACgroupController* controller = ACgroupFile_getController(i); - if (__builtin_available(android 30, *)) { - LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver " - << ACgroupController_getVersion(controller) << " path " - << ACgroupController_getPath(controller) << " flags " - << ACgroupController_getFlags(controller); - } else { - LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver " - << ACgroupController_getVersion(controller) << " path " - << ACgroupController_getPath(controller); - } + for (const auto& [name, descriptor] : descriptors_) { + LOG(INFO) << "\t" << descriptor.controller()->name() << " ver " + << descriptor.controller()->version() << " path " + << descriptor.controller()->path() << " flags " + << descriptor.controller()->flags(); } } CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const { if (!loaded_) { LOG(ERROR) << "CgroupMap::FindController called for [" << getpid() - << "] failed, RC file was not initialized properly"; + << "] failed, cgroups were not initialized properly"; return CgroupControllerWrapper(nullptr); } - auto controller_count = ACgroupFile_getControllerCount(); - for (uint32_t i = 0; i < controller_count; ++i) { - const ACgroupController* controller = ACgroupFile_getController(i); - if (name == ACgroupController_getName(controller)) { - return CgroupControllerWrapper(controller); - } + if (const auto it = descriptors_.find(name); it != descriptors_.end()) { + return CgroupControllerWrapper(it->second.controller()); } return CgroupControllerWrapper(nullptr); @@ -196,15 +181,13 @@ CgroupControllerWrapper CgroupMap::FindController(const std::string& name) const CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) const { if (!loaded_) { LOG(ERROR) << "CgroupMap::FindControllerByPath called for [" << getpid() - << "] failed, RC file was not initialized properly"; + << "] failed, cgroups were not initialized properly"; return CgroupControllerWrapper(nullptr); } - auto controller_count = ACgroupFile_getControllerCount(); - for (uint32_t i = 0; i < controller_count; ++i) { - const ACgroupController* controller = ACgroupFile_getController(i); - if (StartsWith(path, ACgroupController_getPath(controller))) { - return CgroupControllerWrapper(controller); + for (const auto& [name, descriptor] : descriptors_) { + if (path.starts_with(descriptor.controller()->path())) { + return CgroupControllerWrapper(descriptor.controller()); } } @@ -212,31 +195,23 @@ CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) } int CgroupMap::ActivateControllers(const std::string& path) const { - if (__builtin_available(android 30, *)) { - auto controller_count = ACgroupFile_getControllerCount(); - for (uint32_t i = 0; i < controller_count; ++i) { - const ACgroupController* controller = ACgroupFile_getController(i); - const uint32_t flags = ACgroupController_getFlags(controller); - uint32_t max_activation_depth = UINT32_MAX; - if (__builtin_available(android 36, *)) { - max_activation_depth = ACgroupController_getMaxActivationDepth(controller); - } - const int depth = GetCgroupDepth(ACgroupController_getPath(controller), path); + for (const auto& [name, descriptor] : descriptors_) { + const uint32_t flags = descriptor.controller()->flags(); + const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); + const int depth = GetCgroupDepth(descriptor.controller()->path(), path); - if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { - std::string str("+"); - str.append(ACgroupController_getName(controller)); - if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { - if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { - PLOG(WARNING) << "Activation of cgroup controller " << str - << " failed in path " << path; - } else { - return -errno; - } + if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { + std::string str("+"); + str.append(descriptor.controller()->name()); + if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { + if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { + PLOG(WARNING) << "Activation of cgroup controller " << str + << " failed in path " << path; + } else { + return -errno; } } } - return 0; } - return -ENOSYS; + return 0; } diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index 364279414..5ad59bddf 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -18,15 +18,17 @@ #include +#include #include -#include +#include +#include -// Convenient wrapper of an ACgroupController pointer. +// Convenient wrapper of a CgroupController pointer. class CgroupControllerWrapper { public: // Does not own controller - explicit CgroupControllerWrapper(const ACgroupController* controller) + explicit CgroupControllerWrapper(const CgroupController* controller) : controller_(controller) {} uint32_t version() const; @@ -47,7 +49,7 @@ class CgroupControllerWrapper { MISSING = 2, }; - const ACgroupController* controller_ = nullptr; + const CgroupController* controller_ = nullptr; // CgroupMap owns the object behind this pointer ControllerState state_ = ControllerState::UNKNOWN; }; @@ -60,7 +62,8 @@ class CgroupMap { private: bool loaded_ = false; + CgroupDescriptorMap descriptors_; CgroupMap(); - bool LoadRcFile(); + bool LoadDescriptors(); void Print() const; }; From 47580ff76d9d9ecbaa9345a9aa02e95bd6bbce33 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 8 Oct 2024 23:41:33 +0000 Subject: [PATCH 040/183] Reapply "libprocessgroup: Remove ACgroupController_getMaxActivati..." This reverts commit aeca8793f533c243d0f9353bce5e276f48e01363. Change-Id: I06e7e651f0cabfd43b50a278baf36f31f6061a8f --- libprocessgroup/cgrouprc/a_cgroup_controller.cpp | 5 ----- libprocessgroup/cgrouprc/include/android/cgrouprc.h | 8 -------- libprocessgroup/cgrouprc/libcgrouprc.map.txt | 7 ------- 3 files changed, 20 deletions(-) diff --git a/libprocessgroup/cgrouprc/a_cgroup_controller.cpp b/libprocessgroup/cgrouprc/a_cgroup_controller.cpp index 889b3becf..5a326e55d 100644 --- a/libprocessgroup/cgrouprc/a_cgroup_controller.cpp +++ b/libprocessgroup/cgrouprc/a_cgroup_controller.cpp @@ -32,11 +32,6 @@ uint32_t ACgroupController_getFlags(const ACgroupController* controller) { return controller->flags(); } -uint32_t ACgroupController_getMaxActivationDepth(const ACgroupController* controller) { - CHECK(controller != nullptr); - return controller->max_activation_depth(); -} - const char* ACgroupController_getName(const ACgroupController* controller) { CHECK(controller != nullptr); return controller->name(); diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h index 3a57df547..e704a36aa 100644 --- a/libprocessgroup/cgrouprc/include/android/cgrouprc.h +++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h @@ -78,14 +78,6 @@ __attribute__((warn_unused_result)) uint32_t ACgroupController_getVersion(const __attribute__((warn_unused_result, weak)) uint32_t ACgroupController_getFlags( const ACgroupController*) __INTRODUCED_IN(30); -/** - * Returns the maximum activation depth of the given controller. - * Only applicable to cgroup v2 controllers. - * Returns UINT32_MAX if no maximum activation depth is set. - */ -__attribute__((warn_unused_result, weak)) uint32_t ACgroupController_getMaxActivationDepth( - const ACgroupController* controller) __INTRODUCED_IN(36); - /** * Returns the name of the given controller. * If the given controller is null, return nullptr. diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.map.txt index 30bd25f18..b62b10f3b 100644 --- a/libprocessgroup/cgrouprc/libcgrouprc.map.txt +++ b/libprocessgroup/cgrouprc/libcgrouprc.map.txt @@ -16,10 +16,3 @@ LIBCGROUPRC_30 { # introduced=30 local: *; }; - -LIBCGROUPRC_36 { # introduced=36 - global: - ACgroupController_getMaxActivationDepth; # llndk=202504 systemapi - local: - *; -}; From 787ddbc8a57b34d8d74dfd19b47ab5c816ae2af3 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 8 Oct 2024 23:41:34 +0000 Subject: [PATCH 041/183] Reapply "libprocessgroup: Combine all 3 ActivateControllers imple..." This reverts commit 0fa49253a484fc0c99d067ade57a4978059b3a95. Change-Id: I83121ff295caaabc0a2fd8a606ee2d52dacb0174 --- libprocessgroup/cgroup_map.cpp | 22 +--------- libprocessgroup/cgroup_map.h | 2 +- libprocessgroup/processgroup.cpp | 7 ++-- libprocessgroup/setup/cgroup_map_write.cpp | 42 +------------------ .../util/include/processgroup/util.h | 2 + libprocessgroup/util/util.cpp | 23 ++++++++++ 6 files changed, 33 insertions(+), 65 deletions(-) diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index 8180ccf3f..32bef13a1 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -194,24 +194,6 @@ CgroupControllerWrapper CgroupMap::FindControllerByPath(const std::string& path) return CgroupControllerWrapper(nullptr); } -int CgroupMap::ActivateControllers(const std::string& path) const { - for (const auto& [name, descriptor] : descriptors_) { - const uint32_t flags = descriptor.controller()->flags(); - const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); - const int depth = GetCgroupDepth(descriptor.controller()->path(), path); - - if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { - std::string str("+"); - str.append(descriptor.controller()->name()); - if (!WriteStringToFile(str, path + "/cgroup.subtree_control")) { - if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { - PLOG(WARNING) << "Activation of cgroup controller " << str - << " failed in path " << path; - } else { - return -errno; - } - } - } - } - return 0; +bool CgroupMap::ActivateControllers(const std::string& path) const { + return ::ActivateControllers(path, descriptors_); } diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index 5ad59bddf..fb9907645 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -58,7 +58,7 @@ class CgroupMap { static CgroupMap& GetInstance(); CgroupControllerWrapper FindController(const std::string& name) const; CgroupControllerWrapper FindControllerByPath(const std::string& path) const; - int ActivateControllers(const std::string& path) const; + bool ActivateControllers(const std::string& path) const; private: bool loaded_ = false; diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 83a2258bf..d3719eea3 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -662,10 +662,9 @@ static int createProcessGroupInternal(uid_t uid, pid_t initialPid, std::string c return -errno; } if (activate_controllers) { - ret = CgroupMap::GetInstance().ActivateControllers(uid_path); - if (ret) { - LOG(ERROR) << "Failed to activate controllers in " << uid_path; - return ret; + if (!CgroupMap::GetInstance().ActivateControllers(uid_path)) { + PLOG(ERROR) << "Failed to activate controllers in " << uid_path; + return -errno; } } diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index 821168008..d05bf2408 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -180,25 +180,7 @@ static bool ActivateV2CgroupController(const CgroupDescriptor& descriptor) { return false; } - if (controller->flags() & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && - controller->max_activation_depth() > 0) { - std::string str = "+"; - str += controller->name(); - std::string path = controller->path(); - path += "/cgroup.subtree_control"; - - if (!android::base::WriteStringToFile(str, path)) { - if (IsOptionalController(controller)) { - PLOG(INFO) << "Failed to activate optional controller " << controller->name() - << " at " << path; - return true; - } - PLOG(ERROR) << "Failed to activate controller " << controller->name(); - return false; - } - } - - return true; + return ::ActivateControllers(controller->path(), {{controller->name(), descriptor}}); } static bool MountV1CgroupController(const CgroupDescriptor& descriptor) { @@ -323,27 +305,7 @@ static bool CreateV2SubHierarchy(const std::string& path, const CgroupDescriptor // Activate all v2 controllers in path so they can be activated in // children as they are created. - for (const auto& [name, descriptor] : descriptors) { - const CgroupController* controller = descriptor.controller(); - std::uint32_t flags = controller->flags(); - std::uint32_t max_activation_depth = controller->max_activation_depth(); - const int depth = GetCgroupDepth(controller->path(), path); - - if (controller->version() == 2 && name != CGROUPV2_HIERARCHY_NAME && - flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { - std::string str("+"); - str += controller->name(); - if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) { - if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { - PLOG(WARNING) << "Activation of cgroup controller " << str << " failed in path " - << path; - } else { - return false; - } - } - } - } - return true; + return ::ActivateControllers(path, descriptors); } bool CgroupSetup() { diff --git a/libprocessgroup/util/include/processgroup/util.h b/libprocessgroup/util/include/processgroup/util.h index d592a6347..2c7b32926 100644 --- a/libprocessgroup/util/include/processgroup/util.h +++ b/libprocessgroup/util/include/processgroup/util.h @@ -31,3 +31,5 @@ unsigned int GetCgroupDepth(const std::string& controller_root, const std::strin using CgroupControllerName = std::string; using CgroupDescriptorMap = std::map; bool ReadDescriptors(CgroupDescriptorMap* descriptors); + +bool ActivateControllers(const std::string& path, const CgroupDescriptorMap& descriptors); diff --git a/libprocessgroup/util/util.cpp b/libprocessgroup/util/util.cpp index bff4c6f1a..14016751c 100644 --- a/libprocessgroup/util/util.cpp +++ b/libprocessgroup/util/util.cpp @@ -250,3 +250,26 @@ bool ReadDescriptors(CgroupDescriptorMap* descriptors) { return true; } + +bool ActivateControllers(const std::string& path, const CgroupDescriptorMap& descriptors) { + for (const auto& [name, descriptor] : descriptors) { + const uint32_t flags = descriptor.controller()->flags(); + const uint32_t max_activation_depth = descriptor.controller()->max_activation_depth(); + const unsigned int depth = GetCgroupDepth(descriptor.controller()->path(), path); + + if (flags & CGROUPRC_CONTROLLER_FLAG_NEEDS_ACTIVATION && depth < max_activation_depth) { + std::string str("+"); + str.append(descriptor.controller()->name()); + if (!android::base::WriteStringToFile(str, path + "/cgroup.subtree_control")) { + if (flags & CGROUPRC_CONTROLLER_FLAG_OPTIONAL) { + PLOG(WARNING) << "Activation of cgroup controller " << str + << " failed in path " << path; + } else { + return false; + } + } + } + } + return true; +} + From e69b2d427754fa1d9d2758c8068f0adda75095bf Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Tue, 8 Oct 2024 20:53:06 -0700 Subject: [PATCH 042/183] snapshotctl: Initialize snapshot pointer when reverting snapshots Test: snapshotctl revert-snapshots Bug: 368487904 Change-Id: I9743bf412d4bfcf508aeb046ec329568da4e2be1 Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapshotctl.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/snapshotctl.cpp b/fs_mgr/libsnapshot/snapshotctl.cpp index 97a8cb210..46de991d0 100644 --- a/fs_mgr/libsnapshot/snapshotctl.cpp +++ b/fs_mgr/libsnapshot/snapshotctl.cpp @@ -105,7 +105,7 @@ class MapSnapshots { bool FinishSnapshotWrites(); bool UnmapCowImagePath(std::string& name); bool DeleteSnapshots(); - bool CleanupSnapshot() { return sm_->PrepareDeviceToBootWithoutSnapshot(); } + bool CleanupSnapshot(); bool BeginUpdate(); bool ApplyUpdate(); @@ -495,6 +495,11 @@ bool MapSnapshots::UnmapCowImagePath(std::string& name) { return sm_->UnmapCowImage(name); } +bool MapSnapshots::CleanupSnapshot() { + sm_ = SnapshotManager::New(); + return sm_->PrepareDeviceToBootWithoutSnapshot(); +} + bool MapSnapshots::DeleteSnapshots() { sm_ = SnapshotManager::New(); lock_ = sm_->LockExclusive(); From 699faa849bee52c7671e7b5297715f7ac53bd022 Mon Sep 17 00:00:00 2001 From: Per Larsen Date: Wed, 9 Oct 2024 11:23:32 +0000 Subject: [PATCH 043/183] trusty: tipc-test: Fix D argument The D flag requires an argument so it should be followed by a colon in sopts. Adding the missing colon is necessary to prevent a segfault. Test: path/to/tipc-test -D VSOCK:200:1 Bug None Change-Id: I78119b7e42aba5d30b62d88ff5d94c01dbc2eb64 --- trusty/libtrusty/tipc-test/tipc_test.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c index 3cf0c05f9..121837dc0 100644 --- a/trusty/libtrusty/tipc-test/tipc_test.c +++ b/trusty/libtrusty/tipc-test/tipc_test.c @@ -67,7 +67,7 @@ static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl"; static const char* receiver_name = "com.android.trusty.memref.receiver"; static const size_t memref_chunk_size = 4096; -static const char* _sopts = "hsvDS:t:r:m:b:B:"; +static const char* _sopts = "hsvD:S:t:r:m:b:B:"; /* clang-format off */ static const struct option _lopts[] = { {"help", no_argument, 0, 'h'}, From 075008174220c3fcd28eb21b0215f3feb6678d35 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 9 Oct 2024 17:41:32 +0000 Subject: [PATCH 044/183] libprocessgroup: Remove prctl interface for setting timer slack Support for the procfs timerslack interface has existed since linux 4.6. All currently supported Android kernels are newer than 4.6, so remove the userspace support for the prctl interface leaving just the use of /proc//timerslack_ns. Bug: 372498744 Change-Id: Ib34cc6fbb4bab328cde51d60ac4e3b26a0d72851 --- libprocessgroup/task_profiles.cpp | 32 +++++++------------------------ libprocessgroup/task_profiles.h | 2 -- 2 files changed, 7 insertions(+), 27 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 67ecc1d50..bdee9ae75 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -203,33 +203,15 @@ bool SetClampsAction::ExecuteForTask(int) const { // To avoid issues in sdk_mac build #if defined(__ANDROID__) -bool SetTimerSlackAction::IsTimerSlackSupported(pid_t tid) { - auto file = StringPrintf("/proc/%d/timerslack_ns", tid); - - return (access(file.c_str(), W_OK) == 0); -} - bool SetTimerSlackAction::ExecuteForTask(pid_t tid) const { - static bool sys_supports_timerslack = IsTimerSlackSupported(tid); - - // v4.6+ kernels support the /proc//timerslack_ns interface. - // TODO: once we've backported this, log if the open(2) fails. - if (sys_supports_timerslack) { - auto file = StringPrintf("/proc/%d/timerslack_ns", tid); - if (!WriteStringToFile(std::to_string(slack_), file)) { - if (errno == ENOENT) { - // This happens when process is already dead - return true; - } - PLOG(ERROR) << "set_timerslack_ns write failed"; - } - } - - // TODO: Remove when /proc//timerslack_ns interface is backported. - if (tid == 0 || tid == GetThreadId()) { - if (prctl(PR_SET_TIMERSLACK, slack_) == -1) { - PLOG(ERROR) << "set_timerslack_ns prctl failed"; + const auto file = StringPrintf("/proc/%d/timerslack_ns", tid); + if (!WriteStringToFile(std::to_string(slack_), file)) { + if (errno == ENOENT) { + // This happens when process is already dead + return true; } + PLOG(ERROR) << "set_timerslack_ns write failed"; + return false; } return true; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index abb3ca5c3..2e31158d1 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -114,8 +114,6 @@ class SetTimerSlackAction : public ProfileAction { private: unsigned long slack_; - - static bool IsTimerSlackSupported(pid_t tid); }; // Set attribute profile element From b53eb9dbc6b81a08e296147cd9619a9066b8c430 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 9 Oct 2024 22:46:33 +0000 Subject: [PATCH 045/183] libprocessgroup: Use pid_t for ProfileAction::ExecuteForTask This was missed in commit 1c007996b ("libprocessgroup: Use pid_t consistently for TIDs"). Change-Id: Idefc9e7c2161ab3163bd1a0cb68b899e10e9c8ed --- libprocessgroup/task_profiles.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index abb3ca5c3..8ff20789c 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -77,7 +77,7 @@ class ProfileAction { // Default implementations will fail virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; } - virtual bool ExecuteForTask(int) const { return false; } + virtual bool ExecuteForTask(pid_t) const { return false; } virtual bool ExecuteForUID(uid_t) const { return false; } virtual void EnableResourceCaching(ResourceCacheType) {} From cea66e89a1124cc52005e56458dbbe21042c6824 Mon Sep 17 00:00:00 2001 From: Inseob Kim Date: Thu, 10 Oct 2024 17:15:47 +0900 Subject: [PATCH 046/183] Add dirgroup for trusty genrule Bug: 358302178 Test: m lk.elf.x86_64 lk.elf.arm64 Change-Id: Ic3e41c6a38aaa9dd87dbc4a0215c02d19b3063a0 --- Android.bp | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 Android.bp diff --git a/Android.bp b/Android.bp new file mode 100644 index 000000000..c77a80337 --- /dev/null +++ b/Android.bp @@ -0,0 +1,5 @@ +dirgroup { + name: "trusty_dirgroup_system_core", + dirs: ["."], + visibility: ["//trusty/vendor/google/aosp/scripts"], +} From 3e4b58e9d461c2fd554e6b2c1f45f708a5663acf Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Thu, 10 Oct 2024 16:23:55 +0000 Subject: [PATCH 047/183] libprocessgroup: Remove unused prctl include Fixes: 075008174 ("libprocessgroup: Remove prctl interface for setting timer slack") Test: m Bug: 372498744 Change-Id: Icb65d631cdc52b5f5434b33a593adf706314f66e --- libprocessgroup/task_profiles.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index bdee9ae75..7f33d4a40 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -37,11 +37,6 @@ #include -// To avoid issues in sdk_mac build -#if defined(__ANDROID__) -#include -#endif - using android::base::GetThreadId; using android::base::GetUintProperty; using android::base::StringPrintf; From 2a030efe67428b7dbf5163397b5acbf79752b224 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Thu, 10 Oct 2024 21:34:45 +0000 Subject: [PATCH 048/183] libprocessgroup: Remove SetClamps action The SetClamps profile action has always been a no-op. Remove the class and parsing code for this action. Bug: 372915523 Change-Id: Ic6e685aa992b83464dfb5e6446b622a57ed61db5 --- libprocessgroup/profiles/task_profiles.json | 27 ------------------- libprocessgroup/task_profiles.cpp | 29 --------------------- libprocessgroup/task_profiles.h | 13 --------- 3 files changed, 69 deletions(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index 411c38c80..feda3b49c 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -571,33 +571,6 @@ ] }, - { - "Name": "PerfBoost", - "Actions": [ - { - "Name": "SetClamps", - "Params": - { - "Boost": "50%", - "Clamp": "0" - } - } - ] - }, - { - "Name": "PerfClamp", - "Actions": [ - { - "Name": "SetClamps", - "Params": - { - "Boost": "0", - "Clamp": "30%" - } - } - ] - }, - { "Name": "LowMemoryUsage", "Actions": [ diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 7f33d4a40..ff0335592 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -183,18 +183,6 @@ bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const { return true; } -bool SetClampsAction::ExecuteForProcess(uid_t, pid_t) const { - // TODO: add support when kernel supports util_clamp - LOG(WARNING) << "SetClampsAction::ExecuteForProcess is not supported"; - return false; -} - -bool SetClampsAction::ExecuteForTask(int) const { - // TODO: add support when kernel supports util_clamp - LOG(WARNING) << "SetClampsAction::ExecuteForTask is not supported"; - return false; -} - // To avoid issues in sdk_mac build #if defined(__ANDROID__) @@ -902,23 +890,6 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { } else { LOG(WARNING) << "SetAttribute: unknown attribute: " << attr_name; } - } else if (action_name == "SetClamps") { - std::string boost_value = params_val["Boost"].asString(); - std::string clamp_value = params_val["Clamp"].asString(); - char* end; - unsigned long boost; - - boost = strtoul(boost_value.c_str(), &end, 10); - if (end > boost_value.c_str()) { - unsigned long clamp = strtoul(clamp_value.c_str(), &end, 10); - if (end > clamp_value.c_str()) { - profile->Add(std::make_unique(boost, clamp)); - } else { - LOG(WARNING) << "SetClamps: invalid parameter " << clamp_value; - } - } else { - LOG(WARNING) << "SetClamps: invalid parameter: " << boost_value; - } } else if (action_name == "WriteFile") { std::string attr_filepath = params_val["FilePath"].asString(); std::string attr_procfilepath = params_val["ProcFilePath"].asString(); diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index e52ce38fe..782b3ff0f 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -90,19 +90,6 @@ class ProfileAction { }; // Profile actions -class SetClampsAction : public ProfileAction { - public: - SetClampsAction(int boost, int clamp) noexcept : boost_(boost), clamp_(clamp) {} - - const char* Name() const override { return "SetClamps"; } - bool ExecuteForProcess(uid_t uid, pid_t pid) const override; - bool ExecuteForTask(pid_t tid) const override; - - protected: - int boost_; - int clamp_; -}; - class SetTimerSlackAction : public ProfileAction { public: SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {} From 900ef7bf3a7a76de8d98ba155484d31c52d1f3c9 Mon Sep 17 00:00:00 2001 From: Yihan Dong Date: Sat, 12 Oct 2024 08:52:31 +0000 Subject: [PATCH 049/183] Add proposed trendy teams for VTS modules Change-Id: I4f62c5105f51b37fe61efe3ea61a88036cfb4b96 Test: build locally Bug: 368362374 --- fs_mgr/libdm/Android.bp | 1 + fs_mgr/libfiemap/Android.bp | 1 + fs_mgr/liblp/Android.bp | 1 + fs_mgr/libsnapshot/Android.bp | 1 + fs_mgr/libsnapshot/snapuserd/Android.bp | 1 + libprocessgroup/profiles/Android.bp | 1 + 6 files changed, 6 insertions(+) diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp index c3ca758ae..1efd7debc 100644 --- a/fs_mgr/libdm/Android.bp +++ b/fs_mgr/libdm/Android.bp @@ -15,6 +15,7 @@ // package { + default_team: "trendy_team_android_kernel", default_applicable_licenses: ["Android-Apache-2.0"], } diff --git a/fs_mgr/libfiemap/Android.bp b/fs_mgr/libfiemap/Android.bp index c8d575630..a6be58582 100644 --- a/fs_mgr/libfiemap/Android.bp +++ b/fs_mgr/libfiemap/Android.bp @@ -15,6 +15,7 @@ // package { + default_team: "trendy_team_android_kernel", default_applicable_licenses: ["Android-Apache-2.0"], } diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp index 24eebdfb9..b211e83da 100644 --- a/fs_mgr/liblp/Android.bp +++ b/fs_mgr/liblp/Android.bp @@ -15,6 +15,7 @@ // package { + default_team: "trendy_team_android_kernel", default_applicable_licenses: ["Android-Apache-2.0"], } diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 50efb03bd..966696b05 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -15,6 +15,7 @@ // package { + default_team: "trendy_team_android_kernel", default_applicable_licenses: ["Android-Apache-2.0"], } diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 298fd9f30..0314d2528 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -15,6 +15,7 @@ // package { + default_team: "trendy_team_android_kernel", default_applicable_licenses: ["Android-Apache-2.0"], } diff --git a/libprocessgroup/profiles/Android.bp b/libprocessgroup/profiles/Android.bp index 1ec9f7f3b..baa454646 100644 --- a/libprocessgroup/profiles/Android.bp +++ b/libprocessgroup/profiles/Android.bp @@ -13,6 +13,7 @@ // limitations under the License. package { + default_team: "trendy_team_android_kernel", default_applicable_licenses: ["Android-Apache-2.0"], } From 9081b85a1d36b563dbd864fec5ace67e59fa9c54 Mon Sep 17 00:00:00 2001 From: Yihan Dong Date: Sat, 12 Oct 2024 08:53:19 +0000 Subject: [PATCH 050/183] Add proposed trendy teams for VTS modules Change-Id: Ic9eeddd1d7286f38806d4a422914964cf2a80073 Test: build locally Bug: 368362374 --- libcutils/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 3c3eeb663..db4e964ff 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -1,4 +1,5 @@ package { + default_team: "trendy_team_native_tools_libraries", default_applicable_licenses: ["system_core_libcutils_license"], } From 44884d5c319647b499241386b750b7a763581541 Mon Sep 17 00:00:00 2001 From: Newton Lam Date: Mon, 14 Oct 2024 20:52:32 +0000 Subject: [PATCH 051/183] Use uint64_t instead of size_t when calculating extent size to avoid overflow Change-Id: I22a77162d08fd7e82ffaa3e0c6c8adb6e956f7d1 --- fs_mgr/liblp/super_layout_builder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/liblp/super_layout_builder.cpp b/fs_mgr/liblp/super_layout_builder.cpp index fd7416bb2..bff26ea21 100644 --- a/fs_mgr/liblp/super_layout_builder.cpp +++ b/fs_mgr/liblp/super_layout_builder.cpp @@ -184,7 +184,7 @@ std::vector SuperLayoutBuilder::GetImageLayout() { return {}; } - size_t size = e.num_sectors * LP_SECTOR_SIZE; + uint64_t size = e.num_sectors * LP_SECTOR_SIZE; uint64_t super_offset = e.target_data * LP_SECTOR_SIZE; extents.emplace_back(super_offset, size, image_name, image_offset); From 3984611601e9cc8c41b996e8e6dc543b383e0922 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 9 Oct 2024 22:40:26 +0000 Subject: [PATCH 052/183] libprocessgroup: Add SetSchedulerPolicy Action Add a new profile action that allows users to set a scheduler policy and priority for a thread when a profile with the action is applied. This can be used with the POSIX policies specified in the sched_setscheduler man page. A priority value is required for real-time policies. A nice value may optionally be provided for normal policies. If a normal policy is used and a nice value is provided, it will be applied with setpriority() after the scheduler policy is applied. The range of nice values that can be used in the task profiles JSON in this case is [-20, 19]. If a real-time policy is used, the range of priorities that can be used in the task profiles JSON is [1, 99] which will be mapped onto [sched_get_priority_min(), sched_get_priority_max()] at runtime for the the provided policy. Here are some examples: Use lowest-priority with FIFO policy: "Actions": [ { "Name": "SetSchedulerPolicy", "Params": { "Policy": "SCHED_FIFO", "Priority": 1 } } ] Use highest-priority (lowest nice) with standard NORMAL scheduler: "Actions": [ { "Name": "SetSchedulerPolicy", "Params": { "Policy": "SCHED_OTHER", "Nice": -20 } } ] Bug: 368072932 BYPASS_INCLUSIVE_LANGUAGE_REASON=false positive Change-Id: I502ceb3913016e9f4e6b6322cc0eee905c9a5c9a --- libprocessgroup/task_profiles.cpp | 120 +++++++++++++++++++++++++++++- libprocessgroup/task_profiles.h | 20 +++++ 2 files changed, 136 insertions(+), 4 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 7f33d4a40..110ef5267 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -17,11 +17,16 @@ //#define LOG_NDEBUG 0 #define LOG_TAG "libprocessgroup" +#include + +#include +#include + #include #include +#include +#include #include -#include -#include #include #include @@ -30,13 +35,13 @@ #include #include +#include + #include #include #include -#include - using android::base::GetThreadId; using android::base::GetUintProperty; using android::base::StringPrintf; @@ -649,6 +654,57 @@ bool WriteFileAction::IsValidForTask(int) const { return access(task_path_.c_str(), W_OK) == 0; } +bool SetSchedulerPolicyAction::isNormalPolicy(int policy) { + return policy == SCHED_OTHER || policy == SCHED_BATCH || policy == SCHED_IDLE; +} + +bool SetSchedulerPolicyAction::toPriority(int policy, int virtual_priority, int& priority_out) { + constexpr int VIRTUAL_PRIORITY_MIN = 1; + constexpr int VIRTUAL_PRIORITY_MAX = 99; + + if (virtual_priority < VIRTUAL_PRIORITY_MIN || virtual_priority > VIRTUAL_PRIORITY_MAX) { + LOG(WARNING) << "SetSchedulerPolicy: invalid priority (" << virtual_priority + << ") for policy (" << policy << ")"; + return false; + } + + const int min = sched_get_priority_min(policy); + if (min == -1) { + PLOG(ERROR) << "SetSchedulerPolicy: Cannot get min sched priority for policy " << policy; + return false; + } + + const int max = sched_get_priority_max(policy); + if (max == -1) { + PLOG(ERROR) << "SetSchedulerPolicy: Cannot get max sched priority for policy " << policy; + return false; + } + + priority_out = min + (virtual_priority - VIRTUAL_PRIORITY_MIN) * (max - min) / + (VIRTUAL_PRIORITY_MAX - VIRTUAL_PRIORITY_MIN); + + return true; +} + +bool SetSchedulerPolicyAction::ExecuteForTask(pid_t tid) const { + struct sched_param param = {}; + param.sched_priority = isNormalPolicy(policy_) ? 0 : *priority_or_nice_; + if (sched_setscheduler(tid, policy_, ¶m) == -1) { + PLOG(WARNING) << "SetSchedulerPolicy: Failed to apply scheduler policy (" << policy_ + << ") with priority (" << *priority_or_nice_ << ") to tid " << tid; + return false; + } + + if (isNormalPolicy(policy_) && priority_or_nice_ && + setpriority(PRIO_PROCESS, tid, *priority_or_nice_) == -1) { + PLOG(WARNING) << "SetSchedulerPolicy: Failed to apply nice (" << *priority_or_nice_ + << ") to tid " << tid; + return false; + } + + return true; +} + bool ApplyProfileAction::ExecuteForProcess(uid_t uid, pid_t pid) const { for (const auto& profile : profiles_) { profile->ExecuteForProcess(uid, pid); @@ -936,6 +992,62 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { LOG(WARNING) << "WriteFile: invalid parameter: " << "empty value"; } + } else if (action_name == "SetSchedulerPolicy") { + const std::map POLICY_MAP = { + {"SCHED_OTHER", SCHED_OTHER}, + {"SCHED_BATCH", SCHED_BATCH}, + {"SCHED_IDLE", SCHED_IDLE}, + {"SCHED_FIFO", SCHED_FIFO}, + {"SCHED_RR", SCHED_RR}, + }; + const std::string policy_str = params_val["Policy"].asString(); + + const auto it = POLICY_MAP.find(policy_str); + if (it == POLICY_MAP.end()) { + LOG(WARNING) << "SetSchedulerPolicy: invalid policy " << policy_str; + continue; + } + + const int policy = it->second; + + if (SetSchedulerPolicyAction::isNormalPolicy(policy)) { + if (params_val.isMember("Priority")) { + LOG(WARNING) << "SetSchedulerPolicy: Normal policies (" << policy_str + << ") use Nice values, not Priority values"; + } + + if (params_val.isMember("Nice")) { + // If present, this optional value will be passed in an additional syscall + // to setpriority(), since the sched_priority value must be 0 for calls to + // sched_setscheduler() with "normal" policies. + const int nice = params_val["Nice"].asInt(); + + const int LINUX_MIN_NICE = -20; + const int LINUX_MAX_NICE = 19; + if (nice < LINUX_MIN_NICE || nice > LINUX_MAX_NICE) { + LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << nice + << ") appears out of range."; + } + profile->Add(std::make_unique(policy, nice)); + } else { + profile->Add(std::make_unique(policy)); + } + } else { + if (params_val.isMember("Nice")) { + LOG(WARNING) << "SetSchedulerPolicy: Real-time policies (" << policy_str + << ") use Priority values, not Nice values"; + } + + // This is a "virtual priority" as described by `man 2 sched_get_priority_min` + // that will be mapped onto the following range for the provided policy: + // [sched_get_priority_min(), sched_get_priority_max()] + const int virtual_priority = params_val["Priority"].asInt(); + + int priority; + if (SetSchedulerPolicyAction::toPriority(policy, virtual_priority, priority)) { + profile->Add(std::make_unique(policy, priority)); + } + } } else { LOG(WARNING) << "Unknown profile action: " << action_name; } diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index e52ce38fe..ea948b58e 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -187,6 +188,25 @@ class WriteFileAction : public ProfileAction { CacheUseResult UseCachedFd(ResourceCacheType cache_type, const std::string& value) const; }; +// Set scheduler policy action +class SetSchedulerPolicyAction : public ProfileAction { + public: + SetSchedulerPolicyAction(int policy) + : policy_(policy) {} + SetSchedulerPolicyAction(int policy, int priority_or_nice) + : policy_(policy), priority_or_nice_(priority_or_nice) {} + + const char* Name() const override { return "SetSchedulerPolicy"; } + bool ExecuteForTask(pid_t tid) const override; + + static bool isNormalPolicy(int policy); + static bool toPriority(int policy, int virtual_priority, int& priority_out); + + private: + int policy_; + std::optional priority_or_nice_; +}; + class TaskProfile { public: TaskProfile(const std::string& name) : name_(name), res_cached_(false) {} From a6af9bced3f7d7c25d62db36b404cf21b5fbf51d Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Tue, 15 Oct 2024 14:41:49 +0900 Subject: [PATCH 053/183] init: filter .##rc with preview SDK version On a preview device (where codename is not "REL"), filtering .##rc files will choose the highest versions reglardless of ro.build.version.sdk. Bug: n/a Test: add .36rc to an apex and see if init reads it. Change-Id: Icd63cf70e45cc14504f839ce9492e1766147a40e --- init/apex_init_util.cpp | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/init/apex_init_util.cpp b/init/apex_init_util.cpp index e5a7fbcc0..809c805c4 100644 --- a/init/apex_init_util.cpp +++ b/init/apex_init_util.cpp @@ -101,14 +101,21 @@ std::set GetApexListFrom(const std::string& apex_dir) { return apex_list; } +static int GetCurrentSdk() { + bool is_preview = base::GetProperty("ro.build.version.codename", "") != "REL"; + if (is_preview) { + return __ANDROID_API_FUTURE__; + } + return android::base::GetIntProperty("ro.build.version.sdk", __ANDROID_API_FUTURE__); +} + static Result ParseRcScripts(const std::vector& files) { if (files.empty()) { return {}; } // APEXes can have versioned RC files. These should be filtered based on // SDK version. - int sdk = android::base::GetIntProperty("ro.build.version.sdk", INT_MAX); - if (sdk < 35) sdk = 35; // aosp/main merges only into sdk=35+ (ie. __ANDROID_API_V__+) + static int sdk = GetCurrentSdk(); auto filtered = FilterVersionedConfigs(files, sdk); if (filtered.empty()) { return {}; From 3aac36201bc75159cfa801f92765574ce1c77636 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 18 Oct 2024 21:51:45 +0000 Subject: [PATCH 054/183] Remove log spam. When dumping, the code checks if a thread is running as a guest. If it's not, the code always logs an error message if the header data structure cannot be read. Don't print an error message in this case. Test: Crash and no longer see "failed to get the guest state header" Test: message. Change-Id: I6971b57b218a4f653682cfdc82118dc576d9e331 --- debuggerd/crash_dump.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index c9235eeff..15e8319a9 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -470,14 +470,12 @@ static bool GetGuestRegistersFromCrashedProcess([[maybe_unused]] pid_t tid, } NativeBridgeGuestStateHeader header; - if (!process_memory->ReadFully(header_ptr, &header, sizeof(NativeBridgeGuestStateHeader))) { - PLOG(ERROR) << "failed to get the guest state header for thread " << tid; - return false; - } - if (header.signature != NATIVE_BRIDGE_GUEST_STATE_SIGNATURE) { + if (!process_memory->ReadFully(header_ptr, &header, sizeof(NativeBridgeGuestStateHeader)) || + header.signature != NATIVE_BRIDGE_GUEST_STATE_SIGNATURE) { // Return when ptr points to unmapped memory or no valid guest state. return false; } + auto guest_state_data_copy = std::make_unique(header.guest_state_data_size); if (!process_memory->ReadFully(reinterpret_cast(header.guest_state_data), guest_state_data_copy.get(), header.guest_state_data_size)) { From 5ad59a4cffaefd77c137fe5d2bddd43db67a75d7 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Fri, 18 Oct 2024 11:39:44 -0700 Subject: [PATCH 055/183] libsnapshot: Resume snapshot merge if snapshots are in second phase If the device reboots when SnapshotUpdateStatus switches from first phase to second phase, then track the transition and resume the merge. Bug: 374225913 Test: OTA on Pixel - Verify merge resumes when device reboots just after first phase merge Change-Id: I5f62a03852a4b012850b11d0c1e6b96ec0556278 Signed-off-by: Akilesh Kailash --- .../include/libsnapshot/snapshot.h | 1 + fs_mgr/libsnapshot/snapshot.cpp | 29 +++- fs_mgr/libsnapshot/snapshot_test.cpp | 140 ++++++++++++++++++ 3 files changed, 166 insertions(+), 4 deletions(-) diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index 8ff41dbcb..de2052631 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -442,6 +442,7 @@ class SnapshotManager final : public ISnapshotManager { FRIEND_TEST(SnapshotUpdateTest, QueryStatusError); FRIEND_TEST(SnapshotUpdateTest, SnapshotStatusFileWithoutCow); FRIEND_TEST(SnapshotUpdateTest, SpaceSwapUpdate); + FRIEND_TEST(SnapshotUpdateTest, InterruptMergeDuringPhaseUpdate); FRIEND_TEST(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch); friend class SnapshotTest; friend class SnapshotUpdateTest; diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 05dec68d5..acabd6770 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -1343,10 +1343,25 @@ auto SnapshotManager::CheckTargetMergeState(LockedFile* lock, const std::string& } if (merge_status == "snapshot" && - DecideMergePhase(snapshot_status) == MergePhase::SECOND_PHASE && - update_status.merge_phase() == MergePhase::FIRST_PHASE) { - // The snapshot is not being merged because it's in the wrong phase. - return MergeResult(UpdateState::None); + DecideMergePhase(snapshot_status) == MergePhase::SECOND_PHASE) { + if (update_status.merge_phase() == MergePhase::FIRST_PHASE) { + // The snapshot is not being merged because it's in the wrong phase. + return MergeResult(UpdateState::None); + } else { + // update_status is already in second phase but the + // snapshot_status is still not set to SnapshotState::MERGING. + // + // Resume the merge at this point. see b/374225913 + LOG(INFO) << "SwitchSnapshotToMerge: " << name << " after resuming merge"; + auto code = SwitchSnapshotToMerge(lock, name); + if (code != MergeFailureCode::Ok) { + LOG(ERROR) << "Failed to switch snapshot: " << name + << " to merge during second phase"; + return MergeResult(UpdateState::MergeFailed, + MergeFailureCode::UnknownTargetType); + } + return MergeResult(UpdateState::Merging); + } } if (merge_status == "snapshot-merge") { @@ -1442,8 +1457,14 @@ MergeFailureCode SnapshotManager::MergeSecondPhaseSnapshots(LockedFile* lock) { return MergeFailureCode::WriteStatus; } + auto current_slot_suffix = device_->GetSlotSuffix(); MergeFailureCode result = MergeFailureCode::Ok; for (const auto& snapshot : snapshots) { + if (!android::base::EndsWith(snapshot, current_slot_suffix)) { + LOG(ERROR) << "Skipping invalid snapshot: " << snapshot + << " during MergeSecondPhaseSnapshots"; + continue; + } SnapshotStatus snapshot_status; if (!ReadSnapshotStatus(lock, snapshot, &snapshot_status)) { return MergeFailureCode::ReadStatus; diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 46c3a35e9..3e5ae2aff 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -1607,6 +1607,146 @@ TEST_F(SnapshotUpdateTest, SpaceSwapUpdate) { } } +// Test that shrinking and growing partitions at the same time is handled +// correctly in VABC. +TEST_F(SnapshotUpdateTest, InterruptMergeDuringPhaseUpdate) { + if (!snapuserd_required_) { + // b/179111359 + GTEST_SKIP() << "Skipping snapuserd test"; + } + + auto old_sys_size = GetSize(sys_); + auto old_prd_size = GetSize(prd_); + + // Grow |sys| but shrink |prd|. + SetSize(sys_, old_sys_size * 2); + sys_->set_estimate_cow_size(8_MiB); + SetSize(prd_, old_prd_size / 2); + prd_->set_estimate_cow_size(1_MiB); + + AddOperationForPartitions(); + + ASSERT_TRUE(sm->BeginUpdate()); + ASSERT_TRUE(sm->CreateUpdateSnapshots(manifest_)); + + // Check that the old partition sizes were saved correctly. + { + ASSERT_TRUE(AcquireLock()); + auto local_lock = std::move(lock_); + + SnapshotStatus status; + ASSERT_TRUE(sm->ReadSnapshotStatus(local_lock.get(), "prd_b", &status)); + ASSERT_EQ(status.old_partition_size(), 3145728); + ASSERT_TRUE(sm->ReadSnapshotStatus(local_lock.get(), "sys_b", &status)); + ASSERT_EQ(status.old_partition_size(), 3145728); + } + + ASSERT_TRUE(WriteSnapshotAndHash(sys_)); + ASSERT_TRUE(WriteSnapshotAndHash(vnd_)); + ASSERT_TRUE(ShiftAllSnapshotBlocks("prd_b", old_prd_size)); + + sync(); + + // Assert that source partitions aren't affected. + for (const auto& name : {"sys_a", "vnd_a", "prd_a"}) { + ASSERT_TRUE(IsPartitionUnchanged(name)); + } + + ASSERT_TRUE(sm->FinishedSnapshotWrites(false)); + + // Simulate shutting down the device. + ASSERT_TRUE(UnmapAll()); + + // After reboot, init does first stage mount. + auto init = NewManagerForFirstStageMount("_b"); + ASSERT_NE(init, nullptr); + ASSERT_TRUE(init->NeedSnapshotsInFirstStageMount()); + ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_)); + + // Check that the target partitions have the same content. + for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) { + ASSERT_TRUE(IsPartitionUnchanged(name)); + } + + // Initiate the merge and wait for it to be completed. + if (ShouldSkipLegacyMerging()) { + LOG(INFO) << "Skipping legacy merge in test"; + return; + } + ASSERT_TRUE(init->InitiateMerge()); + ASSERT_EQ(init->IsSnapuserdRequired(), snapuserd_required_); + { + // Check that the merge phase is FIRST_PHASE until at least one call + // to ProcessUpdateState() occurs. + ASSERT_TRUE(AcquireLock()); + auto local_lock = std::move(lock_); + auto status = init->ReadSnapshotUpdateStatus(local_lock.get()); + ASSERT_EQ(status.merge_phase(), MergePhase::FIRST_PHASE); + } + + // Wait until prd_b merge is completed which is part of first phase + std::chrono::milliseconds timeout(6000); + auto start = std::chrono::steady_clock::now(); + // Keep polling until the merge is complete or timeout is reached + while (true) { + // Query the merge status + const auto merge_status = init->snapuserd_client()->QuerySnapshotStatus("prd_b"); + if (merge_status == "snapshot-merge-complete") { + break; + } + + auto now = std::chrono::steady_clock::now(); + auto elapsed = std::chrono::duration_cast(now - start); + + ASSERT_TRUE(elapsed < timeout); + // sleep for a second and allow merge to complete + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + } + + // Now, forcefully update the snapshot-update status to SECOND PHASE + // This will not update the snapshot status of sys_b to MERGING + if (init->UpdateUsesUserSnapshots()) { + ASSERT_TRUE(AcquireLock()); + auto local_lock = std::move(lock_); + auto status = init->ReadSnapshotUpdateStatus(local_lock.get()); + status.set_merge_phase(MergePhase::SECOND_PHASE); + ASSERT_TRUE(init->WriteSnapshotUpdateStatus(local_lock.get(), status)); + } + + // Simulate shutting down the device and creating partitions again. + ASSERT_TRUE(UnmapAll()); + ASSERT_TRUE(init->CreateLogicalAndSnapshotPartitions("super", snapshot_timeout_)); + + DeviceMapper::TargetInfo target; + ASSERT_TRUE(init->IsSnapshotDevice("prd_b", &target)); + + ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user"); + ASSERT_TRUE(init->IsSnapshotDevice("sys_b", &target)); + ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user"); + ASSERT_TRUE(init->IsSnapshotDevice("vnd_b", &target)); + ASSERT_EQ(DeviceMapper::GetTargetType(target.spec), "user"); + + // Complete the merge; "sys" and "vnd" should resume the merge + // even though merge was interrupted after update_status was updated to + // SECOND_PHASE + ASSERT_EQ(UpdateState::MergeCompleted, init->ProcessUpdateState()); + + // Make sure the second phase ran and deleted snapshots. + { + ASSERT_TRUE(AcquireLock()); + auto local_lock = std::move(lock_); + std::vector snapshots; + ASSERT_TRUE(init->ListSnapshots(local_lock.get(), &snapshots)); + ASSERT_TRUE(snapshots.empty()); + } + + // Check that the target partitions have the same content after the merge. + for (const auto& name : {"sys_b", "vnd_b", "prd_b"}) { + ASSERT_TRUE(IsPartitionUnchanged(name)) + << "Content of " << name << " changes after the merge"; + } +} + // Test that if new system partitions uses empty space in super, that region is not snapshotted. TEST_F(SnapshotUpdateTest, DirectWriteEmptySpace) { GTEST_SKIP() << "b/141889746"; From cbe09a8058076836f9023bf8869c4ad74cbfbc2b Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Mon, 21 Oct 2024 17:10:34 +0000 Subject: [PATCH 056/183] Remove carlosgalo from libprocessgroup OWNERS Change-Id: I37cac7694491a7efe16e835776dcd8be7335eabe --- libprocessgroup/OWNERS | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libprocessgroup/OWNERS b/libprocessgroup/OWNERS index d5aa7211a..accd7dfcc 100644 --- a/libprocessgroup/OWNERS +++ b/libprocessgroup/OWNERS @@ -1,4 +1,3 @@ # Bug component: 1293033 surenb@google.com -tjmercier@google.com -carlosgalo@google.com +tjmercier@google.com \ No newline at end of file From 5331393cb152a7eed05ee958b88c722518044714 Mon Sep 17 00:00:00 2001 From: Spandan Das Date: Mon, 21 Oct 2024 22:00:11 +0000 Subject: [PATCH 057/183] Mark the phony shell_and_utilities_vendor as vendor: true As part of the make to soong conversion, we are currently autogenerating android_filesystem soong modules for each partition (system, system_ext, vendor, ...), with the goal to eventually substitute the kati built partitions. In order to generate the deps of these partitions, we are currently using a heuristic to classify the modules in `PRODUCT_PACKAGES` with the associated partition. Mark the phony module `shell_and_utilities_vendor` as `vendor: true` to help with this conversion heursitic. Bug: 374371755 Test: verified that /bin/awk is present in the autogenerated soong-built vendor partition Change-Id: I0a99275fb03fbb9adeb1502734759f433585ef25 --- shell_and_utilities/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp index d5893de63..1f5c1795c 100644 --- a/shell_and_utilities/Android.bp +++ b/shell_and_utilities/Android.bp @@ -58,6 +58,7 @@ phony { "toolbox_vendor", "toybox_vendor", ], + vendor: true, } // shell and utilities for first stage console. The list of binaries are From a190ecb6f16b025a9c0c82f4c15ef5f759cd7e97 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Mon, 21 Oct 2024 23:01:56 +0000 Subject: [PATCH 058/183] RefBase: document leak memory case We should fix the leak, but it introduces the possibility that something is use this. Instead, document best practice (not to allocate RefBase objects on the stack). Fixes: 295340906 Test: N/A Change-Id: Ife7a561f790dc687fb99b73729818e61834fa272 --- libutils/binder/RefBase.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libutils/binder/RefBase.cpp b/libutils/binder/RefBase.cpp index 2d2e40b7e..4291f1e21 100644 --- a/libutils/binder/RefBase.cpp +++ b/libutils/binder/RefBase.cpp @@ -787,7 +787,7 @@ RefBase::~RefBase() // sp(T*) constructor, assuming that if the object is around, it is already // owned by an sp<>. ALOGW("RefBase: Explicit destruction, weak count = %d (in %p). Use sp<> to manage this " - "object.", + "object. Note - if weak count is 0, this leaks mRefs (weakref_impl).", mRefs->mWeak.load(), this); #if ANDROID_UTILS_CALLSTACK_ENABLED From 68c2cbf2befa57a9477df27c3c699fdb46f9d5b0 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Mon, 21 Oct 2024 10:04:01 -0700 Subject: [PATCH 059/183] libsnapshot: Fix MapAllSnapshotsWithoutSlotSwitch test IsUserspaceSnapshotUpdateInProgress() would return dm partitions which are backed by verity; this check is invalid for tests. Bug: 369964380 Test: vts_libsnapshot_test64 --gtest_filter=SnapshotUpdateTest.MapAllSnapshotsWithoutSlotSwitch Change-Id: I7d207c472077042ea07b65bf81b64c9c240ae8c7 Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapshot_test.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index 3e5ae2aff..1a0d55979 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2658,9 +2658,6 @@ TEST_F(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch) { // Remove the indicators ASSERT_TRUE(sm->PrepareDeviceToBootWithoutSnapshot()); - // Ensure snapshots are still mounted - ASSERT_TRUE(sm->IsUserspaceSnapshotUpdateInProgress()); - // Cleanup snapshots ASSERT_TRUE(sm->UnmapAllSnapshots()); } From 09c18c17fd00a60f50e8958eddf6b4e4b9dd9760 Mon Sep 17 00:00:00 2001 From: Cole Faust Date: Tue, 22 Oct 2024 16:31:05 -0700 Subject: [PATCH 060/183] Remove dependencies on the 1-variant fallback When adding a dependencies, if the variants don't match, but the dependency only has 1 variant anyways, soong will always use that variant. This makes it hard to add new variants to soong, because the 1-variant fallback stops being used and you start getting missing variant errors. Make changes to bp files such that all dependencies correctly specify the variant to use. Bug: 372091092 Flag: EXEMPT refactor Test: m nothing Change-Id: I35a5ac0e6b63080f692be6597edf5f213c4e7acb --- debuggerd/test_permissive_mte/Android.bp | 2 +- init/test_upgrade_mte/Android.bp | 35 +++++++++++++++--------- 2 files changed, 23 insertions(+), 14 deletions(-) diff --git a/debuggerd/test_permissive_mte/Android.bp b/debuggerd/test_permissive_mte/Android.bp index 0ad32439d..f333242cc 100644 --- a/debuggerd/test_permissive_mte/Android.bp +++ b/debuggerd/test_permissive_mte/Android.bp @@ -39,7 +39,7 @@ java_test_host { "src/**/PermissiveMteTest.java", ":libtombstone_proto-src", ], - data: [":mte_crash"], + device_first_data: [":mte_crash"], test_config: "AndroidTest.xml", test_suites: ["general-tests"], } diff --git a/init/test_upgrade_mte/Android.bp b/init/test_upgrade_mte/Android.bp index 1bfc76c69..dfea325a2 100644 --- a/init/test_upgrade_mte/Android.bp +++ b/init/test_upgrade_mte/Android.bp @@ -17,25 +17,34 @@ package { } cc_binary { - name: "mte_upgrade_test_helper", - srcs: ["mte_upgrade_test_helper.cpp"], - sanitize: { - memtag_heap: true, - diag: { - memtag_heap: false, + name: "mte_upgrade_test_helper", + srcs: ["mte_upgrade_test_helper.cpp"], + sanitize: { + memtag_heap: true, + diag: { + memtag_heap: false, + }, }, - }, - init_rc: [ - "mte_upgrade_test.rc", - ], + init_rc: [ + "mte_upgrade_test.rc", + ], } java_test_host { name: "mte_upgrade_test", libs: ["tradefed"], - static_libs: ["frameworks-base-hostutils", "cts-install-lib-host"], - srcs: ["src/**/MteUpgradeTest.java", ":libtombstone_proto-src"], - data: [":mte_upgrade_test_helper", "mte_upgrade_test.rc" ], + static_libs: [ + "frameworks-base-hostutils", + "cts-install-lib-host", + ], + srcs: [ + "src/**/MteUpgradeTest.java", + ":libtombstone_proto-src", + ], + device_first_data: [ + ":mte_upgrade_test_helper", + "mte_upgrade_test.rc", + ], test_config: "AndroidTest.xml", test_suites: ["general-tests"], } From 77dc1e7df326b126b7a40e836c9b8efa5d76e2e5 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Mon, 21 Oct 2024 10:04:01 -0700 Subject: [PATCH 061/183] libsnapshot: Fix MapAllSnapshotsWithoutSlotSwitch test IsUserspaceSnapshotUpdateInProgress() would return dm partitions which are backed by verity; this check is invalid for tests. Bug: 369964380 Test: vts_libsnapshot_test64 --gtest_filter=SnapshotUpdateTest.MapAllSnapshotsWithoutSlotSwitch Change-Id: I7d207c472077042ea07b65bf81b64c9c240ae8c7 Signed-off-by: Akilesh Kailash (cherry picked from commit 68c2cbf2befa57a9477df27c3c699fdb46f9d5b0) --- fs_mgr/libsnapshot/snapshot_test.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/fs_mgr/libsnapshot/snapshot_test.cpp b/fs_mgr/libsnapshot/snapshot_test.cpp index bf16b0fb3..ba86a51de 100644 --- a/fs_mgr/libsnapshot/snapshot_test.cpp +++ b/fs_mgr/libsnapshot/snapshot_test.cpp @@ -2513,9 +2513,6 @@ TEST_F(SnapshotUpdateTest, MapAllSnapshotsWithoutSlotSwitch) { // Remove the indicators ASSERT_TRUE(sm->PrepareDeviceToBootWithoutSnapshot()); - // Ensure snapshots are still mounted - ASSERT_TRUE(sm->IsUserspaceSnapshotUpdateInProgress()); - // Cleanup snapshots ASSERT_TRUE(sm->UnmapAllSnapshots()); } From 03f7133b0efe03ff0f144f1731c11bdd5098691f Mon Sep 17 00:00:00 2001 From: Karuna Wadhera Date: Wed, 23 Oct 2024 04:05:49 +0000 Subject: [PATCH 062/183] Pin KeyMint dependency to correct/specific version libkeymint depends on the latest version of the HAL, which will soon be bumped to v4. Since this implementation won't immediately be upgraded, and this dependency seems unused, remove it. Bug: 369375199 Test: Treehugger Change-Id: I5e952595bb4d4d8a283b286b5054576394788f16 --- trusty/keymaster/Android.bp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp index aca59b6c6..cb078299e 100644 --- a/trusty/keymaster/Android.bp +++ b/trusty/keymaster/Android.bp @@ -105,19 +105,17 @@ cc_binary { "keymint/TrustySharedSecret.cpp", "keymint/service.cpp", ], - defaults: [ - "keymint_use_latest_hal_aidl_ndk_shared", - ], shared_libs: [ + "android.hardware.security.keymint-V3-ndk", "android.hardware.security.rkp-V3-ndk", "android.hardware.security.secureclock-V1-ndk", "android.hardware.security.sharedsecret-V1-ndk", - "lib_android_keymaster_keymint_utils", + "lib_android_keymaster_keymint_utils_V3", "libbase", "libbinder_ndk", "libhardware", "libkeymaster_messages", - "libkeymint", + "libkeymasterconfig", "liblog", "libtrusty", "libutils", From 5bfb93678fa26e9763699669e6bbf1c2c6a7478d Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Thu, 24 Oct 2024 07:28:25 +0000 Subject: [PATCH 063/183] Revert^2 "init: Look for super partition only on a boot device" This reverts commit 8d71220df28851a7dce351f86601958fdbc3e5ae. Reason for revert: Fix for gcar emulator (basically all QEMU-based emulators) landed at aosp/3315253 and aosp/3160116. Change-Id: If4eddd3f7e224c31019ad3bd752e2375c7567780 --- init/block_dev_initializer.cpp | 6 +++++- init/devices.cpp | 22 ++++++++++++++++++++++ init/devices.h | 1 + 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index 8f5215856..cabeb0109 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -98,7 +98,11 @@ ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent, LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name; - devices->erase(iter); + // Remove partition from the list only if it was found on boot device + if (device_handler_->IsBootDevice(uevent)) { + devices->erase(iter); + } + device_handler_->HandleUevent(uevent); return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue; } diff --git a/init/devices.cpp b/init/devices.cpp index f2bb9d276..6a3a64dd8 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -188,6 +188,28 @@ void SysfsPermissions::SetPermissions(const std::string& path) const { } } +bool DeviceHandler::IsBootDevice(const Uevent& uevent) const { + std::string device; + + if (FindPlatformDevice(uevent.path, &device)) { + // Skip /devices/platform or /devices/ if present + static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; + static constexpr std::string_view devices_prefix = "/devices/"; + + if (StartsWith(device, devices_platform_prefix)) { + device = device.substr(devices_platform_prefix.length()); + } else if (StartsWith(device, devices_prefix)) { + device = device.substr(devices_prefix.length()); + } + } else if (FindPciDevicePrefix(uevent.path, &device)) { + } else if (FindVbdDevicePrefix(uevent.path, &device)) { + } else { + return false; + } + + return boot_devices_.find(device) != boot_devices_.end(); +} + std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) { static const auto partition_map = [] { std::vector> partition_map; diff --git a/init/devices.h b/init/devices.h index 6da123259..4df604d00 100644 --- a/init/devices.h +++ b/init/devices.h @@ -133,6 +133,7 @@ class DeviceHandler : public UeventHandler { // `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to // `userdata`. static std::string GetPartitionNameForDevice(const std::string& device); + bool IsBootDevice(const Uevent& uevent) const; private: void ColdbootDone() override; From 9b9233f4c1c31819fcd0fbc761f3b7ba6bd94344 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Oct 2024 11:01:08 -0700 Subject: [PATCH 064/183] libdm: Redact keys from dm-crypt targets when calling GetTable. Ignore-AOSP-First: security fix Bug: 368069390 Test: libdm_test Change-Id: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d Merged-In: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d (cherry picked from commit bc067ef9f0408f3b7c4f5dcae3b6aec51f386e4d) --- fs_mgr/libdm/dm.cpp | 14 ++++++++++++++ fs_mgr/libdm/dm_test.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index 1e8c14fe2..c6f9192ae 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -540,6 +540,17 @@ bool DeviceMapper::GetTableInfo(const std::string& name, std::vector return GetTable(name, DM_STATUS_TABLE_FLAG, table); } +void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) { + if (DeviceMapper::GetTargetType(spec) == "crypt") { + auto parts = android::base::Split(*data, " "); + if (parts.size() < 2) { + return; + } + parts[1] = "redacted"; + *data = android::base::Join(parts, " "); + } +} + // private methods of DeviceMapper bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, std::vector* table) { @@ -578,6 +589,9 @@ bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, // Note: we use c_str() to eliminate any extra trailing 0s. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str(); } + if (flags & DM_STATUS_TABLE_FLAG) { + RedactTableInfo(*spec, &data); + } table->emplace_back(*spec, data); cursor = next_cursor; } diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index c522eafae..08edbe832 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -757,3 +757,31 @@ TEST_F(DmTest, GetNameAndUuid) { ASSERT_EQ(name, test_name_); ASSERT_FALSE(uuid.empty()); } + +TEST_F(DmTest, RedactDmCrypt) { + static constexpr uint64_t kImageSize = 65536; + unique_fd temp_file(CreateTempFile("file_1", kImageSize)); + ASSERT_GE(temp_file, 0); + + LoopDevice loop(temp_file, 10s); + ASSERT_TRUE(loop.valid()); + + static constexpr const char* kAlgorithm = "aes-cbc-essiv:sha256"; + static constexpr const char* kKey = "0e64ef514e6a1315b1f6390cb57c9e6a"; + + auto target = std::make_unique(0, kImageSize / 512, kAlgorithm, kKey, 0, + loop.device(), 0); + target->AllowDiscards(); + + DmTable table; + table.AddTarget(std::move(target)); + + auto& dm = DeviceMapper::Instance(); + std::string crypt_path; + ASSERT_TRUE(dm.CreateDevice(test_name_, table, &crypt_path, 10s)); + + std::vector targets; + ASSERT_TRUE(dm.GetTableInfo(test_name_, &targets)); + ASSERT_EQ(targets.size(), 1); + EXPECT_EQ(targets[0].data.find(kKey), std::string::npos); +} From 7ae15190df95ca1c02741b17835cea51ccaf6657 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Oct 2024 11:01:08 -0700 Subject: [PATCH 065/183] libdm: Redact keys from dm-crypt targets when calling GetTable. Ignore-AOSP-First: security fix Bug: 368069390 Test: libdm_test Change-Id: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d Merged-In: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d (cherry picked from commit bc067ef9f0408f3b7c4f5dcae3b6aec51f386e4d) --- fs_mgr/libdm/dm.cpp | 14 ++++++++++++++ fs_mgr/libdm/dm_test.cpp | 28 ++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index 1e8c14fe2..c6f9192ae 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -540,6 +540,17 @@ bool DeviceMapper::GetTableInfo(const std::string& name, std::vector return GetTable(name, DM_STATUS_TABLE_FLAG, table); } +void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) { + if (DeviceMapper::GetTargetType(spec) == "crypt") { + auto parts = android::base::Split(*data, " "); + if (parts.size() < 2) { + return; + } + parts[1] = "redacted"; + *data = android::base::Join(parts, " "); + } +} + // private methods of DeviceMapper bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, std::vector* table) { @@ -578,6 +589,9 @@ bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, // Note: we use c_str() to eliminate any extra trailing 0s. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str(); } + if (flags & DM_STATUS_TABLE_FLAG) { + RedactTableInfo(*spec, &data); + } table->emplace_back(*spec, data); cursor = next_cursor; } diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index c522eafae..08edbe832 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -757,3 +757,31 @@ TEST_F(DmTest, GetNameAndUuid) { ASSERT_EQ(name, test_name_); ASSERT_FALSE(uuid.empty()); } + +TEST_F(DmTest, RedactDmCrypt) { + static constexpr uint64_t kImageSize = 65536; + unique_fd temp_file(CreateTempFile("file_1", kImageSize)); + ASSERT_GE(temp_file, 0); + + LoopDevice loop(temp_file, 10s); + ASSERT_TRUE(loop.valid()); + + static constexpr const char* kAlgorithm = "aes-cbc-essiv:sha256"; + static constexpr const char* kKey = "0e64ef514e6a1315b1f6390cb57c9e6a"; + + auto target = std::make_unique(0, kImageSize / 512, kAlgorithm, kKey, 0, + loop.device(), 0); + target->AllowDiscards(); + + DmTable table; + table.AddTarget(std::move(target)); + + auto& dm = DeviceMapper::Instance(); + std::string crypt_path; + ASSERT_TRUE(dm.CreateDevice(test_name_, table, &crypt_path, 10s)); + + std::vector targets; + ASSERT_TRUE(dm.GetTableInfo(test_name_, &targets)); + ASSERT_EQ(targets.size(), 1); + EXPECT_EQ(targets[0].data.find(kKey), std::string::npos); +} From b544df0e15b43391867e864c575b9f4dbd3c242d Mon Sep 17 00:00:00 2001 From: Will McVicker Date: Mon, 21 Oct 2024 15:19:53 -0700 Subject: [PATCH 066/183] Add support to update the DTB when flashing a vendor_boot ramdisk When updating the vendor_boot ramdisk, there may be device tree dependencies that require updating the device tree with the new ramdisk which contains the first stage init kernel modules. This patch adds the support to use the `--dtb /path/to/dtb` option to update the DTB when updating the vendor_boot ramdisk. To do so, run the command: fastboot flash --dtb /path/to/dtb.img \ vendor_boot: /path/to/ramdisk Test: fastboot_vendor_boot_img_utils_test Test: Verifed updating the dtb with the above command on r4 Bug: 368308832 Change-Id: Iaa1867fe64054971a698497a2e3486424fed19fe --- fastboot/Android.bp | 1 + fastboot/fastboot.cpp | 26 +++++++- fastboot/fuzzer/fastboot_fuzzer.cpp | 4 +- fastboot/testdata/Android.bp | 8 +++ fastboot/vendor_boot_img_utils.cpp | 59 +++++++++++++----- fastboot/vendor_boot_img_utils.h | 2 +- fastboot/vendor_boot_img_utils_test.cpp | 82 ++++++++++++++++++++----- 7 files changed, 147 insertions(+), 35 deletions(-) diff --git a/fastboot/Android.bp b/fastboot/Android.bp index bfe0768f8..b61fbd4df 100644 --- a/fastboot/Android.bp +++ b/fastboot/Android.bp @@ -430,6 +430,7 @@ cc_test_host { ], data: [ ":fastboot_test_dtb", + ":fastboot_test_dtb_replace", ":fastboot_test_bootconfig", ":fastboot_test_vendor_ramdisk_none", ":fastboot_test_vendor_ramdisk_platform", diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 6b9e493eb..156dc3b33 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -552,6 +552,12 @@ static int show_help() { " Secondary images may be flashed to inactive slot.\n" " flash PARTITION [FILENAME] Flash given partition, using the image from\n" " $ANDROID_PRODUCT_OUT if no filename is given.\n" + " flash vendor_boot:RAMDISK [FILENAME]\n" + " Flash vendor_boot ramdisk, fetching the existing\n" + " vendor_boot image and repackaging it with the new\n" + " ramdisk.\n" + " --dtb DTB If set with flash vendor_boot:RAMDISK, then\n" + " update the vendor_boot image with provided DTB.\n" "\n" "basics:\n" " devices [-l] List devices in bootloader (-l: with device paths).\n" @@ -1020,6 +1026,8 @@ static uint64_t get_uint_var(const char* var_name, fastboot::IFastBootDriver* fb } int64_t get_sparse_limit(int64_t size, const FlashingPlan* fp) { + if (!fp) return 0; + int64_t limit = int64_t(fp->sparse_limit); if (limit == 0) { // Unlimited, so see what the target device's limit is. @@ -1465,6 +1473,7 @@ static void do_fetch(const std::string& partition, const std::string& slot_overr static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf, fastboot::IFastBootDriver* fb) { std::string_view pname_sv{pname}; + struct fastboot_buffer dtb_buf = {.sz = 0, .fd = unique_fd(-1)}; if (!android::base::StartsWith(pname_sv, "vendor_boot:") && !android::base::StartsWith(pname_sv, "vendor_boot_a:") && @@ -1480,10 +1489,25 @@ static std::string repack_ramdisk(const char* pname, struct fastboot_buffer* buf std::string partition(pname_sv.substr(0, pname_sv.find(':'))); std::string ramdisk(pname_sv.substr(pname_sv.find(':') + 1)); + if (!g_dtb_path.empty()) { + if (!load_buf(g_dtb_path.c_str(), &dtb_buf, nullptr)) { + die("cannot load '%s': %s", g_dtb_path.c_str(), strerror(errno)); + } + + if (dtb_buf.type != FB_BUFFER_FD) { + die("Flashing sparse vendor ramdisk image with dtb is not supported."); + } + if (dtb_buf.sz <= 0) { + die("repack_ramdisk() sees invalid dtb size: %" PRId64, buf->sz); + } + verbose("Updating DTB with %s", pname_sv.data()); + } + unique_fd vendor_boot(make_temporary_fd("vendor boot repack")); uint64_t vendor_boot_size = fetch_partition(partition, vendor_boot, fb); auto repack_res = replace_vendor_ramdisk(vendor_boot, vendor_boot_size, ramdisk, buf->fd, - static_cast(buf->sz)); + static_cast(buf->sz), dtb_buf.fd, + static_cast(dtb_buf.sz)); if (!repack_res.ok()) { die("%s", repack_res.error().message().c_str()); } diff --git a/fastboot/fuzzer/fastboot_fuzzer.cpp b/fastboot/fuzzer/fastboot_fuzzer.cpp index 60940fe3d..4594a8ab4 100644 --- a/fastboot/fuzzer/fastboot_fuzzer.cpp +++ b/fastboot/fuzzer/fastboot_fuzzer.cpp @@ -15,6 +15,7 @@ * */ #include +#include #include "fastboot.h" #include "socket.h" #include "socket_mock_fuzz.h" @@ -25,6 +26,7 @@ #include using namespace std; +using android::base::unique_fd; const size_t kYearMin = 2000; const size_t kYearMax = 2127; @@ -255,7 +257,7 @@ void FastbootFuzzer::InvokeVendorBootImgUtils(const uint8_t* data, size_t size) uint64_t ramdisk_size = fdp_->ConsumeBool() ? content_ramdisk_fd.size() : fdp_->ConsumeIntegral(); (void)replace_vendor_ramdisk(vendor_boot_fd, vendor_boot_size, ramdisk_name, ramdisk_fd, - ramdisk_size); + ramdisk_size, unique_fd(-1), 0); close(vendor_boot_fd); close(ramdisk_fd); } diff --git a/fastboot/testdata/Android.bp b/fastboot/testdata/Android.bp index a490fe270..47bf0959e 100644 --- a/fastboot/testdata/Android.bp +++ b/fastboot/testdata/Android.bp @@ -40,6 +40,14 @@ genrule { cmd: "$(location fastboot_gen_rand) --seed dtb --length 1024 > $(out)", } +// Fake dtb image for replacement. +genrule { + name: "fastboot_test_dtb_replace", + defaults: ["fastboot_test_data_gen_defaults"], + out: ["dtb_replace.img"], + cmd: "$(location fastboot_gen_rand) --seed dtb --length 2048 > $(out)", +} + // Fake bootconfig image. genrule { name: "fastboot_test_bootconfig", diff --git a/fastboot/vendor_boot_img_utils.cpp b/fastboot/vendor_boot_img_utils.cpp index 9f05253c0..da547f1bf 100644 --- a/fastboot/vendor_boot_img_utils.cpp +++ b/fastboot/vendor_boot_img_utils.cpp @@ -209,7 +209,8 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { // Replace the vendor ramdisk as a whole. [[nodiscard]] Result replace_default_vendor_ramdisk(const std::string& vendor_boot, - const std::string& new_ramdisk) { + const std::string& new_ramdisk, + const std::string& new_dtb) { if (auto res = check_vendor_boot_hdr(vendor_boot, 3); !res.ok()) return res.error(); auto hdr = reinterpret_cast(vendor_boot.data()); auto hdr_size = get_vendor_boot_header_size(hdr); @@ -244,8 +245,19 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { return res.error(); if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error(); - // Copy DTB (Q bytes). - if (auto res = updater.Copy(q); !res.ok()) return res.error(); + // Copy DTB (Q bytes). Replace if a new one was provided. + new_hdr->dtb_size = !new_dtb.empty() ? new_dtb.size() : hdr->dtb_size; + const uint32_t new_q = round_up(new_hdr->dtb_size, new_hdr->page_size); + if (new_dtb.empty()) { + if (auto res = updater.Copy(q); !res.ok()) return res.error(); + } else { + if (auto res = updater.Replace(hdr->dtb_size, new_dtb); !res.ok()) return res.error(); + if (auto res = updater.Skip(q - hdr->dtb_size, new_q - new_hdr->dtb_size); !res.ok()) + return res.error(); + } + if (auto res = updater.CheckOffset(o + p + q, o + new_p + new_q); !res.ok()) { + return res.error(); + } if (new_hdr->header_version >= 4) { auto hdr_v4 = static_cast(hdr); @@ -256,7 +268,7 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { auto new_hdr_v4 = static_cast(new_hdr); auto new_r = round_up(new_hdr_v4->vendor_ramdisk_table_size, new_hdr->page_size); if (auto res = updater.Skip(r, new_r); !res.ok()) return res.error(); - if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + new_r); !res.ok()) + if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + new_q + new_r); !res.ok()) return res.error(); // Replace table with single entry representing the full ramdisk. @@ -303,7 +315,8 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { // replace it with the content of |new_ramdisk|. [[nodiscard]] Result replace_vendor_ramdisk_fragment(const std::string& ramdisk_name, const std::string& vendor_boot, - const std::string& new_ramdisk) { + const std::string& new_ramdisk, + const std::string& new_dtb) { if (auto res = check_vendor_boot_hdr(vendor_boot, 4); !res.ok()) return res.error(); auto hdr = reinterpret_cast(vendor_boot.data()); auto hdr_size = get_vendor_boot_header_size(hdr); @@ -368,8 +381,19 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { return res.error(); if (auto res = updater.CheckOffset(o + p, o + new_p); !res.ok()) return res.error(); - // Copy DTB (Q bytes). - if (auto res = updater.Copy(q); !res.ok()) return res.error(); + // Copy DTB (Q bytes). Replace if a new one was provided. + new_hdr->dtb_size = !new_dtb.empty() ? new_dtb.size() : hdr->dtb_size; + const uint32_t new_q = round_up(new_hdr->dtb_size, new_hdr->page_size); + if (new_dtb.empty()) { + if (auto res = updater.Copy(q); !res.ok()) return res.error(); + } else { + if (auto res = updater.Replace(hdr->dtb_size, new_dtb); !res.ok()) return res.error(); + if (auto res = updater.Skip(q - hdr->dtb_size, new_q - new_hdr->dtb_size); !res.ok()) + return res.error(); + } + if (auto res = updater.CheckOffset(o + p + q, o + new_p + new_q); !res.ok()) { + return res.error(); + } // Copy table, but with corresponding entries modified, including: // - ramdisk_size of the entry replaced @@ -392,7 +416,7 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { hdr->vendor_ramdisk_table_entry_size); !res.ok()) return res.error(); - if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + q + r); !res.ok()) + if (auto res = updater.CheckOffset(o + p + q + r, o + new_p + new_q + r); !res.ok()) return res.error(); // Copy bootconfig (S bytes). @@ -404,11 +428,11 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { } // namespace -[[nodiscard]] Result replace_vendor_ramdisk(android::base::borrowed_fd vendor_boot_fd, - uint64_t vendor_boot_size, - const std::string& ramdisk_name, - android::base::borrowed_fd new_ramdisk_fd, - uint64_t new_ramdisk_size) { +[[nodiscard]] Result replace_vendor_ramdisk( + android::base::borrowed_fd vendor_boot_fd, uint64_t vendor_boot_size, + const std::string& ramdisk_name, android::base::borrowed_fd new_ramdisk_fd, + uint64_t new_ramdisk_size, android::base::borrowed_fd new_dtb_fd, uint64_t new_dtb_size) { + Result new_dtb = {""}; if (new_ramdisk_size > std::numeric_limits::max()) { return Errorf("New vendor ramdisk is too big"); } @@ -417,12 +441,17 @@ inline uint32_t round_up(uint32_t value, uint32_t page_size) { if (!vendor_boot.ok()) return vendor_boot.error(); auto new_ramdisk = load_file(new_ramdisk_fd, new_ramdisk_size, "new vendor ramdisk"); if (!new_ramdisk.ok()) return new_ramdisk.error(); + if (new_dtb_size > 0 && new_dtb_fd >= 0) { + new_dtb = load_file(new_dtb_fd, new_dtb_size, "new dtb"); + if (!new_dtb.ok()) return new_dtb.error(); + } Result new_vendor_boot; if (ramdisk_name == "default") { - new_vendor_boot = replace_default_vendor_ramdisk(*vendor_boot, *new_ramdisk); + new_vendor_boot = replace_default_vendor_ramdisk(*vendor_boot, *new_ramdisk, *new_dtb); } else { - new_vendor_boot = replace_vendor_ramdisk_fragment(ramdisk_name, *vendor_boot, *new_ramdisk); + new_vendor_boot = + replace_vendor_ramdisk_fragment(ramdisk_name, *vendor_boot, *new_ramdisk, *new_dtb); } if (!new_vendor_boot.ok()) return new_vendor_boot.error(); if (auto res = store_file(vendor_boot_fd, *new_vendor_boot, "new vendor boot image"); !res.ok()) diff --git a/fastboot/vendor_boot_img_utils.h b/fastboot/vendor_boot_img_utils.h index 0b702bc4d..0ca78dae2 100644 --- a/fastboot/vendor_boot_img_utils.h +++ b/fastboot/vendor_boot_img_utils.h @@ -31,4 +31,4 @@ [[nodiscard]] android::base::Result replace_vendor_ramdisk( android::base::borrowed_fd vendor_boot_fd, uint64_t vendor_boot_size, const std::string& ramdisk_name, android::base::borrowed_fd new_ramdisk_fd, - uint64_t new_ramdisk_size); + uint64_t new_ramdisk_size, android::base::borrowed_fd new_dtb_fd, uint64_t new_dtb_size); diff --git a/fastboot/vendor_boot_img_utils_test.cpp b/fastboot/vendor_boot_img_utils_test.cpp index 81072705d..841e532ac 100644 --- a/fastboot/vendor_boot_img_utils_test.cpp +++ b/fastboot/vendor_boot_img_utils_test.cpp @@ -241,6 +241,7 @@ RepackVendorBootImgTestEnv* env = nullptr; struct RepackVendorBootImgTestParam { std::string vendor_boot_file_name; + std::string dtb_file_name; uint32_t expected_header_version; friend std::ostream& operator<<(std::ostream& os, const RepackVendorBootImgTestParam& param) { return os << param.vendor_boot_file_name; @@ -252,22 +253,50 @@ class RepackVendorBootImgTest : public ::testing::TestWithParam(GetParam().vendor_boot_file_name); ASSERT_RESULT_OK(vboot->Open()); + + if (!GetParam().dtb_file_name.empty()) { + dtb_replacement = std::make_unique(GetParam().dtb_file_name); + ASSERT_RESULT_OK(dtb_replacement->Open()); + } } std::unique_ptr vboot; + std::unique_ptr dtb_replacement; }; TEST_P(RepackVendorBootImgTest, InvalidSize) { - EXPECT_ERROR(replace_vendor_ramdisk(vboot->fd(), vboot->size() + 1, "default", - env->replace->fd(), env->replace->size()), - HasSubstr("Size of vendor boot does not match")); - EXPECT_ERROR(replace_vendor_ramdisk(vboot->fd(), vboot->size(), "default", env->replace->fd(), - env->replace->size() + 1), - HasSubstr("Size of new vendor ramdisk does not match")); + EXPECT_ERROR( + replace_vendor_ramdisk(vboot->fd(), vboot->size() + 1, "default", env->replace->fd(), + env->replace->size(), + !GetParam().dtb_file_name.empty() ? dtb_replacement->fd() + : android::base::unique_fd(-1), + !GetParam().dtb_file_name.empty() ? dtb_replacement->size() : 0), + HasSubstr("Size of vendor boot does not match")); + EXPECT_ERROR( + replace_vendor_ramdisk(vboot->fd(), vboot->size(), "default", env->replace->fd(), + env->replace->size() + 1, + !GetParam().dtb_file_name.empty() ? dtb_replacement->fd() + : android::base::unique_fd(-1), + !GetParam().dtb_file_name.empty() ? dtb_replacement->size() : 0), + HasSubstr("Size of new vendor ramdisk does not match")); + if (!GetParam().dtb_file_name.empty()) { + EXPECT_ERROR(replace_vendor_ramdisk(vboot->fd(), vboot->size(), "default", + env->replace->fd(), env->replace->size(), + dtb_replacement->fd(), dtb_replacement->size() + 1), + HasSubstr("Size of new dtb does not match")); + } + EXPECT_ERROR( + replace_vendor_ramdisk( + vboot->fd(), vboot->size(), "default", env->replace->fd(), env->replace->size(), + android::base::unique_fd(std::numeric_limits::max()), 1), + HasSubstr("Can't seek to the beginning of new dtb image")); } TEST_P(RepackVendorBootImgTest, ReplaceUnknown) { - auto res = replace_vendor_ramdisk(vboot->fd(), vboot->size(), "unknown", env->replace->fd(), - env->replace->size()); + auto res = replace_vendor_ramdisk( + vboot->fd(), vboot->size(), "unknown", env->replace->fd(), env->replace->size(), + !GetParam().dtb_file_name.empty() ? dtb_replacement->fd() + : android::base::unique_fd(-1), + !GetParam().dtb_file_name.empty() ? dtb_replacement->size() : 0); if (GetParam().expected_header_version == 3) { EXPECT_ERROR(res, Eq("Require vendor boot header V4 but is V3")); } else if (GetParam().expected_header_version == 4) { @@ -279,8 +308,11 @@ TEST_P(RepackVendorBootImgTest, ReplaceDefault) { auto old_content = vboot->Read(); ASSERT_RESULT_OK(old_content); - ASSERT_RESULT_OK(replace_vendor_ramdisk(vboot->fd(), vboot->size(), "default", - env->replace->fd(), env->replace->size())); + ASSERT_RESULT_OK(replace_vendor_ramdisk( + vboot->fd(), vboot->size(), "default", env->replace->fd(), env->replace->size(), + !GetParam().dtb_file_name.empty() ? dtb_replacement->fd() + : android::base::unique_fd(-1), + !GetParam().dtb_file_name.empty() ? dtb_replacement->size() : 0)); EXPECT_RESULT(vboot->fsize(), vboot->size()) << "File size should not change after repack"; auto new_content_res = vboot->Read(); @@ -291,14 +323,23 @@ TEST_P(RepackVendorBootImgTest, ReplaceDefault) { ASSERT_EQ(0, memcmp(VENDOR_BOOT_MAGIC, hdr->magic, VENDOR_BOOT_MAGIC_SIZE)); ASSERT_EQ(GetParam().expected_header_version, hdr->header_version); EXPECT_EQ(hdr->vendor_ramdisk_size, env->replace->size()); - EXPECT_EQ(hdr->dtb_size, env->dtb->size()); + if (GetParam().dtb_file_name.empty()) { + EXPECT_EQ(hdr->dtb_size, env->dtb->size()); + } else { + EXPECT_EQ(hdr->dtb_size, dtb_replacement->size()); + } auto o = round_up(sizeof(vendor_boot_img_hdr_v3), hdr->page_size); auto p = round_up(hdr->vendor_ramdisk_size, hdr->page_size); auto q = round_up(hdr->dtb_size, hdr->page_size); EXPECT_THAT(new_content.substr(o, p), IsPadded(env->replace_content)); - EXPECT_THAT(new_content.substr(o + p, q), IsPadded(env->dtb_content)); + if (GetParam().dtb_file_name.empty()) { + EXPECT_THAT(new_content.substr(o + p, q), IsPadded(env->dtb_content)); + } else { + auto dtb_content_res = dtb_replacement->Read(); + EXPECT_THAT(new_content.substr(o + p, q), IsPadded(*dtb_content_res)); + } if (hdr->header_version < 4) return; @@ -321,11 +362,17 @@ TEST_P(RepackVendorBootImgTest, ReplaceDefault) { INSTANTIATE_TEST_SUITE_P( RepackVendorBootImgTest, RepackVendorBootImgTest, - ::testing::Values(RepackVendorBootImgTestParam{"vendor_boot_v3.img", 3}, - RepackVendorBootImgTestParam{"vendor_boot_v4_with_frag.img", 4}, - RepackVendorBootImgTestParam{"vendor_boot_v4_without_frag.img", 4}), + ::testing::Values(RepackVendorBootImgTestParam{"vendor_boot_v3.img", "", 3}, + RepackVendorBootImgTestParam{"vendor_boot_v4_with_frag.img", "", 4}, + RepackVendorBootImgTestParam{"vendor_boot_v4_without_frag.img", "", 4}, + RepackVendorBootImgTestParam{"vendor_boot_v4_with_frag.img", + "dtb_replace.img", 4}, + RepackVendorBootImgTestParam{"vendor_boot_v4_without_frag.img", + "dtb_replace.img", 4}), [](const auto& info) { - return android::base::StringReplace(info.param.vendor_boot_file_name, ".", "_", false); + std::string test_name = + android::base::StringReplace(info.param.vendor_boot_file_name, ".", "_", false); + return test_name + (!info.param.dtb_file_name.empty() ? "_replace_dtb" : ""); }); std::string_view GetRamdiskName(const vendor_ramdisk_table_entry_v4* entry) { @@ -368,7 +415,8 @@ TEST_P(RepackVendorBootImgTestV4, Replace) { ASSERT_RESULT_OK(old_content); ASSERT_RESULT_OK(replace_vendor_ramdisk(vboot->fd(), vboot->size(), replace_ramdisk_name, - env->replace->fd(), env->replace->size())); + env->replace->fd(), env->replace->size(), + android::base::unique_fd(-1), 0)); EXPECT_RESULT(vboot->fsize(), vboot->size()) << "File size should not change after repack"; auto new_content_res = vboot->Read(); From ec0f7774c659d204cfd36b0407dbf7f6dc5be762 Mon Sep 17 00:00:00 2001 From: Ryan Prichard Date: Thu, 24 Oct 2024 15:59:44 -0700 Subject: [PATCH 067/183] fs_mgr: avoid std::vector std::vector uses std::allocator, which is an undocumented libc++ extension to the C++ standard library. The extension was removed in llvm.org/PR96319. Use an ordinary non-const T instead. Bug: http://b/349681543 Bug: http://b/375478563 Test: m libfs_mgr Flag: EXEMPT, refactor to fix build failure Change-Id: I759526c7507824dca0e2e4f5cb2bf3c58dece1d8 --- fs_mgr/fs_mgr.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index fbd990b96..cae8bbe40 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -2213,11 +2213,11 @@ bool fs_mgr_mount_overlayfs_fstab_entry(const FstabEntry& entry) { #if ALLOW_ADBD_DISABLE_VERITY == 0 // Allowlist the mount point if user build. - static const std::vector kAllowedPaths = { + static const std::vector kAllowedPaths = { "/odm", "/odm_dlkm", "/oem", "/product", "/system_dlkm", "/system_ext", "/vendor", "/vendor_dlkm", }; - static const std::vector kAllowedPrefixes = { + static const std::vector kAllowedPrefixes = { "/mnt/product/", "/mnt/vendor/", }; From ac474ff7a0745308dd8f67b66d405f2f78bd9413 Mon Sep 17 00:00:00 2001 From: Grzegorz Jaszczyk Date: Sun, 13 Oct 2024 14:55:38 +0000 Subject: [PATCH 068/183] firmware_handler: extract part responsible for running ext program to lib As a preparation for upcoming commit, extract part which is responsible for external program execution to libmodprobe so it can be later re-used not only for firmware handler but also for dynamic module options handler within libmodprobe. RunExternalHandler is moved entirely to separate library with two changes: - Setting env needed previously by firmware handler was made generic and now external handler can get envs_map containing pairs of env and its value which needs to be set. - "Firmware" was removed from one of the log since now it can be used in different context (s/External Firmware Handler/External Handler/) Bug: 335619610 Test: `atest CtsInitTestCases` passed, especially: [105/129] ueventd_parser#ExternalFirmwareHandlers: PASSED (0ms) [106/129] ueventd_parser#ExternalFirmwareHandlersDuplicate: PASSED (0ms) Change-Id: Ie07cee763278f224bd3c0acfbe06c44eb36d0a81 --- init/firmware_handler.cpp | 104 ++-------------- init/firmware_handler.h | 2 - libmodprobe/Android.bp | 2 + libmodprobe/exthandler.cpp | 131 ++++++++++++++++++++ libmodprobe/include/exthandler/exthandler.h | 23 ++++ 5 files changed, 164 insertions(+), 98 deletions(-) create mode 100644 libmodprobe/exthandler.cpp create mode 100644 libmodprobe/include/exthandler/exthandler.h diff --git a/init/firmware_handler.cpp b/init/firmware_handler.cpp index 01957eff0..dcfda52d6 100644 --- a/init/firmware_handler.cpp +++ b/init/firmware_handler.cpp @@ -38,6 +38,8 @@ #include #include +#include "exthandler/exthandler.h" + using android::base::ReadFdToString; using android::base::Socketpair; using android::base::Split; @@ -136,100 +138,6 @@ FirmwareHandler::FirmwareHandler(std::vector firmware_directories, : firmware_directories_(std::move(firmware_directories)), external_firmware_handlers_(std::move(external_firmware_handlers)) {} -Result FirmwareHandler::RunExternalHandler(const std::string& handler, uid_t uid, - gid_t gid, const Uevent& uevent) const { - unique_fd child_stdout; - unique_fd parent_stdout; - if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stdout, &parent_stdout)) { - return ErrnoError() << "Socketpair() for stdout failed"; - } - - unique_fd child_stderr; - unique_fd parent_stderr; - if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stderr, &parent_stderr)) { - return ErrnoError() << "Socketpair() for stderr failed"; - } - - signal(SIGCHLD, SIG_DFL); - - auto pid = fork(); - if (pid < 0) { - return ErrnoError() << "fork() failed"; - } - - if (pid == 0) { - setenv("FIRMWARE", uevent.firmware.c_str(), 1); - setenv("DEVPATH", uevent.path.c_str(), 1); - parent_stdout.reset(); - parent_stderr.reset(); - close(STDOUT_FILENO); - close(STDERR_FILENO); - dup2(child_stdout.get(), STDOUT_FILENO); - dup2(child_stderr.get(), STDERR_FILENO); - - auto args = Split(handler, " "); - std::vector c_args; - for (auto& arg : args) { - c_args.emplace_back(arg.data()); - } - c_args.emplace_back(nullptr); - - if (gid != 0) { - if (setgid(gid) != 0) { - fprintf(stderr, "setgid() failed: %s", strerror(errno)); - _exit(EXIT_FAILURE); - } - } - - if (setuid(uid) != 0) { - fprintf(stderr, "setuid() failed: %s", strerror(errno)); - _exit(EXIT_FAILURE); - } - - execv(c_args[0], c_args.data()); - fprintf(stderr, "exec() failed: %s", strerror(errno)); - _exit(EXIT_FAILURE); - } - - child_stdout.reset(); - child_stderr.reset(); - - int status; - pid_t waited_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); - if (waited_pid == -1) { - return ErrnoError() << "waitpid() failed"; - } - - std::string stdout_content; - if (!ReadFdToString(parent_stdout.get(), &stdout_content)) { - return ErrnoError() << "ReadFdToString() for stdout failed"; - } - - std::string stderr_content; - if (ReadFdToString(parent_stderr.get(), &stderr_content)) { - auto messages = Split(stderr_content, "\n"); - for (const auto& message : messages) { - if (!message.empty()) { - LOG(ERROR) << "External Firmware Handler: " << message; - } - } - } else { - LOG(ERROR) << "ReadFdToString() for stderr failed"; - } - - if (WIFEXITED(status)) { - if (WEXITSTATUS(status) == EXIT_SUCCESS) { - return Trim(stdout_content); - } else { - return Error() << "exited with status " << WEXITSTATUS(status); - } - } else if (WIFSIGNALED(status)) { - return Error() << "killed by signal " << WTERMSIG(status); - } - - return Error() << "unexpected exit status " << status; -} - std::string FirmwareHandler::GetFirmwarePath(const Uevent& uevent) const { for (const auto& external_handler : external_firmware_handlers_) { if (external_handler.match(uevent.path)) { @@ -237,11 +145,15 @@ std::string FirmwareHandler::GetFirmwarePath(const Uevent& uevent) const { << "' for devpath: '" << uevent.path << "' firmware: '" << uevent.firmware << "'"; + std::unordered_map envs_map; + envs_map["FIRMWARE"] = uevent.firmware; + envs_map["DEVPATH"] = uevent.path; + auto result = RunExternalHandler(external_handler.handler_path, external_handler.uid, - external_handler.gid, uevent); + external_handler.gid, envs_map); if (!result.ok() && NeedsRerunExternalHandler()) { auto res = RunExternalHandler(external_handler.handler_path, external_handler.uid, - external_handler.gid, uevent); + external_handler.gid, envs_map); result = std::move(res); } if (!result.ok()) { diff --git a/init/firmware_handler.h b/init/firmware_handler.h index fceb392db..e5d353809 100644 --- a/init/firmware_handler.h +++ b/init/firmware_handler.h @@ -54,8 +54,6 @@ class FirmwareHandler : public UeventHandler { friend void FirmwareTestWithExternalHandler(const std::string& test_name, bool expect_new_firmware); - Result RunExternalHandler(const std::string& handler, uid_t uid, gid_t gid, - const Uevent& uevent) const; std::string GetFirmwarePath(const Uevent& uevent) const; void ProcessFirmwareEvent(const std::string& path, const std::string& firmware) const; bool ForEachFirmwareDirectory(std::function handler) const; diff --git a/libmodprobe/Android.bp b/libmodprobe/Android.bp index 12906cc39..78b4c83e3 100644 --- a/libmodprobe/Android.bp +++ b/libmodprobe/Android.bp @@ -13,6 +13,7 @@ cc_library_static { vendor_ramdisk_available: true, host_supported: true, srcs: [ + "exthandler.cpp", "libmodprobe.cpp", "libmodprobe_ext.cpp", ], @@ -30,6 +31,7 @@ cc_test { ], local_include_dirs: ["include/"], srcs: [ + "exthandler.cpp", "libmodprobe_test.cpp", "libmodprobe.cpp", "libmodprobe_ext_test.cpp", diff --git a/libmodprobe/exthandler.cpp b/libmodprobe/exthandler.cpp new file mode 100644 index 000000000..f48c25976 --- /dev/null +++ b/libmodprobe/exthandler.cpp @@ -0,0 +1,131 @@ +/* + * Copyright (C) 2024 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 + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using android::base::ErrnoError; +using android::base::Error; +using android::base::ReadFdToString; +using android::base::Result; +using android::base::Split; +using android::base::Trim; +using android::base::unique_fd; + +Result RunExternalHandler(const std::string& handler, uid_t uid, gid_t gid, + std::unordered_map& envs_map) { + unique_fd child_stdout; + unique_fd parent_stdout; + if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stdout, &parent_stdout)) { + return ErrnoError() << "Socketpair() for stdout failed"; + } + + unique_fd child_stderr; + unique_fd parent_stderr; + if (!Socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, &child_stderr, &parent_stderr)) { + return ErrnoError() << "Socketpair() for stderr failed"; + } + + signal(SIGCHLD, SIG_DFL); + + auto pid = fork(); + if (pid < 0) { + return ErrnoError() << "fork() failed"; + } + + if (pid == 0) { + for (auto it = envs_map.begin(); it != envs_map.end(); ++it) { + setenv(it->first.c_str(), it->second.c_str(), 1); + } + parent_stdout.reset(); + parent_stderr.reset(); + close(STDOUT_FILENO); + close(STDERR_FILENO); + dup2(child_stdout.get(), STDOUT_FILENO); + dup2(child_stderr.get(), STDERR_FILENO); + + auto args = Split(handler, " "); + std::vector c_args; + for (auto& arg : args) { + c_args.emplace_back(arg.data()); + } + c_args.emplace_back(nullptr); + + if (gid != 0) { + if (setgid(gid) != 0) { + fprintf(stderr, "setgid() failed: %s", strerror(errno)); + _exit(EXIT_FAILURE); + } + } + + if (setuid(uid) != 0) { + fprintf(stderr, "setuid() failed: %s", strerror(errno)); + _exit(EXIT_FAILURE); + } + + execv(c_args[0], c_args.data()); + fprintf(stderr, "exec() failed: %s", strerror(errno)); + _exit(EXIT_FAILURE); + } + + child_stdout.reset(); + child_stderr.reset(); + + int status; + pid_t waited_pid = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0)); + if (waited_pid == -1) { + return ErrnoError() << "waitpid() failed"; + } + + std::string stdout_content; + if (!ReadFdToString(parent_stdout.get(), &stdout_content)) { + return ErrnoError() << "ReadFdToString() for stdout failed"; + } + + std::string stderr_content; + if (ReadFdToString(parent_stderr.get(), &stderr_content)) { + auto messages = Split(stderr_content, "\n"); + for (const auto& message : messages) { + if (!message.empty()) { + LOG(ERROR) << "External Handler: " << message; + } + } + } else { + LOG(ERROR) << "ReadFdToString() for stderr failed"; + } + + if (WIFEXITED(status)) { + if (WEXITSTATUS(status) == EXIT_SUCCESS) { + return Trim(stdout_content); + } else { + return Error() << "exited with status " << WEXITSTATUS(status); + } + } else if (WIFSIGNALED(status)) { + return Error() << "killed by signal " << WTERMSIG(status); + } + + return Error() << "unexpected exit status " << status; +} diff --git a/libmodprobe/include/exthandler/exthandler.h b/libmodprobe/include/exthandler/exthandler.h new file mode 100644 index 000000000..232aa95a4 --- /dev/null +++ b/libmodprobe/include/exthandler/exthandler.h @@ -0,0 +1,23 @@ +/* + * Copyright (C) 2024 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 +#include + +android::base::Result RunExternalHandler( + const std::string& handler, uid_t uid, gid_t gid, + std::unordered_map& envs_map); From 3063d84e9c0162ba74670f4eb6ef276ceb03c644 Mon Sep 17 00:00:00 2001 From: Grzegorz Jaszczyk Date: Thu, 6 Jun 2024 15:27:08 +0000 Subject: [PATCH 069/183] libmodprobe: add support for dynamic module options Hitherto libmodprobe was supporting modules.options which allows passing extra module options. This commit extends that support and beside `options`, modules.options can now contain `dyn_options` entries. Syntax example: dyn_options snd_sof_pci system "/vendor/bin/mod_options --sof-fw" This allows to determine extra module options, with help of external program, at runtime which can be useful for unibuilds, supporting various device flavors and therefore requiring different module options. Using external program to customize modules parameters are inspired by Android's external firmware handler: https://android.googlesource.com/platform/system/core/+/master/init/README.ueventd.md#firmware-loading and the same RunExternalHandler is reused for both dynamic module handling and firmware handling. Bug: 335619610 Test: Test audio on systems using snd_sof_pci module and verify correctness of custom module parameters. Change-Id: Ibd1a942d4ea022519676435ed525cd7c3e720d31 --- libmodprobe/include/modprobe/modprobe.h | 1 + libmodprobe/libmodprobe.cpp | 61 +++++++++++++++++++++++++ 2 files changed, 62 insertions(+) diff --git a/libmodprobe/include/modprobe/modprobe.h b/libmodprobe/include/modprobe/modprobe.h index d7a90c488..7b691b13a 100644 --- a/libmodprobe/include/modprobe/modprobe.h +++ b/libmodprobe/include/modprobe/modprobe.h @@ -59,6 +59,7 @@ class Modprobe { bool ParseSoftdepCallback(const std::vector& args); bool ParseLoadCallback(const std::vector& args); bool ParseOptionsCallback(const std::vector& args); + bool ParseDynOptionsCallback(const std::vector& args); bool ParseBlocklistCallback(const std::vector& args); void ParseKernelCmdlineOptions(); void ParseCfg(const std::string& cfg, std::function&)> f); diff --git a/libmodprobe/libmodprobe.cpp b/libmodprobe/libmodprobe.cpp index 8cc0b9b2e..bdd114c4b 100644 --- a/libmodprobe/libmodprobe.cpp +++ b/libmodprobe/libmodprobe.cpp @@ -17,8 +17,11 @@ #include #include +#include +#include #include #include +#include #include #include @@ -30,9 +33,12 @@ #include #include #include +#include #include #include +#include "exthandler/exthandler.h" + std::string Modprobe::MakeCanonical(const std::string& module_path) { auto start = module_path.find_last_of('/'); if (start == std::string::npos) { @@ -164,6 +170,10 @@ bool Modprobe::ParseOptionsCallback(const std::vector& args) { auto it = args.begin(); const std::string& type = *it++; + if (type == "dyn_options") { + return ParseDynOptionsCallback(std::vector(it, args.end())); + } + if (type != "options") { LOG(ERROR) << "non-options line encountered in modules.options"; return false; @@ -197,6 +207,57 @@ bool Modprobe::ParseOptionsCallback(const std::vector& args) { return true; } +bool Modprobe::ParseDynOptionsCallback(const std::vector& args) { + auto it = args.begin(); + int arg_size = 3; + + if (args.size() < arg_size) { + LOG(ERROR) << "dyn_options lines in modules.options must have at least" << arg_size + << " entries, not " << args.size(); + return false; + } + + const std::string& module = *it++; + + const std::string& canonical_name = MakeCanonical(module); + if (canonical_name.empty()) { + return false; + } + + const std::string& pwnam = *it++; + passwd* pwd = getpwnam(pwnam.c_str()); + if (!pwd) { + LOG(ERROR) << "invalid handler uid'" << pwnam << "'"; + return false; + } + + std::string handler_with_args = + android::base::Join(std::vector(it, args.end()), ' '); + handler_with_args.erase(std::remove(handler_with_args.begin(), handler_with_args.end(), '\"'), + handler_with_args.end()); + + LOG(DEBUG) << "Launching external module options handler: '" << handler_with_args + << " for module: " << module; + + // There is no need to set envs for external module options handler - pass + // empty map. + std::unordered_map envs_map; + auto result = RunExternalHandler(handler_with_args, pwd->pw_uid, 0, envs_map); + if (!result.ok()) { + LOG(ERROR) << "External module handler failed: " << result.error(); + return false; + } + + LOG(INFO) << "Dynamic options for module: " << module << " are '" << *result << "'"; + + auto [unused, inserted] = this->module_options_.emplace(canonical_name, *result); + if (!inserted) { + LOG(ERROR) << "multiple options lines present for module " << module; + return false; + } + return true; +} + bool Modprobe::ParseBlocklistCallback(const std::vector& args) { auto it = args.begin(); const std::string& type = *it++; From 77ee43a9fe56db6042d9f91d75cab703f04180e7 Mon Sep 17 00:00:00 2001 From: Daeho Jeong Date: Mon, 21 Oct 2024 13:51:14 -0700 Subject: [PATCH 070/183] support f2fs device aliasing feature We can hold the storage space of one of f2fs multi-device for data partition, while allowing the space to be used by another purpose. f2fs will create a sequential and pinned file as a placeholder and it can be deallocated and returned back to data partition after it is done with using it. We can create the file, as we define the device with "exp_alias:" tag in the fstab. Bug: 336319772 Test: add a device with "exp_alias" tag in fstab Change-Id: If55730cedd21ec5a40137d2eb723a97df498c9cb Signed-off-by: Daeho Jeong --- fs_mgr/fs_mgr.cpp | 6 ++++-- fs_mgr/fs_mgr_format.cpp | 16 ++++++++++++---- fs_mgr/libfstab/fstab.cpp | 1 + fs_mgr/libfstab/include/fstab/fstab.h | 1 + 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index fbd990b96..fc105d67d 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -1603,7 +1603,8 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) { attempted_entry.fs_type, attempted_entry.fs_mgr_flags.is_zoned ? "true" : "false", std::to_string(attempted_entry.length), - android::base::Join(attempted_entry.user_devices, ' ')}, + android::base::Join(attempted_entry.user_devices, ' '), + android::base::Join(attempted_entry.device_aliased, ' ')}, nullptr)) { LERROR << "Encryption failed"; set_type_property(encryptable); @@ -1655,7 +1656,8 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) { formattable_entry->fs_type, formattable_entry->fs_mgr_flags.is_zoned ? "true" : "false", std::to_string(formattable_entry->length), - android::base::Join(formattable_entry->user_devices, ' ')}, + android::base::Join(formattable_entry->user_devices, ' '), + android::base::Join(formattable_entry->device_aliased, ' ')}, nullptr)) { LERROR << "Encryption failed"; } else { diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp index 0dde1d374..57e35a275 100644 --- a/fs_mgr/fs_mgr_format.cpp +++ b/fs_mgr/fs_mgr_format.cpp @@ -32,6 +32,7 @@ #include #include #include +#include #include #include "fs_mgr_priv.h" @@ -126,7 +127,8 @@ static int format_ext4(const std::string& fs_blkdev, const std::string& fs_mnt_p static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool needs_projid, bool needs_casefold, bool fs_compress, bool is_zoned, - const std::vector& user_devices) { + const std::vector& user_devices, + const std::vector& device_aliased) { if (!dev_sz) { int rc = get_dev_sz(fs_blkdev, &dev_sz); if (rc) { @@ -164,9 +166,15 @@ static int format_f2fs(const std::string& fs_blkdev, uint64_t dev_sz, bool needs if (is_zoned) { args.push_back("-m"); } - for (auto& device : user_devices) { + for (size_t i = 0; i < user_devices.size(); i++) { + std::string device_name = user_devices[i]; + args.push_back("-c"); - args.push_back(device.c_str()); + if (device_aliased[i]) { + std::filesystem::path path = device_name; + device_name += "@" + path.filename().string(); + } + args.push_back(device_name.c_str()); } if (user_devices.empty()) { @@ -191,7 +199,7 @@ int fs_mgr_do_format(const FstabEntry& entry) { if (entry.fs_type == "f2fs") { return format_f2fs(entry.blk_device, entry.length, needs_projid, needs_casefold, entry.fs_mgr_flags.fs_compress, entry.fs_mgr_flags.is_zoned, - entry.user_devices); + entry.user_devices, entry.device_aliased); } else if (entry.fs_type == "ext4") { return format_ext4(entry.blk_device, entry.mount_point, needs_projid, entry.fs_mgr_flags.ext_meta_csum); diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index d344b2d19..6e4cae18f 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -173,6 +173,7 @@ void ParseUserDevices(const std::string& arg, FstabEntry* entry) { entry->fs_mgr_flags.is_zoned = true; } entry->user_devices.push_back(param[1]); + entry->device_aliased.push_back(param[0] == "exp_alias" ? 1 : 0); } bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h index 21fe01726..070dd9178 100644 --- a/fs_mgr/libfstab/include/fstab/fstab.h +++ b/fs_mgr/libfstab/include/fstab/fstab.h @@ -33,6 +33,7 @@ namespace fs_mgr { struct FstabEntry { std::string blk_device; std::vector user_devices; + std::vector device_aliased; std::string logical_partition_name; std::string mount_point; std::string fs_type; From 9611c18aa286a55de54f46e54e1296f98e0d9194 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Fri, 25 Oct 2024 17:11:02 +0000 Subject: [PATCH 071/183] Don't use android::base::StartsWith / EndsWith These libbase functions now directly pass through to the standard library. [1] Use the standard library directly, and eliminate this dependency on libbase. [1] https://r.android.com/c/platform/system/libbase/+/3315082 Change-Id: I83d79ffa2658f30ae09a7f27cedf14e62b5df41d --- libprocessgroup/processgroup.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index d3719eea3..95221594b 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -37,19 +37,18 @@ #include #include #include +#include #include #include #include #include #include -#include #include #include #include using android::base::GetBoolProperty; -using android::base::StartsWith; using android::base::StringPrintf; using android::base::WriteStringToFile; @@ -255,7 +254,7 @@ static bool RemoveEmptyUidCgroups(const std::string& uid_path) { continue; } - if (!StartsWith(dir->d_name, "pid_")) { + if (!std::string_view(dir->d_name).starts_with("pid_")) { continue; } @@ -296,7 +295,7 @@ void removeAllEmptyProcessGroups() { continue; } - if (!StartsWith(dir->d_name, "uid_")) { + if (!std::string_view(dir->d_name).starts_with("uid_")) { continue; } From d94e6c537fd8283a33d899d627ff154cc2af2d10 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Oct 2024 11:01:08 -0700 Subject: [PATCH 072/183] libdm: Redact keys from dm-crypt targets when calling GetTable. Ignore-AOSP-First: security fix Bug: 368069390 Test: libdm_test Change-Id: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d Merged-In: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d --- fs_mgr/libdm/dm.cpp | 14 ++++++++++++++ fs_mgr/libdm/dm_test.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index 4034e30ab..6da7b48b6 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -512,6 +512,17 @@ bool DeviceMapper::GetTableInfo(const std::string& name, std::vector return GetTable(name, DM_STATUS_TABLE_FLAG, table); } +void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) { + if (DeviceMapper::GetTargetType(spec) == "crypt") { + auto parts = android::base::Split(*data, " "); + if (parts.size() < 2) { + return; + } + parts[1] = "redacted"; + *data = android::base::Join(parts, " "); + } +} + // private methods of DeviceMapper bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, std::vector* table) { @@ -550,6 +561,9 @@ bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, // Note: we use c_str() to eliminate any extra trailing 0s. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str(); } + if (flags & DM_STATUS_TABLE_FLAG) { + RedactTableInfo(*spec, &data); + } table->emplace_back(*spec, data); cursor = next_cursor; } diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index 541f254cb..f4c9784da 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -690,3 +690,32 @@ TEST(libdm, CreateEmptyDevice) { // Empty device should be in suspended state. ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device")); } + +TEST(libdm, RedactDmCrypt) { + static constexpr uint64_t kImageSize = 65536; + static constexpr const char* kTestName = "RedactDmCrypt"; + unique_fd temp_file(CreateTempFile("file_1", kImageSize)); + ASSERT_GE(temp_file, 0); + + LoopDevice loop(temp_file, 10s); + ASSERT_TRUE(loop.valid()); + + static constexpr const char* kAlgorithm = "aes-cbc-essiv:sha256"; + static constexpr const char* kKey = "0e64ef514e6a1315b1f6390cb57c9e6a"; + + auto target = std::make_unique(0, kImageSize / 512, kAlgorithm, kKey, 0, + loop.device(), 0); + target->AllowDiscards(); + + DmTable table; + table.AddTarget(std::move(target)); + + auto& dm = DeviceMapper::Instance(); + std::string crypt_path; + ASSERT_TRUE(dm.CreateDevice(kTestName, table, &crypt_path, 10s)); + + std::vector targets; + ASSERT_TRUE(dm.GetTableInfo(kTestName, &targets)); + ASSERT_EQ(targets.size(), 1); + EXPECT_EQ(targets[0].data.find(kKey), std::string::npos); +} From 390be0ae38d85d4ea755d39b28b0b6dc338b356e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Oct 2024 11:01:08 -0700 Subject: [PATCH 073/183] libdm: Redact keys from dm-crypt targets when calling GetTable. Ignore-AOSP-First: security fix Bug: 368069390 Test: libdm_test Change-Id: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d Merged-In: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d --- fs_mgr/libdm/dm.cpp | 14 ++++++++++++++ fs_mgr/libdm/dm_test.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index 4034e30ab..6da7b48b6 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -512,6 +512,17 @@ bool DeviceMapper::GetTableInfo(const std::string& name, std::vector return GetTable(name, DM_STATUS_TABLE_FLAG, table); } +void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) { + if (DeviceMapper::GetTargetType(spec) == "crypt") { + auto parts = android::base::Split(*data, " "); + if (parts.size() < 2) { + return; + } + parts[1] = "redacted"; + *data = android::base::Join(parts, " "); + } +} + // private methods of DeviceMapper bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, std::vector* table) { @@ -550,6 +561,9 @@ bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, // Note: we use c_str() to eliminate any extra trailing 0s. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str(); } + if (flags & DM_STATUS_TABLE_FLAG) { + RedactTableInfo(*spec, &data); + } table->emplace_back(*spec, data); cursor = next_cursor; } diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index 541f254cb..f4c9784da 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -690,3 +690,32 @@ TEST(libdm, CreateEmptyDevice) { // Empty device should be in suspended state. ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device")); } + +TEST(libdm, RedactDmCrypt) { + static constexpr uint64_t kImageSize = 65536; + static constexpr const char* kTestName = "RedactDmCrypt"; + unique_fd temp_file(CreateTempFile("file_1", kImageSize)); + ASSERT_GE(temp_file, 0); + + LoopDevice loop(temp_file, 10s); + ASSERT_TRUE(loop.valid()); + + static constexpr const char* kAlgorithm = "aes-cbc-essiv:sha256"; + static constexpr const char* kKey = "0e64ef514e6a1315b1f6390cb57c9e6a"; + + auto target = std::make_unique(0, kImageSize / 512, kAlgorithm, kKey, 0, + loop.device(), 0); + target->AllowDiscards(); + + DmTable table; + table.AddTarget(std::move(target)); + + auto& dm = DeviceMapper::Instance(); + std::string crypt_path; + ASSERT_TRUE(dm.CreateDevice(kTestName, table, &crypt_path, 10s)); + + std::vector targets; + ASSERT_TRUE(dm.GetTableInfo(kTestName, &targets)); + ASSERT_EQ(targets.size(), 1); + EXPECT_EQ(targets[0].data.find(kKey), std::string::npos); +} From e68f6cd6c0a925fea1bbe7537f6029ef9b0e142c Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Oct 2024 11:01:08 -0700 Subject: [PATCH 074/183] libdm: Redact keys from dm-crypt targets when calling GetTable. Ignore-AOSP-First: security fix Bug: 368069390 Test: libdm_test Change-Id: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d Merged-In: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d --- fs_mgr/libdm/dm.cpp | 14 ++++++++++++++ fs_mgr/libdm/dm_test.cpp | 29 +++++++++++++++++++++++++++++ 2 files changed, 43 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index b1d5b397a..762e83c30 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -512,6 +512,17 @@ bool DeviceMapper::GetTableInfo(const std::string& name, std::vector return GetTable(name, DM_STATUS_TABLE_FLAG, table); } +void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) { + if (DeviceMapper::GetTargetType(spec) == "crypt") { + auto parts = android::base::Split(*data, " "); + if (parts.size() < 2) { + return; + } + parts[1] = "redacted"; + *data = android::base::Join(parts, " "); + } +} + // private methods of DeviceMapper bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, std::vector* table) { @@ -550,6 +561,9 @@ bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, // Note: we use c_str() to eliminate any extra trailing 0s. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str(); } + if (flags & DM_STATUS_TABLE_FLAG) { + RedactTableInfo(*spec, &data); + } table->emplace_back(*spec, data); cursor = next_cursor; } diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index 541f254cb..f4c9784da 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -690,3 +690,32 @@ TEST(libdm, CreateEmptyDevice) { // Empty device should be in suspended state. ASSERT_EQ(DmDeviceState::SUSPENDED, dm.GetState("empty-device")); } + +TEST(libdm, RedactDmCrypt) { + static constexpr uint64_t kImageSize = 65536; + static constexpr const char* kTestName = "RedactDmCrypt"; + unique_fd temp_file(CreateTempFile("file_1", kImageSize)); + ASSERT_GE(temp_file, 0); + + LoopDevice loop(temp_file, 10s); + ASSERT_TRUE(loop.valid()); + + static constexpr const char* kAlgorithm = "aes-cbc-essiv:sha256"; + static constexpr const char* kKey = "0e64ef514e6a1315b1f6390cb57c9e6a"; + + auto target = std::make_unique(0, kImageSize / 512, kAlgorithm, kKey, 0, + loop.device(), 0); + target->AllowDiscards(); + + DmTable table; + table.AddTarget(std::move(target)); + + auto& dm = DeviceMapper::Instance(); + std::string crypt_path; + ASSERT_TRUE(dm.CreateDevice(kTestName, table, &crypt_path, 10s)); + + std::vector targets; + ASSERT_TRUE(dm.GetTableInfo(kTestName, &targets)); + ASSERT_EQ(targets.size(), 1); + EXPECT_EQ(targets[0].data.find(kKey), std::string::npos); +} From 96fc434b6cb5cc08c045d1610e19398bb29f8657 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Sat, 26 Oct 2024 00:34:51 +0000 Subject: [PATCH 075/183] libprocessgroup: Remove ifdefery around SetTimerSlackAction::ExecuteForTask This appears to have been due to the use of prctl, which apparently caused issues for mac builds. Now that use of prctl has been removed, it doesn't look like we need this anymore. Fixes: 075008174 ("libprocessgroup: Remove prctl interface for setting timer slack") Test: m Bug: 372498744 Change-Id: I8a43951f30d7dd838591a8ba225d712742d7cd4a --- libprocessgroup/task_profiles.cpp | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index cc675b3fe..c96feb314 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -188,9 +188,6 @@ bool ProfileAttribute::GetPathForUID(uid_t uid, std::string* path) const { return true; } -// To avoid issues in sdk_mac build -#if defined(__ANDROID__) - bool SetTimerSlackAction::ExecuteForTask(pid_t tid) const { const auto file = StringPrintf("/proc/%d/timerslack_ns", tid); if (!WriteStringToFile(std::to_string(slack_), file)) { @@ -205,14 +202,6 @@ bool SetTimerSlackAction::ExecuteForTask(pid_t tid) const { return true; } -#else - -bool SetTimerSlackAction::ExecuteForTask(int) const { - return true; -}; - -#endif - bool SetAttributeAction::WriteValueToFile(const std::string& path) const { if (!WriteStringToFile(value_, path)) { if (access(path.c_str(), F_OK) < 0) { From c9e000c7acf8b9a011491424c3e9b6d667c58221 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Oct 2024 11:01:08 -0700 Subject: [PATCH 076/183] libdm: Redact keys from dm-crypt targets when calling GetTable. Ignore-AOSP-First: security fix Bug: 368069390 Test: libdm_test Change-Id: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d Merged-In: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d --- fs_mgr/libdm/dm.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index e43c00b44..dbee8a377 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -494,6 +494,17 @@ bool DeviceMapper::GetTableInfo(const std::string& name, std::vector return GetTable(name, DM_STATUS_TABLE_FLAG, table); } +void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) { + if (DeviceMapper::GetTargetType(spec) == "crypt") { + auto parts = android::base::Split(*data, " "); + if (parts.size() < 2) { + return; + } + parts[1] = "redacted"; + *data = android::base::Join(parts, " "); + } +} + // private methods of DeviceMapper bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, std::vector* table) { @@ -532,6 +543,9 @@ bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, // Note: we use c_str() to eliminate any extra trailing 0s. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str(); } + if (flags & DM_STATUS_TABLE_FLAG) { + RedactTableInfo(*spec, &data); + } table->emplace_back(*spec, data); cursor = next_cursor; } From c434d801d65372dd12d9bc8bd7717ef08f3fa984 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 1 Oct 2024 11:01:08 -0700 Subject: [PATCH 077/183] libdm: Redact keys from dm-crypt targets when calling GetTable. Ignore-AOSP-First: security fix Bug: 368069390 Test: libdm_test Change-Id: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d Merged-In: I40b9a0129e58b1a0f116ca29f0ee66f91a27a73d --- fs_mgr/libdm/dm.cpp | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index e43c00b44..dbee8a377 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -494,6 +494,17 @@ bool DeviceMapper::GetTableInfo(const std::string& name, std::vector return GetTable(name, DM_STATUS_TABLE_FLAG, table); } +void RedactTableInfo(const struct dm_target_spec& spec, std::string* data) { + if (DeviceMapper::GetTargetType(spec) == "crypt") { + auto parts = android::base::Split(*data, " "); + if (parts.size() < 2) { + return; + } + parts[1] = "redacted"; + *data = android::base::Join(parts, " "); + } +} + // private methods of DeviceMapper bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, std::vector* table) { @@ -532,6 +543,9 @@ bool DeviceMapper::GetTable(const std::string& name, uint32_t flags, // Note: we use c_str() to eliminate any extra trailing 0s. data = std::string(&buffer[data_offset], next_cursor - data_offset).c_str(); } + if (flags & DM_STATUS_TABLE_FLAG) { + RedactTableInfo(*spec, &data); + } table->emplace_back(*spec, data); cursor = next_cursor; } From dea6f7c2a53b0fc970f28d8c45bfc390ef69cff2 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 28 Oct 2024 19:47:09 -0700 Subject: [PATCH 078/183] Fix overlayfs on page cf page agnostic builds. Hardcode 4096 block size for f2fs on x86/64. Bug: 375531898 Test: adb_remount_test.sh Change-Id: I9b55f7caf1b77f235168664be2f310bb3bb0d179 --- fs_mgr/fs_mgr.cpp | 8 ++++++++ fs_mgr/fs_mgr_overlayfs_control.cpp | 4 +--- fs_mgr/include/fs_mgr.h | 3 +++ 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index fbd990b96..e39ffe70c 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -2314,6 +2314,14 @@ std::string fs_mgr_get_context(const std::string& mount_point) { return context; } +int fs_mgr_f2fs_ideal_block_size() { +#if defined(__i386__) || defined(__x86_64__) + return 4096; +#else + return getpagesize(); +#endif +} + namespace android { namespace fs_mgr { diff --git a/fs_mgr/fs_mgr_overlayfs_control.cpp b/fs_mgr/fs_mgr_overlayfs_control.cpp index 08ad80caa..489b32e7e 100644 --- a/fs_mgr/fs_mgr_overlayfs_control.cpp +++ b/fs_mgr/fs_mgr_overlayfs_control.cpp @@ -387,10 +387,8 @@ bool MakeScratchFilesystem(const std::string& scratch_device) { auto command = ""s; if (!access(kMkF2fs, X_OK) && fs_mgr_filesystem_available("f2fs")) { fs_type = "f2fs"; - command = kMkF2fs + " -w "s; - command += std::to_string(getpagesize()); command = kMkF2fs + " -b "s; - command += std::to_string(getpagesize()); + command += std::to_string(fs_mgr_f2fs_ideal_block_size()); command += " -f -d1 -l" + android::base::Basename(kScratchMountPoint); } else if (!access(kMkExt4, X_OK) && fs_mgr_filesystem_available("ext4")) { fs_type = "ext4"; diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 9cfa93f78..79690874e 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -137,3 +137,6 @@ bool fs_mgr_mount_overlayfs_fstab_entry(const android::fs_mgr::FstabEntry& entry // File name used to track if encryption was interrupted, leading to a known bad fs state std::string fs_mgr_metadata_encryption_in_progress_file_name( const android::fs_mgr::FstabEntry& entry); + +// Returns the ideal block size for make_f2fs. Returns -1 on failure. +int fs_mgr_f2fs_ideal_block_size(); From 03429acceeb0f7a0316075fd66ac6270be403ebe Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Tue, 29 Oct 2024 16:28:33 +0900 Subject: [PATCH 079/183] init: mount tracefs before apexd-bootstrap This removes the error log when apexd-bootstrap starts: cutils-trace: Error opening trace file: No such file or directory (2) Bug: 376150518 Test: boot-time trace shows apexd-bootstrap see https://source.android.com/docs/core/perf/boot-times#systrace Change-Id: I5feaece50663a602b61377cee034060fd30217f9 --- rootdir/init.rc | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 12d9c4377..5bb64cc60 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -70,6 +70,9 @@ on early-init start ueventd + # Mount tracefs (with GID=AID_READTRACEFS) + mount tracefs tracefs /sys/kernel/tracing gid=3012 + # Run apexd-bootstrap so that APEXes that provide critical libraries # become available. Note that this is executed as exec_start to ensure that # the libraries are available to the processes started after this statement. @@ -80,9 +83,6 @@ on early-init mkdir /dev/boringssl 0755 root root mkdir /dev/boringssl/selftest 0755 root root - # Mount tracefs (with GID=AID_READTRACEFS) - mount tracefs tracefs /sys/kernel/tracing gid=3012 - # create sys dirctory mkdir /dev/sys 0755 system system mkdir /dev/sys/fs 0755 system system From 132b1ecdfdd5a5573010c083c3078e654f010844 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 29 Oct 2024 22:12:01 +0000 Subject: [PATCH 080/183] Switch mkbootfs to C++. Minimum changes just to get it to compile as C++, no real cleanup. Change-Id: I8ff3fa35a07cdc9a6a246e79e33581e5d6598833 --- mkbootfs/Android.bp | 2 +- mkbootfs/{mkbootfs.c => mkbootfs.cpp} | 18 ++++++++---------- 2 files changed, 9 insertions(+), 11 deletions(-) rename mkbootfs/{mkbootfs.c => mkbootfs.cpp} (97%) diff --git a/mkbootfs/Android.bp b/mkbootfs/Android.bp index cd2a6245a..e0191f0dc 100644 --- a/mkbootfs/Android.bp +++ b/mkbootfs/Android.bp @@ -6,7 +6,7 @@ package { cc_binary_host { name: "mkbootfs", - srcs: ["mkbootfs.c"], + srcs: ["mkbootfs.cpp"], cflags: ["-Werror"], static_libs: [ "libbase", diff --git a/mkbootfs/mkbootfs.c b/mkbootfs/mkbootfs.cpp similarity index 97% rename from mkbootfs/mkbootfs.c rename to mkbootfs/mkbootfs.cpp index 84a0a4eee..65cf497ac 100644 --- a/mkbootfs/mkbootfs.c +++ b/mkbootfs/mkbootfs.cpp @@ -75,7 +75,7 @@ static void fix_stat(const char *path, struct stat *s) } } -static void _eject(struct stat *s, char *out, int olen, char *data, unsigned datasize) +static void _eject(struct stat *s, const char *out, int olen, char *data, unsigned datasize) { // Nothing is special about this value, just picked something in the // approximate range that was being used already, and avoiding small @@ -151,9 +151,10 @@ static void _archive_dir(char *in, char *out, int ilen, int olen) DIR* d = opendir(in); if (d == NULL) err(1, "cannot open directory '%s'", in); + // TODO: switch to std::vector int size = 32; int entries = 0; - char** names = malloc(size * sizeof(char*)); + char** names = (char**) malloc(size * sizeof(char*)); if (names == NULL) { errx(1, "failed to allocate dir names array (size %d)", size); } @@ -167,7 +168,7 @@ static void _archive_dir(char *in, char *out, int ilen, int olen) if (entries >= size) { size *= 2; - names = realloc(names, size * sizeof(char*)); + names = (char**) realloc(names, size * sizeof(char*)); if (names == NULL) { errx(1, "failed to reallocate dir names array (size %d)", size); } @@ -445,15 +446,12 @@ int main(int argc, char *argv[]) int num_dirs = argc - optind; argv += optind; - while(num_dirs-- > 0){ + while (num_dirs-- > 0){ char *x = strchr(*argv, '='); - if(x != 0) { - *x++ = 0; - } else { - x = ""; + if (x != nullptr) { + *x++ = '\0'; } - - archive(*argv, x); + archive(*argv, x ?: ""); argv++; } From 930f77b02c8ba5a7bb8e54653455f9885d90748a Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Tue, 15 Oct 2024 13:21:19 -0700 Subject: [PATCH 081/183] Set input thread priority to RT To improve input latency, set the critical input threads to RT priority. This will use RT priority on AOSP devices by default. OEMs can still choose to customize what "input policy" means for their device, which may not necessarily mean RT. For example, on device with multiple small / big cores, input task affinity could be changed to prioritize big cores + higher CPU frequency / voltage, but still keep the standard / default input thread priority. With this patch, I'm finding that sometimes, one of the critical input threads has priority 100 instead of the expected 98. Still looking into that specific issue, but the issue is already present with the existing "input policy" code. Bug: 330719044 Flag: com.android.input.flags.enable_input_policy_profile Test: took perfetto trace and checked the priority on InputDispatcher and InputReader threads. Change-Id: I75b6a726f0d066f16bdec26f6cf90721479d17ff --- libprocessgroup/profiles/task_profiles.json | 15 +++++- libprocessgroup/task_profiles.cpp | 56 +++++++++++++++------ 2 files changed, 54 insertions(+), 17 deletions(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index feda3b49c..d61939f29 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -202,6 +202,19 @@ } ] }, + { + "Name": "RealTimeInputScheduling", + "Actions": [ + { + "Name": "SetSchedulerPolicy", + "Params": + { + "Policy": "SCHED_FIFO", + "Priority": "98" + } + } + ] + }, { "Name": "CameraServicePerformance", "Actions": [ @@ -704,7 +717,7 @@ }, { "Name": "InputPolicy", - "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] + "Profiles": [ "RealTimeInputScheduling", "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] } ] } diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index cc675b3fe..f3594e345 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -54,6 +55,7 @@ static constexpr const char* TASK_PROFILE_DB_VENDOR_FILE = "/vendor/etc/task_pro static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE = "/etc/task_profiles/task_profiles_%u.json"; +namespace { class FdCacheHelper { public: @@ -64,8 +66,11 @@ class FdCacheHelper { }; static void Cache(const std::string& path, android::base::unique_fd& fd); + static void Drop(android::base::unique_fd& fd); + static void Init(const std::string& path, android::base::unique_fd& fd); + static bool IsCached(const android::base::unique_fd& fd) { return fd > FDS_INACCESSIBLE; } private: @@ -116,6 +121,17 @@ bool FdCacheHelper::IsAppDependentPath(const std::string& path) { return path.find("", 0) != std::string::npos || path.find("", 0) != std::string::npos; } +std::optional readLong(const std::string& str) { + char* end; + const long result = strtol(str.c_str(), &end, 10); + if (end > str.c_str()) { + return result; + } + return std::nullopt; +} + +} // namespace + IProfileAttribute::~IProfileAttribute() = default; const std::string& ProfileAttribute::file_name() const { @@ -924,15 +940,12 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { LOG(WARNING) << "JoinCgroup: controller " << controller_name << " is not found"; } } else if (action_name == "SetTimerSlack") { - std::string slack_value = params_val["Slack"].asString(); - char* end; - unsigned long slack; - - slack = strtoul(slack_value.c_str(), &end, 10); - if (end > slack_value.c_str()) { - profile->Add(std::make_unique(slack)); + const std::string slack_string = params_val["Slack"].asString(); + std::optional slack = readLong(slack_string); + if (slack && *slack >= 0) { + profile->Add(std::make_unique(*slack)); } else { - LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_value; + LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_string; } } else if (action_name == "SetAttribute") { std::string attr_name = params_val["Name"].asString(); @@ -991,15 +1004,19 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { // If present, this optional value will be passed in an additional syscall // to setpriority(), since the sched_priority value must be 0 for calls to // sched_setscheduler() with "normal" policies. - const int nice = params_val["Nice"].asInt(); + const std::string nice_string = params_val["Nice"].asString(); + const std::optional nice = readLong(nice_string); + if (!nice) { + LOG(FATAL) << "Invalid nice value specified: " << nice_string; + } const int LINUX_MIN_NICE = -20; const int LINUX_MAX_NICE = 19; - if (nice < LINUX_MIN_NICE || nice > LINUX_MAX_NICE) { - LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << nice + if (*nice < LINUX_MIN_NICE || *nice > LINUX_MAX_NICE) { + LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << *nice << ") appears out of range."; } - profile->Add(std::make_unique(policy, nice)); + profile->Add(std::make_unique(policy, *nice)); } else { profile->Add(std::make_unique(policy)); } @@ -1012,11 +1029,18 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { // This is a "virtual priority" as described by `man 2 sched_get_priority_min` // that will be mapped onto the following range for the provided policy: // [sched_get_priority_min(), sched_get_priority_max()] - const int virtual_priority = params_val["Priority"].asInt(); - int priority; - if (SetSchedulerPolicyAction::toPriority(policy, virtual_priority, priority)) { - profile->Add(std::make_unique(policy, priority)); + const std::string priority_string = params_val["Priority"].asString(); + std::optional virtual_priority = readLong(priority_string); + if (virtual_priority && *virtual_priority > 0) { + int priority; + if (SetSchedulerPolicyAction::toPriority(policy, *virtual_priority, + priority)) { + profile->Add( + std::make_unique(policy, priority)); + } + } else { + LOG(WARNING) << "Invalid priority value: " << priority_string; } } } else { From 5d5c732a3b374c7992dfa79b6d62ea9f95119a0d Mon Sep 17 00:00:00 2001 From: Alice Wang Date: Wed, 30 Oct 2024 09:44:27 +0000 Subject: [PATCH 082/183] Rename KM VM related system properties To organize it under trusty and distinguish it from Widevine VM. Bug: 368502791 Test: launch_cvd --secure_hals=guest_keymint_trusty_insecure Test: atest VtsAidlSharedSecretTargetTest Change-Id: I48e43b9709e59b1cb9e1ba9113d5ef894469f485 --- ...ity.keymint-service.rust.trusty.system.nonsecure.rc | 4 ++-- trusty/utils/rpmb_dev/rpmb_dev.system.rc | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc index 2799188c4..ca6132e5e 100644 --- a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc +++ b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc @@ -12,6 +12,6 @@ service system.keymint.rust-trusty.nonsecure \ # TODO(b/357821690): Start the KeyMint HALs when the KeyMint VM is ready once the Trusty VM # has a mechanism to notify the host. on late-fs && property:ro.hardware.security.keymint.trusty.system=1 && \ - property:trusty_vm_system.vm_cid=* - setprop system.keymint.trusty_ipc_dev VSOCK:${trusty_vm_system.vm_cid}:1 + property:trusty.security_vm.vm_cid=* + setprop system.keymint.trusty_ipc_dev VSOCK:${trusty.security_vm.vm_cid}:1 start system.keymint.rust-trusty.nonsecure diff --git a/trusty/utils/rpmb_dev/rpmb_dev.system.rc b/trusty/utils/rpmb_dev/rpmb_dev.system.rc index b78c4e2a1..52419ed18 100644 --- a/trusty/utils/rpmb_dev/rpmb_dev.system.rc +++ b/trusty/utils/rpmb_dev/rpmb_dev.system.rc @@ -24,7 +24,7 @@ service rpmb_mock_system /system_ext/bin/rpmb_dev.system \ # storageproxyd on late-fs && \ - property:trusty_vm_system_nonsecure.ready=1 && \ + property:trusty.security_vm.nonsecure_vm_ready=1 && \ property:storageproxyd_system.trusty_ipc_dev=* wait /dev/socket/rpmb_mock_system start storageproxyd_system @@ -32,8 +32,8 @@ on late-fs && \ # RPMB Mock on post-fs && \ - property:trusty_vm_system_nonsecure.ready=1 && \ - property:trusty_vm_system.vm_cid=* + property:trusty.security_vm.nonsecure_vm_ready=1 && \ + property:trusty.security_vm.vm_cid=* # Create a persistent location for the RPMB data # (work around lack of RPMb block device on CF). # file contexts secure_storage_rpmb_system_file @@ -49,12 +49,12 @@ on post-fs && \ mkdir /mnt/secure_storage_persist_system 0770 system system symlink /metadata/secure_storage_persist_system \ /mnt/secure_storage_persist_system/persist - setprop storageproxyd_system.trusty_ipc_dev VSOCK:${trusty_vm_system.vm_cid}:1 + setprop storageproxyd_system.trusty_ipc_dev VSOCK:${trusty.security_vm.vm_cid}:1 exec_start rpmb_mock_init_system start rpmb_mock_system on post-fs-data && \ - property:trusty_vm_system_nonsecure.ready=1 && \ + property:trusty.security_vm.nonsecure_vm_ready=1 && \ property:storageproxyd_system.trusty_ipc_dev=* # file contexts secure_storage_system_file mkdir /data/secure_storage_system 0770 root system From 5fd1be1a5a90f4e53d6e7f6bd8562d1940271773 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Wed, 14 Aug 2024 02:54:40 +0000 Subject: [PATCH 083/183] Revert^4 "Set block device as RO/RW before mount" This reverts commit 1df3536b955fd4c0ee4c7b760beea29c1a1bdec5. Previous land got reverted because of selinux denial, which is already taken care of in aosp/3314877 Reason for revert: b/349507086 Change-Id: Id642b4d8726c72f324e369d8506c78eacea331e3 --- fs_mgr/fs_mgr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 5156754a8..ea2e3a8c7 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -826,6 +826,9 @@ static int __mount(const std::string& source, const std::string& target, const F if (read_only) { mountflags |= MS_RDONLY; } + if (!fs_mgr_set_blk_ro(source, read_only)) { + PLOG(ERROR) << "Failed to set " << source << " as " << (read_only ? "RO" : "RW"); + } int ret = 0; int save_errno = 0; int gc_allowance = 0; @@ -880,9 +883,6 @@ static int __mount(const std::string& source, const std::string& target, const F } PINFO << __FUNCTION__ << "(source=" << source << source_missing << ",target=" << target << target_missing << ",type=" << entry.fs_type << ")=" << ret; - if ((ret == 0) && (mountflags & MS_RDONLY) != 0) { - fs_mgr_set_blk_ro(source); - } if (ret == 0) { android::base::SetProperty("ro.boottime.init.mount." + Basename(target), std::to_string(t.duration().count())); From e7f1d41237f2504a0aeb8bcf62c8954b48f282c5 Mon Sep 17 00:00:00 2001 From: terryguan Date: Tue, 29 Oct 2024 13:20:46 -0700 Subject: [PATCH 084/183] read() can return fewer bytes than requested Sometimes read returns fewer bytes than requested. read() only read at most 0x7ffff000 bytes. Bug: 376247649 Test: manual, make mkbootfs, mkbootfs out/target/product../VENDOR_BOOT Change-Id: I8cbbae40c5f5c6c54d19bf77e9a801ed3390ed48 --- mkbootfs/mkbootfs.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/mkbootfs/mkbootfs.cpp b/mkbootfs/mkbootfs.cpp index 65cf497ac..a45c6a20a 100644 --- a/mkbootfs/mkbootfs.cpp +++ b/mkbootfs/mkbootfs.cpp @@ -19,6 +19,9 @@ #include #include +#include +#include + /* NOTES ** ** - see https://www.kernel.org/doc/Documentation/early-userspace/buffer-format.txt @@ -212,20 +215,12 @@ static void _archive(char *in, char *out, int ilen, int olen) if(lstat(in, &s)) err(1, "could not stat '%s'", in); if(S_ISREG(s.st_mode)){ - int fd = open(in, O_RDONLY); - if(fd < 0) err(1, "cannot open '%s' for read", in); - - char* tmp = (char*) malloc(s.st_size); - if(tmp == 0) errx(1, "cannot allocate %zd bytes", s.st_size); - - if(read(fd, tmp, s.st_size) != s.st_size) { - err(1, "cannot read %zd bytes", s.st_size); + std::string content; + if (!android::base::ReadFileToString(in, &content)) { + err(1, "cannot read '%s'", in); } - _eject(&s, out, olen, tmp, s.st_size); - - free(tmp); - close(fd); + _eject(&s, out, olen, content.data(), content.size()); } else if(S_ISDIR(s.st_mode)) { _eject(&s, out, olen, 0, 0); _archive_dir(in, out, ilen, olen); From 39a1730a82a6517f2c4e2ee34edb0ac83bbbb58a Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 7 Mar 2024 17:50:10 -0800 Subject: [PATCH 085/183] Make pbtombstone a host tool. This is preparation for the next patch, which adds host-side symbolization capabilities to pbtombstone. Bug: 328531087 Change-Id: Id5813ae6b121af784643b1ed76084e49fdca118b --- debuggerd/Android.bp | 16 +-- debuggerd/debuggerd_test.cpp | 3 +- .../include/libdebuggerd/tombstone.h | 4 - .../libdebuggerd/tombstone_proto_to_text.h | 26 +++++ .../include/libdebuggerd/utility.h | 7 -- .../include/libdebuggerd/utility_host.h | 31 ++++++ debuggerd/libdebuggerd/scudo.cpp | 1 + .../test/tombstone_proto_to_text_test.cpp | 1 + debuggerd/libdebuggerd/tombstone.cpp | 1 + debuggerd/libdebuggerd/tombstone_proto.cpp | 1 + .../libdebuggerd/tombstone_proto_to_text.cpp | 39 +++---- debuggerd/libdebuggerd/utility.cpp | 1 + debuggerd/libdebuggerd/utility_host.cpp | 101 ++++++++++++++++++ debuggerd/pbtombstone.cpp | 2 +- debuggerd/proto/Android.bp | 1 + 15 files changed, 186 insertions(+), 49 deletions(-) create mode 100644 debuggerd/libdebuggerd/include/libdebuggerd/tombstone_proto_to_text.h create mode 100644 debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h create mode 100644 debuggerd/libdebuggerd/utility_host.cpp diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index c365cac52..d4dc9a340 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -200,22 +200,18 @@ cc_library { ramdisk_available: true, recovery_available: true, vendor_ramdisk_available: true, + host_supported: true, local_include_dirs: ["libdebuggerd/include"], export_include_dirs: ["libdebuggerd/include"], srcs: [ "libdebuggerd/tombstone_proto_to_text.cpp", - ], - - header_libs: [ - "bionic_libc_platform_headers", + "libdebuggerd/utility_host.cpp", ], static_libs: [ "libbase", - "liblog_for_runtime_apex", - "libunwindstack", ], whole_static_libs: [ @@ -223,6 +219,10 @@ cc_library { "libprotobuf-cpp-lite", ], + shared_libs: [ + "liblog", + ], + apex_available: [ "//apex_available:platform", "com.android.runtime", @@ -331,15 +331,15 @@ cc_library_static { cc_binary { name: "pbtombstone", + host_supported: true, defaults: ["debuggerd_defaults"], srcs: ["pbtombstone.cpp"], static_libs: [ "libbase", - "libdebuggerd", + "libdebuggerd_tombstone_proto_to_text", "liblog", "libprotobuf-cpp-lite", "libtombstone_proto", - "libunwindstack", ], } diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index e33cea5c8..13c8d70b5 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -70,6 +70,7 @@ #include "crash_test.h" #include "debuggerd/handler.h" #include "gtest/gtest.h" +#include "libdebuggerd/utility_host.h" #include "protocol.h" #include "tombstoned/tombstoned.h" #include "util.h" @@ -741,8 +742,6 @@ TEST_F(CrasherTest, mte_multiple_causes) { } #if defined(__aarch64__) -constexpr size_t kTagGranuleSize = 16; - static uintptr_t CreateTagMapping() { // Some of the MTE tag dump tests assert that there is an inaccessible page to the left and right // of the PROT_MTE page, so map three pages and set the two guard pages to PROT_NONE. diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h index 074b0957a..39989c3a3 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone.h @@ -67,10 +67,6 @@ void engrave_tombstone_proto(Tombstone* tombstone, unwindstack::AndroidUnwinder* const Architecture* guest_arch, unwindstack::AndroidUnwinder* guest_unwinder); -bool tombstone_proto_to_text( - const Tombstone& tombstone, - std::function callback); - void fill_in_backtrace_frame(BacktraceFrame* f, const unwindstack::FrameData& frame); void set_human_readable_cause(Cause* cause, uint64_t fault_addr); #if defined(__aarch64__) diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone_proto_to_text.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone_proto_to_text.h new file mode 100644 index 000000000..515a15f0a --- /dev/null +++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone_proto_to_text.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 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 +#include + +class Tombstone; + +bool tombstone_proto_to_text( + const Tombstone& tombstone, + std::function callback); diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h index 26c2cd44a..b86c13d08 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h @@ -91,10 +91,3 @@ bool signal_has_si_addr(const siginfo_t*); void get_signal_sender(char* buf, size_t n, const siginfo_t*); const char* get_signame(const siginfo_t*); const char* get_sigcode(const siginfo_t*); - -// Number of bytes per MTE granule. -constexpr size_t kTagGranuleSize = 16; - -// Number of rows and columns to display in an MTE tag dump. -constexpr size_t kNumTagColumns = 16; -constexpr size_t kNumTagRows = 16; diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h new file mode 100644 index 000000000..43fb8bdc1 --- /dev/null +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h @@ -0,0 +1,31 @@ +/* + * Copyright 2024, 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 + +#include + +std::string describe_tagged_addr_ctrl(long ctrl); +std::string describe_pac_enabled_keys(long keys); + +// Number of bytes per MTE granule. +constexpr size_t kTagGranuleSize = 16; + +// Number of rows and columns to display in an MTE tag dump. +constexpr size_t kNumTagColumns = 16; +constexpr size_t kNumTagRows = 16; diff --git a/debuggerd/libdebuggerd/scudo.cpp b/debuggerd/libdebuggerd/scudo.cpp index 4ee87c841..71d5fcfa7 100644 --- a/debuggerd/libdebuggerd/scudo.cpp +++ b/debuggerd/libdebuggerd/scudo.cpp @@ -18,6 +18,7 @@ #include "libdebuggerd/scudo.h" #include "libdebuggerd/tombstone.h" +#include "libdebuggerd/utility_host.h" #include "unwindstack/AndroidUnwinder.h" #include "unwindstack/Memory.h" diff --git a/debuggerd/libdebuggerd/test/tombstone_proto_to_text_test.cpp b/debuggerd/libdebuggerd/test/tombstone_proto_to_text_test.cpp index 4fd264301..3fdb71d48 100644 --- a/debuggerd/libdebuggerd/test/tombstone_proto_to_text_test.cpp +++ b/debuggerd/libdebuggerd/test/tombstone_proto_to_text_test.cpp @@ -22,6 +22,7 @@ #include #include "libdebuggerd/tombstone.h" +#include "libdebuggerd/tombstone_proto_to_text.h" #include "tombstone.pb.h" using CallbackType = std::function; diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index 0ce55738a..d483b9889 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "DEBUG" #include "libdebuggerd/tombstone.h" +#include "libdebuggerd/tombstone_proto_to_text.h" #include #include diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index ed4fd5369..d59358c65 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -69,6 +69,7 @@ #include "libdebuggerd/open_files_list.h" #include "libdebuggerd/utility.h" +#include "libdebuggerd/utility_host.h" #include "util.h" #include "tombstone.pb.h" diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index c3f94700f..611e237b4 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -14,7 +14,8 @@ * limitations under the License. */ -#include +#include +#include #include @@ -30,8 +31,6 @@ #include #include #include -#include -#include #include "tombstone.pb.h" @@ -57,28 +56,6 @@ static std::string describe_end(long value, std::string& desc) { return desc.empty() ? "" : " (" + desc.substr(2) + ")"; } -static std::string describe_tagged_addr_ctrl(long value) { - std::string desc; - DESCRIBE_FLAG(PR_TAGGED_ADDR_ENABLE); - DESCRIBE_FLAG(PR_MTE_TCF_SYNC); - DESCRIBE_FLAG(PR_MTE_TCF_ASYNC); - if (value & PR_MTE_TAG_MASK) { - desc += StringPrintf(", mask 0x%04lx", (value & PR_MTE_TAG_MASK) >> PR_MTE_TAG_SHIFT); - value &= ~PR_MTE_TAG_MASK; - } - return describe_end(value, desc); -} - -static std::string describe_pac_enabled_keys(long value) { - std::string desc; - DESCRIBE_FLAG(PR_PAC_APIAKEY); - DESCRIBE_FLAG(PR_PAC_APIBKEY); - DESCRIBE_FLAG(PR_PAC_APDAKEY); - DESCRIBE_FLAG(PR_PAC_APDBKEY); - DESCRIBE_FLAG(PR_PAC_APGAKEY); - return describe_end(value, desc); -} - static const char* abi_string(const Architecture& arch) { switch (arch) { case Architecture::ARM32: @@ -113,6 +90,13 @@ static int pointer_width(const Tombstone& tombstone) { } } +static uint64_t untag_address(Architecture arch, uint64_t addr) { + if (arch == Architecture::ARM64) { + return addr & ((1ULL << 56) - 1); + } + return addr; +} + static void print_thread_header(CallbackType callback, const Tombstone& tombstone, const Thread& thread, bool should_log) { const char* process_name = ""; @@ -321,7 +305,8 @@ static void print_tag_dump(CallbackType callback, const Tombstone& tombstone) { size_t tag_index = 0; size_t num_tags = tags.length(); - uintptr_t fault_granule = untag_address(signal.fault_address()) & ~(kTagGranuleSize - 1); + uintptr_t fault_granule = + untag_address(tombstone.arch(), signal.fault_address()) & ~(kTagGranuleSize - 1); for (size_t row = 0; tag_index < num_tags; ++row) { uintptr_t row_addr = (memory_dump.begin_address() + row * kNumTagColumns * kTagGranuleSize) & kRowStartMask; @@ -369,7 +354,7 @@ static void print_memory_maps(CallbackType callback, const Tombstone& tombstone) const Signal& signal_info = tombstone.signal_info(); bool has_fault_address = signal_info.has_fault_address(); - uint64_t fault_address = untag_address(signal_info.fault_address()); + uint64_t fault_address = untag_address(tombstone.arch(), signal_info.fault_address()); bool preamble_printed = false; bool printed_fault_address_marker = false; for (const auto& map : tombstone.memory_mappings()) { diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 742ac7c27..b5a93b7db 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -17,6 +17,7 @@ #define LOG_TAG "DEBUG" #include "libdebuggerd/utility.h" +#include "libdebuggerd/utility_host.h" #include #include diff --git a/debuggerd/libdebuggerd/utility_host.cpp b/debuggerd/libdebuggerd/utility_host.cpp new file mode 100644 index 000000000..72a560cfe --- /dev/null +++ b/debuggerd/libdebuggerd/utility_host.cpp @@ -0,0 +1,101 @@ +/* + * Copyright 2024, 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 "libdebuggerd/utility_host.h" + +#include + +#include + +#include + +using android::base::StringPrintf; + +#ifndef PR_MTE_TAG_SHIFT +#define PR_MTE_TAG_SHIFT 3 +#endif + +#ifndef PR_MTE_TAG_MASK +#define PR_MTE_TAG_MASK (0xffffUL << PR_MTE_TAG_SHIFT) +#endif + +#ifndef PR_MTE_TCF_ASYNC +#define PR_MTE_TCF_ASYNC (1UL << 2) +#endif + +#ifndef PR_MTE_TCF_SYNC +#define PR_MTE_TCF_SYNC (1UL << 1) +#endif + +#ifndef PR_PAC_APIAKEY +#define PR_PAC_APIAKEY (1UL << 0) +#endif + +#ifndef PR_PAC_APIBKEY +#define PR_PAC_APIBKEY (1UL << 1) +#endif + +#ifndef PR_PAC_APDAKEY +#define PR_PAC_APDAKEY (1UL << 2) +#endif + +#ifndef PR_PAC_APDBKEY +#define PR_PAC_APDBKEY (1UL << 3) +#endif + +#ifndef PR_PAC_APGAKEY +#define PR_PAC_APGAKEY (1UL << 4) +#endif + +#ifndef PR_TAGGED_ADDR_ENABLE +#define PR_TAGGED_ADDR_ENABLE (1UL << 0) +#endif + +#define DESCRIBE_FLAG(flag) \ + if (value & flag) { \ + desc += ", "; \ + desc += #flag; \ + value &= ~flag; \ + } + +static std::string describe_end(long value, std::string& desc) { + if (value) { + desc += StringPrintf(", unknown 0x%lx", value); + } + return desc.empty() ? "" : " (" + desc.substr(2) + ")"; +} + +std::string describe_tagged_addr_ctrl(long value) { + std::string desc; + DESCRIBE_FLAG(PR_TAGGED_ADDR_ENABLE); + DESCRIBE_FLAG(PR_MTE_TCF_SYNC); + DESCRIBE_FLAG(PR_MTE_TCF_ASYNC); + if (value & PR_MTE_TAG_MASK) { + desc += StringPrintf(", mask 0x%04lx", (value & PR_MTE_TAG_MASK) >> PR_MTE_TAG_SHIFT); + value &= ~PR_MTE_TAG_MASK; + } + return describe_end(value, desc); +} + +std::string describe_pac_enabled_keys(long value) { + std::string desc; + DESCRIBE_FLAG(PR_PAC_APIAKEY); + DESCRIBE_FLAG(PR_PAC_APIBKEY); + DESCRIBE_FLAG(PR_PAC_APDAKEY); + DESCRIBE_FLAG(PR_PAC_APDBKEY); + DESCRIBE_FLAG(PR_PAC_APGAKEY); + return describe_end(value, desc); +} diff --git a/debuggerd/pbtombstone.cpp b/debuggerd/pbtombstone.cpp index 7527e31e1..dcb7c6c21 100644 --- a/debuggerd/pbtombstone.cpp +++ b/debuggerd/pbtombstone.cpp @@ -20,7 +20,7 @@ #include #include -#include +#include #include "tombstone.pb.h" diff --git a/debuggerd/proto/Android.bp b/debuggerd/proto/Android.bp index 7b9e780cc..70deb3cdd 100644 --- a/debuggerd/proto/Android.bp +++ b/debuggerd/proto/Android.bp @@ -38,6 +38,7 @@ cc_library_static { ramdisk_available: true, recovery_available: true, vendor_ramdisk_available: true, + host_supported: true, } java_library_static { From cf9f0870e4fa9504cd2e124456cdb8bdd44dd49f Mon Sep 17 00:00:00 2001 From: Peter Collingbourne Date: Thu, 7 Mar 2024 17:56:14 -0800 Subject: [PATCH 086/183] Add support for tombstone symbolization to pbtombstone. This patch teaches pbtombstone to use llvm-symbolizer to symbolize stack traces and augment the protobuf tombstones with the symbol information, before printing tombstones with the symbolized stack traces included. The main advantage of adding this information to the tombstone as opposed to having developers use the stack tool is that stack does not print all of the information in the original tombstone, which means that both reports may be required to understand a crash. Furthermore, stack traces printed by stack are not correlated with the stack traces in the tombstone, making the report harder to read, especially with GWP-ASan and MTE which may produce multiple stack traces for the crashing thread. Although we could teach stack to print more information, this would continue to be fragile because stack relies on parsing textual tombstones. Switching stack to read proto tombstones would be tantamount to a full rewrite and would require duplicating the C++ proto-to-text logic that we already have in Python. It seems better to reuse the C++ code for the proto-based symbolization tool. llvm-symbolizer will look up the symbol files by build ID using a .build-id directory following the standard here: https://fedoraproject.org/wiki/RolandMcGrath/BuildID It will look for .build-id directories under paths specified with --debug-file-directory, which pbtombstone will pass through to llvm-symbolizer using its own --debug-file-directory flag. The intent is that tools for platform developers will pass the flag --debug-file-directory $ANDROID_PRODUCT_OUT/symbols to pbtombstone. Soong will start creating .build-id under symbols after a corresponding Soong CL lands. Bug: 328531087 Change-Id: Ia4676821cf980c69487cf11aefa2a02dc0c1626f --- debuggerd/Android.bp | 5 +- .../libdebuggerd/tombstone_proto_to_text.h | 4 +- .../test/tombstone_proto_to_text_test.cpp | 16 +- debuggerd/libdebuggerd/tombstone.cpp | 9 +- .../libdebuggerd/tombstone_proto_to_text.cpp | 47 ++--- debuggerd/pbtombstone.cpp | 44 ++++- debuggerd/tombstone_symbolize.cpp | 160 ++++++++++++++++++ debuggerd/tombstone_symbolize.h | 42 +++++ 8 files changed, 292 insertions(+), 35 deletions(-) create mode 100644 debuggerd/tombstone_symbolize.cpp create mode 100644 debuggerd/tombstone_symbolize.h diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index d4dc9a340..3257a2c50 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -333,7 +333,10 @@ cc_binary { name: "pbtombstone", host_supported: true, defaults: ["debuggerd_defaults"], - srcs: ["pbtombstone.cpp"], + srcs: [ + "pbtombstone.cpp", + "tombstone_symbolize.cpp", + ], static_libs: [ "libbase", "libdebuggerd_tombstone_proto_to_text", diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone_proto_to_text.h b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone_proto_to_text.h index 515a15f0a..2de972344 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/tombstone_proto_to_text.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/tombstone_proto_to_text.h @@ -19,8 +19,10 @@ #include #include +class BacktraceFrame; class Tombstone; bool tombstone_proto_to_text( const Tombstone& tombstone, - std::function callback); + std::function callback, + std::function symbolize); diff --git a/debuggerd/libdebuggerd/test/tombstone_proto_to_text_test.cpp b/debuggerd/libdebuggerd/test/tombstone_proto_to_text_test.cpp index 3fdb71d48..aad209a06 100644 --- a/debuggerd/libdebuggerd/test/tombstone_proto_to_text_test.cpp +++ b/debuggerd/libdebuggerd/test/tombstone_proto_to_text_test.cpp @@ -61,12 +61,16 @@ class TombstoneProtoToTextTest : public ::testing::Test { void ProtoToString() { text_ = ""; - EXPECT_TRUE( - tombstone_proto_to_text(*tombstone_, [this](const std::string& line, bool should_log) { + EXPECT_TRUE(tombstone_proto_to_text( + *tombstone_, + [this](const std::string& line, bool should_log) { if (should_log) { text_ += "LOG "; } text_ += line + '\n'; + }, + [&](const BacktraceFrame& frame) { + text_ += "SYMBOLIZE " + frame.build_id() + " " + std::to_string(frame.pc()) + "\n"; })); } @@ -163,3 +167,11 @@ TEST_F(TombstoneProtoToTextTest, stack_record) { EXPECT_MATCH(text_, "stack_record fp:0x1 tag:0xb pc:foo\\.so\\+0x567 \\(BuildId: ABC123\\)"); EXPECT_MATCH(text_, "stack_record fp:0x2 tag:0xc pc:bar\\.so\\+0x678"); } + +TEST_F(TombstoneProtoToTextTest, symbolize) { + BacktraceFrame* frame = main_thread_->add_current_backtrace(); + frame->set_pc(12345); + frame->set_build_id("0123456789abcdef"); + ProtoToString(); + EXPECT_MATCH(text_, "\\(BuildId: 0123456789abcdef\\)\\nSYMBOLIZE 0123456789abcdef 12345\\n"); +} diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index d483b9889..30c6fe4c5 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -146,7 +146,10 @@ void engrave_tombstone(unique_fd output_fd, unique_fd proto_fd, log.tfd = output_fd.get(); log.amfd_data = amfd_data; - tombstone_proto_to_text(tombstone, [&log](const std::string& line, bool should_log) { - _LOG(&log, should_log ? logtype::HEADER : logtype::LOGS, "%s\n", line.c_str()); - }); + tombstone_proto_to_text( + tombstone, + [&log](const std::string& line, bool should_log) { + _LOG(&log, should_log ? logtype::HEADER : logtype::LOGS, "%s\n", line.c_str()); + }, + [](const BacktraceFrame&) {}); } diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index 611e237b4..fedafc0c3 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -41,6 +41,7 @@ using android::base::StringPrintf; #define CBL(...) CB(true, __VA_ARGS__) #define CBS(...) CB(false, __VA_ARGS__) using CallbackType = std::function; +using SymbolizeCallbackType = std::function; #define DESCRIBE_FLAG(flag) \ if (value & flag) { \ @@ -184,7 +185,8 @@ static void print_thread_registers(CallbackType callback, const Tombstone& tombs print_register_row(callback, word_size, special_row, should_log); } -static void print_backtrace(CallbackType callback, const Tombstone& tombstone, +static void print_backtrace(CallbackType callback, SymbolizeCallbackType symbolize, + const Tombstone& tombstone, const google::protobuf::RepeatedPtrField& backtrace, bool should_log) { int index = 0; @@ -209,11 +211,14 @@ static void print_backtrace(CallbackType callback, const Tombstone& tombstone, } line += function + build_id; CB(should_log, "%s", line.c_str()); + + symbolize(frame); } } -static void print_thread_backtrace(CallbackType callback, const Tombstone& tombstone, - const Thread& thread, bool should_log) { +static void print_thread_backtrace(CallbackType callback, SymbolizeCallbackType symbolize, + const Tombstone& tombstone, const Thread& thread, + bool should_log) { CBS(""); CB(should_log, "%d total frames", thread.current_backtrace().size()); CB(should_log, "backtrace:"); @@ -221,7 +226,7 @@ static void print_thread_backtrace(CallbackType callback, const Tombstone& tombs CB(should_log, " NOTE: %s", android::base::Join(thread.backtrace_note(), "\n NOTE: ").c_str()); } - print_backtrace(callback, tombstone, thread.current_backtrace(), should_log); + print_backtrace(callback, symbolize, tombstone, thread.current_backtrace(), should_log); } static void print_thread_memory_dump(CallbackType callback, const Tombstone& tombstone, @@ -274,10 +279,11 @@ static void print_thread_memory_dump(CallbackType callback, const Tombstone& tom } } -static void print_thread(CallbackType callback, const Tombstone& tombstone, const Thread& thread) { +static void print_thread(CallbackType callback, SymbolizeCallbackType symbolize, + const Tombstone& tombstone, const Thread& thread) { print_thread_header(callback, tombstone, thread, false); print_thread_registers(callback, tombstone, thread, false); - print_thread_backtrace(callback, tombstone, thread, false); + print_thread_backtrace(callback, symbolize, tombstone, thread, false); print_thread_memory_dump(callback, tombstone, thread); } @@ -433,8 +439,8 @@ static std::string oct_encode(const std::string& data) { return oct_encoded; } -static void print_main_thread(CallbackType callback, const Tombstone& tombstone, - const Thread& thread) { +static void print_main_thread(CallbackType callback, SymbolizeCallbackType symbolize, + const Tombstone& tombstone, const Thread& thread) { print_thread_header(callback, tombstone, thread, true); const Signal& signal_info = tombstone.signal_info(); @@ -488,7 +494,7 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone, CBL(" in this process. The stack trace below is the first system call or context"); CBL(" switch that was executed after the memory corruption happened."); } - print_thread_backtrace(callback, tombstone, thread, true); + print_thread_backtrace(callback, symbolize, tombstone, thread, true); if (tombstone.causes_size() > 1) { CBS(""); @@ -521,13 +527,13 @@ static void print_main_thread(CallbackType callback, const Tombstone& tombstone, if (heap_object.deallocation_backtrace_size() != 0) { CBS(""); CBL("deallocated by thread %" PRIu64 ":", heap_object.deallocation_tid()); - print_backtrace(callback, tombstone, heap_object.deallocation_backtrace(), true); + print_backtrace(callback, symbolize, tombstone, heap_object.deallocation_backtrace(), true); } if (heap_object.allocation_backtrace_size() != 0) { CBS(""); CBL("allocated by thread %" PRIu64 ":", heap_object.allocation_tid()); - print_backtrace(callback, tombstone, heap_object.allocation_backtrace(), true); + print_backtrace(callback, symbolize, tombstone, heap_object.allocation_backtrace(), true); } } } @@ -576,8 +582,9 @@ void print_logs(CallbackType callback, const Tombstone& tombstone, int tail) { } } -static void print_guest_thread(CallbackType callback, const Tombstone& tombstone, - const Thread& guest_thread, pid_t tid, bool should_log) { +static void print_guest_thread(CallbackType callback, SymbolizeCallbackType symbolize, + const Tombstone& tombstone, const Thread& guest_thread, pid_t tid, + bool should_log) { CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---"); CBS("Guest thread information for tid: %d", tid); print_thread_registers(callback, tombstone, guest_thread, should_log); @@ -585,12 +592,13 @@ static void print_guest_thread(CallbackType callback, const Tombstone& tombstone CBS(""); CB(true, "%d total frames", guest_thread.current_backtrace().size()); CB(true, "backtrace:"); - print_backtrace(callback, tombstone, guest_thread.current_backtrace(), should_log); + print_backtrace(callback, symbolize, tombstone, guest_thread.current_backtrace(), should_log); print_thread_memory_dump(callback, tombstone, guest_thread); } -bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) { +bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback, + SymbolizeCallbackType symbolize) { CBL("*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***"); CBL("Build fingerprint: '%s'", tombstone.build_fingerprint().c_str()); CBL("Revision: '%s'", tombstone.revision().c_str()); @@ -618,14 +626,15 @@ bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) const auto& main_thread = main_thread_it->second; - print_main_thread(callback, tombstone, main_thread); + print_main_thread(callback, symbolize, tombstone, main_thread); print_logs(callback, tombstone, 50); const auto& guest_threads = tombstone.guest_threads(); auto main_guest_thread_it = guest_threads.find(tombstone.tid()); if (main_guest_thread_it != threads.end()) { - print_guest_thread(callback, tombstone, main_guest_thread_it->second, tombstone.tid(), true); + print_guest_thread(callback, symbolize, tombstone, main_guest_thread_it->second, + tombstone.tid(), true); } // protobuf's map is unordered, so sort the keys first. @@ -638,10 +647,10 @@ bool tombstone_proto_to_text(const Tombstone& tombstone, CallbackType callback) for (const auto& tid : thread_ids) { CBS("--- --- --- --- --- --- --- --- --- --- --- --- --- --- --- ---"); - print_thread(callback, tombstone, threads.find(tid)->second); + print_thread(callback, symbolize, tombstone, threads.find(tid)->second); auto guest_thread_it = guest_threads.find(tid); if (guest_thread_it != guest_threads.end()) { - print_guest_thread(callback, tombstone, guest_thread_it->second, tid, false); + print_guest_thread(callback, symbolize, tombstone, guest_thread_it->second, tid, false); } } diff --git a/debuggerd/pbtombstone.cpp b/debuggerd/pbtombstone.cpp index dcb7c6c21..0902b386f 100644 --- a/debuggerd/pbtombstone.cpp +++ b/debuggerd/pbtombstone.cpp @@ -16,32 +16,55 @@ #include #include +#include #include #include +#include +#include + #include #include #include "tombstone.pb.h" +#include "tombstone_symbolize.h" using android::base::unique_fd; [[noreturn]] void usage(bool error) { - fprintf(stderr, "usage: pbtombstone TOMBSTONE.PB\n"); + fprintf(stderr, "usage: pbtombstone [OPTION] TOMBSTONE.PB\n"); fprintf(stderr, "Convert a protobuf tombstone to text.\n"); + fprintf(stderr, "Arguments:\n"); + fprintf(stderr, " -h, --help print this message\n"); + fprintf(stderr, " --debug-file-directory PATH specify the path to a symbols directory\n"); exit(error); } -int main(int argc, const char* argv[]) { - if (argc != 2) { +int main(int argc, char* argv[]) { + std::vector debug_file_directories; + static struct option long_options[] = { + {"debug-file-directory", required_argument, 0, 0}, + {"help", no_argument, 0, 'h'}, + {}, + }; + int c; + while ((c = getopt_long(argc, argv, "h", long_options, 0)) != -1) { + switch (c) { + case 0: + debug_file_directories.push_back(optarg); + break; + + case 'h': + usage(false); + break; + } + } + + if (optind != argc-1) { usage(true); } - if (strcmp("-h", argv[1]) == 0 || strcmp("--help", argv[1]) == 0) { - usage(false); - } - - unique_fd fd(open(argv[1], O_RDONLY | O_CLOEXEC)); + unique_fd fd(open(argv[optind], O_RDONLY | O_CLOEXEC)); if (fd == -1) { err(1, "failed to open tombstone '%s'", argv[1]); } @@ -51,8 +74,11 @@ int main(int argc, const char* argv[]) { err(1, "failed to parse tombstone"); } + Symbolizer sym; + sym.Start(debug_file_directories); bool result = tombstone_proto_to_text( - tombstone, [](const std::string& line, bool) { printf("%s\n", line.c_str()); }); + tombstone, [](const std::string& line, bool) { printf("%s\n", line.c_str()); }, + [&](const BacktraceFrame& frame) { symbolize_backtrace_frame(frame, sym); }); if (!result) { errx(1, "tombstone was malformed"); diff --git a/debuggerd/tombstone_symbolize.cpp b/debuggerd/tombstone_symbolize.cpp new file mode 100644 index 000000000..07735d0ee --- /dev/null +++ b/debuggerd/tombstone_symbolize.cpp @@ -0,0 +1,160 @@ +/* + * Copyright (C) 2024 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 "tombstone_symbolize.h" + +#include +#include +#include + +#include +#include + +#include "android-base/stringprintf.h" +#include "android-base/unique_fd.h" + +#include "tombstone.pb.h" + +using android::base::StringPrintf; +using android::base::unique_fd; + +bool Symbolizer::Start(const std::vector& debug_file_directories) { + unique_fd parent_in, parent_out, child_in, child_out; + if (!Pipe(&parent_in, &child_out) || !Pipe(&child_in, &parent_out)) { + return false; + } + + std::vector args; + args.push_back("llvm-symbolizer"); + for (const std::string &dir : debug_file_directories) { + args.push_back("--debug-file-directory"); + args.push_back(dir.c_str()); + } + args.push_back(0); + + int pid = fork(); + if (pid == -1) { + return false; + } else if (pid == 0) { + parent_in.reset(); + parent_out.reset(); + + dup2(child_in.get(), STDIN_FILENO); + dup2(child_out.get(), STDOUT_FILENO); + + execvp("llvm-symbolizer", const_cast(args.data())); + + fprintf(stderr, "unable to start llvm-symbolizer: %s\n", strerror(errno)); + _exit(1); + } else { + child_in.reset(); + child_out.reset(); + + // TODO: Check that llvm-symbolizer started up successfully. + // There used to be an easy way to do this, but it was removed in: + // https://github.com/llvm/llvm-project/commit/1792852f86dc75efa1f44d46b1a0daf386d64afa + + in_fd = std::move(parent_in); + out_fd = std::move(parent_out); + return true; + } +} + +std::string Symbolizer::read_response() { + std::string resp; + + while (resp.size() < 2 || resp[resp.size() - 2] != '\n' || resp[resp.size() - 1] != '\n') { + char buf[4096]; + ssize_t size = read(in_fd, buf, 4096); + if (size <= 0) { + return ""; + } + resp.append(buf, size); + } + + return resp; +} + +std::vector Symbolizer::SymbolizeCode(std::string path, uint64_t rel_pc) { + std::string request = StringPrintf("CODE %s 0x%" PRIx64 "\n", path.c_str(), rel_pc); + if (write(out_fd, request.c_str(), request.size()) != static_cast(request.size())) { + return {}; + } + + std::string response = read_response(); + if (response.empty()) { + return {}; + } + + std::vector frames; + + size_t frame_start = 0; + while (frame_start < response.size() - 1) { + Symbolizer::Frame frame; + + size_t second_line_start = response.find('\n', frame_start) + 1; + if (second_line_start == std::string::npos + 1) { + return {}; + } + + size_t third_line_start = response.find('\n', second_line_start) + 1; + if (third_line_start == std::string::npos + 1) { + return {}; + } + + frame.function_name = response.substr(frame_start, second_line_start - frame_start - 1); + + size_t column_number_start = response.rfind(':', third_line_start); + if (column_number_start == std::string::npos) { + return {}; + } + + size_t line_number_start = response.rfind(':', column_number_start - 1); + if (line_number_start == std::string::npos) { + return {}; + } + + frame.file = response.substr(second_line_start, line_number_start - second_line_start); + + errno = 0; + frame.line = strtoull(response.c_str() + line_number_start + 1, 0, 10); + frame.column = strtoull(response.c_str() + column_number_start + 1, 0, 10); + if (errno != 0) { + return {}; + } + + frames.push_back(frame); + + frame_start = third_line_start; + } + + if (frames.size() == 1 && frames[0].file == "??") { + return {}; + } + + return frames; +} + +void symbolize_backtrace_frame(const BacktraceFrame& frame, Symbolizer& sym) { + if (frame.build_id().empty()) { + return; + } + + for (Symbolizer::Frame f : sym.SymbolizeCode("BUILDID:" + frame.build_id(), frame.rel_pc())) { + printf(" %s:%" PRId64 ":%" PRId64 " (%s)\n", f.file.c_str(), f.line, f.column, + f.function_name.c_str()); + } +} diff --git a/debuggerd/tombstone_symbolize.h b/debuggerd/tombstone_symbolize.h new file mode 100644 index 000000000..c22d677ee --- /dev/null +++ b/debuggerd/tombstone_symbolize.h @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2024 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 +#include + +#include "android-base/unique_fd.h" + +class BacktraceFrame; + +class Symbolizer { + android::base::unique_fd in_fd, out_fd; + + std::string read_response(); + + public: + bool Start(const std::vector& debug_file_directories); + + struct Frame { + std::string function_name, file; + uint64_t line, column; + }; + + std::vector SymbolizeCode(std::string path, uint64_t rel_pc); +}; + +void symbolize_backtrace_frame(const BacktraceFrame& frame, Symbolizer& sym); From 5cc1ca1762cc0e4aa955fb50e41fcd810d0641ae Mon Sep 17 00:00:00 2001 From: Konrad Adamczyk Date: Thu, 31 Oct 2024 08:25:54 +0000 Subject: [PATCH 087/183] Revert^3 "init: Look for super partition only on a boot device" This reverts commit 5bfb93678fa26e9763699669e6bbf1c2c6a7478d. Reason for revert: b/376468452 and trusty boot up on arm64. This CL is causing a lot of troubles (now only on emulator, but may affect more devices in field) and shall be reverted. Desktop team will handle support for selecting single boot source (while having more than one) as part of boot_part_uuid support (at aosp/3318438). Change-Id: I2804c119631f592d0862f3472ffe18dbb23b17e5 --- init/block_dev_initializer.cpp | 6 +----- init/devices.cpp | 22 ---------------------- init/devices.h | 1 - 3 files changed, 1 insertion(+), 28 deletions(-) diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index cabeb0109..8f5215856 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -98,11 +98,7 @@ ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent, LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name; - // Remove partition from the list only if it was found on boot device - if (device_handler_->IsBootDevice(uevent)) { - devices->erase(iter); - } - + devices->erase(iter); device_handler_->HandleUevent(uevent); return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue; } diff --git a/init/devices.cpp b/init/devices.cpp index 6a3a64dd8..f2bb9d276 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -188,28 +188,6 @@ void SysfsPermissions::SetPermissions(const std::string& path) const { } } -bool DeviceHandler::IsBootDevice(const Uevent& uevent) const { - std::string device; - - if (FindPlatformDevice(uevent.path, &device)) { - // Skip /devices/platform or /devices/ if present - static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; - static constexpr std::string_view devices_prefix = "/devices/"; - - if (StartsWith(device, devices_platform_prefix)) { - device = device.substr(devices_platform_prefix.length()); - } else if (StartsWith(device, devices_prefix)) { - device = device.substr(devices_prefix.length()); - } - } else if (FindPciDevicePrefix(uevent.path, &device)) { - } else if (FindVbdDevicePrefix(uevent.path, &device)) { - } else { - return false; - } - - return boot_devices_.find(device) != boot_devices_.end(); -} - std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) { static const auto partition_map = [] { std::vector> partition_map; diff --git a/init/devices.h b/init/devices.h index 4df604d00..6da123259 100644 --- a/init/devices.h +++ b/init/devices.h @@ -133,7 +133,6 @@ class DeviceHandler : public UeventHandler { // `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to // `userdata`. static std::string GetPartitionNameForDevice(const std::string& device); - bool IsBootDevice(const Uevent& uevent) const; private: void ColdbootDone() override; From a5560db8cc7d0e61e080b7c4bd7696a0daf3d0f2 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Thu, 31 Oct 2024 09:59:19 -0700 Subject: [PATCH 088/183] libsnapshot: Add script to test snapshot updates $time ./system/core/fs_mgr/libsnapshot/apply-update.sh --update-static-partitions Update completed real 1m19.850s user 0m10.319s sys 0m7.448s Dynamic parition update only: $time ./system/core/fs_mgr/libsnapshot/apply-update.sh Update completed real 0m19.032s user 0m10.480s sys 0m7.462s Bug: 329255363 Test: apply-update.sh Change-Id: I2af4fe022e35b2b813ff83e2084d22295b3057dc Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/scripts/apply-update.sh | 77 ++++++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100755 fs_mgr/libsnapshot/scripts/apply-update.sh diff --git a/fs_mgr/libsnapshot/scripts/apply-update.sh b/fs_mgr/libsnapshot/scripts/apply-update.sh new file mode 100755 index 000000000..90b0119a2 --- /dev/null +++ b/fs_mgr/libsnapshot/scripts/apply-update.sh @@ -0,0 +1,77 @@ +#!/bin/bash + +# This is a debug script to quicky test end-to-end flow +# of snapshot updates without going through update-engine. +# +# Usage: +# +# To update both dynamic and static partitions: +# +# ./system/core/fs_mgr/libsnapshot/apply_update.sh [--update-static-partitions] [--wipe] +# +# --update-static-partitions: This will update bootloader and static A/B +# partitions +# --wipe: Allows data wipe as part of update flow +# +# To update dynamic partitions only (this should be used when static +# partitions are present in both the slots): +# +# ./system/core/fs_mgr/libsnapshot/apply_update.sh +# +# + +rm -f $OUT/*.patch + +# Compare images and create snapshot patches. Currently, this +# just compares two identical images in $OUT. In general, any source +# and target images could be passed to create snapshot patches. However, +# care must be taken to ensure source images are already present on the device. +# +# create_snapshot is a host side binary. Build it with `m create_snapshot` +create_snapshot --source=$OUT/system.img --target=$OUT/system.img & +create_snapshot --source=$OUT/product.img --target=$OUT/product.img & +create_snapshot --source=$OUT/vendor.img --target=$OUT/vendor.img & +create_snapshot --source=$OUT/system_ext.img --target=$OUT/system_ext.img & +create_snapshot --source=$OUT/vendor_dlkm.img --target=$OUT/vendor_dlkm.img & +create_snapshot --source=$OUT/system_dlkm.img --target=$OUT/system_dlkm.img & + +echo "Waiting for snapshot patch creation" +wait $(jobs -p) +echo "Snapshot patch creation completed" + +mv *.patch $OUT/ + +adb root +adb wait-for-device +adb shell mkdir -p /data/update/ +adb push $OUT/*.patch /data/update/ + +if [[ "$2" == "--wipe" ]]; then + adb shell snapshotctl apply-update /data/update/ -w +else + adb shell snapshotctl apply-update /data/update/ +fi + +# Check if the --update-static-partitions option is provided. +# For quick developer workflow, there is no need to repeatedly +# apply static partitions. +if [[ "$1" == "--update-static-partitions" ]]; then + adb reboot bootloader + sleep 5 + if [[ "$2" == "--wipe" ]]; then + fastboot -w + fi + fastboot flash bootloader $OUT/bootloader.img + sleep 1 + fastboot reboot bootloader + sleep 1 + fastboot flash radio $OUT/radio.img + sleep 1 + fastboot reboot bootloader + sleep 1 + fastboot flashall --exclude-dynamic-partitions --disable-super-optimization +else + adb reboot +fi + +echo "Update completed" From de6707df0c0decfeb92a1e73a64d3a610e16d061 Mon Sep 17 00:00:00 2001 From: Liana Kazanova Date: Thu, 31 Oct 2024 18:43:18 +0000 Subject: [PATCH 089/183] Revert "Set input thread priority to RT" This reverts commit 930f77b02c8ba5a7bb8e54653455f9885d90748a. Reason for revert: DroidMonitor: Potential culprit for http://b/376665573 - verifying through ABTD before revert submission. This is part of the standard investigation process, and does not mean your CL will be reverted. Change-Id: I9b9914703946f1eb4e40e779aa9cb5154ea108d3 --- libprocessgroup/profiles/task_profiles.json | 15 +----- libprocessgroup/task_profiles.cpp | 56 ++++++--------------- 2 files changed, 17 insertions(+), 54 deletions(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index d61939f29..feda3b49c 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -202,19 +202,6 @@ } ] }, - { - "Name": "RealTimeInputScheduling", - "Actions": [ - { - "Name": "SetSchedulerPolicy", - "Params": - { - "Policy": "SCHED_FIFO", - "Priority": "98" - } - } - ] - }, { "Name": "CameraServicePerformance", "Actions": [ @@ -717,7 +704,7 @@ }, { "Name": "InputPolicy", - "Profiles": [ "RealTimeInputScheduling", "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] + "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] } ] } diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index f3594e345..cc675b3fe 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -20,7 +20,6 @@ #include #include -#include #include #include @@ -55,7 +54,6 @@ static constexpr const char* TASK_PROFILE_DB_VENDOR_FILE = "/vendor/etc/task_pro static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE = "/etc/task_profiles/task_profiles_%u.json"; -namespace { class FdCacheHelper { public: @@ -66,11 +64,8 @@ class FdCacheHelper { }; static void Cache(const std::string& path, android::base::unique_fd& fd); - static void Drop(android::base::unique_fd& fd); - static void Init(const std::string& path, android::base::unique_fd& fd); - static bool IsCached(const android::base::unique_fd& fd) { return fd > FDS_INACCESSIBLE; } private: @@ -121,17 +116,6 @@ bool FdCacheHelper::IsAppDependentPath(const std::string& path) { return path.find("", 0) != std::string::npos || path.find("", 0) != std::string::npos; } -std::optional readLong(const std::string& str) { - char* end; - const long result = strtol(str.c_str(), &end, 10); - if (end > str.c_str()) { - return result; - } - return std::nullopt; -} - -} // namespace - IProfileAttribute::~IProfileAttribute() = default; const std::string& ProfileAttribute::file_name() const { @@ -940,12 +924,15 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { LOG(WARNING) << "JoinCgroup: controller " << controller_name << " is not found"; } } else if (action_name == "SetTimerSlack") { - const std::string slack_string = params_val["Slack"].asString(); - std::optional slack = readLong(slack_string); - if (slack && *slack >= 0) { - profile->Add(std::make_unique(*slack)); + std::string slack_value = params_val["Slack"].asString(); + char* end; + unsigned long slack; + + slack = strtoul(slack_value.c_str(), &end, 10); + if (end > slack_value.c_str()) { + profile->Add(std::make_unique(slack)); } else { - LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_string; + LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_value; } } else if (action_name == "SetAttribute") { std::string attr_name = params_val["Name"].asString(); @@ -1004,19 +991,15 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { // If present, this optional value will be passed in an additional syscall // to setpriority(), since the sched_priority value must be 0 for calls to // sched_setscheduler() with "normal" policies. - const std::string nice_string = params_val["Nice"].asString(); - const std::optional nice = readLong(nice_string); + const int nice = params_val["Nice"].asInt(); - if (!nice) { - LOG(FATAL) << "Invalid nice value specified: " << nice_string; - } const int LINUX_MIN_NICE = -20; const int LINUX_MAX_NICE = 19; - if (*nice < LINUX_MIN_NICE || *nice > LINUX_MAX_NICE) { - LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << *nice + if (nice < LINUX_MIN_NICE || nice > LINUX_MAX_NICE) { + LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << nice << ") appears out of range."; } - profile->Add(std::make_unique(policy, *nice)); + profile->Add(std::make_unique(policy, nice)); } else { profile->Add(std::make_unique(policy)); } @@ -1029,18 +1012,11 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { // This is a "virtual priority" as described by `man 2 sched_get_priority_min` // that will be mapped onto the following range for the provided policy: // [sched_get_priority_min(), sched_get_priority_max()] + const int virtual_priority = params_val["Priority"].asInt(); - const std::string priority_string = params_val["Priority"].asString(); - std::optional virtual_priority = readLong(priority_string); - if (virtual_priority && *virtual_priority > 0) { - int priority; - if (SetSchedulerPolicyAction::toPriority(policy, *virtual_priority, - priority)) { - profile->Add( - std::make_unique(policy, priority)); - } - } else { - LOG(WARNING) << "Invalid priority value: " << priority_string; + int priority; + if (SetSchedulerPolicyAction::toPriority(policy, virtual_priority, priority)) { + profile->Add(std::make_unique(policy, priority)); } } } else { From a3cf826de61ce3eafa4410092e5ae6ed83b932b1 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Thu, 31 Oct 2024 22:38:50 +0000 Subject: [PATCH 090/183] Set input thread priority to RT - try 2 This reverts commit de6707df0c0decfeb92a1e73a64d3a610e16d061. Reason for revert: changing code without modifying JSON file now Original description: To improve input latency, set the critical input threads to RT priority. This will use RT priority on AOSP devices by default. OEMs can still choose to customize what "input policy" means for their device, which may not necessarily mean RT. For example, on device with multiple small / big cores, input task affinity could be changed to prioritize big cores + higher CPU frequency / voltage, but still keep the standard / default input thread priority. With this patch, I'm finding that sometimes, one of the critical input threads has priority 100 instead of the expected 98. Still looking into that specific issue, but the issue is already present with the existing "input policy" code. Bug: 330719044 Flag: com.android.input.flags.enable_input_policy_profile Test: took perfetto trace and checked the priority on InputDispatcher and InputReader threads. Change-Id: I3dabf4da0398324cf542e701c103551343b883cf --- libprocessgroup/task_profiles.cpp | 56 ++++++++++++++++++++++--------- 1 file changed, 40 insertions(+), 16 deletions(-) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index cc675b3fe..f3594e345 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -20,6 +20,7 @@ #include #include +#include #include #include @@ -54,6 +55,7 @@ static constexpr const char* TASK_PROFILE_DB_VENDOR_FILE = "/vendor/etc/task_pro static constexpr const char* TEMPLATE_TASK_PROFILE_API_FILE = "/etc/task_profiles/task_profiles_%u.json"; +namespace { class FdCacheHelper { public: @@ -64,8 +66,11 @@ class FdCacheHelper { }; static void Cache(const std::string& path, android::base::unique_fd& fd); + static void Drop(android::base::unique_fd& fd); + static void Init(const std::string& path, android::base::unique_fd& fd); + static bool IsCached(const android::base::unique_fd& fd) { return fd > FDS_INACCESSIBLE; } private: @@ -116,6 +121,17 @@ bool FdCacheHelper::IsAppDependentPath(const std::string& path) { return path.find("", 0) != std::string::npos || path.find("", 0) != std::string::npos; } +std::optional readLong(const std::string& str) { + char* end; + const long result = strtol(str.c_str(), &end, 10); + if (end > str.c_str()) { + return result; + } + return std::nullopt; +} + +} // namespace + IProfileAttribute::~IProfileAttribute() = default; const std::string& ProfileAttribute::file_name() const { @@ -924,15 +940,12 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { LOG(WARNING) << "JoinCgroup: controller " << controller_name << " is not found"; } } else if (action_name == "SetTimerSlack") { - std::string slack_value = params_val["Slack"].asString(); - char* end; - unsigned long slack; - - slack = strtoul(slack_value.c_str(), &end, 10); - if (end > slack_value.c_str()) { - profile->Add(std::make_unique(slack)); + const std::string slack_string = params_val["Slack"].asString(); + std::optional slack = readLong(slack_string); + if (slack && *slack >= 0) { + profile->Add(std::make_unique(*slack)); } else { - LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_value; + LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slack_string; } } else if (action_name == "SetAttribute") { std::string attr_name = params_val["Name"].asString(); @@ -991,15 +1004,19 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { // If present, this optional value will be passed in an additional syscall // to setpriority(), since the sched_priority value must be 0 for calls to // sched_setscheduler() with "normal" policies. - const int nice = params_val["Nice"].asInt(); + const std::string nice_string = params_val["Nice"].asString(); + const std::optional nice = readLong(nice_string); + if (!nice) { + LOG(FATAL) << "Invalid nice value specified: " << nice_string; + } const int LINUX_MIN_NICE = -20; const int LINUX_MAX_NICE = 19; - if (nice < LINUX_MIN_NICE || nice > LINUX_MAX_NICE) { - LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << nice + if (*nice < LINUX_MIN_NICE || *nice > LINUX_MAX_NICE) { + LOG(WARNING) << "SetSchedulerPolicy: Provided nice (" << *nice << ") appears out of range."; } - profile->Add(std::make_unique(policy, nice)); + profile->Add(std::make_unique(policy, *nice)); } else { profile->Add(std::make_unique(policy)); } @@ -1012,11 +1029,18 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { // This is a "virtual priority" as described by `man 2 sched_get_priority_min` // that will be mapped onto the following range for the provided policy: // [sched_get_priority_min(), sched_get_priority_max()] - const int virtual_priority = params_val["Priority"].asInt(); - int priority; - if (SetSchedulerPolicyAction::toPriority(policy, virtual_priority, priority)) { - profile->Add(std::make_unique(policy, priority)); + const std::string priority_string = params_val["Priority"].asString(); + std::optional virtual_priority = readLong(priority_string); + if (virtual_priority && *virtual_priority > 0) { + int priority; + if (SetSchedulerPolicyAction::toPriority(policy, *virtual_priority, + priority)) { + profile->Add( + std::make_unique(policy, priority)); + } + } else { + LOG(WARNING) << "Invalid priority value: " << priority_string; } } } else { From b1f0c1bfdafbac5f816346cb19ac6323ee8e4c25 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Fri, 1 Nov 2024 21:02:49 +0000 Subject: [PATCH 091/183] libsnapshot: Update libprocessgroup dependencies Bug: 349105928 Change-Id: I0a795c185ae453b86e0373e6786bd77a0d265b01 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index e4d2d0458..06c27e71b 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -88,7 +88,6 @@ cc_library_static { "libprocessgroup", "libprocessgroup_util", "libjsoncpp", - "libcgrouprc", ], include_dirs: ["bionic/libc/kernel"], export_include_dirs: ["include"], @@ -132,7 +131,6 @@ cc_defaults { "libprocessgroup", "libprocessgroup_util", "libjsoncpp", - "libcgrouprc", "libsnapuserd_client", "libz", "liblz4", @@ -224,7 +222,6 @@ cc_defaults { "libprocessgroup", "libprocessgroup_util", "libjsoncpp", - "libcgrouprc", "liburing", "libz", ], @@ -319,7 +316,6 @@ cc_binary_host { "libsnapuserd", "libprocessgroup", "libjsoncpp", - "libcgrouprc", "liburing", "libz", ], From 8a45aaaf128018703546dc5b423778895826e947 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Fri, 1 Nov 2024 21:04:39 +0000 Subject: [PATCH 092/183] libprocessgroup: Update libprocessgroup dependencies Bug: 349105928 Change-Id: Iee047ccafe4c71eaf9c614fbe9a68585645a16f8 --- libprocessgroup/Android.bp | 1 - libprocessgroup/setup/Android.bp | 1 - 2 files changed, 2 deletions(-) diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index 8448a39a4..1e76e766f 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -110,7 +110,6 @@ cc_test { ], shared_libs: [ "libbase", - "libcgrouprc", "libprocessgroup", ], static_libs: [ diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp index cc6c67cf4..25737f5b2 100644 --- a/libprocessgroup/setup/Android.bp +++ b/libprocessgroup/setup/Android.bp @@ -29,7 +29,6 @@ cc_library_shared { ], shared_libs: [ "libbase", - "libcgrouprc", "libjsoncpp", ], static_libs: [ From 0b678adb6adf559e11191f3803be6dbd7194c9db Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Fri, 1 Nov 2024 21:06:30 +0000 Subject: [PATCH 093/183] libcutils: Update libprocessgroup dependencies Bug: 349105928 Change-Id: I9d9230e415724657f9d49a09861f1046fbe4dc55 --- libcutils/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 3471de0f4..10392889d 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -279,7 +279,6 @@ test_libraries = [ "liblog", "libbase", "libprocessgroup", - "libcgrouprc", ] cc_test { From 454167f5bd4504d5394536461eb6ddd3f4e0d9bc Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Sat, 2 Nov 2024 23:43:22 -0700 Subject: [PATCH 094/183] libsnapuserd: Handle empty response from server If server disconnects, then handle the empty response. Bug: 377068272 Test: Full OTA Change-Id: Ic48204c457ef924ba9a3c1ae84a3317fb1ccda04 Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp index ddefb9f91..7c820f32b 100644 --- a/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp +++ b/fs_mgr/libsnapshot/snapuserd/snapuserd_client.cpp @@ -311,6 +311,11 @@ double SnapuserdClient::GetMergePercent() { } std::string response = Receivemsg(); + // If server socket disconnects most likely because of device reboot, + // then we just return 0. + if (response.empty()) { + return 0.0; + } return std::stod(response); } From 1de3ab901368c510c906d3d4e4b9a912af05e7e8 Mon Sep 17 00:00:00 2001 From: Kelvin Zhang Date: Tue, 5 Nov 2024 18:04:32 +0000 Subject: [PATCH 095/183] Revert^5 "Set block device as RO/RW before mount" This reverts commit 5fd1be1a5a90f4e53d6e7f6bd8562d1940271773. Reason for revert: b/377081806 Change-Id: I9c5761f6193979795e4350c9c7f89f18b9a868fd --- fs_mgr/fs_mgr.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index ea2e3a8c7..5156754a8 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -826,9 +826,6 @@ static int __mount(const std::string& source, const std::string& target, const F if (read_only) { mountflags |= MS_RDONLY; } - if (!fs_mgr_set_blk_ro(source, read_only)) { - PLOG(ERROR) << "Failed to set " << source << " as " << (read_only ? "RO" : "RW"); - } int ret = 0; int save_errno = 0; int gc_allowance = 0; @@ -883,6 +880,9 @@ static int __mount(const std::string& source, const std::string& target, const F } PINFO << __FUNCTION__ << "(source=" << source << source_missing << ",target=" << target << target_missing << ",type=" << entry.fs_type << ")=" << ret; + if ((ret == 0) && (mountflags & MS_RDONLY) != 0) { + fs_mgr_set_blk_ro(source); + } if (ret == 0) { android::base::SetProperty("ro.boottime.init.mount." + Basename(target), std::to_string(t.duration().count())); From 519d3f8b368ae87d12814480066a8eb3c8f63216 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 16 Oct 2024 09:23:06 -0700 Subject: [PATCH 096/183] fs_mgr: Add getter for androidboot.boot_part_uuid In order to make booting from some media types (like USB) more robust, the bootloader will be extended to support passing the partition UUID that it loaded the kernel from. It can pass this via kernel commandline or via bootconfig. Add a way to get this. Bug: 316324155 Test: Use the getter in a future change Change-Id: Iab04742c0f2666db18dc48bcaaa2869eba405748 --- fs_mgr/libfstab/fstab.cpp | 16 ++++++++++++++++ fs_mgr/libfstab/include/fstab/fstab.h | 10 ++++++++++ 2 files changed, 26 insertions(+) diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index 6e4cae18f..43547eaf4 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -950,6 +950,22 @@ std::set GetBootDevices() { return ExtraBootDevices(fstab); } +std::string GetBootPartUuid() { + std::string boot_part_uuid; + + if (GetBootconfig("androidboot.boot_part_uuid", &boot_part_uuid)) { + return boot_part_uuid; + } + + ImportKernelCmdline([&](std::string key, std::string value) { + if (key == "androidboot.boot_part_uuid") { + boot_part_uuid = value; + } + }); + + return boot_part_uuid; +} + std::string GetVerityDeviceName(const FstabEntry& entry) { std::string base_device; if (entry.mount_point == "/") { diff --git a/fs_mgr/libfstab/include/fstab/fstab.h b/fs_mgr/libfstab/include/fstab/fstab.h index 070dd9178..0ff3188d4 100644 --- a/fs_mgr/libfstab/include/fstab/fstab.h +++ b/fs_mgr/libfstab/include/fstab/fstab.h @@ -126,6 +126,16 @@ void TransformFstabForDsu(Fstab* fstab, const std::string& dsu_slot, std::set GetBootDevices(); +// Get the Partition UUID the kernel loaded from if the bootloader passed it. +// +// If the kernel's Partition UUID is provided then we can use this to help +// identify which block device contains the filesystems we care about. +// +// NOTE: Nothing secures a UUID other than the convention that two disks +// aren't supposed to both have the same UUID. We still need other mechanisms +// to ensure we've got the right disk. +std::string GetBootPartUuid(); + // Return the name of the dm-verity device for the given fstab entry. This does // not check whether the device is valid or exists; it merely returns the // expected name. From e53e50e3fa8e73b86163806d6f8eeb9eadf28bb7 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 16 Oct 2024 13:51:44 -0700 Subject: [PATCH 097/183] init: Add partition_uuid to Uevent As of commit upstream Linux kernel commit 74f4a8dc0dd8 ("block: add partition uuid into uevent as "PARTUUID""), it's easy to include the partition UUID in the Uevent structure. Add it in so that other parts of the init code can make decisions based on the partition UUID. If this code is run on older kernels we'll never see the partition UUID and it will be left blank. Bug: 316324155 Test: Run w/ a newer kernel and see partition_uuid populated. Change-Id: I48a52aa006c05023f7f1cc5cc0ab5c1f1ec37455 --- init/uevent.h | 1 + init/uevent_listener.cpp | 5 ++++- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/init/uevent.h b/init/uevent.h index dc35fd968..c8ca52aaf 100644 --- a/init/uevent.h +++ b/init/uevent.h @@ -28,6 +28,7 @@ struct Uevent { std::string subsystem; std::string firmware; std::string partition_name; + std::string partition_uuid; std::string device_name; std::string modalias; int partition_num; diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp index 5da67777d..97f3de640 100644 --- a/init/uevent_listener.cpp +++ b/init/uevent_listener.cpp @@ -66,6 +66,9 @@ static void ParseEvent(const char* msg, Uevent* uevent) { } else if (!strncmp(msg, "PARTNAME=", 9)) { msg += 9; uevent->partition_name = msg; + } else if (!strncmp(msg, "PARTUUID=", 9)) { + msg += 9; + uevent->partition_uuid = msg; } else if (!strncmp(msg, "DEVNAME=", 8)) { msg += 8; uevent->device_name = msg; @@ -82,7 +85,7 @@ static void ParseEvent(const char* msg, Uevent* uevent) { if (LOG_UEVENTS) { LOG(INFO) << "event { '" << uevent->action << "', '" << uevent->path << "', '" << uevent->subsystem << "', '" << uevent->firmware << "', " << uevent->major - << ", " << uevent->minor << " }"; + << ", " << uevent->minor << ", " << uevent->partition_uuid << " }"; } } From 9f760f8d4185d231ef2d085d2a7664046250d7e5 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 15 Oct 2024 14:22:02 -0700 Subject: [PATCH 098/183] init: Reorder GetBlockDeviceSymlinks() so FindDmDevice() is first By moving FindDmDevice() it's easier to unify the code with the IsBootDevice() function. In this case the order doesn't matter since anything with the uevent path "/devices/virtual/block/dm-" (the only devices FindDmDevice() looks at) won't match any of the other sections of the if/then/else test. Bug: 316324155 Test: Build & boot Change-Id: I819eb60aa5077f0eb2c2f2783b152e43a52ba8b7 --- init/devices.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/init/devices.cpp b/init/devices.cpp index f2bb9d276..0af843f10 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -376,7 +376,13 @@ std::vector DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev std::string partition; std::string uuid; - if (FindPlatformDevice(uevent.path, &device)) { + if (FindDmDevice(uevent, &partition, &uuid)) { + std::vector symlinks = {"/dev/block/mapper/" + partition}; + if (!uuid.empty()) { + symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid); + } + return symlinks; + } else if (FindPlatformDevice(uevent.path, &device)) { // Skip /devices/platform or /devices/ if present static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; static constexpr std::string_view devices_prefix = "/devices/"; @@ -392,12 +398,6 @@ std::vector DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev type = "pci"; } else if (FindVbdDevicePrefix(uevent.path, &device)) { type = "vbd"; - } else if (FindDmDevice(uevent, &partition, &uuid)) { - std::vector symlinks = {"/dev/block/mapper/" + partition}; - if (!uuid.empty()) { - symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid); - } - return symlinks; } else { return {}; } From 06c4e96fd87cd488aabf5e657a2870a707b9f105 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Tue, 5 Nov 2024 16:49:26 +0900 Subject: [PATCH 099/183] Deprecating libvendorsupport_llndk_headers Versioned LLNDK symbols are guarded with __builtin_available. Bug: 362658565 Test: m --no-skip-soong-tests Change-Id: I0fb3bc87b74da62b8a8fba0c5bb6a3373e6a55dc --- libvendorsupport/Android.bp | 29 ------------ .../include_llndk/android/llndk-versioning.h | 45 ------------------- 2 files changed, 74 deletions(-) delete mode 100644 libvendorsupport/include_llndk/android/llndk-versioning.h diff --git a/libvendorsupport/Android.bp b/libvendorsupport/Android.bp index a22737c06..f9a889b94 100644 --- a/libvendorsupport/Android.bp +++ b/libvendorsupport/Android.bp @@ -35,32 +35,3 @@ cc_library { "libbase", ], } - -cc_library_headers { - name: "libvendorsupport_llndk_headers", - host_supported: true, - vendor_available: true, - recovery_available: true, - ramdisk_available: true, - vendor_ramdisk_available: true, - native_bridge_supported: true, - - export_include_dirs: ["include_llndk"], - llndk: { - llndk_headers: true, - }, - - apex_available: [ - "//apex_available:platform", - "//apex_available:anyapex", - ], - min_sdk_version: "apex_inherit", - - system_shared_libs: [], - stl: "none", - - // This header library is used for libc and must be available to any sdk - // versions. - // Setting sdk_version to the lowest version allows the dependencies. - sdk_version: "1", -} diff --git a/libvendorsupport/include_llndk/android/llndk-versioning.h b/libvendorsupport/include_llndk/android/llndk-versioning.h deleted file mode 100644 index 81d165f47..000000000 --- a/libvendorsupport/include_llndk/android/llndk-versioning.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2024 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 - -// LLNDK (https://source.android.com/docs/core/architecture/vndk/build-system#ll-ndk) is similar to -// NDK, but uses its own versioning of YYYYMM format for vendor builds. The LLNDK symbols are -// enabled when the vendor api level is equal to or newer than the ro.board.api_level. These symbols -// must be annotated in map.txt files with the `# llndk=YYYYMM` annotation. They also must be marked -// with `__INTRODUCED_IN_LLNDK(YYYYMM)` in the header files. It leaves a no-op annotation for ABI -// analysis. -#if !defined(__INTRODUCED_IN_LLNDK) -#define __INTRODUCED_IN_LLNDK(vendor_api_level) \ - __attribute__((annotate("introduced_in_llndk=" #vendor_api_level))) -#endif - -#if defined(__ANDROID_VENDOR_API__) -// __ANDROID_VENDOR_API__ is defined only for vendor or product variant modules. -// Use this macro as an `if` statement to call an API that are available to both NDK and LLNDK. -// This returns true for vendor or product modules if the vendor_api_level is less than or equal to -// the ro.board.api_level. -#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ - constexpr(__ANDROID_VENDOR_API__ >= vendor_api_level) - -#else // __ANDROID_VENDOR_API__ - -// For non-vendor modules, API_LEVEL_AT_LEAST is replaced with __builtin_available(sdk_api_level) to -// guard the API for __INTRODUCED_IN. -#if !defined(API_LEVEL_AT_LEAST) -#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ - (__builtin_available(android sdk_api_level, *)) -#endif - -#endif // __ANDROID_VENDOR_API__ From 01af5431f7b4353706527477aaa3118476e5b8a2 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Tue, 5 Nov 2024 22:22:12 -0800 Subject: [PATCH 100/183] snapuserd: typecast cow_op->new_block to uint64_t On 32-bit devices, cow_op->new_block * BLOCK_SZ can overflow. Bug: 376978542 Test: snapuserd_test on 32-bit device 1: Initiate merge on partition > 4GB. 2: Verify no overflow. Change-Id: I4efc24891e0b330505ddf59b7db7716f054cf9c4 Signed-off-by: Akilesh Kailash --- .../libsnapshot/snapuserd/user-space-merge/merge_worker.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp index e2c58741a..486548cad 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp @@ -55,7 +55,7 @@ int MergeWorker::PrepareMerge(uint64_t* source_offset, int* pending_ops, break; } - *source_offset = cow_op->new_block * BLOCK_SZ; + *source_offset = static_cast(cow_op->new_block) * BLOCK_SZ; if (!checkOrderedOp) { replace_zero_vec->push_back(cow_op); if (cow_op->type() == kCowReplaceOp) { @@ -74,7 +74,7 @@ int MergeWorker::PrepareMerge(uint64_t* source_offset, int* pending_ops, break; } - uint64_t next_offset = op->new_block * BLOCK_SZ; + uint64_t next_offset = static_cast(op->new_block) * BLOCK_SZ; if (next_offset != (*source_offset + nr_consecutive * BLOCK_SZ)) { break; } From a2bd0e6b5db1023638e351cb1c55870b4fb8af8f Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 6 Nov 2024 16:57:37 +0000 Subject: [PATCH 101/183] Set input thread priority to RT - try 3 This partially reverts commit de6707df0c0decfeb92a1e73a64d3a610e16d061. Reason for revert: code change landed, now modifying JSON file only Original description: To improve input latency, set the critical input threads to RT priority. This will use RT priority on AOSP devices by default. OEMs can still choose to customize what "input policy" means for their device, which may not necessarily mean RT. For example, on device with multiple small / big cores, input task affinity could be changed to prioritize big cores + higher CPU frequency / voltage, but still keep the standard / default input thread priority. With this patch, I'm finding that sometimes, one of the critical input threads has priority 100 instead of the expected 98. Still looking into that specific issue, but the issue is already present with the existing "input policy" code. Bug: 330719044 Flag: com.android.input.flags.enable_input_policy_profile Test: took perfetto trace and checked the priority on InputDispatcher and InputReader threads. Change-Id: I7d8a941f36ad9e4b75a7a0f4c5d81895256d6919 --- libprocessgroup/profiles/task_profiles.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index feda3b49c..d61939f29 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -202,6 +202,19 @@ } ] }, + { + "Name": "RealTimeInputScheduling", + "Actions": [ + { + "Name": "SetSchedulerPolicy", + "Params": + { + "Policy": "SCHED_FIFO", + "Priority": "98" + } + } + ] + }, { "Name": "CameraServicePerformance", "Actions": [ @@ -704,7 +717,7 @@ }, { "Name": "InputPolicy", - "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] + "Profiles": [ "RealTimeInputScheduling", "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] } ] } From 743e8f16a731d45850505dd20c2936e6ac430a91 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 6 Nov 2024 09:24:50 -0800 Subject: [PATCH 102/183] init: Use ConsumePrefix() instead of open coding in GetBlockDeviceSymlinks() In GetBlockDeviceSymlinks() we may need to strip the "/devices/platform/" or "/devices/" from a string. Use the helper ConsumePrefix() to do this, which is more convenient and readable. This change is intended to be a no-op and just a cleanup. Bug: 316324155 Test: Build and boot Change-Id: I1adb1906ec37ff8f6f505abc5f26e1e3b157e608 --- init/devices.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/init/devices.cpp b/init/devices.cpp index 0af843f10..3054d3a56 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -45,6 +45,7 @@ using namespace std::chrono_literals; using android::base::Basename; +using android::base::ConsumePrefix; using android::base::Dirname; using android::base::ReadFileToString; using android::base::Readlink; @@ -386,11 +387,10 @@ std::vector DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev // Skip /devices/platform or /devices/ if present static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; static constexpr std::string_view devices_prefix = "/devices/"; + std::string_view str = device; - if (StartsWith(device, devices_platform_prefix)) { - device = device.substr(devices_platform_prefix.length()); - } else if (StartsWith(device, devices_prefix)) { - device = device.substr(devices_prefix.length()); + if (ConsumePrefix(&str, devices_platform_prefix) || ConsumePrefix(&str, devices_prefix)) { + device = str; } type = "platform"; From 9481f976031d58946aa78bb82ee780d28a8267ff Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Wed, 6 Nov 2024 09:28:07 -0800 Subject: [PATCH 103/183] init: Factor GetBlockDeviceInfo() out of GetBlockDeviceSymlinks() Later code will want to use GetBlockDeviceInfo(), so factor it out to a helper function. This change is intended to be a no-op. Bug: 316324155 Test: Build & boot Change-Id: If5d63f39efcd84a07eb8c6fa4f28bda45c4cbe5c --- init/devices.cpp | 57 ++++++++++++++++++++++++++++++------------------ init/devices.h | 7 ++++++ 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/init/devices.cpp b/init/devices.cpp index 3054d3a56..b067e0f4d 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -189,6 +189,34 @@ void SysfsPermissions::SetPermissions(const std::string& path) const { } } +BlockDeviceInfo DeviceHandler::GetBlockDeviceInfo(const std::string& uevent_path) const { + BlockDeviceInfo info; + + if (FindPlatformDevice(uevent_path, &info.str)) { + // Skip /devices/platform or /devices/ if present + static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; + static constexpr std::string_view devices_prefix = "/devices/"; + std::string_view str = info.str; + + if (ConsumePrefix(&str, devices_platform_prefix) || ConsumePrefix(&str, devices_prefix)) { + info.str = str; + } + info.type = "platform"; + } else if (FindPciDevicePrefix(uevent_path, &info.str)) { + info.type = "pci"; + } else if (FindVbdDevicePrefix(uevent_path, &info.str)) { + info.type = "vbd"; + } else { + // Re-clear device to be extra certain in case one of the FindXXX() + // functions returned false but still modified it. + info.str = ""; + } + + info.is_boot_device = boot_devices_.find(info.str) != boot_devices_.end(); + + return info; +} + std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) { static const auto partition_map = [] { std::vector> partition_map; @@ -372,8 +400,7 @@ void SanitizePartitionName(std::string* string) { } std::vector DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uevent) const { - std::string device; - std::string type; + BlockDeviceInfo info; std::string partition; std::string uuid; @@ -383,32 +410,20 @@ std::vector DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev symlinks.emplace_back("/dev/block/mapper/by-uuid/" + uuid); } return symlinks; - } else if (FindPlatformDevice(uevent.path, &device)) { - // Skip /devices/platform or /devices/ if present - static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; - static constexpr std::string_view devices_prefix = "/devices/"; - std::string_view str = device; + } - if (ConsumePrefix(&str, devices_platform_prefix) || ConsumePrefix(&str, devices_prefix)) { - device = str; - } + info = GetBlockDeviceInfo(uevent.path); - type = "platform"; - } else if (FindPciDevicePrefix(uevent.path, &device)) { - type = "pci"; - } else if (FindVbdDevicePrefix(uevent.path, &device)) { - type = "vbd"; - } else { + if (info.type.empty()) { return {}; } std::vector links; - LOG(VERBOSE) << "found " << type << " device " << device; + LOG(VERBOSE) << "found " << info.type << " device " << info.str; - auto link_path = "/dev/block/" + type + "/" + device; + auto link_path = "/dev/block/" + info.type + "/" + info.str; - bool is_boot_device = boot_devices_.find(device) != boot_devices_.end(); if (!uevent.partition_name.empty()) { std::string partition_name_sanitized(uevent.partition_name); SanitizePartitionName(&partition_name_sanitized); @@ -418,10 +433,10 @@ std::vector DeviceHandler::GetBlockDeviceSymlinks(const Uevent& uev } links.emplace_back(link_path + "/by-name/" + partition_name_sanitized); // Adds symlink: /dev/block/by-name/. - if (is_boot_device) { + if (info.is_boot_device) { links.emplace_back("/dev/block/by-name/" + partition_name_sanitized); } - } else if (is_boot_device) { + } else if (info.is_boot_device) { // If we don't have a partition name but we are a partition on a boot device, create a // symlink of /dev/block/by-name/ for symmetry. links.emplace_back("/dev/block/by-name/" + uevent.device_name); diff --git a/init/devices.h b/init/devices.h index 6da123259..82cb56ec0 100644 --- a/init/devices.h +++ b/init/devices.h @@ -116,6 +116,12 @@ class Subsystem { std::string dir_name_ = "/dev"; }; +struct BlockDeviceInfo { + std::string str; + std::string type; + bool is_boot_device; +}; + class DeviceHandler : public UeventHandler { public: friend class DeviceHandlerTester; @@ -136,6 +142,7 @@ class DeviceHandler : public UeventHandler { private: void ColdbootDone() override; + BlockDeviceInfo GetBlockDeviceInfo(const std::string& uevent_path) const; bool FindPlatformDevice(std::string path, std::string* platform_device_path) const; std::tuple GetDevicePermissions( const std::string& path, const std::vector& links) const; From 6519e6d67f68e846c0516e40bd2529330ce60468 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 22 Oct 2024 14:09:26 -0700 Subject: [PATCH 104/183] init: Break FindPlatformDevice() into a helper function We want to use the logic for FindPlatformDevice() in a future change to look for devices that have USB parents. Break out a helper function. This change is intended to be a no-op and just a reorganization. Bug: 316324155 Test: See boot devices still found Change-Id: Ic5a57a89339c43dea1334644be9386637169c61c --- init/devices.cpp | 25 +++++++++++++++++-------- init/devices.h | 2 ++ 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/init/devices.cpp b/init/devices.cpp index b067e0f4d..a2a1d3e1c 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -247,11 +247,12 @@ std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_de return {}; } -// Given a path that may start with a platform device, find the parent platform device by finding a -// parent directory with a 'subsystem' symlink that points to the platform bus. -// If it doesn't start with a platform device, return false -bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const { - platform_device_path->clear(); +// Given a path to a device that may have a parent in the passed set of +// subsystems, find the parent device that's in the passed set of subsystems. +// If we don't find a parent in the passed set of subsystems, return false. +bool DeviceHandler::FindSubsystemDevice(std::string path, std::string* device_path, + const std::set& subsystem_paths) const { + device_path->clear(); // Uevents don't contain the mount point, so we need to add it here. path.insert(0, sysfs_mount_point_); @@ -261,11 +262,10 @@ bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_d while (directory != "/" && directory != ".") { std::string subsystem_link_path; if (Realpath(directory + "/subsystem", &subsystem_link_path) && - (subsystem_link_path == sysfs_mount_point_ + "/bus/platform" || - subsystem_link_path == sysfs_mount_point_ + "/bus/amba")) { + subsystem_paths.find(subsystem_link_path) != subsystem_paths.end()) { // We need to remove the mount point that we added above before returning. directory.erase(0, sysfs_mount_point_.size()); - *platform_device_path = directory; + *device_path = directory; return true; } @@ -279,6 +279,15 @@ bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_d return false; } +bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const { + const std::set subsystem_paths = { + sysfs_mount_point_ + "/bus/platform", + sysfs_mount_point_ + "/bus/amba", + }; + + return FindSubsystemDevice(path, platform_device_path, subsystem_paths); +} + void DeviceHandler::FixupSysPermissions(const std::string& upath, const std::string& subsystem) const { // upaths omit the "/sys" that paths in this list diff --git a/init/devices.h b/init/devices.h index 82cb56ec0..7eee87a12 100644 --- a/init/devices.h +++ b/init/devices.h @@ -143,6 +143,8 @@ class DeviceHandler : public UeventHandler { private: void ColdbootDone() override; BlockDeviceInfo GetBlockDeviceInfo(const std::string& uevent_path) const; + bool FindSubsystemDevice(std::string path, std::string* device_path, + const std::set& subsystem_paths) const; bool FindPlatformDevice(std::string path, std::string* platform_device_path) const; std::tuple GetDevicePermissions( const std::string& path, const std::vector& links) const; From 3de05fcff6df96c20dbfec3a7d78afecd25b005e Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 22 Oct 2024 14:13:19 -0700 Subject: [PATCH 105/183] init: Move the stripping of "/devices" and "/devices/platform/" to a helper A future change will want the same stripping when looking for USB boot devices. Move the stripping down to the helper. This change is intended to be a no-op and just a reorganization. Bug: 316324155 Test: See boot devices still found Change-Id: I025d9d68fedf652055454cbd93e15f480b6056dd --- init/devices.cpp | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/init/devices.cpp b/init/devices.cpp index a2a1d3e1c..501657ac6 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -193,14 +193,6 @@ BlockDeviceInfo DeviceHandler::GetBlockDeviceInfo(const std::string& uevent_path BlockDeviceInfo info; if (FindPlatformDevice(uevent_path, &info.str)) { - // Skip /devices/platform or /devices/ if present - static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; - static constexpr std::string_view devices_prefix = "/devices/"; - std::string_view str = info.str; - - if (ConsumePrefix(&str, devices_platform_prefix) || ConsumePrefix(&str, devices_prefix)) { - info.str = str; - } info.type = "platform"; } else if (FindPciDevicePrefix(uevent_path, &info.str)) { info.type = "pci"; @@ -265,7 +257,17 @@ bool DeviceHandler::FindSubsystemDevice(std::string path, std::string* device_pa subsystem_paths.find(subsystem_link_path) != subsystem_paths.end()) { // We need to remove the mount point that we added above before returning. directory.erase(0, sysfs_mount_point_.size()); - *device_path = directory; + + // Skip /devices/platform or /devices/ if present + static constexpr std::string_view devices_platform_prefix = "/devices/platform/"; + static constexpr std::string_view devices_prefix = "/devices/"; + std::string_view sv = directory; + + if (!ConsumePrefix(&sv, devices_platform_prefix)) { + ConsumePrefix(&sv, devices_prefix); + } + *device_path = sv; + return true; } From e9de3100619c37107c112ecc88e50cfbb210d803 Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 22 Oct 2024 14:34:30 -0700 Subject: [PATCH 106/183] init: Add the ability to find the boot device by partition UUID The current mechanism for specifying boot devices on Android systems involves passing a set of "boot_devices" though command line, bootconfig, or device tree. The bootdevices are specified as strings and, in general, need to match a sysfs path but without the "/sys/devices" or "/sys/devices/platform" prefix. The sysfs path is generally the path to the closest parent of the block device that is a "platform" device. As an example, if the sysfs path of the expected boot device is: /sys/devices/platform/soc@0/7c4000.mmc/mmc_host/mmc1/mmc1:0001/block/mmcblk1 The bootloader would specify it as "soc@0/7c4000.mmc" since: * We strip off "/sys/devices/platform/" * As we move up directories, we don't find one whose subsystem is "platform" until we get up to "/sys/devices/platform/soc@0/7c4000.mmc". The current mechanism is a bit brittle. Specifically: * The sysfs path isn't _really_ stable and can change across kernel upgrades. For instance, during one kernel upgrade the device tree for a product changed so that the root node changed from "soc" to "soc@0" and this changed all sysfs paths. In the past device tree folks have asserted that we shouldn't rely on dts node names to stay consistent, yet those node names are used to construct sysfs paths. * For some devices, like USB, the path of the closest "platform" device tends to be the path of the USB controller. This means that if two USB disks are plugged in we can't guarantee which one will be identified as the boot device. Add a new method of finding the boot device by passing the partition UUID that we loaded the kernel from. Using the partition UUID to identify the boot device is standard on Linux. You can see this because when you're not using an initramfs you can use the syntax "root=PARTUUID=[/PARTNROFF=n]" to specify the root. Using the same idea for Android's boot code makes sense. With this new method for finding the boot device, we can make the code much more specific about matching sysfs paths. Once we find the sysfs path for the kernel we can make sure that all of the other boot partition share the same "scsi" or "mmc" parent instead of going all the way to the closest platform device. In the above example, this means that we'd make sure that all boot devices are found under this sysfs node: /sys/devices/platform/soc@0/7c4000.mmc/mmc_host/mmc1/mmc1:0001/block/mmcblk1 ...instead of just making sure they are under: /sys/devices/platform/soc@0/7c4000.mmc There is the question of what we should do if the bootloader passes _both_ an old style "boot_devices" and also a partition UUID. In this case, we'll issue a warning and then ignore the old "boot_devices". Considering it a warning rather than an error could allow switching to the "boot_part_uuid" method even if an old bootloader is still hardcoding some old "boot_devices". NOTE: Using partition UUID won't cause any security problems even though someone _could_ plug in an external device crafted to have the same UUID as the normal boot device's kernel partition. We already have "verity" in the system making sure our filesystems are not tampered with and this would also protect us from booting a tampered disk. That means that the worst someone could do in this case would be to confuse the system and make the device non-bootable. Chromebooks have been using the partition UUID to find the root filesystems for years and this has never been a problem. NOTE: this new method relies on the commit ("init: Add partition_uuid to Uevent") which in turn relies upstream kernel commit 74f4a8dc0dd8 ("block: add partition uuid into uevent as "PARTUUID""). Bug: 316324155 Test: Use partition UUID to boot Change-Id: If824cb700ca3696a442a28e6ad02d7c522c3b495 --- init/README.ueventd.md | 27 +++++++++++ init/block_dev_initializer.cpp | 44 ++++++++++++++++- init/block_dev_initializer.h | 1 + init/devices.cpp | 89 ++++++++++++++++++++++++++++++++-- init/devices.h | 10 +++- init/first_stage_mount.cpp | 4 ++ init/ueventd.cpp | 21 ++++++-- 7 files changed, 185 insertions(+), 11 deletions(-) diff --git a/init/README.ueventd.md b/init/README.ueventd.md index 7d00195eb..aac4acb6a 100644 --- a/init/README.ueventd.md +++ b/init/README.ueventd.md @@ -39,6 +39,33 @@ for the node path: `device_id` is `uevent MINOR % 128 + 1`. 3. All other devices are created as `/dev/` +Whether a device is considered a "boot device" is a bit complicated. + + - The recommended way to specify the boot device is to provide the "partition UUID" containing the + kernel (or, really, any parition on the boot device) and then boot device is the block device + containing that partition. This is passed via `androidboot.boot_part_uuid` which can be provided + either via the kernel bootconfig or via the kernel commandline. As an example, you could set + `androidboot.boot_part_uuid=12345678-abcd-ef01-0234-6789abcdef01`. + - Though using `boot_part_uuid` is preferred, you can also specify the boot device via + `androidboot.boot_device` or `androidboot.boot_devices`. These can be passed via the kernel + bootconfig or the kernel command line. It is also possible to pass this via device tree by + creating a `boot_devices` property in the Android firmware node. In most cases the `boot_device` + is the sysfs path (without the `/sys/devices` or `/sys/devices/platform` prefix) to the closest + parent of the block device that's on the "platform" bus. As an example, if the block device is + `/sys/devices/platform/soc@0/7c4000.mmc/mmc_host/mmc1/mmc1:0001/block/mmcblk1` then the + `boot_device` is `soc@0/7c4000.mmc` since we strip off the `/sys/devices/platform` and nothing + past the `7c4000.mmc` directory represents a device on the "platform" bus. In the case that none + of the parents are on the "platform" bus there are special rules for block devices under PCI + and VBD (Virtual Block Device). NOTE: sysfs paths for block devices are not guaranteed to be + stable between kernel versions, which is one of the reasons why it is suggested to use + `boot_part_uuid` instead of `boot_devices`. ALSO NOTE: If more than one device matches (either + because multiple `boot_devices` were listed or because there was more than one block device + under the found sysfs directory) and these multiple matching devices provide some of the same + named partitions then the behavior is unspecified. + - There is a further fallback to determine "boot devices" via the vstab, but providing at least + `boot_devices` has been required since Android 12 so this further fallback will not be described + here. + The permissions can be modified using a ueventd.rc script and a line that beings with `/dev`. These lines take the format of diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index 8f5215856..4ca5b8f0e 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -33,7 +33,49 @@ BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) auto boot_devices = android::fs_mgr::GetBootDevices(); device_handler_ = std::make_unique( std::vector{}, std::vector{}, std::vector{}, - std::move(boot_devices), false); + std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), false); +} + +// If boot_part_uuid is specified, use it to set boot_devices +// +// When `androidboot.boot_part_uuid` is specified then that's the partition UUID +// of the kernel. Look for that partition and then set `boot_devices` to be +// exactly one item: the block device containing that partition. +// +// NOTE that `boot_part_uuid` is only specified on newer devices. Older devices +// specified `boot_devices` directly. +bool BlockDevInitializer::InitBootDevicesFromPartUuid() { + bool uuid_check_done = false; + + auto boot_part_callback = [&, this](const Uevent& uevent) -> ListenerAction { + uuid_check_done = device_handler_->CheckUeventForBootPartUuid(uevent); + return uuid_check_done ? ListenerAction::kStop : ListenerAction::kContinue; + }; + + // Re-run already arrived uevents looking for the boot partition UUID. + // + // NOTE: If we're not using the boot partition UUID to find the boot + // device then the first uevent we analyze will cause us to stop looking + // and set `uuid_check_done`. This will shortcut all of the UUID logic. + // Replaying one uevent is not expected to be slow. + uevent_listener_.RegenerateUevents(boot_part_callback); + + // If we're not done looking, poll for uevents for longer + if (!uuid_check_done) { + Timer t; + uevent_listener_.Poll(boot_part_callback, 10s); + LOG(INFO) << "Wait for boot partition returned after " << t; + } + + // Give a nicer error message if we were expecting to find the kernel boot + // partition but didn't. Later code would fail too but the message there + // is a bit further from the root cause of the problem. + if (!uuid_check_done) { + LOG(ERROR) << __PRETTY_FUNCTION__ << ": boot partition not found after polling timeout."; + return false; + } + + return true; } bool BlockDevInitializer::InitDeviceMapper() { diff --git a/init/block_dev_initializer.h b/init/block_dev_initializer.h index cb1d36555..25107c97f 100644 --- a/init/block_dev_initializer.h +++ b/init/block_dev_initializer.h @@ -29,6 +29,7 @@ class BlockDevInitializer final { public: BlockDevInitializer(); + bool InitBootDevicesFromPartUuid(); bool InitDeviceMapper(); bool InitDmUser(const std::string& name); bool InitDevices(std::set devices); diff --git a/init/devices.cpp b/init/devices.cpp index 501657ac6..0b1e13dba 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -192,7 +192,22 @@ void SysfsPermissions::SetPermissions(const std::string& path) const { BlockDeviceInfo DeviceHandler::GetBlockDeviceInfo(const std::string& uevent_path) const { BlockDeviceInfo info; - if (FindPlatformDevice(uevent_path, &info.str)) { + if (!boot_part_uuid_.empty()) { + // Only use the more specific "MMC" or "SCSI" match if a partition UUID + // was passed. Old bootloaders that aren't passing the partition UUID + // instead pass the path to the closest "platform" device. It would + // break them if we chose this deeper (more specific) path. + // + // When we have a UUID we _want_ the more specific path since it can + // handle, for instance, differentiating two USB disks that are on + // the same USB controller. Using the closest platform device would + // classify them both the same by using the path to the USB controller. + if (FindMmcDevice(uevent_path, &info.str)) { + info.type = "mmc"; + } else if (FindScsiDevice(uevent_path, &info.str)) { + info.type = "scsi"; + } + } else if (FindPlatformDevice(uevent_path, &info.str)) { info.type = "platform"; } else if (FindPciDevicePrefix(uevent_path, &info.str)) { info.type = "pci"; @@ -290,6 +305,22 @@ bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_d return FindSubsystemDevice(path, platform_device_path, subsystem_paths); } +bool DeviceHandler::FindMmcDevice(std::string path, std::string* mmc_device_path) const { + const std::set subsystem_paths = { + sysfs_mount_point_ + "/bus/mmc", + }; + + return FindSubsystemDevice(path, mmc_device_path, subsystem_paths); +} + +bool DeviceHandler::FindScsiDevice(std::string path, std::string* scsi_device_path) const { + const std::set subsystem_paths = { + sysfs_mount_point_ + "/bus/scsi", + }; + + return FindSubsystemDevice(path, scsi_device_path, subsystem_paths); +} + void DeviceHandler::FixupSysPermissions(const std::string& upath, const std::string& subsystem) const { // upaths omit the "/sys" that paths in this list @@ -567,6 +598,48 @@ void DeviceHandler::HandleAshmemUevent(const Uevent& uevent) { } } +// Check Uevents looking for the kernel's boot partition UUID +// +// When we can stop checking uevents (either because we're done or because +// we weren't looking for the kernel's boot partition UUID) then return +// true. Return false if we're not done yet. +bool DeviceHandler::CheckUeventForBootPartUuid(const Uevent& uevent) { + // If we aren't using boot_part_uuid then we're done. + if (boot_part_uuid_.empty()) { + return true; + } + + // Finding the boot partition is a one-time thing that we do at init + // time, not steady state. This is because the boot partition isn't + // allowed to go away or change. Once we found the boot partition we don't + // expect to run again. + if (found_boot_part_uuid_) { + LOG(WARNING) << __PRETTY_FUNCTION__ + << " shouldn't run after kernel boot partition is found"; + return true; + } + + // We only need to look at newly-added block devices. Note that if someone + // is replaying events all existing devices will get "add"ed. + if (uevent.subsystem != "block" || uevent.action != "add") { + return false; + } + + // If it's not the partition we care about then move on. + if (uevent.partition_uuid != boot_part_uuid_) { + return false; + } + + auto device = GetBlockDeviceInfo(uevent.path); + + LOG(INFO) << "Boot device " << device.str << " found via partition UUID"; + found_boot_part_uuid_ = true; + boot_devices_.clear(); + boot_devices_.insert(device.str); + + return true; +} + void DeviceHandler::HandleUevent(const Uevent& uevent) { if (uevent.action == "add" || uevent.action == "change" || uevent.action == "bind" || uevent.action == "online") { @@ -629,17 +702,25 @@ void DeviceHandler::ColdbootDone() { DeviceHandler::DeviceHandler(std::vector dev_permissions, std::vector sysfs_permissions, std::vector subsystems, std::set boot_devices, - bool skip_restorecon) + std::string boot_part_uuid, bool skip_restorecon) : dev_permissions_(std::move(dev_permissions)), sysfs_permissions_(std::move(sysfs_permissions)), subsystems_(std::move(subsystems)), boot_devices_(std::move(boot_devices)), + boot_part_uuid_(boot_part_uuid), skip_restorecon_(skip_restorecon), - sysfs_mount_point_("/sys") {} + sysfs_mount_point_("/sys") { + // If both a boot partition UUID and a list of boot devices are + // specified then we ignore the boot_devices in favor of boot_part_uuid. + if (boot_devices_.size() && !boot_part_uuid.empty()) { + LOG(WARNING) << "Both boot_devices and boot_part_uuid provided; ignoring bootdevices"; + boot_devices_.clear(); + } +} DeviceHandler::DeviceHandler() : DeviceHandler(std::vector{}, std::vector{}, - std::vector{}, std::set{}, false) {} + std::vector{}, std::set{}, "", false) {} } // namespace init } // namespace android diff --git a/init/devices.h b/init/devices.h index 7eee87a12..cac52bc17 100644 --- a/init/devices.h +++ b/init/devices.h @@ -128,10 +128,12 @@ class DeviceHandler : public UeventHandler { DeviceHandler(); DeviceHandler(std::vector dev_permissions, - std::vector sysfs_permissions, std::vector subsystems, - std::set boot_devices, bool skip_restorecon); + std::vector sysfs_permissions, + std::vector subsystems, std::set boot_devices, + std::string boot_part_uuid, bool skip_restorecon); virtual ~DeviceHandler() = default; + bool CheckUeventForBootPartUuid(const Uevent& uevent); void HandleUevent(const Uevent& uevent) override; // `androidboot.partition_map` allows associating a partition name for a raw block device @@ -146,6 +148,8 @@ class DeviceHandler : public UeventHandler { bool FindSubsystemDevice(std::string path, std::string* device_path, const std::set& subsystem_paths) const; bool FindPlatformDevice(std::string path, std::string* platform_device_path) const; + bool FindMmcDevice(std::string path, std::string* mmc_device_path) const; + bool FindScsiDevice(std::string path, std::string* scsi_device_path) const; std::tuple GetDevicePermissions( const std::string& path, const std::vector& links) const; void MakeDevice(const std::string& path, bool block, int major, int minor, @@ -160,6 +164,8 @@ class DeviceHandler : public UeventHandler { std::vector sysfs_permissions_; std::vector subsystems_; std::set boot_devices_; + std::string boot_part_uuid_; + bool found_boot_part_uuid_; bool skip_restorecon_; std::string sysfs_mount_point_; }; diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index 4f1af3038..aa6b55166 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -288,6 +288,10 @@ static bool IsMicrodroidStrictBoot() { } bool FirstStageMountVBootV2::InitDevices() { + if (!block_dev_init_.InitBootDevicesFromPartUuid()) { + return false; + } + std::set devices; GetSuperDeviceName(&devices); diff --git a/init/ueventd.cpp b/init/ueventd.cpp index 3f0d0e95b..286e47266 100644 --- a/init/ueventd.cpp +++ b/init/ueventd.cpp @@ -353,10 +353,25 @@ int ueventd_main(int argc, char** argv) { auto ueventd_configuration = GetConfiguration(); - uevent_handlers.emplace_back(std::make_unique( + UeventListener uevent_listener(ueventd_configuration.uevent_socket_rcvbuf_size); + + // Right after making DeviceHandler, replay all events looking for which + // block device has the boot partition. This lets us make symlinks + // for all of the other partitions on the same disk. Note that by the time + // we get here we know that the boot partition has already shown up (if + // we're looking for it) so just regenerating events is enough to know + // we'll see it. + std::unique_ptr device_handler = std::make_unique( std::move(ueventd_configuration.dev_permissions), std::move(ueventd_configuration.sysfs_permissions), - std::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), true)); + std::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), + android::fs_mgr::GetBootPartUuid(), true); + uevent_listener.RegenerateUevents([&](const Uevent& uevent) -> ListenerAction { + bool uuid_check_done = device_handler->CheckUeventForBootPartUuid(uevent); + return uuid_check_done ? ListenerAction::kStop : ListenerAction::kContinue; + }); + + uevent_handlers.emplace_back(std::move(device_handler)); uevent_handlers.emplace_back(std::make_unique( std::move(ueventd_configuration.firmware_directories), std::move(ueventd_configuration.external_firmware_handlers))); @@ -365,8 +380,6 @@ int ueventd_main(int argc, char** argv) { std::vector base_paths = {"/odm/lib/modules", "/vendor/lib/modules"}; uevent_handlers.emplace_back(std::make_unique(base_paths)); } - UeventListener uevent_listener(ueventd_configuration.uevent_socket_rcvbuf_size); - if (!android::base::GetBoolProperty(kColdBootDoneProp, false)) { ColdBoot cold_boot(uevent_listener, uevent_handlers, ueventd_configuration.enable_parallel_restorecon, From eb3d280f1ee89dd42bffaf1ec6fd200f9f8d7b3e Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Tue, 5 Nov 2024 09:15:25 -0800 Subject: [PATCH 107/183] init: Look for partition only on a boot device if using boot_part_uuid The current code waits for boot partitions to show up by waiting to see a uevent with the right partition name. However, nothing in the waiting code validates that the partition that showed up is actually on the boot device. That means that the current code can be confused if there is another block device in the system (possibly connected via USB) that has a partition name matching one of the system ones. It can be noted that the problem is specifically just that the "waiting" part returns too early. Later parts of the system, specifically the parts of the system that create the "/dev/block/by-name" symlinks, do properly look at the list of "boot devices". This means that the problem we're fixing is that later code, which assumes that the boot partitions have already initialized, can fail to find an initialized partition. To make it concrete, imagine that you have two block devices in your system: the builtin emmc and an external USB disk. Let's say you're booting over USB and "boot_devices" properly lists only USB. Both the "emmc" and "USB" block devices are properly formatted Android disks and have the full slew of partitions. At boot time, you can see: 1. We get to the point where we need to wait for the "boot" source (USB) to show up. 2. We see the eMMC show up. 3. The eMMC has all the needed partitions, so we consider our wait done. ...but eMMC isn't in the list of "boot devices" so we don't create the "/dev/block/by-name" symlinks. 4. Later code assumes that the "/dev/block/by-name" symlinks are already setup and fails. 5. The device fails to boot. Fix it so that the wait makes sure that the partitions are on the boot device. Unfortunately, it appears that in some cases products (especially emulators) aren't setting the "boot devices" and/or are not making sure all boot partitions are on the same device. Limit the fix to only devices using the new "boot_part_uuid" to make sure we don't break old code. NOTE: this is effectively the same change as a previous one ("init: Look for super partition only on a boot device") but with the added fix to only enable the check when using "boot_part_uuid". Bug: 309244873 Bug: 349144493 Bug: 316324155 Test: Boot isn't confused when two boot devices are present Change-Id: Iaae453ed661307f485cdf4dde86294105cae9b2d --- init/block_dev_initializer.cpp | 34 +++++++++++++++++++++++++++++++++- init/devices.cpp | 11 +++++++++++ init/devices.h | 2 ++ 3 files changed, 46 insertions(+), 1 deletion(-) diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index 4ca5b8f0e..7f83037ae 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -140,11 +140,43 @@ ListenerAction BlockDevInitializer::HandleUevent(const Uevent& uevent, LOG(VERBOSE) << __PRETTY_FUNCTION__ << ": found partition: " << name; - devices->erase(iter); + // Remove the partition from the list of partitions we're waiting for. + // + // Partitions that we're waiting for here are expected to be on the boot + // device, so only remove from the list if they're on the boot device. + // This prevents us from being confused if there are multiple disks (some + // perhaps connected via USB) that have matching partition names. + // + // ...but... + // + // Some products (especialy emulators) don't seem to set up boot_devices + // or possibly not all the partitions that we need to wait for are on the + // specified boot device. Thus, only require partitions to be on the boot + // device in "strict" mode, which should be used on newer systems. + if (device_handler_->IsBootDevice(uevent) || !device_handler_->IsBootDeviceStrict()) { + devices->erase(iter); + } + device_handler_->HandleUevent(uevent); return devices->empty() ? ListenerAction::kStop : ListenerAction::kContinue; } +// Wait for partitions that are expected to be on the "boot device" to initialize. +// +// Wait (for up to 10 seconds) for partitions passed in `devices` to show up. +// All block devices found while waiting will be initialized, which includes +// creating symlinks for them in /dev/block. Once all `devices` are found we'll +// return success (true). If any devices aren't found we'll return failure +// (false). As devices are found they will be removed from `devices`. +// +// The contents of `devices` is the names of the partitions. This can be: +// - The `partition_name` reported by a uevent, or the final component in the +// `path` reported by a uevent if the `partition_name` is blank. +// - The result of DeviceHandler::GetPartitionNameForDevice() on the +// `device_name` reported by a uevent. +// +// NOTE: on newer systems partitions _must_ be on the "boot device". See +// comments inside HandleUevent(). bool BlockDevInitializer::InitDevices(std::set devices) { auto uevent_callback = [&, this](const Uevent& uevent) -> ListenerAction { return HandleUevent(uevent, &devices); diff --git a/init/devices.cpp b/init/devices.cpp index 0b1e13dba..4de1e2030 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -224,6 +224,17 @@ BlockDeviceInfo DeviceHandler::GetBlockDeviceInfo(const std::string& uevent_path return info; } +bool DeviceHandler::IsBootDeviceStrict() const { + // When using the newer "boot_part_uuid" to specify the boot device then + // we require all core system partitions to be on the boot device. + return !boot_part_uuid_.empty(); +} + +bool DeviceHandler::IsBootDevice(const Uevent& uevent) const { + auto device = GetBlockDeviceInfo(uevent.path); + return device.is_boot_device; +} + std::string DeviceHandler::GetPartitionNameForDevice(const std::string& query_device) { static const auto partition_map = [] { std::vector> partition_map; diff --git a/init/devices.h b/init/devices.h index cac52bc17..8b6cf6cb1 100644 --- a/init/devices.h +++ b/init/devices.h @@ -141,6 +141,8 @@ class DeviceHandler : public UeventHandler { // `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to // `userdata`. static std::string GetPartitionNameForDevice(const std::string& device); + bool IsBootDeviceStrict() const; + bool IsBootDevice(const Uevent& uevent) const; private: void ColdbootDone() override; From 52da71d47b8af5d3796cb0b4bb626de66a0a8435 Mon Sep 17 00:00:00 2001 From: Liana Kazanova Date: Wed, 6 Nov 2024 21:42:29 +0000 Subject: [PATCH 108/183] Revert "Set input thread priority to RT - try 3" This reverts commit a2bd0e6b5db1023638e351cb1c55870b4fb8af8f. Reason for revert:DroidMonitor: Potential culprit for http://b/377739155 - verifying through ABTD before revert submission. This is part of the standard investigation process, and does not mean your CL will be reverted. Change-Id: I4c2b686aaf291db819d37711d4427d0094ca2295 --- libprocessgroup/profiles/task_profiles.json | 15 +-------------- 1 file changed, 1 insertion(+), 14 deletions(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index d61939f29..feda3b49c 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -202,19 +202,6 @@ } ] }, - { - "Name": "RealTimeInputScheduling", - "Actions": [ - { - "Name": "SetSchedulerPolicy", - "Params": - { - "Policy": "SCHED_FIFO", - "Priority": "98" - } - } - ] - }, { "Name": "CameraServicePerformance", "Actions": [ @@ -717,7 +704,7 @@ }, { "Name": "InputPolicy", - "Profiles": [ "RealTimeInputScheduling", "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] + "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] } ] } From e5a2af34b3231a13f509993aeced19c3d3509aa8 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Thu, 7 Nov 2024 13:24:01 -0800 Subject: [PATCH 109/183] Increase the test timeout Bug: 338329603 Test: Build success Change-Id: I97008dbe112d87ef2f4bff5605beb41cc4b1fac7 Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapuserd/Android.bp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 06c27e71b..97cfe7616 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -169,7 +169,7 @@ cc_binary { recovery_available: true, } -// This target will install to /system/bin/snapuserd_ramdisk +// This target will install to /system/bin/snapuserd_ramdisk // It will also create a symblink on /system/bin/snapuserd that point to // /system/bin/snapuserd_ramdisk . // This way, init can check if generic ramdisk copy exists. @@ -265,6 +265,10 @@ cc_test { name: "force-no-test-error", value: "false", }, + { + name: "native-test-timeout", + value: "15m", + }, ], }, } From ce6f7330ad2d335d780bf20d6516048325da0d87 Mon Sep 17 00:00:00 2001 From: Hung Nguyen Date: Thu, 7 Nov 2024 13:15:20 -0800 Subject: [PATCH 110/183] Increase zram size percentage limit To allow experimenting with zram size larger than device memory size. Bug: 368286978 Test: atest CtsFsMgrTestCases Change-Id: I47a4a4e6af39571d13e4622d110c92936008127e --- fs_mgr/libfstab/fstab.cpp | 2 +- fs_mgr/tests/fs_mgr_test.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index 6e4cae18f..1db716974 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -262,7 +262,7 @@ bool ParseFsMgrFlags(const std::string& flags, FstabEntry* entry) { if (!arg.empty() && arg.back() == '%') { arg.pop_back(); int val; - if (ParseInt(arg, &val, 0, 100)) { + if (ParseInt(arg, &val, 0, 200)) { entry->zram_size = CalculateZramSize(val); } else { LWARNING << "Warning: zramsize= flag malformed: " << arg; diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index 6522c02e8..6e050cf4b 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -710,6 +710,7 @@ source none2 swap defaults zramsize=blah% source none3 swap defaults zramsize=5% source none4 swap defaults zramsize=105% source none5 swap defaults zramsize=% +source none6 swap defaults zramsize=210% )fs"; ASSERT_TRUE(android::base::WriteStringToFile(fstab_contents, tf.path)); @@ -742,12 +743,17 @@ source none5 swap defaults zramsize=% EXPECT_EQ("none4", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); - EXPECT_EQ(0, entry->zram_size); + EXPECT_NE(0, entry->zram_size); entry++; EXPECT_EQ("none5", entry->mount_point); EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); EXPECT_EQ(0, entry->zram_size); + entry++; + + EXPECT_EQ("none6", entry->mount_point); + EXPECT_TRUE(CompareFlags(flags, entry->fs_mgr_flags)); + EXPECT_EQ(0, entry->zram_size); } TEST(fs_mgr, ReadFstabFromFile_FsMgrOptions_FileEncryption) { From 76afb4a2c2fb50ad6785e02dbaab724efc090bbe Mon Sep 17 00:00:00 2001 From: Inseob Kim Date: Wed, 6 Nov 2024 17:07:04 +0900 Subject: [PATCH 111/183] Add BOARD_GENFS_LABELS_VERSION If it's 202504 or later, /sys/class/udc will be labeled as sysfs_udc. If it's not set, /sys/class/udc will stay at the label sysfs. This is to support GRF vendors older than 202504. 202404 or old vendors can choose either way. If they want to customize permissions to /sys/class/udc, they can turn off BOARD_GENFS_LABELS_VERSION and assign their own label to /sys/class/udc /sys/class/udc with vendor sepolicy. 202504 or newer vendors must set BOARD_GENFS_LABELS_VERSION to a version greater than or equal to 202504. For now there's only one node /sys/class/udc, but more labels can be added until 202504 freeze. Bug: 361985697 Test: boot with and without BOARD_GENFS_LABELS_VERSION Change-Id: I1a28109119368f1475628be85dd8d990c824922e --- init/selinux.cpp | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/init/selinux.cpp b/init/selinux.cpp index c2d9b8d28..5ced0b81a 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -190,6 +190,22 @@ bool GetVendorMappingVersion(std::string* plat_vers) { return true; } +int GetVendorGenfsVersion() { + std::string line; + if (!ReadFirstLine("/vendor/etc/selinux/genfs_labels_version.txt", &line)) { + PLOG(ERROR) << "Failed to read /vendor/etc/selinux/genfs_labels_version.txt; assuming it's " + "202404"; + return 202404; + } + int version; + if (!ParseInt(line, &version)) { + PLOG(ERROR) << "Failed to parse the genfs labels version " << line + << "; assuming it's 202404"; + return 202404; + } + return version; +} + constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; bool IsSplitPolicyDevice() { @@ -324,6 +340,15 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { } const std::string version_as_string = std::to_string(SEPOLICY_VERSION); + std::vector genfs_cil_files; + + int vendor_genfs_version = GetVendorGenfsVersion(); + std::string genfs_cil_file = + std::format("/system/etc/selinux/plat_sepolicy_genfs_{}.cil", vendor_genfs_version); + if (access(genfs_cil_file.c_str(), F_OK) != 0) { + genfs_cil_file.clear(); + } + // clang-format off std::vector compile_args { "/system/bin/secilc", @@ -364,6 +389,9 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { if (!odm_policy_cil_file.empty()) { compile_args.push_back(odm_policy_cil_file.c_str()); } + if (!genfs_cil_file.empty()) { + compile_args.push_back(genfs_cil_file.c_str()); + } compile_args.push_back(nullptr); if (!ForkExecveAndWaitForCompletion(compile_args[0], (char**)compile_args.data())) { From ab8f9717f1cb70afd28d67cee61996ef223aa10e Mon Sep 17 00:00:00 2001 From: "Priyanka Advani (xWF)" Date: Fri, 8 Nov 2024 17:37:24 +0000 Subject: [PATCH 112/183] Revert "Deprecating libvendorsupport_llndk_headers" Revert submission 3334193-no-llndk-versioning Reason for revert: Droidmonitor created revert due to b/378038995. Will be verifying through ABTD before submission. Reverted changes: /q/submissionid:3334193-no-llndk-versioning Change-Id: Id8d85be1930bef68f94cee66a0fe29278de48d64 --- libvendorsupport/Android.bp | 29 ++++++++++++ .../include_llndk/android/llndk-versioning.h | 45 +++++++++++++++++++ 2 files changed, 74 insertions(+) create mode 100644 libvendorsupport/include_llndk/android/llndk-versioning.h diff --git a/libvendorsupport/Android.bp b/libvendorsupport/Android.bp index f9a889b94..a22737c06 100644 --- a/libvendorsupport/Android.bp +++ b/libvendorsupport/Android.bp @@ -35,3 +35,32 @@ cc_library { "libbase", ], } + +cc_library_headers { + name: "libvendorsupport_llndk_headers", + host_supported: true, + vendor_available: true, + recovery_available: true, + ramdisk_available: true, + vendor_ramdisk_available: true, + native_bridge_supported: true, + + export_include_dirs: ["include_llndk"], + llndk: { + llndk_headers: true, + }, + + apex_available: [ + "//apex_available:platform", + "//apex_available:anyapex", + ], + min_sdk_version: "apex_inherit", + + system_shared_libs: [], + stl: "none", + + // This header library is used for libc and must be available to any sdk + // versions. + // Setting sdk_version to the lowest version allows the dependencies. + sdk_version: "1", +} diff --git a/libvendorsupport/include_llndk/android/llndk-versioning.h b/libvendorsupport/include_llndk/android/llndk-versioning.h new file mode 100644 index 000000000..81d165f47 --- /dev/null +++ b/libvendorsupport/include_llndk/android/llndk-versioning.h @@ -0,0 +1,45 @@ +// Copyright (C) 2024 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 + +// LLNDK (https://source.android.com/docs/core/architecture/vndk/build-system#ll-ndk) is similar to +// NDK, but uses its own versioning of YYYYMM format for vendor builds. The LLNDK symbols are +// enabled when the vendor api level is equal to or newer than the ro.board.api_level. These symbols +// must be annotated in map.txt files with the `# llndk=YYYYMM` annotation. They also must be marked +// with `__INTRODUCED_IN_LLNDK(YYYYMM)` in the header files. It leaves a no-op annotation for ABI +// analysis. +#if !defined(__INTRODUCED_IN_LLNDK) +#define __INTRODUCED_IN_LLNDK(vendor_api_level) \ + __attribute__((annotate("introduced_in_llndk=" #vendor_api_level))) +#endif + +#if defined(__ANDROID_VENDOR_API__) +// __ANDROID_VENDOR_API__ is defined only for vendor or product variant modules. +// Use this macro as an `if` statement to call an API that are available to both NDK and LLNDK. +// This returns true for vendor or product modules if the vendor_api_level is less than or equal to +// the ro.board.api_level. +#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ + constexpr(__ANDROID_VENDOR_API__ >= vendor_api_level) + +#else // __ANDROID_VENDOR_API__ + +// For non-vendor modules, API_LEVEL_AT_LEAST is replaced with __builtin_available(sdk_api_level) to +// guard the API for __INTRODUCED_IN. +#if !defined(API_LEVEL_AT_LEAST) +#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ + (__builtin_available(android sdk_api_level, *)) +#endif + +#endif // __ANDROID_VENDOR_API__ From 3c700588c75d29a78679260bc9847b22b852f724 Mon Sep 17 00:00:00 2001 From: Ted Bauer Date: Fri, 8 Nov 2024 17:15:46 +0000 Subject: [PATCH 113/183] Start aconfigd_system processes in init.rc aconfigd_system is replacing aconfigd. Which one executes is toggled by RO flag enable_system_aconfigd_rust, introduced in https://android-review.googlesource.com/q/topic:%22switch-to-aconfigd-system%22. Bug: 378079539 Test: m Change-Id: I6a04c38e9ef22da2b230046ddace73d6f7e39652 --- rootdir/init.rc | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index 5bb64cc60..617e60a0f 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -614,6 +614,9 @@ on post-fs mkdir /metadata/aconfig/boot 0775 root system mkdir /metadata/aconfig_test_missions 0775 root system + + # See flag enable_system_aconfigd_rust, which toggles these processes. + exec_start system_aconfigd_platform_init exec_start aconfigd-platform-init on late-fs @@ -1002,7 +1005,16 @@ on post-fs-data # Wait for apexd to finish activating APEXes before starting more processes. wait_for_prop apexd.status activated perform_apex_config + + # See flag enable_system_aconfigd_rust, which toggles these processes. exec_start aconfigd-mainline-init + exec_start system_aconfigd_mainline_init + + # system_aconfigd_socket_service is replacing aconfigd: + # - A flag (enable_system_aconfigd_rust) toggles which socket executes. + # - When enabled, aconfigd is a no-op, system_aconfigd_socket_service executes. + # - Conversely, when disabled, aconfigd executes, and system_aconfigd_socket_service is a no-op. + start system_aconfigd_socket_service start aconfigd # Create directories for boot animation. From 46afe22f9da648487d6e8b7c8a3f35cc15a3412b Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Fri, 8 Nov 2024 14:38:41 -0800 Subject: [PATCH 114/183] init: Avoid extra string copies when finding devices by using const refs Now that FindPlatformDevice() isn't modifying the path argument, and is just passing it on to FindSubsystemDevice(), take this argument by const reference. That should avoid an unnecessary string copy. Bug: 316324155 Test: Compile Change-Id: I1d92a322d0c311ee46a117dd9d650896ec02520f --- init/devices.cpp | 7 ++++--- init/devices.h | 6 +++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/init/devices.cpp b/init/devices.cpp index 4de1e2030..2cdececf6 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -307,7 +307,8 @@ bool DeviceHandler::FindSubsystemDevice(std::string path, std::string* device_pa return false; } -bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_device_path) const { +bool DeviceHandler::FindPlatformDevice(const std::string& path, + std::string* platform_device_path) const { const std::set subsystem_paths = { sysfs_mount_point_ + "/bus/platform", sysfs_mount_point_ + "/bus/amba", @@ -316,7 +317,7 @@ bool DeviceHandler::FindPlatformDevice(std::string path, std::string* platform_d return FindSubsystemDevice(path, platform_device_path, subsystem_paths); } -bool DeviceHandler::FindMmcDevice(std::string path, std::string* mmc_device_path) const { +bool DeviceHandler::FindMmcDevice(const std::string& path, std::string* mmc_device_path) const { const std::set subsystem_paths = { sysfs_mount_point_ + "/bus/mmc", }; @@ -324,7 +325,7 @@ bool DeviceHandler::FindMmcDevice(std::string path, std::string* mmc_device_path return FindSubsystemDevice(path, mmc_device_path, subsystem_paths); } -bool DeviceHandler::FindScsiDevice(std::string path, std::string* scsi_device_path) const { +bool DeviceHandler::FindScsiDevice(const std::string& path, std::string* scsi_device_path) const { const std::set subsystem_paths = { sysfs_mount_point_ + "/bus/scsi", }; diff --git a/init/devices.h b/init/devices.h index 8b6cf6cb1..67a3d00b1 100644 --- a/init/devices.h +++ b/init/devices.h @@ -149,9 +149,9 @@ class DeviceHandler : public UeventHandler { BlockDeviceInfo GetBlockDeviceInfo(const std::string& uevent_path) const; bool FindSubsystemDevice(std::string path, std::string* device_path, const std::set& subsystem_paths) const; - bool FindPlatformDevice(std::string path, std::string* platform_device_path) const; - bool FindMmcDevice(std::string path, std::string* mmc_device_path) const; - bool FindScsiDevice(std::string path, std::string* scsi_device_path) const; + bool FindPlatformDevice(const std::string& path, std::string* platform_device_path) const; + bool FindMmcDevice(const std::string& path, std::string* mmc_device_path) const; + bool FindScsiDevice(const std::string& path, std::string* scsi_device_path) const; std::tuple GetDevicePermissions( const std::string& path, const std::vector& links) const; void MakeDevice(const std::string& path, bool block, int major, int minor, From dbb080d9bfacb5c57e64470c8817333291991fd9 Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Sat, 9 Nov 2024 02:41:06 +0000 Subject: [PATCH 115/183] Revert^2 "Deprecating libvendorsupport_llndk_headers" ab8f9717f1cb70afd28d67cee61996ef223aa10e Change-Id: Ie981692be554942df762a4c9be7c250b0b202f31 --- libvendorsupport/Android.bp | 29 ------------ .../include_llndk/android/llndk-versioning.h | 45 ------------------- 2 files changed, 74 deletions(-) delete mode 100644 libvendorsupport/include_llndk/android/llndk-versioning.h diff --git a/libvendorsupport/Android.bp b/libvendorsupport/Android.bp index a22737c06..f9a889b94 100644 --- a/libvendorsupport/Android.bp +++ b/libvendorsupport/Android.bp @@ -35,32 +35,3 @@ cc_library { "libbase", ], } - -cc_library_headers { - name: "libvendorsupport_llndk_headers", - host_supported: true, - vendor_available: true, - recovery_available: true, - ramdisk_available: true, - vendor_ramdisk_available: true, - native_bridge_supported: true, - - export_include_dirs: ["include_llndk"], - llndk: { - llndk_headers: true, - }, - - apex_available: [ - "//apex_available:platform", - "//apex_available:anyapex", - ], - min_sdk_version: "apex_inherit", - - system_shared_libs: [], - stl: "none", - - // This header library is used for libc and must be available to any sdk - // versions. - // Setting sdk_version to the lowest version allows the dependencies. - sdk_version: "1", -} diff --git a/libvendorsupport/include_llndk/android/llndk-versioning.h b/libvendorsupport/include_llndk/android/llndk-versioning.h deleted file mode 100644 index 81d165f47..000000000 --- a/libvendorsupport/include_llndk/android/llndk-versioning.h +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright (C) 2024 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 - -// LLNDK (https://source.android.com/docs/core/architecture/vndk/build-system#ll-ndk) is similar to -// NDK, but uses its own versioning of YYYYMM format for vendor builds. The LLNDK symbols are -// enabled when the vendor api level is equal to or newer than the ro.board.api_level. These symbols -// must be annotated in map.txt files with the `# llndk=YYYYMM` annotation. They also must be marked -// with `__INTRODUCED_IN_LLNDK(YYYYMM)` in the header files. It leaves a no-op annotation for ABI -// analysis. -#if !defined(__INTRODUCED_IN_LLNDK) -#define __INTRODUCED_IN_LLNDK(vendor_api_level) \ - __attribute__((annotate("introduced_in_llndk=" #vendor_api_level))) -#endif - -#if defined(__ANDROID_VENDOR_API__) -// __ANDROID_VENDOR_API__ is defined only for vendor or product variant modules. -// Use this macro as an `if` statement to call an API that are available to both NDK and LLNDK. -// This returns true for vendor or product modules if the vendor_api_level is less than or equal to -// the ro.board.api_level. -#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ - constexpr(__ANDROID_VENDOR_API__ >= vendor_api_level) - -#else // __ANDROID_VENDOR_API__ - -// For non-vendor modules, API_LEVEL_AT_LEAST is replaced with __builtin_available(sdk_api_level) to -// guard the API for __INTRODUCED_IN. -#if !defined(API_LEVEL_AT_LEAST) -#define API_LEVEL_AT_LEAST(sdk_api_level, vendor_api_level) \ - (__builtin_available(android sdk_api_level, *)) -#endif - -#endif // __ANDROID_VENDOR_API__ From fc7ec65a00b6105ceeac872da875d4c9e5936942 Mon Sep 17 00:00:00 2001 From: Hung Nguyen Date: Sat, 9 Nov 2024 23:05:32 -0800 Subject: [PATCH 116/183] Add AID for memory management daemon Bug: 370509309 Bug: 375432464 Test: adb shell id -(u|g) mmd Change-Id: I02440604b1947abc70235bfac132473e8bafa90d --- libcutils/include/private/android_filesystem_config.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h index b0bddf501..2aaafbe24 100644 --- a/libcutils/include/private/android_filesystem_config.h +++ b/libcutils/include/private/android_filesystem_config.h @@ -143,6 +143,7 @@ #define AID_PRNG_SEEDER 1092 /* PRNG seeder daemon */ #define AID_UPROBESTATS 1093 /* uid for uprobestats */ #define AID_CROS_EC 1094 /* uid for accessing ChromeOS EC (cros_ec) */ +#define AID_MMD 1095 /* uid for memory management daemon */ // Additions to this file must be made in AOSP, *not* in internal branches. // You will also need to update expect_ids() in bionic/tests/grp_pwd_test.cpp. From f1eaa75168352a3bd3cc6ffb0733d09a4b028f8b Mon Sep 17 00:00:00 2001 From: Dennis Shen Date: Mon, 11 Nov 2024 17:44:14 +0000 Subject: [PATCH 117/183] move aconfigd platform init service from init.rc into aconfigd.rc Bug: 378079539 Test: m Change-Id: I10c306468bf3efe3b5186851cb09b576b143512a --- rootdir/init.rc | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 617e60a0f..6bff34aa1 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -608,17 +608,6 @@ on post-fs mkdir /metadata/staged-install 0770 root system - mkdir /metadata/aconfig 0775 root system - mkdir /metadata/aconfig/flags 0770 root system - mkdir /metadata/aconfig/maps 0775 root system - mkdir /metadata/aconfig/boot 0775 root system - - mkdir /metadata/aconfig_test_missions 0775 root system - - # See flag enable_system_aconfigd_rust, which toggles these processes. - exec_start system_aconfigd_platform_init - exec_start aconfigd-platform-init - on late-fs # Ensure that tracefs has the correct permissions. # This does not work correctly if it is called in post-fs. From e8ff8b494a342ae758ec03bcd27b784d4a4168a2 Mon Sep 17 00:00:00 2001 From: Karuna Wadhera Date: Sun, 10 Nov 2024 23:42:57 +0000 Subject: [PATCH 118/183] Set the proper FEATURE_HARDWARE_KEYSTORE version The binary implements V3 of the KeyMint HAL, so the feature version should match. Bug: 369375199 Bug: 378384123 Test: treehugger Change-Id: Ib26ac73cf6593d9a50f7a019129c6e5e237ae2cd --- trusty/keymaster/Android.bp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp index cb078299e..5a1e4202d 100644 --- a/trusty/keymaster/Android.bp +++ b/trusty/keymaster/Android.bp @@ -121,7 +121,7 @@ cc_binary { "libutils", ], required: [ - "android.hardware.hardware_keystore.xml", + "android.hardware.hardware_keystore_V3.xml", ], } From 5969d69248c8216bde0c905fa2a4ea0987c5ae8a Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Mon, 11 Nov 2024 17:52:45 +0000 Subject: [PATCH 119/183] Declare previous version when using frozen HALs The KeyMint HAL has been updated to v4, but frozen builds (e.g. 25Q1) remain on the previous version. The core AIDL version is handled automatically, but we also have a package manager flag whose value is (100 * HAL-version). Use `RELEASE_AIDL_USE_UNFROZEN` to switch between `required` configs for that. Test: TreeHugger Bug: 377808462 Bug: 378026324 Change-Id: Id042bee2a81e8563e1029ea7bb43452715e3edee --- trusty/keymint/Android.bp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/trusty/keymint/Android.bp b/trusty/keymint/Android.bp index 5cdd381e1..36efb1b89 100644 --- a/trusty/keymint/Android.bp +++ b/trusty/keymint/Android.bp @@ -42,9 +42,10 @@ rust_binary { defaults: ["android.hardware.security.keymint-service.rust.trusty.default"], init_rc: ["android.hardware.security.keymint-service.rust.trusty.rc"], vintf_fragments: ["android.hardware.security.keymint-service.rust.trusty.xml"], - required: [ - "android.hardware.hardware_keystore.xml", - ], + required: select(release_flag("RELEASE_AIDL_USE_UNFROZEN"), { + true: ["android.hardware.hardware_keystore.xml"], + default: ["android.hardware.hardware_keystore_V3.xml"], + }), } rust_binary { From 6facd1bfd3d9e2672215630d944228e983d95986 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Fri, 8 Nov 2024 15:23:53 -0800 Subject: [PATCH 120/183] Test stack buffer size calculation. Bug: 378140560 Change-Id: Idca03cac925bc0d8bd574817391c4eaca11f2bff --- .../test/mte_stack_record_test.cpp | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/debuggerd/libdebuggerd/test/mte_stack_record_test.cpp b/debuggerd/libdebuggerd/test/mte_stack_record_test.cpp index 4b788f3b7..bcda0ca5d 100644 --- a/debuggerd/libdebuggerd/test/mte_stack_record_test.cpp +++ b/debuggerd/libdebuggerd/test/mte_stack_record_test.cpp @@ -26,6 +26,8 @@ #include "unwindstack/Memory.h" #include +#include + #include "gtest/gtest.h" #include "libdebuggerd/tombstone.h" @@ -82,6 +84,33 @@ TEST(MteStackHistoryUnwindTest, TestOne) { EXPECT_EQ(e.tag(), 1ULL); } +static std::optional FindMapping(void* data) { + std::optional result; + android::procinfo::ReadMapFile( + "/proc/self/maps", [&result, data](const android::procinfo::MapInfo& info) { + auto data_int = reinterpret_cast(data) & ((1ULL << 56ULL) - 1ULL); + if (info.start <= data_int && data_int < info.end) { + result = info; + } + }); + return result; +} + +TEST_P(MteStackHistoryTest, TestFree) { + int size_cls = GetParam(); + size_t size = stack_mte_ringbuffer_size(size_cls); + void* data = stack_mte_ringbuffer_allocate(size_cls, nullptr); + EXPECT_EQ(stack_mte_ringbuffer_size_from_pointer(reinterpret_cast(data)), size); + auto before = FindMapping(data); + ASSERT_TRUE(before.has_value()); + EXPECT_EQ(before->end - before->start, size); + stack_mte_free_ringbuffer(reinterpret_cast(data)); + for (size_t i = 0; i < size; i += page_size()) { + auto after = FindMapping(static_cast(data) + i); + EXPECT_TRUE(!after.has_value() || after->name != before->name); + } +} + TEST_P(MteStackHistoryTest, TestEmpty) { int size_cls = GetParam(); size_t size = stack_mte_ringbuffer_size(size_cls); From 945dd526edd47dc5121764dc88927ef934893027 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Tue, 12 Nov 2024 15:25:09 +0000 Subject: [PATCH 121/183] Stop explicitly adding bionic subdirectories to the include path. Change-Id: I24776f1008ca5f030cd8c94147d9630519ef6a24 --- fastboot/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/fastboot/Android.bp b/fastboot/Android.bp index b61fbd4df..d3e058150 100644 --- a/fastboot/Android.bp +++ b/fastboot/Android.bp @@ -201,7 +201,6 @@ cc_binary { "update_metadata-protos", "liburing", ], - include_dirs: ["bionic/libc/kernel"], header_libs: [ "avb_headers", From 5f216ffdc35266acf175db0e73e952f2bca80c39 Mon Sep 17 00:00:00 2001 From: Armelle Laine Date: Sun, 6 Oct 2024 05:40:40 +0000 Subject: [PATCH 122/183] trusty: utils: rpmb_dev: add wv secure storage init.rc Bug: 371777025 Change-Id: Id4f26509568dac1045e0b2ba58a045874555a303 Test: cuttlefish with trusty-vm enablement apex, run WV VTS --- trusty/utils/rpmb_dev/Android.bp | 9 +++ trusty/utils/rpmb_dev/rpmb_dev.wv.system.rc | 62 +++++++++++++++++++++ 2 files changed, 71 insertions(+) create mode 100644 trusty/utils/rpmb_dev/rpmb_dev.wv.system.rc diff --git a/trusty/utils/rpmb_dev/Android.bp b/trusty/utils/rpmb_dev/Android.bp index 13f151d2e..ef23cc50f 100644 --- a/trusty/utils/rpmb_dev/Android.bp +++ b/trusty/utils/rpmb_dev/Android.bp @@ -49,3 +49,12 @@ cc_binary { "rpmb_dev.system.rc", ], } + +cc_binary { + name: "rpmb_dev.wv.system", + defaults: ["rpmb_dev.cc_defaults"], + system_ext_specific: true, + init_rc: [ + "rpmb_dev.wv.system.rc", + ], +} diff --git a/trusty/utils/rpmb_dev/rpmb_dev.wv.system.rc b/trusty/utils/rpmb_dev/rpmb_dev.wv.system.rc new file mode 100644 index 000000000..3e7f8b44f --- /dev/null +++ b/trusty/utils/rpmb_dev/rpmb_dev.wv.system.rc @@ -0,0 +1,62 @@ +service storageproxyd_wv_system /system_ext/bin/storageproxyd.system \ + -d ${storageproxyd_wv_system.trusty_ipc_dev:-/dev/trusty-ipc-dev0} \ + -r /dev/socket/rpmb_mock_wv_system \ + -p /data/secure_storage_wv_system \ + -t sock + disabled + class hal + user system + group system + +service rpmb_mock_init_wv_system /system_ext/bin/rpmb_dev.wv.system \ + --dev /mnt/secure_storage_rpmb_wv_system/persist/RPMB_DATA --init --size 2048 + disabled + user system + group system + oneshot + +service rpmb_mock_wv_system /system_ext/bin/rpmb_dev.wv.system \ + --dev /mnt/secure_storage_rpmb_wv_system/persist/RPMB_DATA \ + --sock rpmb_mock_wv_system + disabled + user system + group system + socket rpmb_mock_wv_system stream 660 system system + +# storageproxyd +on boot && \ + property:trusty.widevine_vm.nonsecure_vm_ready=1 && \ + property:storageproxyd_wv_system.trusty_ipc_dev=* + wait /dev/socket/rpmb_mock_wv_system + enable storageproxyd_wv_system + + +# RPMB Mock +on early-boot && \ + property:ro.hardware.security.trusty.widevine_vm.system=1 && \ + property:trusty.widevine_vm.vm_cid=* && \ + property:ro.boot.vendor.apex.com.android.services.widevine=\ +com.android.services.widevine.cf_guest_trusty_nonsecure + # Create a persistent location for the RPMB data + # (work around lack of RPMb block device on CF). + # file contexts secure_storage_rpmb_system_file + # (only used on Cuttlefish as this is non secure) + mkdir /metadata/secure_storage_rpmb_wv_system 0770 system system + mkdir /mnt/secure_storage_rpmb_wv_system 0770 system system + symlink /metadata/secure_storage_rpmb_wv_system \ + /mnt/secure_storage_rpmb_wv_system/persist + # Create a system persist directory in /metadata + # (work around lack of dedicated system persist partition). + # file contexts secure_storage_persist_system_file + mkdir /metadata/secure_storage_persist_wv_system 0770 system system + mkdir /mnt/secure_storage_persist_wv_system 0770 system system + symlink /metadata/secure_storage_persist_wv_system \ + /mnt/secure_storage_persist_wv_system/persist + # file contexts secure_storage_system_file + mkdir /data/secure_storage_wv_system 0770 root system + symlink /mnt/secure_storage_persist_wv_system/persist \ + /data/secure_storage_wv_system/persist + chown root system /data/secure_storage_wv_system/persist + setprop storageproxyd_wv_system.trusty_ipc_dev VSOCK:${trusty.widevine_vm.vm_cid}:1 + exec_start rpmb_mock_init_wv_system + start rpmb_mock_wv_system From 4be70e7db3f681e11ae804ea399275fc148134d3 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Tue, 12 Nov 2024 20:46:08 +0000 Subject: [PATCH 123/183] Remove mitchp from OWNERS file Change-Id: Ifb0e1598f3908fcc2206a2b51611b996f8b48cb8 --- init/test_upgrade_mte/OWNERS | 1 - 1 file changed, 1 deletion(-) diff --git a/init/test_upgrade_mte/OWNERS b/init/test_upgrade_mte/OWNERS index 79625dfb1..c95d3cfd0 100644 --- a/init/test_upgrade_mte/OWNERS +++ b/init/test_upgrade_mte/OWNERS @@ -1,5 +1,4 @@ fmayer@google.com eugenis@google.com -mitchp@google.com pcc@google.com From 64148e33d195e82f00062d0db4166f42e6a28f83 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 12 Nov 2024 23:57:50 +0000 Subject: [PATCH 124/183] libprocessgroup: Remove libcgrouprc_format This is no longer depended on anywhere. Bug: 349105928 Change-Id: I7aba0a0d4e8a851edfc5e43daa1d9b5553adcdc3 --- libprocessgroup/cgrouprc_format/Android.bp | 26 ---------------------- 1 file changed, 26 deletions(-) delete mode 100644 libprocessgroup/cgrouprc_format/Android.bp diff --git a/libprocessgroup/cgrouprc_format/Android.bp b/libprocessgroup/cgrouprc_format/Android.bp deleted file mode 100644 index 6f9ab3e73..000000000 --- a/libprocessgroup/cgrouprc_format/Android.bp +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (C) 2019 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package { - default_applicable_licenses: ["Android-Apache-2.0"], -} - -cc_library_static { - name: "libcgrouprc_format", - host_supported: true, - ramdisk_available: true, - vendor_ramdisk_available: true, - recovery_available: true, - native_bridge_supported: true, -} From 9ad453ffae7e03b1b3711d9a41ff6c5f8b3d6bc9 Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Wed, 13 Nov 2024 00:55:32 +0000 Subject: [PATCH 125/183] Set input thread priority to RT - try 4 This reverts commit 52da71d47b8af5d3796cb0b4bb626de66a0a8435. Reason for revert: camera was using its own stale copy of libprocessgroup, and now has revved up its version that includes the new parsing code. So this time the json file update should work OK. Original description: To improve input latency, set the critical input threads to RT priority. This will use RT priority on AOSP devices by default. OEMs can still choose to customize what "input policy" means for their device, which may not necessarily mean RT. For example, on device with multiple small / big cores, input task affinity could be changed to prioritize big cores + higher CPU frequency / voltage, but still keep the standard / default input thread priority. Note: there is an open issue where the thread priority is not remaining constant. See b/378761104. Bug: 330719044 Bug: 378761104 Flag: com.android.input.flags.enable_input_policy_profile Test: took perfetto trace and checked the priority on InputDispatcher and InputReader threads. Change-Id: I449be0eeeac989222f5deefa62615478bd65b968 --- libprocessgroup/profiles/task_profiles.json | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libprocessgroup/profiles/task_profiles.json b/libprocessgroup/profiles/task_profiles.json index feda3b49c..28902efe8 100644 --- a/libprocessgroup/profiles/task_profiles.json +++ b/libprocessgroup/profiles/task_profiles.json @@ -202,6 +202,19 @@ } ] }, + { + "Name": "RealTimeInputScheduling", + "Actions": [ + { + "Name": "SetSchedulerPolicy", + "Params": + { + "Policy": "SCHED_FIFO", + "Priority": "2" + } + } + ] + }, { "Name": "CameraServicePerformance", "Actions": [ @@ -704,7 +717,7 @@ }, { "Name": "InputPolicy", - "Profiles": [ "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] + "Profiles": [ "RealTimeInputScheduling", "MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal" ] } ] } From ac810ad71850e52d9d2d6c7cde22bbb78852eb33 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Tue, 12 Nov 2024 10:16:40 -0800 Subject: [PATCH 126/183] Move snapuserd_test to presubmit-large group Bug: 338329603 Test: Build Change-Id: I20d722a797093e40eb653a418a1963acf8c4292b Signed-off-by: Akilesh Kailash --- fs_mgr/TEST_MAPPING | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING index 192232d6c..0b922c871 100644 --- a/fs_mgr/TEST_MAPPING +++ b/fs_mgr/TEST_MAPPING @@ -27,7 +27,9 @@ }, { "name": "cow_api_test" - }, + } + ], + "presubmit-large": [ { "name": "snapuserd_test" } From 1b5a7addd9eca8b5593fc8b24c86ec41d9904966 Mon Sep 17 00:00:00 2001 From: "Priyanka Advani (xWF)" Date: Wed, 13 Nov 2024 20:12:45 +0000 Subject: [PATCH 127/183] Revert "Move snapuserd_test to presubmit-large group" This reverts commit ac810ad71850e52d9d2d6c7cde22bbb78852eb33. Reason for revert: Droidmonitor created revert due to b/378924658. Will be verifying ABTD before submission. Change-Id: Icb08a969ba13d863832a90d224f96fe60af9de4b --- fs_mgr/TEST_MAPPING | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING index 0b922c871..192232d6c 100644 --- a/fs_mgr/TEST_MAPPING +++ b/fs_mgr/TEST_MAPPING @@ -27,9 +27,7 @@ }, { "name": "cow_api_test" - } - ], - "presubmit-large": [ + }, { "name": "snapuserd_test" } From cbb59dd2408e77d2cb8b80112ec9903d4cb68109 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Thu, 14 Nov 2024 03:54:13 +0000 Subject: [PATCH 128/183] Add source of unwind when fatal error. Sometimes the only log left is the errors messages. This means that the information about why the unwind part of debuggerd is being called. Therefore, add a little bit of extra information in the error message to indicate why the unwind was triggered. Bug: 377050125 Test: Forced the exec of the crash dump to fail and verified that the Test: message is crash for a crash and unwind for debuggerd -b Test: and debuggerd . Change-Id: I0632ed9118c79caf4dabe6f174b25066fa9058fc --- debuggerd/handler/debuggerd_handler.cpp | 31 +++++++++++++++++-------- 1 file changed, 21 insertions(+), 10 deletions(-) diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index ddc3244f1..88278ca66 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -389,6 +389,13 @@ static DebuggerdDumpType get_dump_type(const debugger_thread_info* thread_info) return kDebuggerdTombstoneProto; } +static const char* get_unwind_type(const debugger_thread_info* thread_info) { + if (thread_info->siginfo->si_signo == BIONIC_SIGNAL_DEBUGGER) { + return "Unwind request"; + } + return "Crash due to signal"; +} + static int debuggerd_dispatch_pseudothread(void* arg) { debugger_thread_info* thread_info = static_cast(arg); @@ -502,8 +509,8 @@ static int debuggerd_dispatch_pseudothread(void* arg) { execle(CRASH_DUMP_PATH, CRASH_DUMP_NAME, main_tid, pseudothread_tid, debuggerd_dump_type, nullptr, nullptr); - async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to exec crash_dump helper: %s", - strerror(errno)); + async_safe_format_log(ANDROID_LOG_FATAL, "libc", "%s: failed to exec crash_dump helper: %s", + get_unwind_type(thread_info), strerror(errno)); return 1; } @@ -524,26 +531,30 @@ static int debuggerd_dispatch_pseudothread(void* arg) { } else { // Something went wrong, log it. if (rc == -1) { - async_safe_format_log(ANDROID_LOG_FATAL, "libc", "read of IPC pipe failed: %s", - strerror(errno)); + async_safe_format_log(ANDROID_LOG_FATAL, "libc", "%s: read of IPC pipe failed: %s", + get_unwind_type(thread_info), strerror(errno)); } else if (rc == 0) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", - "crash_dump helper failed to exec, or was killed"); + "%s: crash_dump helper failed to exec, or was killed", + get_unwind_type(thread_info)); } else if (rc != 1) { async_safe_format_log(ANDROID_LOG_FATAL, "libc", - "read of IPC pipe returned unexpected value: %zd", rc); + "%s: read of IPC pipe returned unexpected value: %zd", + get_unwind_type(thread_info), rc); } else if (buf[0] != '\1') { - async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper reported failure"); + async_safe_format_log(ANDROID_LOG_FATAL, "libc", "%s: crash_dump helper reported failure", + get_unwind_type(thread_info)); } } // Don't leave a zombie child. int status; if (TEMP_FAILURE_RETRY(waitpid(crash_dump_pid, &status, 0)) == -1) { - async_safe_format_log(ANDROID_LOG_FATAL, "libc", "failed to wait for crash_dump helper: %s", - strerror(errno)); + async_safe_format_log(ANDROID_LOG_FATAL, "libc", "%s: failed to wait for crash_dump helper: %s", + get_unwind_type(thread_info), strerror(errno)); } else if (WIFSTOPPED(status) || WIFSIGNALED(status)) { - async_safe_format_log(ANDROID_LOG_FATAL, "libc", "crash_dump helper crashed or stopped"); + async_safe_format_log(ANDROID_LOG_FATAL, "libc", "%s: crash_dump helper crashed or stopped", + get_unwind_type(thread_info)); } if (success) { From 16693fae255a5a25dbb22ac5d48c7c1997099ff4 Mon Sep 17 00:00:00 2001 From: Alice Wang Date: Fri, 8 Nov 2024 12:19:10 +0000 Subject: [PATCH 129/183] Rename system property to enable KeyMint VM This allows us to regroup Widevine VM under the same trusty group. Bug: 368502791 Test: launch_cvd --secure_hals=guest_keymint_trusty_insecure Test: atest VtsAidlSharedSecretTargetTest Change-Id: Ica76a896e99f70a64af229bda68622a2ce0dea1f --- ...are.security.keymint-service.rust.trusty.system.nonsecure.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc index ca6132e5e..410e10a61 100644 --- a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc +++ b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc @@ -11,7 +11,7 @@ service system.keymint.rust-trusty.nonsecure \ # Only starts the non-secure KeyMint HALs when the KeyMint VM feature is enabled # TODO(b/357821690): Start the KeyMint HALs when the KeyMint VM is ready once the Trusty VM # has a mechanism to notify the host. -on late-fs && property:ro.hardware.security.keymint.trusty.system=1 && \ +on late-fs && property:ro.hardware.trusty.security_vm.keymint.enabled=1 && \ property:trusty.security_vm.vm_cid=* setprop system.keymint.trusty_ipc_dev VSOCK:${trusty.security_vm.vm_cid}:1 start system.keymint.rust-trusty.nonsecure From a4e852d032bdfd0febcbcb8a2a53dd4b85b3c027 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 14 Nov 2024 18:14:26 +0000 Subject: [PATCH 130/183] Stop explicitly adding bionic subdirectories to the include path. Change-Id: I9961fa6ac957d8613f93fa33731da797f9ba8615 --- fs_mgr/libsnapshot/snapuserd/Android.bp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/Android.bp b/fs_mgr/libsnapshot/snapuserd/Android.bp index 97cfe7616..639116e8d 100644 --- a/fs_mgr/libsnapshot/snapuserd/Android.bp +++ b/fs_mgr/libsnapshot/snapuserd/Android.bp @@ -89,7 +89,6 @@ cc_library_static { "libprocessgroup_util", "libjsoncpp", ], - include_dirs: ["bionic/libc/kernel"], export_include_dirs: ["include"], header_libs: [ "libcutils_headers", @@ -144,7 +143,6 @@ cc_defaults { "libstorage_literals_headers", ], - include_dirs: ["bionic/libc/kernel"], system_shared_libs: [], // snapuserd is started during early boot by first-stage init. At that @@ -226,7 +224,6 @@ cc_defaults { "libz", ], include_dirs: [ - "bionic/libc/kernel", ".", ], header_libs: [ @@ -324,7 +321,6 @@ cc_binary_host { "libz", ], include_dirs: [ - "bionic/libc/kernel", ".", ], header_libs: [ From 03a14f5284b80dea659d2003cf8404f569f7d344 Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Thu, 14 Nov 2024 16:37:58 +0000 Subject: [PATCH 131/183] Declare support for v4 of KeyMint HAL Bug: 377744414 Bug: 369375199 Test: vts_treble_vintf_vendor_test Change-Id: I1fc04834819cc9291d89a6ee6803cbc5d5d91437 --- .../android.hardware.security.keymint-service.rust.trusty.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.xml b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.xml index 3dc9c88ea..f74d21285 100644 --- a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.xml +++ b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.xml @@ -1,7 +1,7 @@ android.hardware.security.keymint - 3 + 4 IKeyMintDevice/default From 9d062088260a9a50dd91d22869089c625c8628d6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 14 Nov 2024 10:39:19 -0800 Subject: [PATCH 132/183] Fix failure in CowTest#InvalidMergeOrderTest. This is failing on hwasan builds due to a typo in the test method. The actual writer logic is unaffected. Bug: 377298650 Test: valgrind cow_api_test Change-Id: I5c3f32ae57bf90b9fd29c7446bf34bdcb004328c --- fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp index ce80cd705..b7bc2c8b7 100644 --- a/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp +++ b/fs_mgr/libsnapshot/libsnapshot_cow/test_v2.cpp @@ -1487,7 +1487,7 @@ TEST_F(CowTest, InvalidMergeOrderTest) { writer = std::make_unique(options, GetCowFd()); ASSERT_TRUE(writer->Initialize()); ASSERT_TRUE(writer->AddCopy(2, 1)); - ASSERT_TRUE(writer->AddXorBlocks(3, &data, data.size(), 1, 1)); + ASSERT_TRUE(writer->AddXorBlocks(3, data.data(), data.size(), 1, 1)); ASSERT_TRUE(writer->Finalize()); ASSERT_TRUE(reader.Parse(cow_->fd)); ASSERT_FALSE(reader.VerifyMergeOps()); From dd8edea8593f81f0abc0080d6aa503f6ffaa064d Mon Sep 17 00:00:00 2001 From: Douglas Anderson Date: Thu, 14 Nov 2024 13:53:54 -0800 Subject: [PATCH 133/183] init: Add NVME support to the `boot_part_uuid` method of managing boot devices NVME devices have a subsystem of "class/nvme". Add that to the list of subsystems we check so we can identify them properly. Bug: 316324155 Test: Boot on a device with nvme Change-Id: I2ab3f6890f62f525dba150a0368c666a1c4c875e --- init/devices.cpp | 18 +++++++++++++++--- init/devices.h | 1 + 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/init/devices.cpp b/init/devices.cpp index 2cdececf6..fafa58f45 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -193,9 +193,11 @@ BlockDeviceInfo DeviceHandler::GetBlockDeviceInfo(const std::string& uevent_path BlockDeviceInfo info; if (!boot_part_uuid_.empty()) { - // Only use the more specific "MMC" or "SCSI" match if a partition UUID - // was passed. Old bootloaders that aren't passing the partition UUID - // instead pass the path to the closest "platform" device. It would + // Only use the more specific "MMC" / "NVME" / "SCSI" match if a + // partition UUID was passed. + // + // Old bootloaders that aren't passing the partition UUID instead + // pass the path to the closest "platform" device. It would // break them if we chose this deeper (more specific) path. // // When we have a UUID we _want_ the more specific path since it can @@ -204,6 +206,8 @@ BlockDeviceInfo DeviceHandler::GetBlockDeviceInfo(const std::string& uevent_path // classify them both the same by using the path to the USB controller. if (FindMmcDevice(uevent_path, &info.str)) { info.type = "mmc"; + } else if (FindNvmeDevice(uevent_path, &info.str)) { + info.type = "nvme"; } else if (FindScsiDevice(uevent_path, &info.str)) { info.type = "scsi"; } @@ -325,6 +329,14 @@ bool DeviceHandler::FindMmcDevice(const std::string& path, std::string* mmc_devi return FindSubsystemDevice(path, mmc_device_path, subsystem_paths); } +bool DeviceHandler::FindNvmeDevice(const std::string& path, std::string* nvme_device_path) const { + const std::set subsystem_paths = { + sysfs_mount_point_ + "/class/nvme", + }; + + return FindSubsystemDevice(path, nvme_device_path, subsystem_paths); +} + bool DeviceHandler::FindScsiDevice(const std::string& path, std::string* scsi_device_path) const { const std::set subsystem_paths = { sysfs_mount_point_ + "/bus/scsi", diff --git a/init/devices.h b/init/devices.h index 67a3d00b1..b8f8e542f 100644 --- a/init/devices.h +++ b/init/devices.h @@ -151,6 +151,7 @@ class DeviceHandler : public UeventHandler { const std::set& subsystem_paths) const; bool FindPlatformDevice(const std::string& path, std::string* platform_device_path) const; bool FindMmcDevice(const std::string& path, std::string* mmc_device_path) const; + bool FindNvmeDevice(const std::string& path, std::string* nvme_device_path) const; bool FindScsiDevice(const std::string& path, std::string* scsi_device_path) const; std::tuple GetDevicePermissions( const std::string& path, const std::vector& links) const; From 148c2531eef1881a5034615f8248bef2d0d92d7c Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Thu, 14 Nov 2024 22:43:16 +0000 Subject: [PATCH 134/183] libprocessgroup: Remove CGROUPS_RC_PATH /dev/cgroup_info/cgroup.rc doesn't exist anymore! Bug: 349105928 Change-Id: I2f49fab15d083f0c1617989ccf96ca843f998140 --- libprocessgroup/include/processgroup/processgroup.h | 2 -- 1 file changed, 2 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 805775744..85796ea8e 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -57,8 +57,6 @@ __BEGIN_DECLS bool SetProcessProfilesCached(uid_t uid, pid_t pid, const std::vector& profiles); -[[deprecated]] static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; - bool UsePerAppMemcg(); // Drop the fd cache of cgroup path. It is used for when resource caching is enabled and a process From 9e5f74d4e466b00777667b147ca8eac77ea26805 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 7 Aug 2024 16:41:32 +0000 Subject: [PATCH 135/183] libprocessgroup: Remove CGROUPV2_CONTROLLER_NAME This was deprecated a year ago, and should no longer be used. Change-Id: I19c75e50fd3cc86734fa9cc7f3d883260b2484ca --- libprocessgroup/include/processgroup/processgroup.h | 1 - 1 file changed, 1 deletion(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 85796ea8e..02f7c2508 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -27,7 +27,6 @@ __BEGIN_DECLS static constexpr const char* CGROUPV2_HIERARCHY_NAME = "cgroup2"; -[[deprecated]] static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2"; bool CgroupsAvailable(); bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path); From b6071f19c318fd19ed37d9fa4ba0cf77d7d32d13 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Wed, 7 Aug 2024 16:35:55 +0000 Subject: [PATCH 136/183] libprocessgroup: Convert CGROUPV2_HIERARCHY_NAME to std::string Almost everywhere CGROUPV2_HIERARCHY_NAME is used a std::string is required, so change its type to avoid temporaries. Change-Id: I4466838c510f2eb8212fc71999cdaa47359ce9c3 --- libprocessgroup/include/processgroup/processgroup.h | 2 +- libprocessgroup/setup/cgroup_map_write.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 02f7c2508..d27b56895 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -26,7 +26,7 @@ __BEGIN_DECLS -static constexpr const char* CGROUPV2_HIERARCHY_NAME = "cgroup2"; +static constexpr std::string CGROUPV2_HIERARCHY_NAME = "cgroup2"; bool CgroupsAvailable(); bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path); diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index d05bf2408..c4e1fb680 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -222,7 +222,7 @@ static bool SetupCgroup(const CgroupDescriptor& descriptor) { const CgroupController* controller = descriptor.controller(); if (controller->version() == 2) { - if (!strcmp(controller->name(), CGROUPV2_HIERARCHY_NAME)) { + if (controller->name() == CGROUPV2_HIERARCHY_NAME) { return MountV2CgroupController(descriptor); } else { return ActivateV2CgroupController(descriptor); From fdf4432356ddb597f46cfb7b047ab4e0bb808ba2 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Thu, 14 Nov 2024 23:04:10 +0000 Subject: [PATCH 137/183] libprocessgroup: Remove __BEGIN_DECLS and __END_DECLS These macros have been useless in this file since commit 82b72a566 ("libprocessgroup: Add support for task profiles") in 2018 which added C++ includes, and C++ types and keywords inside an extern "C" block. Change-Id: Iae1cbfcc5cb974034d88fb466b79088496190940 --- libprocessgroup/include/processgroup/processgroup.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index d27b56895..6a026a717 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -16,7 +16,6 @@ #pragma once -#include #include #include #include @@ -24,8 +23,6 @@ #include #include -__BEGIN_DECLS - static constexpr std::string CGROUPV2_HIERARCHY_NAME = "cgroup2"; bool CgroupsAvailable(); @@ -39,8 +36,6 @@ bool SetTaskProfiles(pid_t tid, const std::vector& profiles, bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles); bool SetUserProfiles(uid_t uid, const std::vector& profiles); -__END_DECLS - bool SetTaskProfiles(pid_t tid, std::initializer_list profiles, bool use_fd_cache = false); bool SetProcessProfiles(uid_t uid, pid_t pid, std::initializer_list profiles); @@ -50,7 +45,6 @@ bool SetTaskProfiles(pid_t tid, std::span profiles, bool SetProcessProfiles(uid_t uid, pid_t pid, std::span profiles); #endif -__BEGIN_DECLS #ifndef __ANDROID_VNDK__ @@ -96,5 +90,3 @@ bool getAttributePathForTask(const std::string& attr_name, pid_t tid, std::strin bool isProfileValidForProcess(const std::string& profile_name, uid_t uid, pid_t pid); #endif // __ANDROID_VNDK__ - -__END_DECLS From 5996d608af75755f0c1964e62fe69482761efd24 Mon Sep 17 00:00:00 2001 From: Chan Wang Date: Thu, 14 Nov 2024 13:25:37 +0000 Subject: [PATCH 138/183] Use the new 'partition' field in 'ApexInfo' to identify vendor apexes A new field 'partition' was added to `ApexInfo` recently which stores pre-installed partition information as string (e.g. 'SYSTEM') in aosp/3335753. Using 'partition' field for Subcontext vendor apex initialization because the existing field `preinstalledModulePath` won't be populated for brand-new apex (a new type we introduced recently). Bug: 377111286 Test: atest CtsInitTestCases Change-Id: I8970b3cb5884bdb949035f5bdc5b2e18618cc9cc --- init/init.cpp | 3 +-- init/subcontext.cpp | 11 ++++++++--- init/subcontext.h | 6 +++++- init/subcontext_benchmark.cpp | 2 +- init/subcontext_test.cpp | 15 ++++++++++++++- 5 files changed, 29 insertions(+), 8 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index 17498da6d..5b0b0ddee 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -315,8 +315,7 @@ Parser CreateApexConfigParser(ActionManager& action_manager, ServiceList& servic if (apex_info_list.has_value()) { std::vector subcontext_apexes; for (const auto& info : apex_info_list->getApexInfo()) { - if (info.hasPreinstalledModulePath() && - subcontext->PathMatchesSubcontext(info.getPreinstalledModulePath())) { + if (subcontext->PartitionMatchesSubcontext(info.getPartition())) { subcontext_apexes.push_back(info.getModuleName()); } } diff --git a/init/subcontext.cpp b/init/subcontext.cpp index 6a095fb7b..3fe448fe3 100644 --- a/init/subcontext.cpp +++ b/init/subcontext.cpp @@ -263,6 +263,10 @@ bool Subcontext::PathMatchesSubcontext(const std::string& path) const { return false; } +bool Subcontext::PartitionMatchesSubcontext(const std::string& partition) const { + return std::find(partitions_.begin(), partitions_.end(), partition) != partitions_.end(); +} + void Subcontext::SetApexList(std::vector&& apex_list) { apex_list_ = std::move(apex_list); } @@ -352,12 +356,13 @@ void InitializeSubcontext() { } if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_P__) { - subcontext.reset( - new Subcontext(std::vector{"/vendor", "/odm"}, kVendorContext)); + subcontext.reset(new Subcontext(std::vector{"/vendor", "/odm"}, + std::vector{"VENDOR", "ODM"}, kVendorContext)); } } + void InitializeHostSubcontext(std::vector vendor_prefixes) { - subcontext.reset(new Subcontext(vendor_prefixes, kVendorContext, /*host=*/true)); + subcontext.reset(new Subcontext(vendor_prefixes, {}, kVendorContext, /*host=*/true)); } Subcontext* GetSubcontext() { diff --git a/init/subcontext.h b/init/subcontext.h index 93ebacea2..23c4a241c 100644 --- a/init/subcontext.h +++ b/init/subcontext.h @@ -36,8 +36,10 @@ static constexpr const char kTestContext[] = "test-test-test"; class Subcontext { public: - Subcontext(std::vector path_prefixes, std::string_view context, bool host = false) + Subcontext(std::vector path_prefixes, std::vector partitions, + std::string_view context, bool host = false) : path_prefixes_(std::move(path_prefixes)), + partitions_(std::move(partitions)), context_(context.begin(), context.end()), pid_(0) { if (!host) { @@ -49,6 +51,7 @@ class Subcontext { Result> ExpandArgs(const std::vector& args); void Restart(); bool PathMatchesSubcontext(const std::string& path) const; + bool PartitionMatchesSubcontext(const std::string& partition) const; void SetApexList(std::vector&& apex_list); const std::string& context() const { return context_; } @@ -59,6 +62,7 @@ class Subcontext { Result TransmitMessage(const SubcontextCommand& subcontext_command); std::vector path_prefixes_; + std::vector partitions_; std::vector apex_list_; std::string context_; pid_t pid_; diff --git a/init/subcontext_benchmark.cpp b/init/subcontext_benchmark.cpp index ccef2f36a..172ee3173 100644 --- a/init/subcontext_benchmark.cpp +++ b/init/subcontext_benchmark.cpp @@ -33,7 +33,7 @@ static void BenchmarkSuccess(benchmark::State& state) { return; } - auto subcontext = Subcontext({"path"}, context); + auto subcontext = Subcontext({"path"}, {"partition"}, context); free(context); while (state.KeepRunning()) { diff --git a/init/subcontext_test.cpp b/init/subcontext_test.cpp index da1f45550..85a2f2a94 100644 --- a/init/subcontext_test.cpp +++ b/init/subcontext_test.cpp @@ -41,7 +41,7 @@ namespace init { template void RunTest(F&& test_function) { - auto subcontext = Subcontext({"dummy_path"}, kTestContext); + auto subcontext = Subcontext({"dummy_path"}, {"dummy_partition"}, kTestContext); ASSERT_NE(0, subcontext.pid()); test_function(subcontext); @@ -177,6 +177,19 @@ TEST(subcontext, ExpandArgsFailure) { }); } +TEST(subcontext, PartitionMatchesSubcontext) { + RunTest([](auto& subcontext) { + static auto& existent_partition = "dummy_partition"; + static auto& non_existent_partition = "not_dummy_partition"; + + auto existent_result = subcontext.PartitionMatchesSubcontext(existent_partition); + auto non_existent_result = subcontext.PartitionMatchesSubcontext(non_existent_partition); + + ASSERT_TRUE(existent_result); + ASSERT_FALSE(non_existent_result); + }); +} + BuiltinFunctionMap BuildTestFunctionMap() { // For CheckDifferentPid auto do_return_pids_as_error = [](const BuiltinArguments& args) -> Result { From d02b74411b968a5e5792e25861f2c58f895f2bf5 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Thu, 14 Nov 2024 11:17:32 -0800 Subject: [PATCH 139/183] snapuserd: Change error message to verbose These error logs gets printed even when I/O gracefully terminates which might be confusing. Bug: 377819507 Test: Build Change-Id: I93d4ec2203566e75195215babc0042370be43ccb Signed-off-by: Akilesh Kailash --- .../libsnapshot/snapuserd/user-space-merge/merge_worker.cpp | 1 - .../snapuserd/user-space-merge/snapuserd_readahead.cpp | 2 +- .../snapuserd/user-space-merge/snapuserd_transitions.cpp | 6 ++++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp index 486548cad..a0c5c6658 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp @@ -582,7 +582,6 @@ bool MergeWorker::Run() { pthread_setname_np(pthread_self(), "MergeWorker"); if (!snapuserd_->WaitForMergeBegin()) { - SNAP_LOG(ERROR) << "Merge terminated early..."; return true; } auto merge_thread_priority = android::base::GetUintProperty( diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index 9a1d441c4..3007d45f4 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -702,7 +702,7 @@ bool ReadAhead::ReadAheadIOStart() { // window. If there is a crash during this time frame, merge should resume // based on the contents of the scratch space. if (!snapuserd_->WaitForMergeReady()) { - SNAP_LOG(ERROR) << "ReadAhead failed to wait for merge ready"; + SNAP_LOG(VERBOSE) << "ReadAhead failed to wait for merge ready"; return false; } diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp index 2ad4ea1c2..714c64124 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_transitions.cpp @@ -202,7 +202,7 @@ bool SnapshotHandler::WaitForMergeBegin() { cv.wait(lock, [this]() -> bool { return MergeInitiated() || IsMergeBeginError(io_state_); }); if (IsMergeBeginError(io_state_)) { - SNAP_LOG(ERROR) << "WaitForMergeBegin failed with state: " << io_state_; + SNAP_LOG(VERBOSE) << "WaitForMergeBegin failed with state: " << io_state_; return false; } @@ -276,7 +276,9 @@ bool SnapshotHandler::WaitForMergeReady() { if (io_state_ == MERGE_IO_TRANSITION::MERGE_FAILED || io_state_ == MERGE_IO_TRANSITION::MERGE_COMPLETE || io_state_ == MERGE_IO_TRANSITION::IO_TERMINATED) { - SNAP_LOG(ERROR) << "Wait for merge ready failed: " << io_state_; + if (io_state_ == MERGE_IO_TRANSITION::MERGE_FAILED) { + SNAP_LOG(ERROR) << "Wait for merge ready failed: " << io_state_; + } return false; } return true; From 6a5db6838514d92d9d2361810f9b96d5039e2801 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 15 Nov 2024 01:06:55 +0000 Subject: [PATCH 140/183] Remove non-UTF8 characters from string fields. The string type in the tombstone proto does not support non-UTF8 characters. Therefore, use the oct_encode function to encode the abort_message field and message field from LogMessage. Fix up stl includes, add ones that were missing and remove those not being used. Add new unit test to verify that the abort and log messages are sanitized. Bug: 279496937 Bug: 377940849 Bug: 378185483 Test: All unit tests pass. Test: Ran pbtombstone on a crash with non-UTF8 characters and verified Test: it processes properly after this change and fails before the change. Change-Id: I3554d56caf9fcbfc410b4d554f6c3b4888b37e28 --- debuggerd/debuggerd_test.cpp | 27 +++++++++++++++++++ .../include/libdebuggerd/utility_host.h | 2 ++ debuggerd/libdebuggerd/tombstone_proto.cpp | 9 +++++-- .../libdebuggerd/tombstone_proto_to_text.cpp | 26 +++--------------- debuggerd/libdebuggerd/utility_host.cpp | 23 ++++++++++++++++ 5 files changed, 62 insertions(+), 25 deletions(-) diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index 13c8d70b5..5bdc94646 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -3302,3 +3302,30 @@ TEST_F(CrasherTest, log_with_newline) { ASSERT_MATCH(result, ":\\s*This line has a newline."); ASSERT_MATCH(result, ":\\s*This is on the next line."); } + +TEST_F(CrasherTest, log_with_non_utf8) { + StartProcess([]() { LOG(FATAL) << "Invalid UTF-8: \xA0\xB0\xC0\xD0 and some other data."; }); + + unique_fd output_fd; + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGABRT); + int intercept_result; + FinishIntercept(&intercept_result); + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + // Verify the abort message is sanitized properly. + size_t pos = result.find( + "Abort message: 'Invalid UTF-8: " + "\x5C\x32\x34\x30\x5C\x32\x36\x30\x5C\x33\x30\x30\x5C\x33\x32\x30 and some other data.'"); + EXPECT_TRUE(pos != std::string::npos) << "Couldn't find sanitized abort message: " << result; + + // Make sure that the log message is sanitized properly too. + EXPECT_TRUE( + result.find("Invalid UTF-8: \x5C\x32\x34\x30\x5C\x32\x36\x30\x5C\x33\x30\x30\x5C\x33\x32\x30 " + "and some other data.", + pos + 30) != std::string::npos) + << "Couldn't find sanitized log message: " << result; +} diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h index 43fb8bdc1..df22e017c 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility_host.h @@ -29,3 +29,5 @@ constexpr size_t kTagGranuleSize = 16; // Number of rows and columns to display in an MTE tag dump. constexpr size_t kNumTagColumns = 16; constexpr size_t kNumTagRows = 16; + +std::string oct_encode(const std::string& data); diff --git a/debuggerd/libdebuggerd/tombstone_proto.cpp b/debuggerd/libdebuggerd/tombstone_proto.cpp index d59358c65..ef303f065 100644 --- a/debuggerd/libdebuggerd/tombstone_proto.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto.cpp @@ -34,10 +34,13 @@ #include #include +#include #include #include #include #include +#include +#include #include @@ -463,7 +466,8 @@ static void dump_abort_message(Tombstone* tombstone, } msg.resize(index); - tombstone->set_abort_message(msg); + // Make sure only UTF8 characters are present since abort_message is a string. + tombstone->set_abort_message(oct_encode(msg)); } static void dump_open_fds(Tombstone* tombstone, const OpenFilesList* open_files) { @@ -771,7 +775,8 @@ static void dump_log_file(Tombstone* tombstone, const char* logger, pid_t pid) { log_msg->set_tid(log_entry.entry.tid); log_msg->set_priority(prio); log_msg->set_tag(tag); - log_msg->set_message(msg); + // Make sure only UTF8 characters are present since message is a string. + log_msg->set_message(oct_encode(msg)); } while ((msg = nl)); } android_logger_list_free(logger_list); diff --git a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp index fedafc0c3..e885c5a73 100644 --- a/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp +++ b/debuggerd/libdebuggerd/tombstone_proto_to_text.cpp @@ -19,9 +19,9 @@ #include -#include +#include #include -#include +#include #include #include #include @@ -32,6 +32,7 @@ #include #include +#include "libdebuggerd/utility_host.h" #include "tombstone.pb.h" using android::base::StringAppendF; @@ -418,27 +419,6 @@ static void print_memory_maps(CallbackType callback, const Tombstone& tombstone) } } -static std::string oct_encode(const std::string& data) { - std::string oct_encoded; - oct_encoded.reserve(data.size()); - - // N.B. the unsigned here is very important, otherwise e.g. \255 would render as - // \-123 (and overflow our buffer). - for (unsigned char c : data) { - if (isprint(c)) { - oct_encoded += c; - } else { - std::string oct_digits("\\\0\0\0", 4); - // char is encodable in 3 oct digits - static_assert(std::numeric_limits::max() <= 8 * 8 * 8); - auto [ptr, ec] = std::to_chars(oct_digits.data() + 1, oct_digits.data() + 4, c, 8); - oct_digits.resize(ptr - oct_digits.data()); - oct_encoded += oct_digits; - } - } - return oct_encoded; -} - static void print_main_thread(CallbackType callback, SymbolizeCallbackType symbolize, const Tombstone& tombstone, const Thread& thread) { print_thread_header(callback, tombstone, thread, true); diff --git a/debuggerd/libdebuggerd/utility_host.cpp b/debuggerd/libdebuggerd/utility_host.cpp index 72a560cfe..4efa03c8c 100644 --- a/debuggerd/libdebuggerd/utility_host.cpp +++ b/debuggerd/libdebuggerd/utility_host.cpp @@ -18,6 +18,8 @@ #include +#include +#include #include #include @@ -99,3 +101,24 @@ std::string describe_pac_enabled_keys(long value) { DESCRIBE_FLAG(PR_PAC_APGAKEY); return describe_end(value, desc); } + +std::string oct_encode(const std::string& data) { + std::string oct_encoded; + oct_encoded.reserve(data.size()); + + // N.B. the unsigned here is very important, otherwise e.g. \255 would render as + // \-123 (and overflow our buffer). + for (unsigned char c : data) { + if (isprint(c)) { + oct_encoded += c; + } else { + std::string oct_digits("\\\0\0\0", 4); + // char is encodable in 3 oct digits + static_assert(std::numeric_limits::max() <= 8 * 8 * 8); + auto [ptr, ec] = std::to_chars(oct_digits.data() + 1, oct_digits.data() + 4, c, 8); + oct_digits.resize(ptr - oct_digits.data()); + oct_encoded += oct_digits; + } + } + return oct_encoded; +} From 28b2556e90dcad4e2ecaabb2e8f5413986dce1de Mon Sep 17 00:00:00 2001 From: Aeric Date: Mon, 18 Nov 2024 17:30:46 +0800 Subject: [PATCH 141/183] Fix typo of snapuserd_verify.h "advisible" should be "advisable" "fucntionality" should be "functionality" Bug: 379603290 Test: build pass Change-Id: I6c95f2b186f479ba51df8603ce87c0522e91bf64 --- .../libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h index 7c9908515..b300a7000 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_verify.h @@ -62,8 +62,8 @@ class UpdateVerify { * (/proc/pressure/{cpu,memory}; and monitoring the Inactive(file) and * Active(file) pages from /proc/meminfo. * - * Additionally, for low memory devices, it is advisible to use O_DIRECT - * fucntionality for source block device. + * Additionally, for low memory devices, it is advisable to use O_DIRECT + * functionality for source block device. */ int kMinThreadsToVerify = 1; int kMaxThreadsToVerify = 3; From 6105d9dc8aeec5ef54092854121cd6ff5859f3a4 Mon Sep 17 00:00:00 2001 From: Gabriel Biren Date: Mon, 18 Nov 2024 20:24:58 +0000 Subject: [PATCH 142/183] Create the mainline supplicant directory during initialization. Bug: 365585450 Test: Manual test - verify that the mainline supplicant can add/remove interfaces Change-Id: Ib41b361a8b032c04586f108be9d1933214934286 --- rootdir/init.rc | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index 617e60a0f..eeafd4c85 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -781,6 +781,8 @@ on post-fs-data mkdir /data/misc/shared_relro 0771 shared_relro shared_relro mkdir /data/misc/systemkeys 0700 system system mkdir /data/misc/wifi 0770 wifi wifi + mkdir /data/misc/wifi/mainline_supplicant 0770 wifi wifi + mkdir /data/misc/wifi/mainline_supplicant/sockets 0770 wifi wifi mkdir /data/misc/wifi/sockets 0770 wifi wifi mkdir /data/misc/wifi/wpa_supplicant 0770 wifi wifi mkdir /data/misc/ethernet 0770 system system From f1d00f0f2a897f76060b5083b9b0f9c051b16c51 Mon Sep 17 00:00:00 2001 From: Neill Kapron Date: Tue, 19 Nov 2024 02:13:33 +0000 Subject: [PATCH 143/183] libcutils: create rust bindings for android ids For work on the new rust based bpfloader, we need access to the IDs in android_filesystem_config.h for owner/group permissions of pinned bpf programs and maps. Create android_ids crate to expose this information to rust. Bug: 359646531 Test: Manual Change-Id: Iee827d8a80a82fbee02a76280668071713625abf Signed-off-by: Neill Kapron --- libcutils/Android.bp | 11 +++++++++++ libcutils/rust/aid_bindings.h | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 libcutils/rust/aid_bindings.h diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 10392889d..ec9b75493 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -21,6 +21,17 @@ filegroup { srcs: ["include/private/android_filesystem_config.h"], } +rust_bindgen { + name: "libandroid_ids", + crate_name: "android_ids", + source_stem: "bindings", + wrapper_src: "rust/aid_bindings.h", + header_libs: ["libcutils_headers"], + visibility: [ + "//system/bpf/loader", + ], +} + cc_defaults { name: "libcutils_defaults", cflags: [ diff --git a/libcutils/rust/aid_bindings.h b/libcutils/rust/aid_bindings.h new file mode 100644 index 000000000..1b175a26f --- /dev/null +++ b/libcutils/rust/aid_bindings.h @@ -0,0 +1,16 @@ +/* + * Copyright (C) 2024 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 From 668ffc395d0c83c9e9cdcca972e35e936a5f85f0 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 18 Nov 2024 19:23:45 -0800 Subject: [PATCH 144/183] snapuserd: Use GTEST_SKIP in snapuserd_test. The test harness treats an early exit as a failure, so use GTEST_SKIP() instead. Bug: 379242140 Test: vts_snapuserd_test Change-Id: I25351bb7ebf65e6c56865662d297feb4a1f635b3 --- .../user-space-merge/snapuserd_test.cpp | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) 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 4dfb9bf4e..469fd091a 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -82,6 +82,8 @@ class SnapuserdTestBase : public ::testing::TestWithParam { unique_fd GetCowFd() { return unique_fd{dup(cow_system_->fd)}; } + bool ShouldSkipSetUp(); + std::unique_ptr harness_; size_t size_ = 10_MiB; int total_base_size_ = 0; @@ -97,6 +99,10 @@ class SnapuserdTestBase : public ::testing::TestWithParam { }; void SnapuserdTestBase::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } + #if __ANDROID__ harness_ = std::make_unique(); #else @@ -104,6 +110,16 @@ void SnapuserdTestBase::SetUp() { #endif } +bool SnapuserdTestBase::ShouldSkipSetUp() { +#ifdef __ANDROID__ + if (!android::snapshot::CanUseUserspaceSnapshots() || + android::snapshot::IsVendorFromAndroid12()) { + return true; + } +#endif + return false; +} + void SnapuserdTestBase::TearDown() { cow_system_ = nullptr; } @@ -302,6 +318,9 @@ class SnapuserdTest : public SnapuserdTestBase { }; void SnapuserdTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); handlers_ = std::make_unique(); } @@ -312,6 +331,9 @@ void SnapuserdTest::TearDown() { } void SnapuserdTest::Shutdown() { + if (!handlers_) { + return; + } if (dmuser_dev_) { ASSERT_TRUE(dmuser_dev_->Destroy()); } @@ -1181,6 +1203,9 @@ void SnapuserdVariableBlockSizeTest::ReadSnapshotWithVariableBlockSize() { } void SnapuserdVariableBlockSizeTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTest::SetUp()); } @@ -1244,6 +1269,9 @@ void HandlerTest::InitializeDevice() { } void HandlerTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); ASSERT_NO_FATAL_FAILURE(SetUpV2Cow()); @@ -1251,6 +1279,9 @@ void HandlerTest::SetUp() { } void HandlerTest::TearDown() { + if (ShouldSkipSetUp()) { + return; + } ASSERT_TRUE(factory_.DeleteQueue(system_device_ctrl_name_)); ASSERT_TRUE(handler_thread_.get()); SnapuserdTestBase::TearDown(); @@ -1326,6 +1357,9 @@ class HandlerTestV3 : public HandlerTest { }; void HandlerTestV3::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); ASSERT_NO_FATAL_FAILURE(SetUpV3Cow()); @@ -1530,14 +1564,6 @@ INSTANTIATE_TEST_SUITE_P(Io, HandlerTest, ::testing::ValuesIn(GetTestConfigs())) int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); -#ifdef __ANDROID__ - if (!android::snapshot::CanUseUserspaceSnapshots() || - android::snapshot::IsVendorFromAndroid12()) { - std::cerr << "snapuserd_test not supported on this device\n"; - return 0; - } -#endif - gflags::ParseCommandLineFlags(&argc, &argv, false); return RUN_ALL_TESTS(); From d17d5c585efe81d2e8a048efb919c2b7faabcb4a Mon Sep 17 00:00:00 2001 From: Eric Caruso Date: Mon, 28 Oct 2024 15:30:11 -0400 Subject: [PATCH 145/183] ueventd: add support for driver section in ueventd.rc Allow ueventd configuration to specify what to do with devices based on driver. This responds to bind events and treats them similarly to add events. The format of the driver stanza is exactly the same as that of the subsystem stanza. Bug: 376900376 Test: set up cbc_mbim driver stanza and ensure it properly creates and destroys device nodes when a USB device with that driver appears and disappears or is bound and unbound Change-Id: I31f5c91bd074d14075b74fe7beefaa6ac07a7ac9 --- init/README.ueventd.md | 16 +++++--- init/block_dev_initializer.cpp | 3 +- init/devices.cpp | 72 ++++++++++++++++++++++++++++++++-- init/devices.h | 15 ++++++- init/uevent.h | 1 + init/uevent_listener.cpp | 4 ++ init/ueventd.cpp | 4 +- init/ueventd_parser.cpp | 2 + init/ueventd_parser.h | 1 + init/ueventd_parser_test.cpp | 56 +++++++++++++++++++++----- 10 files changed, 151 insertions(+), 23 deletions(-) diff --git a/init/README.ueventd.md b/init/README.ueventd.md index aac4acb6a..0e84c6f5f 100644 --- a/init/README.ueventd.md +++ b/init/README.ueventd.md @@ -76,17 +76,17 @@ For example When `/dev/null` is created, its mode will be set to `0666`, its user to `root` and its group to `root`. -The path can be modified using a ueventd.rc script and a `subsystem` section. There are three to set -for a subsystem: the subsystem name, which device name to use, and which directory to place the -device in. The section takes the below format of +The path can be modified using a ueventd.rc script and a `subsystem` and/or `driver` section. +There are three options to set for a subsystem or driver: the name, which device name to use, +and which directory to place the device in. The section takes the below format of subsystem devname uevent_devname|uevent_devpath [dirname ] -`subsystem_name` is used to match uevent `SUBSYSTEM` value +`subsystem_name` is used to match the uevent `SUBSYSTEM` value. -`devname` takes one of three options +`devname` takes one of three options: 1. `uevent_devname` specifies that the name of the node will be the uevent `DEVNAME` 2. `uevent_devpath` specifies that the name of the node will be basename uevent `DEVPATH` 3. `sys_name` specifies that the name of the node will be the contents of `/sys/DEVPATH/name` @@ -99,9 +99,13 @@ For example subsystem sound devname uevent_devpath dirname /dev/snd -Indicates that all uevents with `SUBSYSTEM=sound` will create nodes as `/dev/snd/`. +The `driver` section has the exact same structure as a `subsystem` section, but +will instead match the `DRIVER` value in a `bind`/`unbind` uevent. However, the +`driver` section will be ignored for block devices. + ## /sys ---- Ueventd by default takes no action for `/sys`, however it can be instructed to set permissions for diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index 7f83037ae..deb68e9ac 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -33,7 +33,8 @@ BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) auto boot_devices = android::fs_mgr::GetBootDevices(); device_handler_ = std::make_unique( std::vector{}, std::vector{}, std::vector{}, - std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), false); + std::vector{}, std::move(boot_devices), android::fs_mgr::GetBootPartUuid(), + false); } // If boot_part_uuid is specified, use it to set boot_devices diff --git a/init/devices.cpp b/init/devices.cpp index fafa58f45..aeaa43133 100644 --- a/init/devices.cpp +++ b/init/devices.cpp @@ -345,6 +345,26 @@ bool DeviceHandler::FindScsiDevice(const std::string& path, std::string* scsi_de return FindSubsystemDevice(path, scsi_device_path, subsystem_paths); } +void DeviceHandler::TrackDeviceUevent(const Uevent& uevent) { + // No need to track any events if we won't bother handling any bind events + // later. + if (drivers_.size() == 0) return; + + // Only track add, and not for block devices. We don't track remove because + // unbind events may arrive after remove events, so unbind will be the + // trigger to untrack those events. + if ((uevent.action != "add") || uevent.subsystem == "block" || + (uevent.major < 0 || uevent.minor < 0)) { + return; + } + + std::string path = sysfs_mount_point_ + uevent.path + "/device"; + std::string device; + if (!Realpath(path, &device)) return; + + tracked_uevents_.emplace_back(uevent, device); +} + void DeviceHandler::FixupSysPermissions(const std::string& upath, const std::string& subsystem) const { // upaths omit the "/sys" that paths in this list @@ -664,12 +684,53 @@ bool DeviceHandler::CheckUeventForBootPartUuid(const Uevent& uevent) { return true; } +void DeviceHandler::HandleBindInternal(std::string driver_name, std::string action, + const Uevent& uevent) { + if (uevent.subsystem == "block") { + LOG(FATAL) << "Tried to handle bind event for block device"; + } + + // Get tracked uevents for all devices that have this uevent's path as + // their canonical device path. Then handle those again if their driver + // is one of the ones we're interested in. + const auto driver = std::find(drivers_.cbegin(), drivers_.cend(), driver_name); + if (driver == drivers_.cend()) return; + + std::string bind_path = sysfs_mount_point_ + uevent.path; + for (const TrackedUevent& tracked : tracked_uevents_) { + if (tracked.canonical_device_path != bind_path) continue; + + LOG(VERBOSE) << "Propagating " << uevent.action << " as " << action << " for " + << uevent.path; + + std::string devpath = driver->ParseDevPath(tracked.uevent); + mkdir_recursive(Dirname(devpath), 0755); + HandleDevice(action, devpath, false, tracked.uevent.major, tracked.uevent.minor, + std::vector{}); + } +} + void DeviceHandler::HandleUevent(const Uevent& uevent) { if (uevent.action == "add" || uevent.action == "change" || uevent.action == "bind" || uevent.action == "online") { FixupSysPermissions(uevent.path, uevent.subsystem); } + if (uevent.action == "bind") { + bound_drivers_[uevent.path] = uevent.driver; + HandleBindInternal(uevent.driver, "add", uevent); + return; + } else if (uevent.action == "unbind") { + if (bound_drivers_.count(uevent.path) == 0) return; + HandleBindInternal(bound_drivers_[uevent.path], "remove", uevent); + + std::string sys_path = sysfs_mount_point_ + uevent.path; + std::erase_if(tracked_uevents_, [&sys_path](const TrackedUevent& tracked) { + return sys_path == tracked.canonical_device_path; + }); + return; + } + // if it's not a /dev device, nothing to do if (uevent.major < 0 || uevent.minor < 0) return; @@ -677,6 +738,8 @@ void DeviceHandler::HandleUevent(const Uevent& uevent) { std::vector links; bool block = false; + TrackDeviceUevent(uevent); + if (uevent.subsystem == "block") { block = true; devpath = "/dev/block/" + Basename(uevent.path); @@ -725,10 +788,12 @@ void DeviceHandler::ColdbootDone() { DeviceHandler::DeviceHandler(std::vector dev_permissions, std::vector sysfs_permissions, - std::vector subsystems, std::set boot_devices, - std::string boot_part_uuid, bool skip_restorecon) + std::vector drivers, std::vector subsystems, + std::set boot_devices, std::string boot_part_uuid, + bool skip_restorecon) : dev_permissions_(std::move(dev_permissions)), sysfs_permissions_(std::move(sysfs_permissions)), + drivers_(std::move(drivers)), subsystems_(std::move(subsystems)), boot_devices_(std::move(boot_devices)), boot_part_uuid_(boot_part_uuid), @@ -744,7 +809,8 @@ DeviceHandler::DeviceHandler(std::vector dev_permissions, DeviceHandler::DeviceHandler() : DeviceHandler(std::vector{}, std::vector{}, - std::vector{}, std::set{}, "", false) {} + std::vector{}, std::vector{}, std::set{}, "", + false) {} } // namespace init } // namespace android diff --git a/init/devices.h b/init/devices.h index b8f8e542f..69a244978 100644 --- a/init/devices.h +++ b/init/devices.h @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -128,7 +129,7 @@ class DeviceHandler : public UeventHandler { DeviceHandler(); DeviceHandler(std::vector dev_permissions, - std::vector sysfs_permissions, + std::vector sysfs_permissions, std::vector drivers, std::vector subsystems, std::set boot_devices, std::string boot_part_uuid, bool skip_restorecon); virtual ~DeviceHandler() = default; @@ -145,6 +146,11 @@ class DeviceHandler : public UeventHandler { bool IsBootDevice(const Uevent& uevent) const; private: + struct TrackedUevent { + Uevent uevent; + std::string canonical_device_path; + }; + void ColdbootDone() override; BlockDeviceInfo GetBlockDeviceInfo(const std::string& uevent_path) const; bool FindSubsystemDevice(std::string path, std::string* device_path, @@ -163,14 +169,21 @@ class DeviceHandler : public UeventHandler { void FixupSysPermissions(const std::string& upath, const std::string& subsystem) const; void HandleAshmemUevent(const Uevent& uevent); + void TrackDeviceUevent(const Uevent& uevent); + void HandleBindInternal(std::string driver_name, std::string action, const Uevent& uevent); + std::vector dev_permissions_; std::vector sysfs_permissions_; + std::vector drivers_; std::vector subsystems_; std::set boot_devices_; std::string boot_part_uuid_; bool found_boot_part_uuid_; bool skip_restorecon_; std::string sysfs_mount_point_; + + std::vector tracked_uevents_; + std::map bound_drivers_; }; // Exposed for testing diff --git a/init/uevent.h b/init/uevent.h index c8ca52aaf..e7ed2266e 100644 --- a/init/uevent.h +++ b/init/uevent.h @@ -26,6 +26,7 @@ struct Uevent { std::string action; std::string path; std::string subsystem; + std::string driver; std::string firmware; std::string partition_name; std::string partition_uuid; diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp index 97f3de640..d329c174f 100644 --- a/init/uevent_listener.cpp +++ b/init/uevent_listener.cpp @@ -36,6 +36,7 @@ static void ParseEvent(const char* msg, Uevent* uevent) { uevent->action.clear(); uevent->path.clear(); uevent->subsystem.clear(); + uevent->driver.clear(); uevent->firmware.clear(); uevent->partition_name.clear(); uevent->device_name.clear(); @@ -51,6 +52,9 @@ static void ParseEvent(const char* msg, Uevent* uevent) { } else if (!strncmp(msg, "SUBSYSTEM=", 10)) { msg += 10; uevent->subsystem = msg; + } else if (!strncmp(msg, "DRIVER=", 7)) { + msg += 7; + uevent->driver = msg; } else if (!strncmp(msg, "FIRMWARE=", 9)) { msg += 9; uevent->firmware = msg; diff --git a/init/ueventd.cpp b/init/ueventd.cpp index 286e47266..cb6b851d6 100644 --- a/init/ueventd.cpp +++ b/init/ueventd.cpp @@ -364,8 +364,8 @@ int ueventd_main(int argc, char** argv) { std::unique_ptr device_handler = std::make_unique( std::move(ueventd_configuration.dev_permissions), std::move(ueventd_configuration.sysfs_permissions), - std::move(ueventd_configuration.subsystems), android::fs_mgr::GetBootDevices(), - android::fs_mgr::GetBootPartUuid(), true); + std::move(ueventd_configuration.drivers), std::move(ueventd_configuration.subsystems), + android::fs_mgr::GetBootDevices(), android::fs_mgr::GetBootPartUuid(), true); uevent_listener.RegenerateUevents([&](const Uevent& uevent) -> ListenerAction { bool uuid_check_done = device_handler->CheckUeventForBootPartUuid(uevent); return uuid_check_done ? ListenerAction::kStop : ListenerAction::kContinue; diff --git a/init/ueventd_parser.cpp b/init/ueventd_parser.cpp index 4395d8838..097ef09d7 100644 --- a/init/ueventd_parser.cpp +++ b/init/ueventd_parser.cpp @@ -264,6 +264,8 @@ UeventdConfiguration ParseConfig(const std::vector& configs) { parser.AddSectionParser("import", std::make_unique(&parser)); parser.AddSectionParser("subsystem", std::make_unique(&ueventd_configuration.subsystems)); + parser.AddSectionParser("driver", + std::make_unique(&ueventd_configuration.drivers)); using namespace std::placeholders; parser.AddSingleLineParser( diff --git a/init/ueventd_parser.h b/init/ueventd_parser.h index 81f4e9d54..ffe6072df 100644 --- a/init/ueventd_parser.h +++ b/init/ueventd_parser.h @@ -27,6 +27,7 @@ namespace init { struct UeventdConfiguration { std::vector subsystems; + std::vector drivers; std::vector sysfs_permissions; std::vector dev_permissions; std::vector firmware_directories; diff --git a/init/ueventd_parser_test.cpp b/init/ueventd_parser_test.cpp index 41924e235..6d910398a 100644 --- a/init/ueventd_parser_test.cpp +++ b/init/ueventd_parser_test.cpp @@ -106,7 +106,32 @@ subsystem test_devpath_dirname {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}}; - TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}, {}}); + TestUeventdFile(ueventd_file, {subsystems, {}, {}, {}, {}, {}, {}}); +} + +TEST(ueventd_parser, Drivers) { + auto ueventd_file = R"( +driver test_devname + devname uevent_devname + +driver test_devpath_no_dirname + devname uevent_devpath + +driver test_devname2 + devname uevent_devname + +driver test_devpath_dirname + devname uevent_devpath + dirname /dev/graphics +)"; + + auto drivers = std::vector{ + {"test_devname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, + {"test_devpath_no_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"}, + {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, + {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}}; + + TestUeventdFile(ueventd_file, {{}, drivers, {}, {}, {}, {}, {}, {}}); } TEST(ueventd_parser, Permissions) { @@ -132,7 +157,7 @@ TEST(ueventd_parser, Permissions) { {"/sys/devices/virtual/*/input", "poll_delay", 0660, AID_ROOT, AID_INPUT, true}, }; - TestUeventdFile(ueventd_file, {{}, sysfs_permissions, permissions, {}, {}, {}}); + TestUeventdFile(ueventd_file, {{}, {}, sysfs_permissions, permissions, {}, {}, {}}); } TEST(ueventd_parser, FirmwareDirectories) { @@ -148,7 +173,7 @@ firmware_directories /more "/more", }; - TestUeventdFile(ueventd_file, {{}, {}, {}, firmware_directories, {}, {}}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, firmware_directories, {}, {}}); } TEST(ueventd_parser, ExternalFirmwareHandlers) { @@ -214,7 +239,7 @@ external_firmware_handler /devices/path/firmware/something004.bin radio radio "/ }, }; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers, {}}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, external_firmware_handlers, {}}); } TEST(ueventd_parser, ExternalFirmwareHandlersDuplicate) { @@ -232,7 +257,7 @@ external_firmware_handler devpath root handler_path2 }, }; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, external_firmware_handlers, {}}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, external_firmware_handlers, {}}); } TEST(ueventd_parser, ParallelRestoreconDirs) { @@ -246,7 +271,7 @@ parallel_restorecon_dir /sys/devices "/sys/devices", }; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, parallel_restorecon_dirs}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, parallel_restorecon_dirs}); } TEST(ueventd_parser, UeventSocketRcvbufSize) { @@ -255,7 +280,7 @@ uevent_socket_rcvbuf_size 8k uevent_socket_rcvbuf_size 8M )"; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, false, 8 * 1024 * 1024}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, {}, false, 8 * 1024 * 1024}); } TEST(ueventd_parser, EnabledDisabledLines) { @@ -265,7 +290,7 @@ parallel_restorecon enabled modalias_handling disabled )"; - TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, false, 0, true}); + TestUeventdFile(ueventd_file, {{}, {}, {}, {}, {}, {}, {}, false, 0, true}); auto ueventd_file2 = R"( parallel_restorecon enabled @@ -273,7 +298,7 @@ modalias_handling enabled parallel_restorecon disabled )"; - TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, {}, true, 0, false}); + TestUeventdFile(ueventd_file2, {{}, {}, {}, {}, {}, {}, {}, true, 0, false}); } TEST(ueventd_parser, AllTogether) { @@ -286,6 +311,9 @@ firmware_directories /first/ /second /third subsystem test_devname devname uevent_devname +driver d_test_devpath + devname uevent_devpath + /dev/graphics/* 0660 root graphics subsystem test_devpath_no_dirname @@ -303,6 +331,10 @@ subsystem test_devpath_dirname devname uevent_devpath dirname /dev/graphics +driver d_test_devname_dirname + devname uevent_devname + dirname /dev/sound + /dev/*/test 0660 root system /sys/devices/virtual/*/input poll_delay 0660 root input no_fnm_pathname firmware_directories /more @@ -325,6 +357,10 @@ parallel_restorecon_dir /sys/devices {"test_devname2", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev"}, {"test_devpath_dirname", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev/graphics"}}; + auto drivers = std::vector{ + {"d_test_devpath", Subsystem::DEVNAME_UEVENT_DEVPATH, "/dev"}, + {"d_test_devname_dirname", Subsystem::DEVNAME_UEVENT_DEVNAME, "/dev/graphics"}}; + auto permissions = std::vector{ {"/dev/rtc0", 0640, AID_SYSTEM, AID_SYSTEM, false}, {"/dev/graphics/*", 0660, AID_ROOT, AID_GRAPHICS, false}, @@ -356,7 +392,7 @@ parallel_restorecon_dir /sys/devices size_t uevent_socket_rcvbuf_size = 6 * 1024 * 1024; TestUeventdFile(ueventd_file, - {subsystems, sysfs_permissions, permissions, firmware_directories, + {subsystems, drivers, sysfs_permissions, permissions, firmware_directories, external_firmware_handlers, parallel_restorecon_dirs, true, uevent_socket_rcvbuf_size, true}); } From 44461354fda5b30194b04672bff0d954646d0b63 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 18 Nov 2024 19:23:45 -0800 Subject: [PATCH 146/183] snapuserd: Use GTEST_SKIP in snapuserd_test. The test harness treats an early exit as a failure, so use GTEST_SKIP() instead. Bug: 379242140 Test: vts_snapuserd_test Change-Id: I25351bb7ebf65e6c56865662d297feb4a1f635b3 (cherry picked from commit 668ffc395d0c83c9e9cdcca972e35e936a5f85f0) --- .../user-space-merge/snapuserd_test.cpp | 42 +++++++++++++++---- 1 file changed, 34 insertions(+), 8 deletions(-) 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 271090fa5..bd835e280 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_test.cpp @@ -81,6 +81,8 @@ class SnapuserdTestBase : public ::testing::TestWithParam { unique_fd GetCowFd() { return unique_fd{dup(cow_system_->fd)}; } + bool ShouldSkipSetUp(); + std::unique_ptr harness_; size_t size_ = 10_MiB; int total_base_size_ = 0; @@ -96,6 +98,10 @@ class SnapuserdTestBase : public ::testing::TestWithParam { }; void SnapuserdTestBase::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } + #if __ANDROID__ harness_ = std::make_unique(); #else @@ -103,6 +109,16 @@ void SnapuserdTestBase::SetUp() { #endif } +bool SnapuserdTestBase::ShouldSkipSetUp() { +#ifdef __ANDROID__ + if (!android::snapshot::CanUseUserspaceSnapshots() || + android::snapshot::IsVendorFromAndroid12()) { + return true; + } +#endif + return false; +} + void SnapuserdTestBase::TearDown() { cow_system_ = nullptr; } @@ -301,6 +317,9 @@ class SnapuserdTest : public SnapuserdTestBase { }; void SnapuserdTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); handlers_ = std::make_unique(); } @@ -311,6 +330,9 @@ void SnapuserdTest::TearDown() { } void SnapuserdTest::Shutdown() { + if (!handlers_) { + return; + } if (dmuser_dev_) { ASSERT_TRUE(dmuser_dev_->Destroy()); } @@ -1180,6 +1202,9 @@ void SnapuserdVariableBlockSizeTest::ReadSnapshotWithVariableBlockSize() { } void SnapuserdVariableBlockSizeTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTest::SetUp()); } @@ -1243,6 +1268,9 @@ void HandlerTest::InitializeDevice() { } void HandlerTest::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); ASSERT_NO_FATAL_FAILURE(SetUpV2Cow()); @@ -1250,6 +1278,9 @@ void HandlerTest::SetUp() { } void HandlerTest::TearDown() { + if (ShouldSkipSetUp()) { + return; + } ASSERT_TRUE(factory_.DeleteQueue(system_device_ctrl_name_)); ASSERT_TRUE(handler_thread_.get()); SnapuserdTestBase::TearDown(); @@ -1325,6 +1356,9 @@ class HandlerTestV3 : public HandlerTest { }; void HandlerTestV3::SetUp() { + if (ShouldSkipSetUp()) { + GTEST_SKIP() << "snapuserd not supported on this device"; + } ASSERT_NO_FATAL_FAILURE(SnapuserdTestBase::SetUp()); ASSERT_NO_FATAL_FAILURE(CreateBaseDevice()); ASSERT_NO_FATAL_FAILURE(SetUpV3Cow()); @@ -1528,14 +1562,6 @@ INSTANTIATE_TEST_SUITE_P(Io, HandlerTest, ::testing::ValuesIn(GetTestConfigs())) int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); -#ifdef __ANDROID__ - if (!android::snapshot::CanUseUserspaceSnapshots() || - android::snapshot::IsVendorFromAndroid12()) { - std::cerr << "snapuserd_test not supported on this device\n"; - return 0; - } -#endif - gflags::ParseCommandLineFlags(&argc, &argv, false); return RUN_ALL_TESTS(); From 6028880ac00210661da0c9fa6a10324e1bfb41d3 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Tue, 12 Nov 2024 10:16:40 -0800 Subject: [PATCH 147/183] Move snapuserd_test to postsubmit Bug: 338329603 Test: Build Change-Id: Ibee6be732078ea7e11fe7348772837b9b2699fbf Signed-off-by: Akilesh Kailash --- fs_mgr/TEST_MAPPING | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fs_mgr/TEST_MAPPING b/fs_mgr/TEST_MAPPING index 192232d6c..13af1e2a3 100644 --- a/fs_mgr/TEST_MAPPING +++ b/fs_mgr/TEST_MAPPING @@ -27,7 +27,9 @@ }, { "name": "cow_api_test" - }, + } + ], + "postsubmit": [ { "name": "snapuserd_test" } From fdaaef95238d1de873040482938585cb01f724d6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Tue, 19 Nov 2024 19:24:54 +0000 Subject: [PATCH 148/183] Revert "libprocessgroup: Remove __BEGIN_DECLS and __END_DECLS" This reverts commit fdf4432356ddb597f46cfb7b047ab4e0bb808ba2. Reason for revert: b/379796721 Change-Id: I34cdc69d5b8d11446da02106b7bd593a8c8151c3 --- libprocessgroup/include/processgroup/processgroup.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 6a026a717..d27b56895 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -16,6 +16,7 @@ #pragma once +#include #include #include #include @@ -23,6 +24,8 @@ #include #include +__BEGIN_DECLS + static constexpr std::string CGROUPV2_HIERARCHY_NAME = "cgroup2"; bool CgroupsAvailable(); @@ -36,6 +39,8 @@ bool SetTaskProfiles(pid_t tid, const std::vector& profiles, bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles); bool SetUserProfiles(uid_t uid, const std::vector& profiles); +__END_DECLS + bool SetTaskProfiles(pid_t tid, std::initializer_list profiles, bool use_fd_cache = false); bool SetProcessProfiles(uid_t uid, pid_t pid, std::initializer_list profiles); @@ -45,6 +50,7 @@ bool SetTaskProfiles(pid_t tid, std::span profiles, bool SetProcessProfiles(uid_t uid, pid_t pid, std::span profiles); #endif +__BEGIN_DECLS #ifndef __ANDROID_VNDK__ @@ -90,3 +96,5 @@ bool getAttributePathForTask(const std::string& attr_name, pid_t tid, std::strin bool isProfileValidForProcess(const std::string& profile_name, uid_t uid, pid_t pid); #endif // __ANDROID_VNDK__ + +__END_DECLS From 267207a1720927acfb575ea348a7067631be2c41 Mon Sep 17 00:00:00 2001 From: Daniel Zheng Date: Tue, 12 Nov 2024 14:26:46 -0800 Subject: [PATCH 149/183] use V4 Health HAL use health HAL v4 for fastbootd, healthd, and storaged Ignore-AOSP-First: deprecated_ota_test compilation Bug: 371322457 Test: th Change-Id: Ia941d67a5248641246a7298487c6a13fe92d8d66 --- fastboot/Android.bp | 2 +- healthd/Android.bp | 19 +++++++++++-------- storaged/Android.bp | 4 ++-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/fastboot/Android.bp b/fastboot/Android.bp index d3e058150..4d9898758 100644 --- a/fastboot/Android.bp +++ b/fastboot/Android.bp @@ -170,7 +170,7 @@ cc_binary { "android.hardware.fastboot@1.1", "android.hardware.fastboot-V1-ndk", "android.hardware.health@2.0", - "android.hardware.health-V3-ndk", + "android.hardware.health-V4-ndk", "libasyncio", "libbase", "libbinder_ndk", diff --git a/healthd/Android.bp b/healthd/Android.bp index e158e07e4..7eb6edde1 100644 --- a/healthd/Android.bp +++ b/healthd/Android.bp @@ -4,7 +4,10 @@ package { cc_defaults { name: "libbatterymonitor_defaults", - cflags: ["-Wall", "-Werror"], + cflags: [ + "-Wall", + "-Werror", + ], vendor_available: true, recovery_available: true, export_include_dirs: ["include"], @@ -76,7 +79,7 @@ cc_library_static { defaults: ["libbatterymonitor_defaults"], srcs: ["BatteryMonitor.cpp"], static_libs: [ - "android.hardware.health-V3-ndk", + "android.hardware.health-V4-ndk", ], whole_static_libs: [ // Need to translate HIDL to AIDL to support legacy APIs in @@ -165,12 +168,12 @@ cc_library_static { defaults: ["libhealthd_charger_ui_defaults"], static_libs: [ - "android.hardware.health-V3-ndk", + "android.hardware.health-V4-ndk", "android.hardware.health-translate-ndk", ], export_static_lib_headers: [ - "android.hardware.health-V3-ndk", + "android.hardware.health-V4-ndk", ], } @@ -242,7 +245,7 @@ cc_defaults { static_libs: [ // common "android.hardware.health@1.0-convert", - "android.hardware.health-V3-ndk", + "android.hardware.health-V4-ndk", "libbatterymonitor", "libcharger_sysprop", "libhealthd_charger_nops", @@ -287,8 +290,8 @@ cc_binary { "libminui", "libsuspend", ], - } - } + }, + }, } cc_test { @@ -307,7 +310,7 @@ cc_test { defaults: ["charger_defaults"], srcs: [ "AnimationParser_test.cpp", - "healthd_mode_charger_test.cpp" + "healthd_mode_charger_test.cpp", ], static_libs: [ "android.hardware.health@1.0", diff --git a/storaged/Android.bp b/storaged/Android.bp index 357c0e601..335874280 100644 --- a/storaged/Android.bp +++ b/storaged/Android.bp @@ -24,7 +24,7 @@ cc_defaults { shared_libs: [ "android.hardware.health@1.0", "android.hardware.health@2.0", - "android.hardware.health-V3-ndk", + "android.hardware.health-V4-ndk", "libbase", "libbinder", "libbinder_ndk", @@ -47,7 +47,7 @@ cc_defaults { "-Wall", "-Werror", "-Wextra", - "-Wno-unused-parameter" + "-Wno-unused-parameter", ], } From ae8313f8e694eeb019211066229ace7720dbe304 Mon Sep 17 00:00:00 2001 From: Vikram Auradkar Date: Mon, 11 Nov 2024 15:27:34 -0800 Subject: [PATCH 150/183] libprefetch: library to prefetch data using tracing. 1: This supports "mem" tracing only. 2: Replay option is modified to use "pread" instead of readahead. A simple utility binary "prefetch" is built which links to the library. The binary allows record, replay and verifying the generated metadata. Bug: 362507272 Test: cargo test passes all unit tests. Verify record, replay and dump options: ./prefetch record --duration 10 --path /data/test/trace-test ./prefetch replay --path /data/test/trace-test ./prefetch dump /data/test/trace-test --format csv Change-Id: I1661e49183c6120d2878510e609571fe6d608bb5 Signed-off-by: Vikram Auradkar Signed-off-by: Akilesh Kailash --- init/libprefetch/prefetch/Android.bp | 80 ++ init/libprefetch/prefetch/Cargo.lock | 743 ++++++++++++++ init/libprefetch/prefetch/Cargo.toml | 51 + init/libprefetch/prefetch/OWNERS | 3 + init/libprefetch/prefetch/prefetch.rc | 13 + init/libprefetch/prefetch/src/args.rs | 108 ++ .../prefetch/src/args/args_argh.rs | 217 ++++ init/libprefetch/prefetch/src/error.rs | 187 ++++ init/libprefetch/prefetch/src/format.rs | 823 +++++++++++++++ init/libprefetch/prefetch/src/lib.rs | 186 ++++ init/libprefetch/prefetch/src/main.rs | 41 + init/libprefetch/prefetch/src/replay.rs | 762 ++++++++++++++ init/libprefetch/prefetch/src/tracer/mem.rs | 897 ++++++++++++++++ init/libprefetch/prefetch/src/tracer/mod.rs | 965 ++++++++++++++++++ 14 files changed, 5076 insertions(+) create mode 100644 init/libprefetch/prefetch/Android.bp create mode 100644 init/libprefetch/prefetch/Cargo.lock create mode 100644 init/libprefetch/prefetch/Cargo.toml create mode 100644 init/libprefetch/prefetch/OWNERS create mode 100644 init/libprefetch/prefetch/prefetch.rc create mode 100644 init/libprefetch/prefetch/src/args.rs create mode 100644 init/libprefetch/prefetch/src/args/args_argh.rs create mode 100644 init/libprefetch/prefetch/src/error.rs create mode 100644 init/libprefetch/prefetch/src/format.rs create mode 100644 init/libprefetch/prefetch/src/lib.rs create mode 100644 init/libprefetch/prefetch/src/main.rs create mode 100644 init/libprefetch/prefetch/src/replay.rs create mode 100644 init/libprefetch/prefetch/src/tracer/mem.rs create mode 100644 init/libprefetch/prefetch/src/tracer/mod.rs diff --git a/init/libprefetch/prefetch/Android.bp b/init/libprefetch/prefetch/Android.bp new file mode 100644 index 000000000..778ea8a8c --- /dev/null +++ b/init/libprefetch/prefetch/Android.bp @@ -0,0 +1,80 @@ +// +// Copyright (C) 2024 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_team: "trendy_team_android_kernel", + default_applicable_licenses: ["Android-Apache-2.0"], +} + +rust_library_rlib { + name: "libprefetch_rs", + crate_name: "prefetch_rs", + srcs: ["src/lib.rs"], + rustlibs: [ + "libandroid_logger", + "libargh", + "libchrono", + "libcrc32fast", + "libcsv", + "liblibc", + "liblog_rust", + "liblru_cache", + "libnix", + "librand", + "librayon", + "libregex", + "libserde_cbor", + "libserde_json", + "libserde", + "libthiserror", + "libwalkdir", + "librustutils", + ], + prefer_rlib: true, + features: [ + "derive", + "error-context", + "help", + "std", + "usage", + "use_argh", + ], +} + +rust_binary { + name: "prefetch", + crate_name: "prefetch", + srcs: ["src/main.rs"], + rustlibs: [ + "libprefetch_rs", + "liblog_rust", + "libandroid_logger", + ], + prefer_rlib: true, + features: [ + "default", + "derive", + "error-context", + "help", + "std", + "usage", + "use_argh", + ], + init_rc: [ + "prefetch.rc", + ], +} + +// TODO: Add rust_test to enable unit testing - b/378554334 diff --git a/init/libprefetch/prefetch/Cargo.lock b/init/libprefetch/prefetch/Cargo.lock new file mode 100644 index 000000000..d6b214d26 --- /dev/null +++ b/init/libprefetch/prefetch/Cargo.lock @@ -0,0 +1,743 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "aho-corasick" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7404febffaa47dac81aa44dba71523c9d069b1bdc50a77db41195149e17f68e5" +dependencies = [ + "memchr", +] + +[[package]] +name = "android_log-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e" + +[[package]] +name = "android_logger" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9ed09b18365ed295d722d0b5ed59c01b79a826ff2d2a8f73d5ecca8e6fb2f66" +dependencies = [ + "android_log-sys", + "env_logger", + "lazy_static", + "log", +] + +[[package]] +name = "argh" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab257697eb9496bf75526f0217b5ed64636a9cfafa78b8365c71bd283fcef93e" +dependencies = [ + "argh_derive", + "argh_shared", +] + +[[package]] +name = "argh_derive" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b382dbd3288e053331f03399e1db106c9fb0d8562ad62cb04859ae926f324fa6" +dependencies = [ + "argh_shared", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "argh_shared" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5693f39141bda5760ecc4111ab08da40565d1771038c4a0250f03457ec707531" +dependencies = [ + "serde", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +dependencies = [ + "hermit-abi 0.1.19", + "libc", + "winapi 0.3.9", +] + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "bincode" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b92615d57e4048e480bd7e3c2d7f6ec252819fffec95efbc30ec7c68744aa66c" +dependencies = [ + "byteorder", + "serde", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "bstr" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a40b47ad93e1a5404e6c18dec46b628214fee441c70f4ab5d6942142cc268a3d" +dependencies = [ + "lazy_static", + "memchr", + "regex-automata", + "serde", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd16c4719339c4530435d38e511904438d07cce7950afa3718a84ac36c10e89e" + +[[package]] +name = "chrono" +version = "0.4.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" +dependencies = [ + "libc", + "num-integer", + "num-traits", + "serde", + "time", + "winapi 0.3.9", +] + +[[package]] +name = "crc32fast" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b540bd8bc810d3885c6ea91e2018302f68baba2129ab3e88f32389ee9370880d" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "176dc175b78f56c0f321911d9c8eb2b77a78a4860b9c19db83835fea1a46649b" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-deque" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613f8cc01fe9cf1a3eb3d7f488fd2fa8388403e97039e2f73692932e291a770d" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "248e3bacc7dc6baa3b21e405ee045c3047101a49145e7e9eca583ab4c2ca5345" + +[[package]] +name = "csv" +version = "1.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22813a6dc45b335f9bade10bf7271dc477e81113e89eb251a0bc2a8a81c536e1" +dependencies = [ + "bstr", + "csv-core", + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "csv-core" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5efa2b3d7902f4b634a20cae3c9c4e6209dc4779feb6863329607560143efa70" +dependencies = [ + "memchr", +] + +[[package]] +name = "either" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a26ae43d7bcc3b814de94796a5e736d4029efb0ee900c12e2d54c993ad1a1e07" + +[[package]] +name = "env_logger" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a19187fea3ac7e84da7dacf48de0c45d63c6a76f9490dae389aead16c243fce3" +dependencies = [ + "atty", + "humantime", + "log", + "regex", + "termcolor", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "getrandom" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "190092ea657667030ac6a35e305e62fc4dd69fd98ac98631e5d3a2b1575a12b5" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.11.0+wasi-snapshot-preview1", +] + +[[package]] +name = "half" +version = "1.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eabb4a44450da02c90444cf74558da904edde8fb4e9035a9a6a4e15445af0bd7" + +[[package]] +name = "hermit-abi" +version = "0.1.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62b467343b94ba476dcb2500d242dadbb39557df889310ac77c5d99100aaac33" +dependencies = [ + "libc", +] + +[[package]] +name = "hermit-abi" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d3d0e0f38255e7fa3cf31335b3a56f05febd18025f4db5ef7a0cfb4f8da651f" + +[[package]] +name = "humantime" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3a5bfb195931eeb336b2a7b4d761daec841b97f947d34394601737a7bba5e4" + +[[package]] +name = "itoa" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b71991ff56294aa922b450139ee08b3bfc70982c6b2c7562771375cf73542dd4" + +[[package]] +name = "kernel32-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" +dependencies = [ + "winapi 0.2.8", + "winapi-build", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.162" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "18d287de67fe55fd7e1581fe933d965a5a9477b38e949cfa9f8574ef01506398" + +[[package]] +name = "linked-hash-map" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0717cef1bc8b636c6e1c1bbdefc09e6322da8a9321966e8928ef80d20f7f770f" + +[[package]] +name = "log" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "lru-cache" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "31e24f1ad8321ca0e8a1e0ac13f23cb668e6f5466c2c57319f6a5cf1cc8e3b1c" +dependencies = [ + "linked-hash-map", +] + +[[package]] +name = "memchr" +version = "2.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee1c47aaa256ecabcaea351eae4a9b01ef39ed810004e298d2511ed284b1525" + +[[package]] +name = "nix" +version = "0.28.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab2156c4fce2f8df6c499cc1c763e4394b7482525bf2a9701c9d79d215f519e4" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_cpus" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4161fcb6d602d4d2081af7c3a45852d875a03dd337a6bfdd6e06407b61342a43" +dependencies = [ + "hermit-abi 0.3.4", + "libc", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "prefetch" +version = "0.1.0" +dependencies = [ + "android_logger", + "argh", + "bincode", + "chrono", + "crc32fast", + "csv", + "env_logger", + "libc", + "log", + "lru-cache", + "memchr", + "nix", + "proc-macro2", + "quote", + "rand 0.8.5", + "rayon", + "rayon-core", + "regex", + "serde", + "serde_cbor", + "serde_derive", + "serde_json", + "tempfile", + "thiserror", + "thiserror-impl", + "walkdir", +] + +[[package]] +name = "proc-macro2" +version = "1.0.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a152013215dca273577e18d2bf00fa862b89b24169fb78c4c95aeb07992c9cec" +dependencies = [ + "unicode-xid", +] + +[[package]] +name = "quote" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3d0b9745dc2debf507c8422de05d7226cc1f0644216dfdfead988f9b1ab32a7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" +dependencies = [ + "libc", + "rand 0.4.6", +] + +[[package]] +name = "rand" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" +dependencies = [ + "fuchsia-cprng", + "libc", + "rand_core 0.3.1", + "rdrand", + "winapi 0.3.9", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rayon" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b0d8e0819fadc20c74ea8373106ead0600e3a67ef1fe8da56e39b9ae7275674" +dependencies = [ + "autocfg", + "crossbeam-deque", + "either", + "rayon-core", +] + +[[package]] +name = "rayon-core" +version = "1.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ab346ac5921dc62ffa9f89b7a773907511cdfa5490c572ae9be1be33e8afa4a" +dependencies = [ + "crossbeam-channel", + "crossbeam-deque", + "crossbeam-utils", + "lazy_static", + "num_cpus", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[package]] +name = "regex" +version = "1.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a26af418b574bd56588335b3a3659a65725d4e636eb1016c2f9e3b38c7cc759" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132" + +[[package]] +name = "regex-syntax" +version = "0.6.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1" + +[[package]] +name = "ryu" +version = "1.0.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f98d2aa92eebf49b69786be48e4477826b256916e84a57ff2a4f21923b48eb4c" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "serde" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92d5161132722baa40d802cc70b15262b98258453e85e5d1d365c757c73869ae" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_cbor" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" +dependencies = [ + "half", + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.123" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9391c295d64fc0abb2c556bad848f33cb8296276b1ad2677d1ae1ace4f258f31" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.62" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea1c6153794552ea7cf7cf63b1231a25de00ec90db326ba6264440fa08e31486" +dependencies = [ + "itoa", + "ryu", + "serde", +] + +[[package]] +name = "syn" +version = "1.0.80" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d010a1623fbd906d51d650a9916aaefc05ffa0e4053ff7fe601167f3e715d194" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + +[[package]] +name = "tempfile" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" +dependencies = [ + "kernel32-sys", + "libc", + "rand 0.3.23", + "redox_syscall", + "winapi 0.2.8", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0f4a65597094d4483ddaed134f409b2cb7c1beccf25201a9f73c719254fa98e" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7765189610d8241a44529806d6fd1f2e0a08734313a35d5b3a556f92b381f3c0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "time" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a" +dependencies = [ + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", + "winapi 0.3.9", +] + +[[package]] +name = "unicode-xid" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f962df74c8c05a667b5ee8bcf162993134c104e96440b663c8daa176dc772d8c" + +[[package]] +name = "walkdir" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71d857dc86794ca4c280d616f7da00d2dbfd8cd788846559a6813e6aa4b54ee" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "winapi" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-build" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc" + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f29e6f9198ba0d26b4c9f07dbe6f9ed633e1f3d5b8b414090084349e46a52596" +dependencies = [ + "winapi 0.3.9", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/init/libprefetch/prefetch/Cargo.toml b/init/libprefetch/prefetch/Cargo.toml new file mode 100644 index 000000000..7da4fc68b --- /dev/null +++ b/init/libprefetch/prefetch/Cargo.toml @@ -0,0 +1,51 @@ +[package] +name = "prefetch" +version = "0.1.0" +edition = "2018" +default-run = "prefetch" + +[lib] +name = "prefetch_rs" +path = "src/lib.rs" + +[[bin]] +name = "prefetch" +path = "src/main.rs" + +[features] +default = ["use_argh"] +use_argh = ["argh"] + +[dependencies] +argh = { version = "0.1.10", optional = true } +chrono = { version = "=0.4.19", features = ["serde"] } +crc32fast = "1.2.1" +csv = "=1.1.6" +libc = "0.2.82" +log = "=0.4.14" +lru-cache = "0.1.2" +memchr = "=2.3.4" +nix = {version = "0.28", features = ["fs", "time", "feature", "mman", "uio"]} +proc-macro2 = "=1.0.26" +quote = "=1.0.9" +rand = "0.8.3" +rayon = "=1.5.0" +rayon-core = "=1.9.0" +regex = "1.4.5" +serde = { version = "*", features = ["derive"] } +serde_cbor = "0.11.2" +serde_derive = "=1.0.123" +serde_json = "=1.0.62" +thiserror = "=1.0.24" +thiserror-impl = "1.0.24" +walkdir = "2.3.2" + +# crates required for android builds +[target.'cfg(target_os = "android")'.dependencies] +android_logger = "0.10.1" + +# crates not present in android builds +[target.'cfg(not(target_os = "android"))'.dependencies] +bincode = "=0.9.0" +env_logger = "=0.8.4" +tempfile = "2.2.0" diff --git a/init/libprefetch/prefetch/OWNERS b/init/libprefetch/prefetch/OWNERS new file mode 100644 index 000000000..a1b54bf5c --- /dev/null +++ b/init/libprefetch/prefetch/OWNERS @@ -0,0 +1,3 @@ +akailash@google.com +auradkar@google.com +takayas@google.com diff --git a/init/libprefetch/prefetch/prefetch.rc b/init/libprefetch/prefetch/prefetch.rc new file mode 100644 index 000000000..9f2cb7f46 --- /dev/null +++ b/init/libprefetch/prefetch/prefetch.rc @@ -0,0 +1,13 @@ +service prefetch_record /system/bin/prefetch record --duration ${ro.prefetch_boot.duration_s:-0} + class main + user root + group root system + disabled + oneshot + +service prefetch_replay /system/bin/prefetch replay --io-depth ${ro.prefetch_boot.io_depth:-2} --max-fds ${ro.prefetch_boot.max_fds:-128} + class main + user root + group root system + disabled + oneshot diff --git a/init/libprefetch/prefetch/src/args.rs b/init/libprefetch/prefetch/src/args.rs new file mode 100644 index 000000000..4c1e68919 --- /dev/null +++ b/init/libprefetch/prefetch/src/args.rs @@ -0,0 +1,108 @@ +// Copyright (C) 2024 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. + +pub(crate) static DEFAULT_IO_DEPTH: u16 = 2; +pub(crate) static DEFAULT_MAX_FDS: u16 = 128; +pub(crate) static DEFAULT_EXIT_ON_ERROR: bool = false; + +mod args_argh; +use args_argh as args_internal; + +use std::path::Path; +use std::path::PathBuf; +use std::process::exit; + +pub use args_internal::OutputFormat; +pub use args_internal::ReplayArgs; +pub use args_internal::TracerType; +pub use args_internal::{DumpArgs, MainArgs, RecordArgs, SubCommands}; +use serde::Deserialize; +use serde::Serialize; + +use crate::Error; +use log::error; + +// Deserialized form of the config file +#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)] +pub struct ConfigFile { + // Files to be excluded in prefetch. These files might have been + // added in the record file while recording,but we do not want to + // replay these files. These can be two types of files: + // 1) installation-specific files (e.g. files in /data) and + // 2) large files which we do not want to load in replay (e.g. APK files). + pub files_to_exclude_regex: Vec, + // Files that are not in the record file, but need to be loaded during replay + pub additional_replay_files: Vec, +} + +fn verify_and_fix(args: &mut MainArgs) -> Result<(), Error> { + match &mut args.nested { + SubCommands::Record(arg) => { + if arg.debug && arg.int_path.is_none() { + arg.int_path = Some(PathBuf::from(format!("{}.int", arg.path.to_str().unwrap()))); + } + + if let Some(p) = &arg.int_path { + ensure_path_doesnt_exist(p)?; + } + } + SubCommands::Replay(arg) => { + ensure_path_exists(&arg.path)?; + if !arg.config_path.as_os_str().is_empty() { + ensure_path_exists(&arg.config_path)?; + } + } + SubCommands::Dump(arg) => { + ensure_path_exists(&arg.path)?; + } + } + Ok(()) +} + +/// Returns error if the given path at `p` exist. +pub(crate) fn ensure_path_doesnt_exist(p: &Path) -> Result<(), Error> { + if p.exists() { + Err(Error::InvalidArgs { + arg_name: "path".to_string(), + arg_value: p.display().to_string(), + error: "Path already exists".to_string(), + }) + } else { + Ok(()) + } +} + +/// Returns error if the given path at `p` doesn't exist. +pub(crate) fn ensure_path_exists(p: &Path) -> Result<(), Error> { + if p.is_file() { + Ok(()) + } else { + Err(Error::InvalidArgs { + arg_name: "path".to_string(), + arg_value: p.display().to_string(), + error: "Path does not exist".to_string(), + }) + } +} + +/// Builds `MainArgs` from command line arguments. On error prints error/help message +/// and exits. +pub fn args_from_env() -> MainArgs { + let mut args = args_internal::args_from_env(); + if let Err(e) = verify_and_fix(&mut args) { + error!("failed to verify args: {}", e); + exit(1); + } + args +} diff --git a/init/libprefetch/prefetch/src/args/args_argh.rs b/init/libprefetch/prefetch/src/args/args_argh.rs new file mode 100644 index 000000000..8ac95fce7 --- /dev/null +++ b/init/libprefetch/prefetch/src/args/args_argh.rs @@ -0,0 +1,217 @@ +// Copyright (C) 2024 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. + +use std::{option::Option, path::PathBuf, result::Result::Ok, str::FromStr}; + +use argh::FromArgs; +use serde::Deserialize; + +use crate::args::DEFAULT_EXIT_ON_ERROR; +use crate::args::DEFAULT_IO_DEPTH; +use crate::args::DEFAULT_MAX_FDS; +use crate::Error; + +/// prefetch-rs +#[derive(Eq, PartialEq, Debug, Default, FromArgs)] +pub struct MainArgs { + /// subcommands + #[argh(subcommand)] + pub nested: SubCommands, +} + +/// Sub commands for prefetch functions +#[derive(Eq, PartialEq, Debug, FromArgs)] +#[argh(subcommand)] +pub enum SubCommands { + /// Records prefetch data. + Record(RecordArgs), + /// Replays from prefetch data + Replay(ReplayArgs), + /// Dump prefetch data in human readable format + Dump(DumpArgs), +} + +impl Default for SubCommands { + fn default() -> Self { + Self::Dump(DumpArgs::default()) + } +} + +fn default_path() -> PathBuf { + PathBuf::from("/metadata/prefetch/prefetch.pack") +} + +fn parse_tracing_instance(value: &str) -> Result, String> { + Ok(Some(value.to_string())) +} + +#[derive(Eq, PartialEq, Debug, Default, FromArgs)] +/// Records prefect data. +#[argh(subcommand, name = "record")] +pub struct RecordArgs { + /// duration in seconds to record the data + /// + /// On Android, if duration count is set to zero, recording + /// will continue until the property sys.boot_completed = 1. + #[argh(option)] + pub duration: u16, + + /// file path where the records will be written to + /// + /// A new file is created at the given path. If the path exists, it + /// will be overwritten + #[argh(option, default = "default_path()")] + pub path: PathBuf, + + /// when set an intermediate file will be created that provides more information + /// about collected data. + #[argh(option, default = "false")] + pub debug: bool, + + /// file path where the intermediate file will be written to + /// + /// A new file is created at the given path. Errors out if the file + /// already exists. + #[argh(option)] + pub int_path: Option, + + /// size of the trace buffer which holds trace events. We need larger + /// buffer on a system that has faster disks or has large number of events + /// enabled. Defaults to TRACE_BUFFER_SIZE_KIB KiB. + #[argh(option, long = "trace-buffer-size")] + pub trace_buffer_size_kib: Option, + + /// trace subsystem to use. "mem" subsystem is set by default. + #[argh(option, default = "Default::default()")] + pub tracing_subsystem: TracerType, + + /// if true enables all the needed trace events. And at the end it restores + /// the values of those events. + /// If false, assumes that user has setup the needed trace events. + #[argh(option, default = "true")] + pub setup_tracing: bool, + + /// if specified, works on a tracing instance (like /sys/kernel/tracing/instance/my_instance) + /// rather than using on shared global instance (i.e. /sys/kernel/tracing)." + #[argh( + option, + default = "Some(\"prefetch\".to_string())", + from_str_fn(parse_tracing_instance) + )] + pub tracing_instance: Option, +} + +/// Type of tracing subsystem to use. +#[derive(Deserialize, Clone, Eq, PartialEq, Debug)] +pub enum TracerType { + /// mem tracing subsystem relies on when a file's in-memory page gets added to the fs cache. + Mem, +} + +impl FromStr for TracerType { + type Err = Error; + fn from_str(s: &str) -> std::result::Result { + Ok(match s.to_lowercase().as_str() { + "mem" => Self::Mem, + _ => { + return Err(Error::InvalidArgs { + arg_name: "tracing_subsystem".to_owned(), + arg_value: s.to_owned(), + error: "unknown value".to_owned(), + }) + } + }) + } +} + +impl Default for TracerType { + fn default() -> Self { + Self::Mem + } +} + +#[derive(Eq, PartialEq, Debug, Default, FromArgs)] +/// Prefetch data from the recorded file. +#[argh(subcommand, name = "replay")] +pub struct ReplayArgs { + /// file path from where the records will be read + #[argh(option, default = "default_path()")] + pub path: PathBuf, + + /// IO depth. Number of IO that can go in parallel. + #[argh(option, long = "io-depth", default = "DEFAULT_IO_DEPTH")] + pub io_depth: u16, + + /// max number of open fds to cache + #[argh(option, arg_name = "max-fds", default = "DEFAULT_MAX_FDS")] + pub max_fds: u16, + + /// if true, command exits on encountering any error. + /// + /// This defaults to false as there is not harm prefetching if we encounter + /// non-fatal errors. + #[argh(option, default = "DEFAULT_EXIT_ON_ERROR")] + pub exit_on_error: bool, + + /// file path from where the prefetch config file will be read + #[argh(option, default = "PathBuf::new()")] + pub config_path: PathBuf, +} + +/// dump records file in given format +#[derive(Eq, PartialEq, Debug, Default, FromArgs)] +#[argh(subcommand, name = "dump")] +pub struct DumpArgs { + /// file path from where the records will be read + #[argh(option)] + pub path: PathBuf, + /// output format. One of json or csv. + /// Note: In csv format, few fields are excluded from the output. + #[argh(option)] + pub format: OutputFormat, +} + +#[derive(Deserialize, Eq, PartialEq, Debug)] +pub enum OutputFormat { + Json, + Csv, +} + +impl FromStr for OutputFormat { + type Err = Error; + fn from_str(s: &str) -> std::result::Result { + Ok(match s.to_lowercase().as_str() { + "csv" => Self::Csv, + "json" => Self::Json, + _ => { + return Err(Error::InvalidArgs { + arg_name: "format".to_owned(), + arg_value: s.to_owned(), + error: "unknown value".to_owned(), + }) + } + }) + } +} + +impl Default for OutputFormat { + fn default() -> Self { + Self::Json + } +} + +/// Build args struct from command line arguments +pub fn args_from_env() -> MainArgs { + argh::from_env() +} diff --git a/init/libprefetch/prefetch/src/error.rs b/init/libprefetch/prefetch/src/error.rs new file mode 100644 index 000000000..8dd938a7e --- /dev/null +++ b/init/libprefetch/prefetch/src/error.rs @@ -0,0 +1,187 @@ +// Copyright (C) 2024 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. + +use thiserror::Error; + +use crate::{format::FileId, InodeInfo}; + +/// Enumerates all possible errors returned by this library. +#[derive(Debug, Error)] +pub enum Error { + /// Represents a failure to open a file. + #[error("Open error: {path}: {source}")] + Open { + /// The IO error + source: std::io::Error, + /// Path on which the operation failed. + path: String, + }, + + /// Represents a failure to create a file. + #[error("Create error. {path} {source}")] + Create { + /// The IO error + source: std::io::Error, + /// Path on which the operation failed. + path: String, + }, + + /// Represents a failure to read trace file. + #[error("Read error. {error}")] + Read { + /// Detailed error message. + error: String, + }, + + /// Represents a failure to write to a file. + #[error("Write error. {source}")] + Write { + /// The IO error + source: std::io::Error, + + /// file path + path: String, + }, + + /// Represents a failure to delete a file. + #[error("Delete error. {path} {source}")] + Delete { + /// The IO error + source: std::io::Error, + /// Path on which the operation failed. + path: String, + }, + + /// Represents a failure to stat a file. + #[error("Stat error. {path} {source}")] + Stat { + /// The IO error + source: std::io::Error, + /// Path on which the operation failed. + path: String, + }, + + /// Represents a failure to stat a file. + #[error("clone failed. {id} {source}")] + FileClone { + /// The IO error + source: std::io::Error, + /// File id for which we could not clone the file. + id: FileId, + }, + + /// Represents a failure to mmap a file. + #[error("mmap failed. {path} {error}")] + Mmap { + /// Detailed error message. + error: String, + /// Path on which the operation failed. + path: String, + }, + + /// Represents a failure to munmap a file. + #[error("munmap failed. {length} {error}")] + Munmap { + /// Detailed error message. + error: String, + /// Size of file which this munmap failed + length: usize, + }, + + /// Represents all other cases of `std::io::Error`. + /// + #[error(transparent)] + IoError( + /// The IO error + #[from] + std::io::Error, + ), + + /// Represents a failure to map FileId to path + /// + #[error("Failed to map id to path: {id}")] + IdNoFound { + /// File id for which path lookup failed. + id: FileId, + }, + + /// Indicates that the file is skipped for prefetching + /// because it is in the exclude files list. + /// + #[error("Skipped prefetching file from path: {path}")] + SkipPrefetch { + /// Path to file for which prefetching is skipped. + path: String, + }, + + /// Represents spurious InodeInfo or missing Record. + /// + #[error( + "Stale inode(s) info found.\n\ + missing_file_ids: {missing_file_ids:#?}\n\ + stale_inodes: {stale_inodes:#?} \n\ + missing_paths:{missing_paths:#?}" + )] + StaleInode { + /// FileIds for which InodeInfo is missing. + missing_file_ids: Vec, + + /// InodeInfos for which no records exist. + stale_inodes: Vec, + + /// InodeInfos in which no paths were found. + missing_paths: Vec, + }, + + /// Represents a failure to serialize records file. + #[error("Serialize error: {error}")] + Serialize { + /// Detailed error message. + error: String, + }, + + /// Represents a failure to deserialize records file. + #[error("Deserialize error: {error}")] + Deserialize { + /// Detailed error message. + error: String, + }, + + /// Represents a failure from thread pool. + #[error("Thread pool error: {error}")] + ThreadPool { + /// Detailed error message. + error: String, + }, + + /// Represents a failure to setup file. + #[error("Failed to setup prefetch: {error}")] + Custom { + /// Detailed error message. + error: String, + }, + + /// Represents a failure to parse args. + #[error("Failed to parse arg:{arg_name} value:{arg_value} error:{error}")] + InvalidArgs { + /// Arg name. + arg_name: String, + + /// Arg value. + arg_value: String, + + /// Detailed error message. + error: String, + }, +} diff --git a/init/libprefetch/prefetch/src/format.rs b/init/libprefetch/prefetch/src/format.rs new file mode 100644 index 000000000..ac89a74eb --- /dev/null +++ b/init/libprefetch/prefetch/src/format.rs @@ -0,0 +1,823 @@ +// Copyright (C) 2024 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. + +use std::cmp::{max, min}; +use std::collections::{BTreeMap, HashMap, HashSet}; +use std::fmt; +use std::fmt::Display; +use std::fs::{File, Metadata, OpenOptions}; +use std::hash::Hash; +use std::io::Write; +use std::ops::{Deref, DerefMut}; +use std::os::unix::fs::MetadataExt; +use std::time::SystemTime; + +use crc32fast::Hasher; +use log::debug; +use regex::Regex; +use serde::Deserializer; +use serde::Serialize; +use serde::{Deserialize, Serializer}; + +use crate::error::Error; + +static MAGIC_UUID: [u8; 16] = [ + 0x10, 0x54, 0x3c, 0xb8, 0x60, 0xdb, 0x49, 0x45, 0xa1, 0xd5, 0xde, 0xa7, 0xd2, 0x3b, 0x05, 0x49, +]; +static MAJOR_VERSION: u16 = 0; +static MINOR_VERSION: u16 = 1; + +/// Represents inode number which is unique within a filesystem. +pub(crate) type InodeNumber = u64; + +/// Represents device number which is unique for given block device. +pub(crate) type DeviceNumber = u64; + +/// Convenience name for string that represents a path. +pub(crate) type PathString = String; + +/// Represents unique file id across filesystems. +#[derive(Clone, Debug, Deserialize, Eq, Hash, Default, PartialEq, PartialOrd, Ord, Serialize)] +pub struct FileId(pub u64); + +impl Display for FileId { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +fn serialize_hashmap( + value: &HashMap, + serializer: S, +) -> Result +where + S: Serializer, +{ + let mut btree = BTreeMap::new(); + for (k, v) in value { + btree.insert(k.clone(), v.clone()); + } + btree.serialize(serializer) +} + +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub(crate) struct SerializableHashMap< + K: Ord + Serialize + Clone + Hash + PartialEq, + V: Serialize + Clone, +> { + #[serde(serialize_with = "serialize_hashmap")] + pub map: HashMap, +} + +impl Deref for SerializableHashMap +where + K: Ord + Serialize + Clone + Hash + PartialEq, + V: Serialize + Clone, +{ + type Target = HashMap; + fn deref(&self) -> &Self::Target { + &self.map + } +} + +impl DerefMut for SerializableHashMap +where + K: Ord + Serialize + Clone + Hash + PartialEq, + V: Serialize + Clone, +{ + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.map + } +} + +/// The InodeInfo is unique per (device, inode) combination. It is +/// used to verify that we are prefetching a file for which we generated +/// the records for. +/// `Record` refers to this information with a unique `FileId`. +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct InodeInfo { + // Inode number of the file. + pub(crate) inode_number: InodeNumber, + + // File size in bytes. + pub(crate) file_size: u64, + + // Helps to get to a file from a Record. The field is used to get to the file + // that needs to be prefetched. + // + // This struct is built by getting data from trace lines and querying filesystem + // for other fields about the file/inode. + // + // One instance per file to be prefetched. A file/inode can have multiple paths. + // We store multiple paths so that we can still get to it if some of the + // paths get deleted. + // + // See comments for `Record`. + #[serde(deserialize_with = "check_inode_info_paths")] + pub(crate) paths: Vec, + + // Block device number on which the file is located. + pub(crate) device_number: DeviceNumber, +} + +impl InodeInfo { + /// Returns InodeInfo. + pub fn new( + inode_number: InodeNumber, + file_size: u64, + paths: Vec, + device_number: DeviceNumber, + ) -> Self { + Self { inode_number, file_size, paths, device_number } + } +} + +// Helps us check block alignment. +// +// A records file can have multiple FsInfos. +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct FsInfo { + // This is filesystem block size and is not underlying device's block size + pub(crate) block_size: u64, +} + +/// Prefetch record. +/// Each record translates to one filesystem `read()` request. +/// +/// Tracer builds `Record` by parsing trace lines or by querying filesystem. +/// +/// Multiple `Record`s can belong to a single InodeInfo. For example if there were two +/// reads for file `/data/my.apk` which is assigned FileId 10 at offsets 0 and 8k of length +/// 1 byte each then we will have two `Records` in `RecordsFile` that look like +/// `Record {file_id: 10, offset: 0, length: 1, timestamp: t1}` +/// `Record {file_id: 10, offset: 8192, length: 1, timestamp: t2}` +#[derive(Clone, Debug, Default, Deserialize, Eq, PartialEq, Serialize)] +pub struct Record { + /// Points to the file that should be fetched./ file_id is unique per `InodeInfo` + /// in a `RecordsFile` + pub file_id: FileId, + + /// start offset to fetch data from. This is FsInfo.block_size aligned. + pub offset: u64, + + /// length of the read. This is generally rounded up to Fs.Info.block_size + /// except when the rounding up crosses `InodeInfo.file_size` + pub length: u64, + + /// Timestamp in nanoseconds since the start when the data was loaded. + pub timestamp: u64, +} + +impl Record { + /// Returns a new record if two records belong to same file and overlap. + fn overlaps(&self, other: &Self) -> Option { + if self.file_id == other.file_id { + let self_start = self.offset; + let self_end = self.offset + self.length; + let other_start = other.offset; + let other_end = other.offset + other.length; + + if (self_start <= other_end) && (self_end >= other_start) { + let offset = min(self_start, other_start); + let length = max(self_end, other_end) - offset; + return Some(Self { + file_id: self.file_id.clone(), + offset, + length, + timestamp: min(self.timestamp, other.timestamp), + }); + } + } + None + } +} + +fn group_record_by_file_id(records: Vec) -> Vec { + let mut map: HashMap> = HashMap::new(); + + for record in &records { + let recs = map.entry(record.file_id.clone()).or_default(); + recs.entry(record.offset).or_insert_with(|| record.clone()); + } + + let mut grouped = vec![]; + for record in &records { + if let Some(inode) = map.get(&record.file_id) { + for rec in inode.values() { + grouped.push(rec.clone()); + } + } + let _ = map.remove(&record.file_id); + } + + grouped +} + +/// When records are coalesced, because their file ids match and IO offsets overlap, the least +/// timestamp of the coalesced records is retained. +pub(crate) fn coalesce_records(records: Vec, group_by_file_id: bool) -> Vec { + let records = if group_by_file_id { group_record_by_file_id(records) } else { records }; + + let mut coalesced = vec![]; + let mut current: Option = None; + for r in records { + current = match current { + None => Some(r), + Some(c) => { + let merged = c.overlaps(&r); + match merged { + None => { + coalesced.push(c); + Some(r) + } + Some(m) => Some(m), + } + } + } + } + if let Some(r) = current { + coalesced.push(r); + } + coalesced +} + +// Records file header. +#[derive(Clone, Debug, Deserialize, Eq, PartialEq, Serialize)] +pub struct Header { + /// magic number as uuid to identify the header/format. + #[serde(deserialize_with = "check_magic")] + magic: [u8; 16], + + // major version number. + #[serde(deserialize_with = "check_major_number")] + major_number: u16, + + // minor version number. + #[serde(deserialize_with = "check_minor_number")] + minor_number: u16, + + /// timestamp when the records file was generated. + date: SystemTime, + + /// Checksum of the `RecordsFile` with `digest` being empty vector. + digest: u32, +} + +fn check_version_number<'de, D>( + deserializer: D, + expected: u16, + version_type: &str, +) -> Result +where + D: Deserializer<'de>, +{ + let found = u16::deserialize(deserializer)?; + if expected != found { + return Err(serde::de::Error::custom(format!( + "Failed to parse {} version. Expected: {} Found: {}", + version_type, expected, found + ))); + } + Ok(found) +} + +fn check_major_number<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + check_version_number(deserializer, MAJOR_VERSION, "major") +} + +fn check_minor_number<'de, D>(deserializer: D) -> Result +where + D: Deserializer<'de>, +{ + check_version_number(deserializer, MINOR_VERSION, "minor") +} + +fn check_magic<'de, D>(deserializer: D) -> Result<[u8; 16], D::Error> +where + D: Deserializer<'de>, +{ + let found: [u8; 16] = <[u8; 16]>::deserialize(deserializer)?; + if found != MAGIC_UUID { + return Err(serde::de::Error::custom(format!( + "Failed to parse magic number. Expected: {:?} Found: {:?}", + MAGIC_UUID, found + ))); + } + Ok(found) +} + +fn check_inode_info_paths<'de, D>(deserializer: D) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + let parsed: Vec = Vec::deserialize(deserializer)?; + if parsed.is_empty() { + return Err(serde::de::Error::custom("No paths found for in InodeInfo")); + } + Ok(parsed) +} + +// Helper inner struct of RecordsFile meant to verify checksum. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)] +pub(crate) struct RecordsFileInner { + // One instance per mounted block device. + pub(crate) filesystems: SerializableHashMap, + + /// Helps to get to a file path from a given `FileId`. + /// One instance per file to be prefetched. + pub(crate) inode_map: SerializableHashMap, + + /// Helps to get to a file and offset to be replayed.. + /// + // The records are chronologically arranged meaning the data that + // needs first is at the beginning of the vector and the data that + // needs last is at the end. + // + // One instance per part of the file that needs to be prefetched. + pub records: Vec, +} + +/// Deserialized form of records file. +#[derive(Clone, Debug, Default, Deserialize, Serialize, Eq, PartialEq)] +#[serde(remote = "Self")] +pub struct RecordsFile { + /// Helps the prefetch tool to parse rest of the file + pub header: Header, + + /// Helps the prefetch tool to verify checksum. + pub(crate) inner: RecordsFileInner, +} + +impl RecordsFile { + /// Given file id, looks up path of the file and returns open File handle. + pub fn open_file(&self, id: FileId, exclude_files_regex: &[Regex]) -> Result { + if let Some(inode) = self.inner.inode_map.get(&id) { + let path = inode.paths.first().unwrap(); + + for regex in exclude_files_regex { + if regex.is_match(path) { + return Err(Error::SkipPrefetch { path: path.to_owned() }); + } + } + debug!("Opening {} file {}", id.0, path); + OpenOptions::new() + .read(true) + .write(false) + .open(path) + .map_err(|source| Error::Open { source, path: path.to_owned() }) + } else { + Err(Error::IdNoFound { id }) + } + } + + /// Inserts given record in RecordsFile + pub fn insert_record(&mut self, records: Record) { + self.inner.records.push(records); + } + + /// Inserts given InodeInfo into in RecordsFile. + pub fn insert_or_update_inode_info(&mut self, id: FileId, info: InodeInfo) { + if let Some(inode) = self.inner.inode_map.get_mut(&id) { + if let Some(first_path) = info.paths.first() { + inode.paths.push(first_path.clone()); + } + } else { + self.inner.inode_map.insert(id, info); + } + } + + /// Verifies the integrity of records file. + /// + /// check saves us from serializing a improperly built record file or replaying an inconsistent + /// `RecordFile`. + /// + /// Note: check only works on the `RecordsFile` and doesn't access filesystem. We limit the + /// scope so that we avoid issuing filesystem operations(directory lookup, stats) twice - once + /// during check and once during replaying. + pub fn check(&self) -> Result<(), Error> { + let mut unique_files = HashSet::new(); + let mut missing_file_ids = vec![]; + + for record in &self.inner.records { + if !self.inner.inode_map.contains_key(&record.file_id) { + missing_file_ids.push(record.file_id.clone()); + } + unique_files.insert(record.file_id.clone()); + } + + let mut stale_inodes = vec![]; + let mut missing_paths = vec![]; + for (file_id, inode_info) in &self.inner.inode_map.map { + if inode_info.paths.is_empty() { + missing_paths.push(inode_info.clone()); + } + if !unique_files.contains(file_id) { + stale_inodes.push(inode_info.clone()); + } + } + + if !stale_inodes.is_empty() || !missing_paths.is_empty() || !missing_file_ids.is_empty() { + return Err(Error::StaleInode { stale_inodes, missing_paths, missing_file_ids }); + } + + Ok(()) + } + + /// Builds InodeInfo from args and inserts inode info in RecordsFile. + pub fn insert_or_update_inode(&mut self, id: FileId, stat: &Metadata, path: PathString) { + self.insert_or_update_inode_info( + id, + InodeInfo { + inode_number: stat.ino(), + file_size: stat.len(), + paths: vec![path], + device_number: stat.dev(), + }, + ) + } + + /// Serialize records in the form of csv. + pub fn serialize_records_to_csv(&self, writer: &mut dyn Write) -> Result<(), Error> { + let mut wtr = csv::Writer::from_writer(writer); + + #[derive(Serialize)] + struct TempRecord<'a> { + timestamp: u64, + file: &'a PathString, + offset: u64, + length: u64, + file_size: u64, + } + + for record in &self.inner.records { + if let Some(inode_info) = self.inner.inode_map.get(&record.file_id) { + let mut inode_info = inode_info.clone(); + inode_info.paths.sort(); + + if let Some(first_path) = inode_info.paths.first().cloned() { + // Clone the &String inside Option + let record = TempRecord { + timestamp: record.timestamp, + file: &first_path, // Now you have &String + offset: record.offset, + length: record.length, + file_size: inode_info.file_size, + }; + wtr.serialize(&record) + .map_err(|e| Error::Serialize { error: e.to_string() })?; + } + } + } + wtr.flush()?; + Ok(()) + } + + fn compute_digest(&mut self) -> Result { + self.header.digest = Default::default(); + let serialized = serde_cbor::to_vec(self) + .map_err(|source| Error::Serialize { error: source.to_string() })?; + + let mut hasher = Hasher::new(); + hasher.update(&serialized); + + Ok(hasher.finalize()) + } + + /// Convenience wrapper around serialize that adds checksum/digest to the file + /// to verify file consistency during replay/deserialize. + pub fn add_checksum_and_serialize(&mut self) -> Result, Error> { + self.header.digest = self.compute_digest()?; + + serde_cbor::to_vec(self).map_err(|source| Error::Serialize { error: source.to_string() }) + } +} + +impl Default for Header { + fn default() -> Self { + Self { + major_number: MAJOR_VERSION, + minor_number: MINOR_VERSION, + date: SystemTime::now(), + digest: 0, + magic: MAGIC_UUID, + } + } +} + +// Wrapper around deserialize to check any inconsistencies in the file format. +impl<'de> Deserialize<'de> for RecordsFile { + fn deserialize(deserializer: D) -> std::result::Result + where + D: Deserializer<'de>, + { + let rf = Self::deserialize(deserializer)?; + + rf.check().map_err(|e| { + serde::de::Error::custom(format!("failed to validate records file: {}", e)) + })?; + + let mut zero_digest = rf.clone(); + zero_digest.header.digest = 0; + let digest = + zero_digest.compute_digest().map_err(|e| serde::de::Error::custom(format!("{}", e)))?; + + if digest != rf.header.digest { + return Err(serde::de::Error::custom(format!( + "file consistency check failed. Expected: {}. Found: {}", + digest, rf.header.digest + ))); + } + + Ok(rf) + } +} + +// Wrapper around serialize to check any inconsistencies in the file format before serializing +impl Serialize for RecordsFile { + fn serialize(&self, serializer: S) -> std::result::Result + where + S: Serializer, + { + self.check().map(|_| self).map_err(|e| { + serde::ser::Error::custom(format!("failed to validate records file: {}", e)) + })?; + Self::serialize(self, serializer) + } +} + +#[cfg(test)] +pub mod tests { + + use std::assert_eq; + + use super::*; + + #[test] + fn test_major_version_mismatch() { + let mut rf = RecordsFile::default(); + + rf.header.major_number += 1; + + let serialized: Result = + serde_cbor::from_slice(&serde_cbor::to_vec(&rf).unwrap()); + + assert_eq!( + serialized.unwrap_err().to_string(), + format!( + "Failed to parse major version. Expected: {} Found: {}", + MAJOR_VERSION, + MAJOR_VERSION + 1 + ) + ); + } + + #[test] + fn test_minor_version_mismatch() { + let mut rf = RecordsFile::default(); + + rf.header.minor_number += 1; + + let serialized: Result = + serde_cbor::from_slice(&serde_cbor::to_vec(&rf).unwrap()); + + assert_eq!( + serialized.unwrap_err().to_string(), + format!( + "Failed to parse minor version. Expected: {} Found: {}", + MINOR_VERSION, + MINOR_VERSION + 1 + ) + ); + } + + #[test] + fn deserialize_inode_info_without_path() { + let inode = InodeInfo { inode_number: 1, file_size: 10, paths: vec![], device_number: 1 }; + let serialized = serde_cbor::to_vec(&inode).unwrap(); + let deserialized: Result = + serde_cbor::from_slice(&serialized); + assert_eq!( + deserialized.unwrap_err().to_string(), + "No paths found for in InodeInfo".to_owned() + ); + } + #[test] + fn test_serialize_records_to_csv() { + let mut rf = RecordsFile::default(); + let file_count = 4; + for i in 0..file_count { + rf.insert_or_update_inode_info( + FileId(i), + InodeInfo { + inode_number: i, + file_size: i * 10, + paths: vec![format!("/hello/{}", i)], + device_number: i + 10, + }, + ) + } + for i in 0..10 { + rf.insert_record(Record { + file_id: FileId(i % file_count), + offset: i * 3, + length: i + 4, + timestamp: i * file_count, + }); + } + + let mut buf = vec![]; + rf.serialize_records_to_csv(&mut buf).unwrap(); + + let data = String::from_utf8(buf).unwrap(); + assert_eq!( + data, + "timestamp,file,offset,length,file_size\n\ + 0,/hello/0,0,4,0\n\ + 4,/hello/1,3,5,10\n\ + 8,/hello/2,6,6,20\n\ + 12,/hello/3,9,7,30\n\ + 16,/hello/0,12,8,0\n\ + 20,/hello/1,15,9,10\n\ + 24,/hello/2,18,10,20\n\ + 28,/hello/3,21,11,30\n\ + 32,/hello/0,24,12,0\n\ + 36,/hello/1,27,13,10\n" + ); + } + + fn new_record(file: u64, offset: u64, length: u64, timestamp: u64) -> Record { + Record { file_id: FileId(file), offset, length, timestamp } + } + + #[test] + fn test_coalesced_without_group() { + let non_coalescable_same_inode = + vec![new_record(1, 2, 3, 4), new_record(1, 6, 3, 5), new_record(1, 10, 3, 6)]; + assert_eq!( + coalesce_records(non_coalescable_same_inode.clone(), false), + non_coalescable_same_inode + ); + + let non_coalescable_different_inode = + vec![new_record(1, 2, 3, 4), new_record(2, 5, 3, 5), new_record(3, 8, 3, 6)]; + assert_eq!( + coalesce_records(non_coalescable_different_inode.clone(), false), + non_coalescable_different_inode + ); + + let some_coalesced = + vec![new_record(1, 2, 3, 4), new_record(1, 5, 3, 5), new_record(3, 8, 3, 6)]; + assert_eq!( + coalesce_records(some_coalesced, false), + vec![new_record(1, 2, 6, 4), new_record(3, 8, 3, 6),] + ); + + let coalesced_into_one = + vec![new_record(1, 2, 3, 4), new_record(1, 5, 3, 5), new_record(1, 8, 3, 6)]; + assert_eq!(coalesce_records(coalesced_into_one, false), vec![new_record(1, 2, 9, 4)]); + + let no_grouping_or_coalescing = + vec![new_record(1, 2, 3, 4), new_record(3, 8, 3, 5), new_record(1, 5, 3, 6)]; + assert_eq!( + coalesce_records(no_grouping_or_coalescing, false), + vec![new_record(1, 2, 3, 4), new_record(3, 8, 3, 5), new_record(1, 5, 3, 6),] + ); + } + + #[test] + fn test_coalesced_with_grouping() { + let non_coalescable_same_inode = + vec![new_record(1, 2, 3, 4), new_record(1, 6, 3, 5), new_record(1, 10, 3, 6)]; + assert_eq!( + coalesce_records(non_coalescable_same_inode.clone(), true), + non_coalescable_same_inode + ); + + let non_coalescable_different_inode = + vec![new_record(1, 2, 3, 4), new_record(2, 5, 3, 5), new_record(3, 8, 3, 6)]; + assert_eq!( + coalesce_records(non_coalescable_different_inode.clone(), true), + non_coalescable_different_inode + ); + + let some_coalesced = + vec![new_record(1, 2, 3, 4), new_record(1, 5, 3, 5), new_record(3, 8, 3, 6)]; + assert_eq!( + coalesce_records(some_coalesced, true), + vec![new_record(1, 2, 6, 4), new_record(3, 8, 3, 6),] + ); + + let coalesced_into_one = + vec![new_record(1, 2, 3, 4), new_record(1, 5, 3, 5), new_record(1, 8, 3, 6)]; + assert_eq!(coalesce_records(coalesced_into_one, true), vec![new_record(1, 2, 9, 4)]); + + let some_grouped_coalesced = + vec![new_record(1, 2, 3, 4), new_record(3, 8, 3, 5), new_record(1, 5, 3, 6)]; + assert_eq!( + coalesce_records(some_grouped_coalesced, true), + vec![new_record(1, 2, 6, 4), new_record(3, 8, 3, 5),] + ); + } + + #[test] + fn check_missing_records() { + let mut rf = RecordsFile::default(); + rf.inner.inode_map.insert( + FileId(0), + InodeInfo { + inode_number: 0, + file_size: 1, + paths: vec!["hello".to_owned()], + device_number: 2, + }, + ); + rf.insert_record(Record { file_id: FileId(0), offset: 10, length: 20, timestamp: 30 }); + + rf.inner.inode_map.insert( + FileId(1), + InodeInfo { + inode_number: 1, + file_size: 2, + paths: vec!["world".to_owned()], + device_number: 3, + }, + ); + let e = rf.check().unwrap_err(); + assert_eq!( + e.to_string(), + "Stale inode(s) info found.\n\ + missing_file_ids: []\n\ + stale_inodes: [\n \ + InodeInfo {\n \ + inode_number: 1,\n \ + file_size: 2,\n \ + paths: [\n \"world\",\n ],\n \ + device_number: 3,\n },\n] \n\ + missing_paths:[]" + ); + } + + #[test] + fn check_missing_file() { + let mut rf = RecordsFile::default(); + rf.inner.inode_map.insert( + FileId(0), + InodeInfo { + inode_number: 0, + file_size: 1, + paths: vec!["hello".to_owned()], + device_number: 2, + }, + ); + rf.insert_record(Record { file_id: FileId(0), offset: 10, length: 20, timestamp: 30 }); + rf.insert_record(Record { file_id: FileId(1), offset: 10, length: 20, timestamp: 30 }); + + let e = rf.check().unwrap_err(); + assert_eq!( + e.to_string(), + "Stale inode(s) info found.\n\ + missing_file_ids: [\n \ + FileId(\n 1,\n ),\n]\n\ + stale_inodes: [] \n\ + missing_paths:[]" + ); + } + + #[test] + fn check_missing_paths() { + let mut rf = RecordsFile::default(); + rf.inner.inode_map.insert( + FileId(0), + InodeInfo { inode_number: 0, file_size: 1, paths: vec![], device_number: 2 }, + ); + rf.insert_record(Record { file_id: FileId(0), offset: 10, length: 20, timestamp: 30 }); + + let e = rf.check().unwrap_err(); + assert_eq!( + e.to_string(), + "Stale inode(s) info found.\n\ + missing_file_ids: []\n\ + stale_inodes: [] \n\ + missing_paths:[\n \ + InodeInfo {\n \ + inode_number: 0,\n \ + file_size: 1,\n \ + paths: [],\n \ + device_number: 2,\n },\n]" + ); + } +} diff --git a/init/libprefetch/prefetch/src/lib.rs b/init/libprefetch/prefetch/src/lib.rs new file mode 100644 index 000000000..4b56b13ee --- /dev/null +++ b/init/libprefetch/prefetch/src/lib.rs @@ -0,0 +1,186 @@ +// Copyright (C) 2024 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. + +//! A library to prefetch files on the file system to optimize startup times +//! + +mod args; +mod error; +mod format; +mod replay; +mod tracer; + +use std::fs::File; +use std::fs::OpenOptions; +use std::io; +use std::io::Write; +use std::os::unix::fs::PermissionsExt; +use std::string::ToString; +use std::thread; +use std::time::Duration; + +#[cfg(target_os = "android")] +use log::Level; +#[cfg(target_os = "linux")] +use log::LevelFilter; + +pub use args::args_from_env; +use args::OutputFormat; +pub use args::ReplayArgs; +pub use args::{DumpArgs, MainArgs, RecordArgs, SubCommands}; +pub use error::Error; +pub use format::FileId; +pub use format::InodeInfo; +pub use format::Record; +pub use format::RecordsFile; +use log::info; +#[cfg(target_os = "android")] +use log::warn; +pub use replay::Replay; +pub use tracer::nanoseconds_since_boot; + +#[cfg(target_os = "android")] +use rustutils::system_properties; +#[cfg(target_os = "android")] +use rustutils::system_properties::error::PropertyWatcherError; +#[cfg(target_os = "android")] +use rustutils::system_properties::PropertyWatcher; + +#[cfg(target_os = "android")] +fn wait_for_property_true(property_name: &str) -> Result<(), PropertyWatcherError> { + let mut prop = PropertyWatcher::new(property_name)?; + loop { + prop.wait(None)?; + if system_properties::read_bool(property_name, false)? { + break; + } + } + Ok(()) +} + +/// Records prefetch data for the given configuration +pub fn record(args: &RecordArgs) -> Result<(), Error> { + let (mut tracer, exit_tx) = tracer::Tracer::create( + args.trace_buffer_size_kib, + args.tracing_subsystem.clone(), + args.tracing_instance.clone(), + args.setup_tracing, + )?; + let duration = Duration::from_secs(args.duration as u64); + + let thd = thread::spawn(move || { + if !duration.is_zero() { + info!("Record start - waiting for duration: {:?}", duration); + thread::sleep(duration); + } else { + #[cfg(target_os = "android")] + wait_for_property_true("sys.boot_completed").unwrap_or_else(|e| { + warn!("failed to wait for sys.boot_completed with error: {}", e) + }); + } + + // We want to unwrap here on failure to send this signal. Otherwise + // tracer will continue generating huge records data. + exit_tx.send(()).unwrap(); + }); + + let mut rf = tracer.trace(args.int_path.as_ref())?; + thd.join() + .map_err(|_| Error::ThreadPool { error: "Failed to join timeout thread".to_string() })?; + + let mut out_file = + OpenOptions::new().write(true).create(true).truncate(true).open(&args.path).map_err( + |source| Error::Create { source, path: args.path.to_str().unwrap().to_owned() }, + )?; + + std::fs::set_permissions(&args.path, std::fs::Permissions::from_mode(0o644)) + .map_err(|source| Error::Create { source, path: args.path.to_str().unwrap().to_owned() })?; + + out_file + .write_all(&rf.add_checksum_and_serialize()?) + .map_err(|source| Error::Write { path: args.path.to_str().unwrap().to_owned(), source })?; + Ok(()) +} + +/// Replays prefetch data for the given configuration +pub fn replay(args: &ReplayArgs) -> Result<(), Error> { + let replay = Replay::new(args)?; + replay.replay() +} + +/// Dumps prefetch data in the human readable form +pub fn dump(args: &DumpArgs) -> Result<(), Error> { + let reader = File::open(&args.path) + .map_err(|source| Error::Open { source, path: args.path.to_str().unwrap().to_string() })?; + let rf: RecordsFile = + serde_cbor::from_reader(reader).map_err(|e| Error::Deserialize { error: e.to_string() })?; + match args.format { + OutputFormat::Json => println!( + "{:#}", + serde_json::to_string_pretty(&rf) + .map_err(|e| Error::Serialize { error: e.to_string() })? + ), + OutputFormat::Csv => rf.serialize_records_to_csv(&mut io::stdout())?, + } + Ok(()) +} + +/// An alias of android_logger::Level to use log level across android and linux. +#[cfg(target_os = "android")] +pub type LogLevel = Level; + +/// An alias of log::LevelFilter to use log level across android and linux. +#[cfg(not(target_os = "android"))] +pub type LogLevel = LevelFilter; + +/// Convenience logging initializer that is shared between the prefetch tool and c wrapper library +#[cfg(target_os = "android")] +pub fn init_logging(_level: LogLevel) { + android_logger::init_once( + android_logger::Config::default().with_max_level(log::LevelFilter::Info).format( + |f, record| { + write!( + f, + "{} prefetch_rs: {}:{} {}: {}", + nanoseconds_since_boot(), + record.file().unwrap_or("unknown_file"), + record.line().unwrap_or(0), + record.level(), + record.args() + ) + }, + ), + ) +} + +/// Convenience logging initializer that is shared between the prefetch tool and c wrapper library +#[cfg(target_os = "linux")] +pub fn init_logging(level: LogLevel) { + let mut builder = env_logger::Builder::from_default_env(); + + builder + .filter(None, level) + .format(|buf, record| { + writeln!( + buf, + "{} prefetch_rs: {}:{} {}: {}", + nanoseconds_since_boot(), + record.file().unwrap_or("unknown_file"), + record.line().unwrap_or(0), + record.level(), + record.args() + ) + }) + .init(); +} diff --git a/init/libprefetch/prefetch/src/main.rs b/init/libprefetch/prefetch/src/main.rs new file mode 100644 index 000000000..046e07eda --- /dev/null +++ b/init/libprefetch/prefetch/src/main.rs @@ -0,0 +1,41 @@ +// Copyright (C) 2024 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. + +//! A utility wrapper around libprefetch that allows to record, replay and dump +//! prefetch data. + +use log::error; + +use prefetch_rs::args_from_env; +use prefetch_rs::dump; +use prefetch_rs::init_logging; +use prefetch_rs::record; +use prefetch_rs::replay; +use prefetch_rs::LogLevel; +use prefetch_rs::MainArgs; +use prefetch_rs::SubCommands; + +fn main() { + init_logging(LogLevel::Debug); + let args: MainArgs = args_from_env(); + let ret = match &args.nested { + SubCommands::Record(args) => record(args), + SubCommands::Replay(args) => replay(args), + SubCommands::Dump(args) => dump(args), + }; + + if let Err(err) = ret { + error!("{:?} command failed: {:?}", args, err); + } +} diff --git a/init/libprefetch/prefetch/src/replay.rs b/init/libprefetch/prefetch/src/replay.rs new file mode 100644 index 000000000..b68d74762 --- /dev/null +++ b/init/libprefetch/prefetch/src/replay.rs @@ -0,0 +1,762 @@ +// Copyright (C) 2024 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. + +use std::clone::Clone; +use std::convert::TryInto; +use std::fmt::Display; +use std::mem::replace; +use std::os::unix::io::AsRawFd; +use std::sync::Arc; +use std::sync::Mutex; +use std::sync::RwLock; +use std::thread; + +use log::debug; +use log::error; +use log::warn; +use lru_cache::LruCache; +use nix::errno::Errno; +use nix::fcntl::posix_fadvise; +use regex::Regex; + +use crate::args::ConfigFile; +use crate::format::Record; +use crate::format::{FileId, RecordsFile}; +use crate::Error; +use crate::ReplayArgs; +use libc::{c_void, off64_t, pread64}; +use std::fs::File; + +const READ_SZ: usize = 1024 * 1024; + +struct ScopedLog { + msg: T, + thd_id: usize, +} + +fn scoped_log(ctx: usize, msg: T) -> ScopedLog { + let thd_id = ctx; + debug!("{} {} start", thd_id, msg); + ScopedLog { msg, thd_id } +} + +impl Drop for ScopedLog { + fn drop(&mut self) { + debug!("{} {} end", self.thd_id, self.msg); + } +} + +fn readahead( + id: usize, + file: Arc, + record: &Record, + buffer: &mut [u8; READ_SZ], +) -> Result<(), Error> { + debug!("readahead {:?}", record); + let _dbg = scoped_log(id, "readahead"); + + let mut current_offset: off64_t = record + .offset + .try_into() + .map_err(|_| Error::Read { error: "Failed to convert offset".to_string() })?; + let mut remaining_data: usize = record + .length + .try_into() + .map_err(|_| Error::Read { error: "Failed to convert length".to_string() })?; + + while remaining_data > 0 { + let read_size = std::cmp::min(READ_SZ, remaining_data); + + // SAFETY: This is safe because + // - the file is known to exist and opened + // - buffer is allocated upfront and is guaranteed by the fact it comes from a mutable slice reference. + // - read_size is guaranteed not to exceed length of the buffer. + let bytes_read = unsafe { + pread64(file.as_raw_fd(), buffer.as_mut_ptr() as *mut c_void, read_size, current_offset) + }; + + if bytes_read == -1 { + return Err(Error::Read { error: format!("readahead failed: {}", Errno::last_raw()) }); + } + + if bytes_read == 0 { + break; // End of file reached + } + + current_offset += bytes_read as off64_t; + remaining_data -= bytes_read as usize; + } + + // TODO: Try readahead() syscall or async I/O + Ok(()) +} + +fn worker_internal( + id: usize, + state: Arc>, + records_file: Arc>, + exit_on_error: bool, + exclude_files_regex: Vec, + buffer: &mut [u8], +) -> Result<(), Error> { + loop { + let index = { + let mut state = state.lock().unwrap(); + if state.result.is_err() { + return Ok(()); + } + state.next_record() + }; + + let record = { + let rf = records_file.read().unwrap(); + if index >= rf.inner.records.len() { + return Ok(()); + } + rf.inner.records.get(index).unwrap().clone() + }; + + let _dbg = scoped_log(id, "record_replay"); + + let file = state.lock().unwrap().fds.get_mut(&record.file_id).map(|f| f.clone()); + + let file = match file { + Some(file) => file, + None => { + let file = Arc::new({ + let file = records_file + .read() + .unwrap() + .open_file(record.file_id.clone(), &exclude_files_regex); + if let Err(e) = file { + if exit_on_error { + return Err(e); + } else { + match e { + Error::SkipPrefetch { path } => { + debug!("Skipping file during replay: {}", path); + } + _ => error!( + "Failed to open file id: {} with {}", + record.file_id.clone(), + e.to_string() + ), + } + continue; + } + } + + let file = file.unwrap(); + // We do not want the filesystem be intelligent and prefetch more than what this + // code is reading. So turn off prefetch. + + if let Err(e) = posix_fadvise( + file.as_raw_fd(), + 0, + 0, + nix::fcntl::PosixFadviseAdvice::POSIX_FADV_RANDOM, + ) { + warn!( + "Failed to turn off filesystem read ahead for file id: {} with {}", + record.file_id.clone(), + e.to_string() + ); + } + file + }); + let cache_file = file.clone(); + state.lock().unwrap().fds.insert(record.file_id.clone(), cache_file); + file + } + }; + if let Err(e) = readahead(id, file, &record, buffer.try_into().unwrap()) { + if exit_on_error { + return Err(e); + } else { + error!( + "readahead failed on file id: {} with: {}", + record.file_id.clone(), + e.to_string() + ); + continue; + } + } + } +} + +fn worker( + id: usize, + state: Arc>, + records_file: Arc>, + exit_on_error: bool, + exclude_files_regex: Vec, + buffer: &mut [u8], +) { + let _dbg = scoped_log(id, "read_loop"); + let result = worker_internal( + id, + state.clone(), + records_file, + exit_on_error, + exclude_files_regex, + buffer, + ); + if result.is_err() { + error!("worker failed with {:?}", result); + let mut state = state.lock().unwrap(); + if state.result.is_ok() { + state.result = result; + } + } +} + +#[derive(Debug)] +pub struct SharedState { + fds: LruCache>, + records_index: usize, + result: Result<(), Error>, +} + +impl SharedState { + fn next_record(&mut self) -> usize { + let ret = self.records_index; + self.records_index += 1; + ret + } +} + +/// Runtime, in-memory, representation of records file structure. +#[derive(Debug)] +pub struct Replay { + records_file: Arc>, + io_depth: u16, + exit_on_error: bool, + state: Arc>, + exclude_files_regex: Vec, +} + +impl Replay { + /// Creates Replay from input `args`. + pub fn new(args: &ReplayArgs) -> Result { + let _dbg = scoped_log(1, "new"); + let reader: File = File::open(&args.path).map_err(|source| Error::Open { + source, + path: args.path.to_str().unwrap().to_owned(), + })?; + let rf: RecordsFile = serde_cbor::from_reader(reader) + .map_err(|error| Error::Deserialize { error: error.to_string() })?; + + let mut exclude_files_regex: Vec = Vec::new(); + // The path to the configuration file is optional in the command. + // If the path is provided, the configuration file will be read. + if !&args.config_path.as_os_str().is_empty() { + let config_reader = File::open(&args.config_path).map_err(|source| Error::Open { + source, + path: args.path.to_str().unwrap().to_owned(), + })?; + let cf: ConfigFile = serde_json::from_reader(config_reader) + .map_err(|error| Error::Deserialize { error: error.to_string() })?; + + for file_to_exclude in &cf.files_to_exclude_regex { + exclude_files_regex.push(Regex::new(file_to_exclude).unwrap()); + } + } + + Ok(Self { + records_file: Arc::new(RwLock::new(rf)), + io_depth: args.io_depth, + exit_on_error: args.exit_on_error, + state: Arc::new(Mutex::new(SharedState { + fds: LruCache::new(args.max_fds.into()), + records_index: 0, + result: Ok(()), + })), + exclude_files_regex, + }) + } + + /// Replay records. + pub fn replay(self) -> Result<(), Error> { + let _dbg = scoped_log(1, "replay"); + let mut threads = vec![]; + for i in 0..self.io_depth { + let i_clone = i as usize; + let state = self.state.clone(); + let records_file = self.records_file.clone(); + let exit_on_error = self.exit_on_error; + let exclude_files_regex = self.exclude_files_regex.clone(); + + let mut buffer = Box::new([0u8; READ_SZ]); + + threads.push(thread::Builder::new().spawn(move || { + worker( + i_clone, + state, + records_file, + exit_on_error, + exclude_files_regex, + buffer.as_mut_slice(), + ) + })); + } + for thread in threads { + thread.unwrap().join().unwrap(); + } + replace(&mut self.state.lock().unwrap().result, Ok(())) + } +} + +// WARNING: flaky tests. +// In these tests we create files, invalidate their caches and then replay. +// Verify that after reply the same portions of data is in memory. +// +// Since these tests to rely on presence or absence of data in cache, the +// files used by the tests should not be in tmp filesystem. So we use relative +// path as target directory. There is no guarantee that this target directory +// is not on temp filesystem but chances are better than using target directory +// in tempfs. +// +// Tests can be flaky if the system under tests is running low on memory. The +// tests create file using O_DIRECT so that no data is left in file cache. +// Though this is sufficient to avoid caching, but other processes reading these +// files(like anti-virus) or some other system processes might change the state +// of the cache. Or it may happen that the filesystem evicts the file before +// we verify that read ahead worked as intended. +#[cfg(test)] +pub mod tests { + use std::{ + assert, + io::Write, + ops::Range, + path::{Path, PathBuf}, + time::Duration, + }; + + use crate::format::DeviceNumber; + use crate::format::FsInfo; + use crate::format::InodeNumber; + use crate::nanoseconds_since_boot; + use nix::sys::mman::MapFlags; + use nix::sys::mman::ProtFlags; + use serde::Deserialize; + use serde::Serialize; + use std::collections::HashMap; + use std::fs::OpenOptions; + use std::num::NonZeroUsize; + use std::os::fd::AsFd; + use std::os::unix::fs::symlink; + use std::os::unix::fs::MetadataExt; + use std::ptr::NonNull; + use tempfile::NamedTempFile; + + use super::*; + use crate::tracer::{ + page_size, + tests::{copy_uncached_files_and_record_from, setup_test_dir}, + }; + + static MB: u64 = 1024 * 1024; + static KB: u64 = 1024; + + fn random_write(file: &mut NamedTempFile, base: u64) -> Range { + let start: u64 = base + (rand::random::() % (base / 2)) as u64; + let len: u64 = rand::random::() % (32 * KB); + let buf = vec![5; len as usize]; + nix::sys::uio::pwrite(file.as_fd(), &buf, start as i64).unwrap(); + start..(start + len) + } + + pub(crate) fn create_file( + path: Option<&Path>, + align: Option, + ) -> (NamedTempFile, Vec>) { + let mut file = if let Some(path) = path { + NamedTempFile::new_in(path).unwrap() + } else { + NamedTempFile::new().unwrap() + }; + let range1 = random_write(&mut file, 32 * KB); + let range2 = random_write(&mut file, 128 * KB); + let range3 = random_write(&mut file, 4 * MB); + if let Some(align) = align { + let orig_size = file.metadata().unwrap().len(); + let aligned_size = orig_size + (align - (orig_size % align)); + file.set_len(aligned_size).unwrap(); + } + (file, vec![range1, range2, range3]) + } + + pub(crate) fn generate_cached_files_and_record( + path: Option<&Path>, + create_symlink: bool, + align: Option, + ) -> (RecordsFile, Vec<(NamedTempFile, Vec>)>) { + let file1 = create_file(path, align); + let file2 = create_file(path, align); + let file3 = create_file(path, align); + + let mut f: RecordsFileBuilder = Default::default(); + f.add_file(file1.0.path().to_str().unwrap()); + f.add_file(file2.0.path().to_str().unwrap()); + f.add_file(file3.0.path().to_str().unwrap()); + if create_symlink { + let symlink_path = format!("{}-symlink", file1.0.path().to_str().unwrap()); + symlink(file1.0.path().file_name().unwrap(), &symlink_path).unwrap(); + + f.add_file(&symlink_path); + } + let rf = f.build().unwrap(); + (rf, vec![file1, file2, file3]) + } + + /// RecordsFileBuilder is primarily used for testing purpose. This + /// is a thin wrapper around "Record". This gives the ability + /// to test Records functionality. The flow of this test is as follows: + /// + /// 1: generate_cached_files_and_record -> This will create temporary files of different length + /// and builds the "RecordFile" format. + /// 2: For each of the file path create, a "RecordsFile" is generated. + /// a: mmap the file based on the length. + /// b: call mincore() to get the residency of pages in memory for the given + /// length. + /// c: Iterate over the buffer of pages returned by mincore(). If a page + /// is not resident in RAM, construct the "Record" structure. + /// 3: build() function will finally return a constructed Prefetch Record which + /// contains all the "Record" structure required for "Replay". + #[derive(Debug, Default, Deserialize, Serialize)] + pub struct RecordsFileBuilder { + // Temporarily holds paths of all files opened by other processes. + pub(crate) paths: HashMap, + + // Read inode numbers + inode_numbers: HashMap<(DeviceNumber, InodeNumber), FileId>, + } + + impl RecordsFileBuilder { + pub fn add_file(&mut self, path: &str) { + if self.paths.contains_key(path) { + return; + } + + self.paths.insert(path.to_owned(), FileId(self.paths.len() as u64)); + } + + pub fn build(&mut self) -> Result { + let mut rf = RecordsFile::default(); + for (path, mut id) in self.paths.drain() { + let stat = Path::new(&path) + .metadata() + .map_err(|source| Error::Stat { source, path: path.clone() })?; + + rf.inner + .filesystems + .entry(stat.dev()) + .or_insert(FsInfo { block_size: stat.blksize() }); + + if let Some(orig_id) = self.inode_numbers.get(&(stat.dev(), stat.ino())) { + let inode = rf.inner.inode_map.get_mut(orig_id).unwrap(); + inode.paths.push(path.clone()); + + // There may be multiple paths for the file so from those path we may have multiple + // ids. Override the id. + id = orig_id.clone(); + } else { + self.inode_numbers.insert((stat.dev(), stat.ino()), id.clone()); + rf.insert_or_update_inode(id.clone(), &stat, path.clone()); + } + if let Some(mmap) = Mmap::create(&path, id)? { + mmap.get_records(&mut rf.inner.records)?; + } + } + Ok(rf) + } + } + + #[derive(Debug)] + pub(crate) struct Mmap { + map_addr: *mut c_void, + length: usize, + #[allow(dead_code)] + file: File, + file_id: FileId, + } + + impl Mmap { + pub fn create(path: &str, file_id: FileId) -> Result, Error> { + let file = OpenOptions::new() + .read(true) + .write(false) + .open(path) + .map_err(|source| Error::Open { source, path: path.to_owned() })?; + + let length = file + .metadata() + .map_err(|source| Error::Stat { source, path: path.to_owned() })? + .len() as usize; + + if length == 0 { + return Ok(None); + } + + // SAFETY: This is safe because + // - the length is checked for zero + // - offset is set to 0 + let map_addr = unsafe { + nix::sys::mman::mmap( + None, + NonZeroUsize::new(length).unwrap(), + ProtFlags::PROT_READ, + MapFlags::MAP_SHARED, + file.as_fd(), + 0, + ) + .map_err(|source| Error::Mmap { + error: source.to_string(), + path: path.to_owned(), + })? + }; + + Ok(Some(Self { map_addr: map_addr.as_ptr(), length, file, file_id })) + } + + /// Construct the "Record" file based on pages resident in RAM. + pub(crate) fn get_records(&self, records: &mut Vec) -> Result<(), Error> { + let page_size = page_size()?; + let page_count = (self.length + page_size - 1) / page_size; + let mut buf: Vec = vec![0_u8; page_count]; + // SAFETY: This is safe because + // - the file is mapped + // - buf points to a valid and sufficiently large memory region with the + // requirement of (length+PAGE_SIZE-1) / PAGE_SIZE bytes + let ret = unsafe { libc::mincore(self.map_addr, self.length, buf.as_mut_ptr()) }; + if ret < 0 { + return Err(Error::Custom { + error: format!("failed to query resident pages: {}", Errno::last_raw()), + }); + } + let mut i = 0; + + let mut offset_length: Option<(u64, u64)> = None; + for (index, resident) in buf.iter().enumerate() { + if *resident != 0 { + if let Some((_, length)) = &mut offset_length { + *length += page_size as u64; + } else { + offset_length = Some((index as u64 * page_size as u64, page_size as u64)); + } + } else if let Some((offset, length)) = offset_length { + i += 1; + records.push(Record { + file_id: self.file_id.clone(), + offset, + length, + timestamp: nanoseconds_since_boot(), + }); + + offset_length = None; + } + } + + if let Some((offset, length)) = offset_length { + i += 1; + records.push(Record { + file_id: self.file_id.clone(), + offset, + length, + timestamp: nanoseconds_since_boot(), + }); + } + debug!("records found: {} for {:?}", i, self); + + Ok(()) + } + } + + impl Drop for Mmap { + fn drop(&mut self) { + // SAFETY: This is safe because + // - addr is mapped and is multiple of page_size + let ret = unsafe { + nix::sys::mman::munmap(NonNull::new(self.map_addr).unwrap(), self.length) + }; + if let Err(e) = ret { + error!( + "failed to munmap {:p} {} with {}", + self.map_addr, + self.length, + e.to_string() + ); + } + } + } + + // Please see comment above RecordsFileBuilder. + fn rebuild_records_file(files: &[(PathBuf, Vec>)]) -> RecordsFile { + // Validate that caches are dropped + let mut f: RecordsFileBuilder = Default::default(); + for (path, _) in files { + f.add_file(path.to_str().unwrap()); + } + f.build().unwrap() + } + + fn ensure_files_not_cached(files: &mut [(PathBuf, Vec>)]) { + assert!(rebuild_records_file(files).inner.records.is_empty()); + } + + fn has_record(records: &[Record], key: &Record) -> bool { + for r in records { + if r.offset == key.offset && r.length == key.length { + return true; + } + } + false + } + + fn compare_records(old: &[Record], new: &[Record]) { + for key in new { + if !has_record(old, key) { + panic!("Failed to file {:?} in {:?}", key, old); + } + } + } + + fn create_test_config_file(files_to_exclude_regex: Vec) -> String { + let cfg = ConfigFile { files_to_exclude_regex, ..Default::default() }; + serde_json::to_string(&cfg).unwrap() + } + + // TODO: Split this into individual tests for better readability. + // b/378554334 + fn test_replay_internal( + create_symlink: bool, + exit_on_error: bool, + inject_error: bool, + exclude_all_files: bool, + empty_exclude_file_list: bool, + ) { + let page_size = page_size().unwrap() as u64; + let test_base_dir = setup_test_dir(); + let (rf, mut files) = + generate_cached_files_and_record(None, create_symlink, Some(page_size)); + + // Here "uncached_files" emulate the files after reboot when none of those files data is in cache. + let (mut uncached_rf, mut uncached_files) = + copy_uncached_files_and_record_from(Path::new(&test_base_dir), &mut files, &rf); + + // Injects error(s) in the form of invalid filename + if inject_error { + if let Some(v) = uncached_rf.inner.inode_map.values_mut().next() { + for path in &mut v.paths { + path.push('-'); + } + } + } + + let mut file = NamedTempFile::new().unwrap(); + file.write_all(&uncached_rf.add_checksum_and_serialize().unwrap()).unwrap(); + let mut config_file = NamedTempFile::new().unwrap(); + + let mut files_to_exclude: Vec = Vec::new(); + if exclude_all_files { + // Exclude files from replay by adding them in config + for v in uncached_rf.inner.inode_map.values_mut() { + for path in &mut v.paths { + files_to_exclude.push(path.to_string()) + } + } + } else if empty_exclude_file_list { + files_to_exclude.extend(vec![]); + } else { + // Exclude file1 and file2 during replay + files_to_exclude.extend(vec!["file1".to_owned(), "file2".to_owned()]); + } + + // Create a config json to exclude files during replay + let config_file_contents = create_test_config_file(files_to_exclude); + config_file.write_all(config_file_contents.as_bytes()).unwrap(); + + ensure_files_not_cached(&mut uncached_files); + + let replay = Replay::new(&ReplayArgs { + path: file.path().to_owned(), + io_depth: 32, + max_fds: 128, + exit_on_error, + config_path: config_file.path().to_owned(), + }) + .unwrap(); + + let result = replay.replay(); + // Sleep a bit so that readaheads are complete. + thread::sleep(Duration::from_secs(1)); + + if exit_on_error && inject_error { + result.expect_err("Failure was expected"); + } else if exclude_all_files { + let new_rf = rebuild_records_file(&uncached_files); + assert!(new_rf.inner.records.is_empty()); + } else { + result.unwrap(); + + // At this point, we have prefetched data for uncached file bringing same set of + // data in memory as the original cached files. + // If we record prefetch data for new files, we should get same records files + // (offset and lengths) except that the file names should be different. + // This block verifies it. + // Note: `new_rf` is for uncached_files. But, [un]fortunately, those "uncached_files" + // are now cached after we replayed the records. + let new_rf = rebuild_records_file(&uncached_files); + assert!(!new_rf.inner.records.is_empty()); + assert_eq!(rf.inner.inode_map.len(), new_rf.inner.inode_map.len()); + assert_eq!(rf.inner.records.len(), new_rf.inner.records.len()); + compare_records(&rf.inner.records, &new_rf.inner.records); + } + } + + #[test] + fn test_replay() { + test_replay_internal(true, false, false, false, false); + } + + #[test] + fn test_replay_strict() { + test_replay_internal(true, true, false, false, false); + } + + #[test] + fn test_replay_no_symlink() { + test_replay_internal(false, false, false, false, false); + } + + #[test] + fn test_replay_no_symlink_strict() { + test_replay_internal(false, true, false, false, false); + } + + #[test] + fn test_replay_fails_on_error() { + test_replay_internal(true, true, true, false, false); + } + + #[test] + fn test_replay_exclude_all_files() { + test_replay_internal(true, false, false, true, false); + } + + #[test] + fn test_replay_empty_exclude_files_list() { + test_replay_internal(true, false, false, false, true); + } +} diff --git a/init/libprefetch/prefetch/src/tracer/mem.rs b/init/libprefetch/prefetch/src/tracer/mem.rs new file mode 100644 index 000000000..f69ae807b --- /dev/null +++ b/init/libprefetch/prefetch/src/tracer/mem.rs @@ -0,0 +1,897 @@ +// Copyright (C) 2024 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. + +//! See top level documentation for `crate::tracer`. + +use std::collections::hash_map::Iter; +use std::fs::symlink_metadata; +use std::io::{ErrorKind, Write}; +use std::iter::Iterator; +use std::mem::take; +use std::os::unix::fs::MetadataExt; +use std::{ + collections::{HashMap, HashSet}, + fs::read_to_string, + option::Option, + path::{Path, PathBuf}, +}; + +use log::{debug, error, info, warn}; +use regex::Regex; +use serde::Deserialize; +use serde::Serialize; +use walkdir::{DirEntry, WalkDir}; + +use crate::format::{coalesce_records, FsInfo}; +use crate::tracer::{page_size, TracerConfigs}; +use crate::{ + format::{DeviceNumber, InodeNumber}, + tracer::{TraceSubsystem, EXCLUDE_PATHS}, + Error, FileId, Record, RecordsFile, +}; + +static MOUNTINFO_PATH: &str = "/proc/self/mountinfo"; + +// Trace events to enable +// Paths are relative to trace mount point +static TRACE_EVENTS: &[&str] = + &["events/filemap/mm_filemap_add_to_page_cache/enable", "tracing_on"]; + +// Filesystem types to ignore +static EXCLUDED_FILESYSTEM_TYPES: &[&str] = &[ + "binder", + "bpf", + "cgroup", + "cgroup2", + "configfs", + "devpts", + "fuse", // No emulated storage + "fusectl", + "proc", + "pstore", + "selinuxfs", + "sysfs", + "tmpfs", // Check for apex mount points + "tracefs", + "functionfs", // adb, fastboot + "f2fs", // Skip /data mounts +]; + +#[cfg(target_os = "linux")] +type MajorMinorType = u32; +#[cfg(target_os = "android")] +type MajorMinorType = i32; + +// TODO(b/302056482): Once we uprev nix crate, we can use the function exported by the crate. +fn major(dev: DeviceNumber) -> MajorMinorType { + (((dev >> 32) & 0xffff_f000) | ((dev >> 8) & 0x0000_0fff)) as MajorMinorType +} + +// TODO(b/302056482): Once we uprev nix crate, we can use the function exported by the crate. +fn minor(dev: DeviceNumber) -> MajorMinorType { + (((dev >> 12) & 0xffff_ff00) | ((dev) & 0x0000_00ff)) as MajorMinorType +} + +// TODO(b/302056482): Once we uprev nix crate, we can use the function exported by the crate. +fn makedev(major: MajorMinorType, minor: MajorMinorType) -> DeviceNumber { + let major = major as DeviceNumber; + let minor = minor as DeviceNumber; + ((major & 0xffff_f000) << 32) + | ((major & 0x0000_0fff) << 8) + | ((minor & 0xffff_ff00) << 12) + | (minor & 0x0000_00ff) +} + +fn build_device_number(major: &str, minor: &str) -> Result { + Ok(makedev( + major.parse::().map_err(|e| Error::Custom { + error: format!("Failed to parse major number from {} with {}", major, e), + })?, + minor.parse::().map_err(|e| Error::Custom { + error: format!("Failed to parse major number from {} with {}", major, e), + })?, + )) +} + +// Returns timestamp in nanoseconds +fn build_timestamp(seconds: &str, microseconds: &str) -> Result { + let seconds = seconds.parse::().map_err(|e| Error::Custom { + error: format!("Failed to parse seconds from {} with {}", seconds, e), + })?; + let microseconds = microseconds.parse::().map_err(|e| Error::Custom { + error: format!("Failed to parse microseconds from {} with {}", seconds, e), + })?; + Ok((seconds * 1_000_000_000) + (microseconds * 1_000)) +} + +#[cfg(not(target_os = "android"))] +fn is_highly_privileged_path(_path: &Path) -> bool { + false +} + +#[cfg(target_os = "android")] +fn is_highly_privileged_path(path: &Path) -> bool { + // Following directories contain a mix of files with and without access to stat/read. + // We do not completely exclude these directories as there is still a lot of + // file we can issue readahead on. Some of the files on which readahead fails include + // - /system/bin/run-as + // - /data/data/com.android.storagemanager + // - /system/apex/com.android.art/bin/dex2oat32 + // - /data/user/0/com.android.systemui + // + // - TODO: /system/apex: Apex files in read-only partition may be read during boot. + // However, some files may not have access. Double check the record files + // to filter out the exact path. + let privileged_paths = [ + "/data/data", + "/data/user/0", + "/data/user_de/0", + "/system/bin/", + "/system/etc/selinux/", + "/system/system_ext/etc/selinux/", + "/system/product/etc/selinux/", + "/system/vendor/etc/selinux/", + "/system_ext/etc/selinux/", + "/product/etc/selinux/", + "/vendor/etc/selinux/", + "/system/xbin", + "/system/etc/", + "/data/", + "/postinstall/", + "/mnt/", + "/metadata/", + ]; + for privileged in privileged_paths { + if path.to_str().unwrap().starts_with(privileged) { + return true; + } + } + false +} + +enum DeviceState { + Include((DeviceNumber, PathBuf)), + Exclude(DeviceNumber), +} + +/// Utility struct that helps to include and exclude devices and mount points that need and don't +/// need prefetching. +#[derive(Debug, Deserialize, Serialize)] +struct MountInfo { + // Map of device number to mount points + included_devices: HashMap, + + // Devices that we don't want to prefetch - like devices backing tempfs and sysfs + excluded_devices: HashSet, +} + +impl MountInfo { + // Parses file at `path` to build `Self`.` + fn create(path: &str) -> Result { + let buf = read_to_string(path) + .map_err(|e| Error::Read { error: format!("Reading {} failed with: {}", path, e) })?; + Self::with_buf(&buf) + } + + // Parses string in `buf` to build `Self`. + fn with_buf(buf: &str) -> Result { + let regex = Self::get_regex()?; + let mut included_devices: HashMap = HashMap::new(); + let mut excluded_devices = HashSet::new(); + let excluded_filesystem_types: HashSet = + EXCLUDED_FILESYSTEM_TYPES.iter().map(|s| String::from(*s)).collect(); + for line in buf.lines() { + if let Some(state) = Self::parse_line(®ex, &excluded_filesystem_types, line)? { + match state { + DeviceState::Include((device, path)) => { + included_devices.insert(device, path); + } + DeviceState::Exclude(device) => { + excluded_devices.insert(device); + } + } + } + } + + Ok(Self { included_devices, excluded_devices }) + } + + fn parse_line( + re: &Regex, + excluded_filesystem_types: &HashSet, + line: &str, + ) -> Result, Error> { + let caps = match re.captures(line) { + Some(caps) => caps, + None => { + return Ok(None); + } + }; + if &caps["relative_path"] != "/" { + return Ok(None); + } + + let mount_point = &caps["mount_point"]; + let mnt_pnt_with_slash = format!("{}/", mount_point); + let device_number = build_device_number(&caps["major"], &caps["minor"])?; + let fs_type = &caps["fs_type"]; + + if excluded_filesystem_types.contains(fs_type) { + info!( + "excluding fs type: {} for {} mount-point {} slash {}", + fs_type, line, mount_point, mnt_pnt_with_slash + ); + return Ok(Some(DeviceState::Exclude(device_number))); + } + + for excluded in EXCLUDE_PATHS { + if mnt_pnt_with_slash.starts_with(excluded) { + info!( + "exclude-paths fs type: {} for {} mount-point {} slash {}", + fs_type, line, mount_point, mnt_pnt_with_slash + ); + return Ok(Some(DeviceState::Exclude(device_number))); + } + } + + Ok(Some(DeviceState::Include((device_number, PathBuf::from(mount_point))))) + } + + fn get_regex() -> Result { + Regex::new(concat!( + r"^\s*(?P\S+)", + r"\s+(?P\S+)", + r"\s+(?P[0-9]+):(?P[0-9]+)", + r"\s+(?P\S+)", + r"\s+(?P\S+)", + r"\s+(?P\S+)", + r"\s+(?P\S+)", + r"\s+\S+", + r"\s+(?P\S+)", + r"\s+(?P\S+)" + )) + .map_err(|e| Error::Custom { + error: format!("create regex for parsing mountinfo failed with: {}", e), + }) + } + + fn is_excluded(&self, device: &DeviceNumber) -> bool { + self.excluded_devices.contains(device) + } + + fn get_included(&self) -> Iter { + self.included_devices.iter() + } +} + +#[derive(Default, PartialEq, Debug, Eq, Hash)] +struct TraceLineInfo { + device: DeviceNumber, + inode: InodeNumber, + offset: u64, + timestamp: u64, +} + +impl TraceLineInfo { + pub fn from_trace_line(re: &Regex, line: &str) -> Result, Error> { + let caps = match re.captures(line) { + Some(caps) => caps, + None => return Ok(None), + }; + let major = &caps["major"]; + let minor = &caps["minor"]; + let ino = &caps["ino"]; + let offset = &caps["offset"]; + let timestamp = build_timestamp(&caps["seconds"], &caps["microseconds"])?; + Ok(Some(TraceLineInfo { + device: build_device_number(major, minor)?, + inode: u64::from_str_radix(ino, 16).map_err(|e| Error::Custom { + error: format!("failed parsing inode: {} : {}", ino, e), + })?, + offset: offset.parse::().map_err(|e| Error::Custom { + error: format!("failed parsing offset: {} : {}", offset, e), + })?, + timestamp, + })) + } + + #[cfg(test)] + pub fn from_fields( + major: MajorMinorType, + minor: MajorMinorType, + inode: u64, + offset: u64, + timestamp: u64, + ) -> Self { + Self { device: makedev(major, minor), inode, offset, timestamp } + } + + // Convenience function to create regex. Used once per life of `record` but multiple times in + // case of tests. + pub fn get_trace_line_regex() -> Result { + // TODO: Fix this Regex expression for 5.15 kernels. This expression + // works only on 6.1+. Prior to 6.1, "" was present in the output. + Regex::new(concat!( + r"^\s+(?P\S+)", + r"\s+(?P\S+)", + r"\s+(?P\S+)", + r"\s+(?P[0-9]+)\.(?P[0-9]+):", + r"\s+mm_filemap_add_to_page_cache:", + r"\s+dev\s+(?P[0-9]+):(?P[0-9]+)", + r"\s+ino\s+(?P\S+)", + //r"\s+(?P\S+)", + r"\s+(?P\S+)", + r"\s+ofs=(?P[0-9]+)" + )) + .map_err(|e| Error::Custom { + error: format!("create regex for tracing failed with: {}", e), + }) + } +} + +#[derive(Debug, Serialize, Deserialize)] +struct MissingFile { + major_no: MajorMinorType, + minor_no: MajorMinorType, + inode: InodeNumber, + records: Vec, +} + +#[derive(Debug, Default, Deserialize, Serialize)] +struct DebugInfo { + // Check all inodes for which paths don't exists. These are the files which + // * got deleted before we got to them + // * are filesystem internal files that fs access only via inode numbers. + missing_files: HashMap, + + // Number of bytes read that belongs to directory type inodes. + directory_read_bytes: u64, + + // Number of bytes read from files for which we could not find a path in + // the filesystems. + missing_path_bytes: u64, + + // Paths for which the current process doesn't have read permission. + privileged_paths: Vec, +} + +#[derive(Debug, Serialize)] +pub(crate) struct MemTraceSubsystem { + device_inode_map: HashMap>, + // Count of all InodeNumber held by `device_inode_map`. This is handy to assign unique + // FileId. + inode_count: u64, + + // `Record`s built from parsing read trace lines. + records: Vec, + + // Regex to parse lines from trace_pipe. + #[serde(skip_serializing)] + regex: Regex, + + // Mounted devices/filesystems either at the time of parsing trace file or at the time + // of building RecordsFile from parsed lines. + mount_info: MountInfo, + + // A copy of TracerConfigs + tracer_configs: Option, + + // system page size stored to avoid frequent syscall to get the page size. + page_size: u64, + + // The fields of the debug_info are populated when build_records_file is called (after lines + // are parsed from the trace file/pipe). + debug_info: DebugInfo, +} + +impl MemTraceSubsystem { + pub fn update_configs(configs: &mut TracerConfigs) { + for path in EXCLUDE_PATHS { + configs.excluded_paths.push(path.to_owned().to_string()); + } + + for event in TRACE_EVENTS { + configs.trace_events.push(event.to_owned().to_string()); + } + configs.mountinfo_path = Some(MOUNTINFO_PATH.to_string()); + } + + pub fn create_with_configs(tracer_configs: TracerConfigs) -> Result { + static INITIAL_RECORDS_CAPACITY: usize = 100_000; + debug!("TracerConfig: {:#?}", tracer_configs); + + let regex = TraceLineInfo::get_trace_line_regex()?; + let mount_info = MountInfo::create(tracer_configs.mountinfo_path.as_ref().unwrap())?; + debug!("mountinfo: {:#?}", mount_info); + + Ok(Self { + device_inode_map: HashMap::new(), + inode_count: 0, + // For one product of android, we see around 50k records. To avoid a lot allocations + // and copying of records, we create a vec of this size. + // + // We do this to reduces chances of losing data, however unlikely, coming over + // `trace_pipe`. + // + // Note: Once we are done reading trace lines, we are less pedantic about allocations + // and mem copies. + records: Vec::with_capacity(INITIAL_RECORDS_CAPACITY), + regex, + mount_info, + tracer_configs: Some(tracer_configs), + page_size: page_size()? as u64, + debug_info: DebugInfo { + missing_files: HashMap::new(), + directory_read_bytes: 0, + missing_path_bytes: 0, + privileged_paths: vec![], + }, + }) + } + + fn new_file_id(&mut self) -> FileId { + let id = self.inode_count; + self.inode_count += 1; + FileId(id) + } + + fn get_trace_info(&self, line: &str) -> Result, Error> { + TraceLineInfo::from_trace_line(&self.regex, line) + } + + // Returns true if the file or directory is on a device which is excluded from walking. + // If the path was excluded because the current process doesn't have privileged to read it, + // the path gets added to `privileged` list. + fn is_excluded(&self, entry: &DirEntry, device: u64, privileged: &mut Vec) -> bool { + // We skip paths that are reside on excluded devices here. This is ok because a + // non-excluded mount point will have a separate entry in MountInfo. For example + // - `/` has ext4 + // - `/tmp` has tempfs + // - `/tmp/mnt` has ext4 that we are interested in. + // MountInfo will have three entries - `/`, `/tmp/` and `/tmp/mnt`. Skipping walking + // `/tmp` while walking `/` is ok as next `mount_info.get_included()` will return + // `/tmp/mnt` path. + // + // + // We skip links here as they can refer to mount points across + // filesystems. If that path is valid and access are valid, then + // we should have entry by the file's pair. + // + // + // We skip devices that don't match current walking device because we eventually + // walk other devices. + match symlink_metadata(entry.path()) { + Ok(lstat) => { + if self.mount_info.is_excluded(&lstat.dev()) + || lstat.dev() != device + || lstat.file_type().is_symlink() + { + return true; + } + } + Err(e) => { + error!("stat on {} failed with {}", entry.path().to_str().unwrap(), e); + + // We treat EACCES special because on some platforms, like android, process needs to + // have very special set of permissions to access some inodes. + // We ignore errors in such cases *after* making an effort to get to them. + if e.kind() == ErrorKind::PermissionDenied + && is_highly_privileged_path(entry.path()) + { + privileged.push(entry.path().to_owned()); + return true; + } + } + } + + // On error, we return false because if lstat has failed, it will fail following operations + // including stat. + false + } +} + +impl TraceSubsystem for MemTraceSubsystem { + fn add_line(&mut self, line: &str) -> Result<(), Error> { + if let Some(info) = self.get_trace_info(line)? { + if self.mount_info.is_excluded(&info.device) { + return Ok(()); + } + + self.device_inode_map.entry(info.device).or_default(); + + let file_id = if let Some(id) = + self.device_inode_map.get_mut(&info.device).unwrap().get(&info.inode) + { + id.clone() + } else { + self.new_file_id() + }; + self.device_inode_map + .get_mut(&info.device) + .unwrap() + .insert(info.inode, file_id.clone()); + + self.records.push(Record { + file_id, + offset: info.offset, + length: self.page_size, + timestamp: info.timestamp, + }); + } + + Ok(()) + } + + fn build_records_file(&mut self) -> Result { + // reset debug_info in case build_records_file was called twice. + self.debug_info = DebugInfo::default(); + let mut rf = RecordsFile::default(); + let mut directories = HashSet::new(); + + // TODO(b/302194377): We are holding all privileged_paths in this variable and then + // transferring it to `self.debug_info.privileged_paths` later. We can avoid this step + // if we directly update `self.debug_info.privileged_paths`. To do so, we need to refactor + // code to make borrow not complain at several places - ex. immutably borrowing + // `self.mount_info` in outer loop and then mutably borrowing + // `self.debug_info.privileged_paths`. + let mut privileged_paths = vec![]; + + // Reload mount_info. When we created mount_info for the first time, maybe + // the system was in early boot phase. Reload the mount_info so as to get + // current/new mount points. + if let Some(tracer_config) = &self.tracer_configs { + self.mount_info = MountInfo::create(tracer_config.mountinfo_path.as_ref().unwrap())?; + debug!("reloaded mountinfo: {:#?}", self.mount_info); + } + + for (device, root_path) in self.mount_info.get_included() { + let inode_map = if let Some(map) = self.device_inode_map.get(device) { + map + } else { + continue; + }; + + if inode_map.is_empty() { + return Err(Error::Custom { + error: format!("Unexpected empty records for {:?}", root_path), + }); + } + + let mut block_size = 0; + let walker = WalkDir::new(root_path).into_iter(); + + for entry in + walker.filter_entry(|e| !self.is_excluded(e, *device, &mut privileged_paths)) + { + let path = match entry { + Ok(entry) => entry.path().to_owned(), + Err(e) => { + error!("walking directory failed: {} {}", root_path.to_str().unwrap(), e); + continue; + } + }; + + let stat = match path.metadata() { + Ok(stat) => stat, + Err(e) => { + error!("stat on {} failed with {}", path.to_str().unwrap(), e); + continue; + } + }; + + block_size = stat.blksize(); + + let file_id = if let Some(id) = inode_map.get(&stat.ino()) { + id.clone() + } else { + continue; + }; + + // We cannot issue a normal readahead on directories. So we skip those records that + // belong to directories. + if stat.file_type().is_dir() { + info!( + "skipping directory readahead record for file_id:{file_id} ino:{} path:{} ", + stat.ino(), + path.to_str().unwrap() + ); + directories.insert(file_id.clone()); + continue; + } + + rf.insert_or_update_inode(file_id, &stat, path.to_str().unwrap().to_owned()); + } + + rf.inner.filesystems.insert(*device, FsInfo { block_size }); + } + + self.debug_info.privileged_paths.append(&mut privileged_paths); + + for (device, inode_map) in &self.device_inode_map { + for (inode, file_id) in inode_map { + if !rf.inner.inode_map.contains_key(file_id) { + let major_no: MajorMinorType = major(*device); + let minor_no: MajorMinorType = minor(*device); + self.debug_info.missing_files.insert( + file_id.clone(), + MissingFile { major_no, minor_no, inode: *inode, records: vec![] }, + ); + } + } + } + + // Remove all records that belong to directories or for which we did not find paths. + let mut records = vec![]; + for record in take(&mut self.records) { + if directories.contains(&record.file_id) { + self.debug_info.directory_read_bytes += record.length; + } else if let Some(missing_file) = + self.debug_info.missing_files.get_mut(&record.file_id) + { + self.debug_info.missing_path_bytes += record.length; + missing_file.records.push(record); + } else { + records.push(record); + } + } + + warn!( + "Recorded {} bytes worth of data read from directories", + self.debug_info.directory_read_bytes + ); + warn!( + "Recorded {} bytes worth of data read from files that don't have paths", + self.debug_info.missing_path_bytes + ); + + rf.inner.records = coalesce_records(records, true); + + Ok(rf) + } + + fn serialize(&self, write: &mut dyn Write) -> Result<(), Error> { + write + .write_all( + &serde_json::to_vec(&self) + .map_err(|e| Error::Serialize { error: e.to_string() })?, + ) + .map_err(|source| Error::Write { path: "intermediate file".to_owned(), source }) + } +} + +#[cfg(test)] +mod tests { + use nix::sys::stat::{major, minor}; + use std::assert_eq; + use std::path::Path; + + use crate::tracer::tests::{copy_uncached_files_and_record_from, setup_test_dir}; + + use crate::replay::tests::generate_cached_files_and_record; + + use super::*; + + static TRACE_BUFFER: &str = r#" + Settingide-502 [001] .... 484.360292: mm_filemap_add_to_page_CACHE: dev 254:6 ino cf1 page=68d477 pfn=59833 ofs=32768 + Settingide-502 [001] .... 484.360311: mm_filemap_add_to_page_cache: dev 254:6 ino cf1 page=759458 pfn=59827 ofs=57344 + BOX_ENTDED-3071 [001] .... 485.276715: mm_filemap_add_to_pag_ecache: dev 254:6 ino 1 page=00cc1c pfn=81748 ofs=13574144 + BOX_ENTDED-3071 [001] .... 485.276990: mm_filemap_add_to_page_cache: dev 254:6 ino cf2 page=36540b pfn=60952 ofs=0 + .gms.peent-843 [001] .... 485.545516: mm_filemap_add_to_page_cache: dev 254:6 ino 1 page=002e8b pfn=58928 ofs=13578240 + .gms.peent-843 [001] .... 485.545820: mm_filemap_add_to_page_cache: dev 254:6 ino cf3 page=6233ce pfn=58108 ofs=0 + an.bg-459 [001] .... 494.029396: mm_filemap_add_to_page_cache: dev 254:3 ino 7cf page=c5b5c7 pfn=373933 ofs=1310720 + an.bg-459 [001] .... 494.029398: mm_filemap_add_to_page_cache: dev 254:3 ino 7cf page=b8b9ec pfn=410074 ofs=1314816 + "#; + + fn sample_mem_traces() -> (String, Vec>) { + ( + TRACE_BUFFER.to_owned(), + vec![ + None, + None, + Some(TraceLineInfo::from_fields(254, 6, 0xcf1, 57344, 484360311000)), + None, + Some(TraceLineInfo::from_fields(254, 6, 0xcf2, 0, 485276990000)), + Some(TraceLineInfo::from_fields(254, 6, 0x1, 13578240, 485545516000)), + Some(TraceLineInfo::from_fields(254, 6, 0xcf3, 0, 485545820000)), + Some(TraceLineInfo::from_fields(254, 3, 0x7cf, 1310720, 494029396000)), + Some(TraceLineInfo::from_fields(254, 3, 0x7cf, 1314816, 494029398000)), + None, + ], + ) + } + + #[test] + fn test_parse_trace_line() { + let (buf, res) = sample_mem_traces(); + let re = TraceLineInfo::get_trace_line_regex().unwrap(); + for (index, line) in buf.lines().enumerate() { + let found = TraceLineInfo::from_trace_line(&re, line).unwrap(); + let expected = res.get(index).unwrap(); + assert_eq!(found.is_some(), expected.is_some()); + if found.is_some() { + assert_eq!(found.unwrap(), *expected.as_ref().unwrap()); + } + } + } + + #[test] + fn test_add_line() { + let test_base_dir = setup_test_dir(); + let (rf, mut files) = + generate_cached_files_and_record(None, true, Some(page_size().unwrap() as u64)); + let (_uncached_rf, uncached_files) = + copy_uncached_files_and_record_from(Path::new(&test_base_dir), &mut files, &rf); + let mut mount_include = HashMap::new(); + + let included_dev = uncached_files.get(0).unwrap().0.metadata().unwrap().dev(); + let included_inode1 = uncached_files.get(0).unwrap().0.metadata().unwrap().ino(); + let included_inode2 = uncached_files.get(1).unwrap().0.metadata().unwrap().ino(); + let included_major = major(included_dev); + let included_minor = minor(included_dev); + mount_include.insert(included_dev, std::fs::canonicalize(test_base_dir).unwrap()); + let mut mount_exclude = HashSet::new(); + mount_exclude.insert(0); + + let mut mem_tracer = MemTraceSubsystem { + device_inode_map: HashMap::new(), + inode_count: 0, + records: vec![], + regex: TraceLineInfo::get_trace_line_regex().unwrap(), + mount_info: MountInfo { + included_devices: mount_include, + excluded_devices: mount_exclude, + }, + tracer_configs: None, + page_size: page_size().unwrap() as u64, + debug_info: DebugInfo { + missing_files: HashMap::new(), + directory_read_bytes: 0, + missing_path_bytes: 0, + privileged_paths: vec![], + }, + }; + + let pg_size = page_size().unwrap(); + // Format is major, minor, inode, offset + let inputs = vec![ + (0, 0, 2, 10), // to be excluded. bad device. + (included_major, included_minor, included_inode1, 0), + (included_major, included_minor, included_inode1, 3 * pg_size), + // duplicate read + (included_major, included_minor, included_inode1, 3 * pg_size), + (0, 0, included_inode1, 10), // to be excluded. bad device. + (included_major, included_minor, included_inode1, 2 * pg_size), // contiguous + // non-contiguous + (included_major, included_minor, included_inode1, 12 * pg_size), + // same offset different inode + (included_major, included_minor, included_inode2, 3 * pg_size), + // Contiguous offset different inode + (included_major, included_minor, included_inode2, pg_size), + ]; + + for (i, (major, minor, inode, offset)) in inputs.iter().enumerate() { + // used to timestamp the log line. + let seconds = i; + // used to timestamp the log line. + let microseconds = i; + for operation in &["mm_filemap_add_to_page_cache", "some_other_operation"] { + let line = format!( + " BOX_ENTRY_ADDED-3071 [001] .... {}.{}: {}: \ + dev {}:{} ino {:x} page=00000000f936540b pfn=60952 ofs={}", + seconds, microseconds, operation, major, minor, inode, offset + ); + mem_tracer.add_line(&line).unwrap(); + } + } + assert_eq!(mem_tracer.records.len(), 7); + assert_eq!(mem_tracer.device_inode_map.len(), 1); + assert_eq!(mem_tracer.device_inode_map.get(&included_dev).unwrap().len(), 2); + assert!(mem_tracer + .device_inode_map + .get(&included_dev) + .unwrap() + .contains_key(&included_inode1)); + assert!(mem_tracer + .device_inode_map + .get(&included_dev) + .unwrap() + .contains_key(&included_inode2)); + } + + fn new_record(file: u64, offset: u64, length: u64, timestamp: u64) -> Record { + Record { file_id: FileId(file), offset, length, timestamp } + } + + #[test] + fn test_get_records_file() { + let test_base_dir = setup_test_dir(); + let (rf, mut files) = + generate_cached_files_and_record(None, true, Some(page_size().unwrap() as u64)); + let (_uncached_rf, uncached_files) = + copy_uncached_files_and_record_from(Path::new(&test_base_dir), &mut files, &rf); + let mut mount_include = HashMap::new(); + + let included_dev = uncached_files.get(0).unwrap().0.metadata().unwrap().dev(); + let included_inode1 = uncached_files.get(0).unwrap().0.metadata().unwrap().ino(); + let included_inode2 = uncached_files.get(1).unwrap().0.metadata().unwrap().ino(); + let included_major = major(included_dev); + let included_minor = minor(included_dev); + mount_include.insert(included_dev, std::fs::canonicalize(test_base_dir).unwrap()); + let mut mount_exclude = HashSet::new(); + mount_exclude.insert(0); + + let mut mem_tracer = MemTraceSubsystem { + device_inode_map: HashMap::new(), + inode_count: 0, + records: vec![], + regex: TraceLineInfo::get_trace_line_regex().unwrap(), + mount_info: MountInfo { + included_devices: mount_include, + excluded_devices: mount_exclude, + }, + tracer_configs: None, + page_size: page_size().unwrap() as u64, + debug_info: DebugInfo { + missing_files: HashMap::new(), + directory_read_bytes: 0, + missing_path_bytes: 0, + privileged_paths: vec![], + }, + }; + + let pg_size = page_size().unwrap() as u64; + // Format is major, minor, inode, offset + let inputs = vec![ + (0, 0, 2, 10), // to be excluded. bad device. + (included_major, included_minor, included_inode1, 0), + (included_major, included_minor, included_inode1, 3 * pg_size), + // duplicate read + (included_major, included_minor, included_inode1, 3 * pg_size), + (0, 0, included_inode1, 10), // to be excluded. bad device. + (included_major, included_minor, included_inode1, 2 * pg_size), // contiguous + // non-contiguous + (included_major, included_minor, included_inode1, 12 * pg_size), + // same offset different inode + (included_major, included_minor, included_inode2, 3 * pg_size), + // Contiguous offset different inode + (included_major, included_minor, included_inode2, pg_size), + ]; + + for (i, (major, minor, inode, offset)) in inputs.iter().enumerate() { + // used to timestamp the log line. + let seconds = i; + // used to timestamp the log line. + let microseconds = i; + for operation in &["mm_filemap_add_to_page_cache", "some_other_operation"] { + let line = format!( + " BOX_ENTRY_ADDED-3071 [001] .... {}.{}: {}: \ + dev {}:{} ino {:x} page=00000000f936540b pfn=60952 ofs={}", + seconds, microseconds, operation, major, minor, inode, offset + ); + mem_tracer.add_line(&line).unwrap(); + } + } + let rf = mem_tracer.build_records_file().unwrap(); + assert_eq!( + rf.inner.records, + vec![ + new_record(0, 0, pg_size, 1000001000), + new_record(0, 2 * pg_size, 2 * pg_size, 2000002000), + new_record(0, 12 * pg_size, pg_size, 6000006000), + new_record(1, pg_size, pg_size, 8000008000), + new_record(1, 3 * pg_size, pg_size, 7000007000), + ] + ); + } +} diff --git a/init/libprefetch/prefetch/src/tracer/mod.rs b/init/libprefetch/prefetch/src/tracer/mod.rs new file mode 100644 index 000000000..0f1611675 --- /dev/null +++ b/init/libprefetch/prefetch/src/tracer/mod.rs @@ -0,0 +1,965 @@ +// Copyright (C) 2024 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. + +//! Tracer supports collecting information based off of two different tracing +//! subsystems within `/sys/kernel/tracing`. +//! +//! ## Mem +//! Mem is preferred tracer. +//! ### Phase 1: +//! This phase relies on a trace event at +//! "events/filemap/mm_filemap_add_to_page_cache". When enabled, the event logs +//! a message that contains device id, inode number, offset of the page that is +//! being read. The tracer makes a note of this. +//! +//! ### Phase 2: +//! When the recording of events is done, tracer all get mount points for which +//! device id is recorded. Once it knows the mount points, it looks up file +//! paths for the inode numbers that it records. The paths, offset and lengths +//! are then stored in records file. +//! +//! Phase 2 is very IO intensive as entire filesystem is walked to find paths +//! for different inodes. +//! +pub(crate) mod mem; + +use std::{ + boxed::Box, + collections::HashSet, + fs::{create_dir, read_to_string, rename, File, OpenOptions}, + io::{BufRead, BufReader, Read, Write}, + path::{Path, PathBuf}, + string::ToString, + sync::mpsc::{self, Receiver, Sender}, +}; + +use log::{error, info}; +use nix::time::ClockId; +use serde::Deserialize; +use serde::Serialize; + +use crate::error::Error; +use crate::{args::TracerType, format::RecordsFile}; +use mem::MemTraceSubsystem; + +pub(crate) static EXCLUDE_PATHS: &[&str] = + &["/dev/", "/proc/", "/sys/", "/tmp/", "/run/", "/config/", "/mnt/", "/storage/"]; + +/// During record phase, prefetch may modify files under `/sys/kernel/tracing/` to +/// - change trace buffer size so that we don't lose trace events +/// - enable a few trace events +/// - enable tracing +/// +/// The old values are restored at the end of record. +#[derive(Debug, Serialize, Deserialize)] +pub(crate) struct TraceEventFile { + path: PathBuf, + restore_value: Option, +} + +impl TraceEventFile { + fn open_and_write(path: &Path, value: &str) -> Result<(), Error> { + let mut f = OpenOptions::new() + .write(true) + .read(true) + .open(path) + .map_err(|e| Error::Open { source: e, path: path.to_str().unwrap().to_string() })?; + f.write_all(value.as_bytes()) + .map_err(|e| Error::Write { path: path.to_str().unwrap().to_owned(), source: e }) + } + + pub fn write(path: PathBuf, value: &str) -> Result { + let restore_value = read_to_string(&path).map_err(|s| Error::Read { + error: format!("Reading {} failed:{}", path.to_str().unwrap(), s), + })?; + + Self::open_and_write(&path, value)?; + + info!( + "Changed contents of {} from {:?} to {}", + path.to_str().unwrap(), + restore_value, + value + ); + Ok(Self { path, restore_value: Some(restore_value) }) + } + + pub fn enable(path: PathBuf) -> Result { + Self::write(path, "1") + } + + pub fn restore(&self) -> Result<(), Error> { + if let Some(restore_value) = &self.restore_value { + Self::open_and_write(&self.path, restore_value) + } else { + Ok(()) + } + } +} + +impl Drop for TraceEventFile { + fn drop(&mut self) { + if let Err(ret) = self.restore() { + error!( + "Failed to restore state of file {:?} with value: {:?}. Error: {}", + self.path, + self.restore_value, + ret.to_string() + ); + } + } +} + +#[derive(Debug, Deserialize, Serialize)] +pub(crate) struct TracerConfigs { + pub excluded_paths: Vec, + pub buffer_size_file_path: String, + pub trace_base_path: PathBuf, + pub trace_events: Vec, + pub mountinfo_path: Option, + pub trace_operations: HashSet, + // We never read back these fields. The only use for holding these around is to restore state at + // the end of run. + #[allow(dead_code)] + trace_files: Vec, +} + +impl TracerConfigs { + pub fn new( + kb_buffer_size: Option, + setup_tracing: bool, + tracer_type: TracerType, + trace_mount_point: Option, + tracing_instance: Option, + ) -> Result { + static TRACE_MOUNT_POINT: &str = "/sys/kernel/tracing"; + + // Trace buffer size file relative to trace mount point + static TRACE_BUFFER_SIZE_FILE: &str = "buffer_size_kb"; + + let trace_mount_point = trace_mount_point.unwrap_or_else(|| TRACE_MOUNT_POINT.to_owned()); + let trace_base_path = if let Some(instance) = tracing_instance { + Path::new(&trace_mount_point).join("instances").join(instance) + } else { + Path::new(&trace_mount_point).to_owned() + }; + + if setup_tracing && !trace_base_path.exists() { + create_dir(&trace_base_path).map_err(|e| Error::Create { + source: e, + path: trace_base_path.to_str().unwrap().to_owned(), + })?; + } + + if !trace_base_path.exists() { + return Err(Error::Custom { + error: format!( + "trace mount point doesn't exist: {}", + trace_base_path.to_str().unwrap().to_owned() + ), + }); + } + + let mut configs = TracerConfigs { + excluded_paths: vec![], + buffer_size_file_path: TRACE_BUFFER_SIZE_FILE.to_owned(), + trace_base_path, + trace_events: vec![], + mountinfo_path: None, + trace_operations: HashSet::new(), + trace_files: vec![], + }; + + match tracer_type { + TracerType::Mem => MemTraceSubsystem::update_configs(&mut configs), + } + + if setup_tracing { + let trace_base_dir = Path::new(&configs.trace_base_path); + if let Some(kb_buffer_size) = kb_buffer_size { + configs.trace_files.push(TraceEventFile::write( + trace_base_dir.join(&configs.buffer_size_file_path), + &kb_buffer_size.to_string(), + )?); + } + for path in &configs.trace_events { + configs.trace_files.push(TraceEventFile::enable(trace_base_dir.join(path))?); + } + } + + Ok(configs) + } +} + +/// Returns time, in nanoseconds, since boot +pub fn nanoseconds_since_boot() -> u64 { + if let Ok(t) = nix::time::clock_gettime(ClockId::CLOCK_MONOTONIC) { + //((t.tv_sec() * 1_000_000_000) + t.tv_nsec()) as u64 + (1 + t.tv_nsec()) as u64 + } else { + 0 + } +} + +pub(crate) trait TraceSubsystem { + /// This routine is called whenever there is a new line available to be parsed. + /// The impl potentially want to parse the line and retain the data in memory. + /// Implementors are not expected to do heavy lifting tasks, like IO, in this context. + fn add_line(&mut self, line: &str) -> Result<(), Error>; + + /// Generates a records file from all the collected data. + /// From this context, the implementors might process data by issuing queries to filesystems. + fn build_records_file(&mut self) -> Result; + + /// This helps us serialize internat state of tracing subsystem during record phase. + /// This allows us to get raw data for analysis of read pattern and debugging in situations + /// when we might not have access to system yet(ex. early boot phase) . + fn serialize(&self, writer: &mut dyn Write) -> Result<(), Error>; +} + +/// Returns page size in bytes +pub(crate) fn page_size() -> Result { + Ok(nix::unistd::sysconf(nix::unistd::SysconfVar::PAGE_SIZE) + .map_err(|e| Error::Custom { error: format!("failed to query page size: {}", e) })? + .ok_or(Error::Custom { error: "failed to query page size: None returned".to_string() })? + as usize) +} + +pub struct Tracer { + // Open handle to static trace buffer file which is usually located at + // `/sys/kernel/tracing/trace`. + // See comment on top of `trace` function. + trace_file: BufReader, + + // Open handle to trace pipe which is usually located at + // `/sys/kernel/tracing/trace_pipe`. + // See comment on top of `trace` function. + trace_pipe: BufReader, + + // Signal to exit the infinite loop in `trace()` + exit_rx: Receiver<()>, + + // tracing subsystem that actually parses trace lines and builds records. + tracing_subsystem: Box, +} + +impl Tracer { + pub fn create( + kb_buffer_size: Option, + tracer_type: TracerType, + tracing_instance: Option, + setup_tracing: bool, + ) -> Result<(Self, Sender<()>), Error> { + /// Trace pipe path relative to trace mount point + static TRACE_PIPE_PATH: &str = "trace_pipe"; + + /// Trace file path relative to trace mount point + static TRACE_FILE_PATH: &str = "trace"; + + let configs = TracerConfigs::new( + kb_buffer_size, + setup_tracing, + tracer_type.clone(), + None, + tracing_instance, + )?; + + let pipe_path = Path::new(&configs.trace_base_path).join(TRACE_PIPE_PATH); + let trace_pipe = File::open(&pipe_path) + .map_err(|e| Error::Open { source: e, path: pipe_path.to_str().unwrap().to_owned() })?; + + let file_path = Path::new(&configs.trace_base_path).join(TRACE_FILE_PATH); + let trace_file = File::open(&file_path) + .map_err(|e| Error::Open { source: e, path: file_path.to_str().unwrap().to_owned() })?; + let tracer: Box = match tracer_type { + TracerType::Mem => Box::new(MemTraceSubsystem::create_with_configs(configs)?), + }; + + Self::create_with_config(trace_file, trace_pipe, tracer) + } + + fn create_with_config( + file: File, + pipe: File, + tracer: Box, + ) -> Result<(Self, Sender<()>), Error> { + let (exit_tx, exit_rx) = mpsc::channel(); + let trace_pipe = BufReader::new(pipe); + let trace_file = BufReader::new(file); + + Ok((Self { trace_file, trace_pipe, exit_rx, tracing_subsystem: tracer }, exit_tx)) + } + + fn save_intermediate_state(&self, intermediate_file: Option<&PathBuf>) -> Result<(), Error> { + if let Some(int_path) = intermediate_file { + let mut tmp_file = int_path.clone(); + tmp_file.set_extension("int.tmp"); + let mut out_file = File::create(&tmp_file).map_err(|source| Error::Create { + source, + path: int_path.to_str().unwrap().to_owned(), + })?; + self.tracing_subsystem.serialize(&mut out_file)?; + rename(&tmp_file, int_path).map_err(|e| Error::Custom { + error: format!( + "rename file from{} to:{} failed with {}", + tmp_file.to_str().unwrap(), + int_path.to_str().unwrap(), + e + ), + })?; + } + Ok(()) + } + + /// This routine parses all the events since last reset of trace buffer. + /// + /// The linux tracing subsystem exposes two interfaces to get trace events from + /// 1. a file - usually at `/sys/kernel/tracing/trace` + /// 2. a pipe - usually at `/sys/kernel/tracing/trace_pipe` + /// + /// The file is *sort of* ring buffer which works off of `buffer_size_kb` sized buffer. + /// Relying on it is not very efficient as we end up getting a lot of duplicates. + /// + /// The pipe only contains line traces. Any trace events that occurred before opening + /// of this file are lost. + /// + /// IMPORTANT: The moment we start reading from the pipe, the events in the file + /// disappear/reset. So we should read file entirely before we start reading the pipe. + pub fn trace(&mut self, intermediate_file: Option<&PathBuf>) -> Result { + let mut buf = String::new(); + self.trace_file + .read_to_string(&mut buf) + .map_err(|e| Error::Read { error: format!("failed to read trace file: {}", e) })?; + + for line in buf.lines() { + let trimmed = line.trim_end(); + self.tracing_subsystem.add_line(trimmed)?; + } + + // The logic here is to block on trace_pipe forever. We break out of loop only when we read + // a line from the pipe *and* we have received an event on exit_rx. + // This logic works because the system will have one or more read syscalls and also we, + // at the moment, use prefetch on build systems and not in production to generate records + // file. + // + // TODO(b/302045304): async read trace_pipe. + while self.exit_rx.try_recv().is_err() { + let mut line = String::new(); + let len = self + .trace_pipe + .read_line(&mut line) + .map_err(|e| Error::Read { error: e.to_string() })?; + let trimmed = line.trim_end(); + if len == 0 { + // We should never read zero length line or reach EOF of the pipe. + return Err(Error::Read { + error: "read zero length line from trace_pipe".to_string(), + }); + } + self.tracing_subsystem.add_line(trimmed)?; + } + + // We are here because the above loop exited normally. Traced lines are stored in `Self`. + // Build `RecordsFile` from processing data from read lines above. + self.save_intermediate_state(intermediate_file)?; + let rf = self.tracing_subsystem.build_records_file()?; + self.save_intermediate_state(intermediate_file)?; + Ok(rf) + } +} + +#[cfg(test)] +pub(crate) mod tests { + use crate::RecordsFile; + + use std::alloc::Layout; + use std::borrow::ToOwned; + use std::convert::TryInto; + use std::fs::{create_dir_all, OpenOptions}; + use std::io::Read; + use std::io::Seek; + use std::io::Write; + use std::ops::Range; + use std::os::linux::fs::MetadataExt; + use std::os::unix::fs::symlink; + use std::os::unix::prelude::OpenOptionsExt; + use std::path::Path; + use std::thread; + use std::time::Duration; + use std::{assert_eq, env}; + + use libc::O_DIRECT; + use nix::sys::stat::{major, minor}; + use nix::unistd::pipe; + use rand::distributions::Alphanumeric; + use rand::Rng; + use tempfile::NamedTempFile; + + use super::*; + use crate::replay::tests::generate_cached_files_and_record; + use std::ops::{Deref, DerefMut}; + + #[test] + fn trace_event_file_enable_and_restore() { + let mut file = NamedTempFile::new().unwrap(); + let _ = file.write("0".as_bytes()).unwrap(); + { + let _e = TraceEventFile::enable(file.path().to_owned()).unwrap(); + assert_eq!(read_to_string(file.path()).unwrap(), "1"); + } + assert_eq!(read_to_string(file.path()).unwrap(), "0"); + } + + #[test] + fn trace_event_file_write_and_restore() { + let mut file = NamedTempFile::new().unwrap(); + let _ = file.write("hello".as_bytes()).unwrap(); + { + let _e = TraceEventFile::write(file.path().to_owned(), "world").unwrap(); + assert_eq!(read_to_string(file.path()).unwrap(), "world"); + } + assert_eq!(read_to_string(file.path()).unwrap(), "hello"); + } + + fn setup_trace_mount_point( + create_mount_point: bool, + create_instances: bool, + instance_name: Option, + ) -> PathBuf { + assert!( + create_mount_point || !create_instances, + "cannot create instances without creating mount point" + ); + + let mount_point = env::temp_dir().join( + rand::thread_rng() + .sample_iter(&Alphanumeric) + .take(10) + .map(char::from) + .collect::(), + ); + + let mut base_path = Path::new(&mount_point).to_owned(); + if create_mount_point { + create_dir(&mount_point).unwrap(); + } + + if create_instances { + base_path = base_path.join("instances"); + if let Some(instance_name) = &instance_name { + base_path = base_path.join(instance_name) + } + create_dir_all(&base_path).unwrap(); + } + + if create_mount_point || create_instances { + std::fs::write(&base_path.join("buffer_size_kb"), "100").unwrap(); + std::fs::write(&base_path.join("tracing_on"), "0").unwrap(); + std::fs::write(&base_path.join("trace"), "0").unwrap(); + std::fs::write(&base_path.join("trace_pipe"), "0").unwrap(); + + for event in [ + "events/fs/do_sys_open", + "events/fs/open_exec", + "events/fs/uselib", + "events/filemap/mm_filemap_add_to_page_cache", + ] { + let event_path = base_path.join(event); + std::fs::create_dir_all(&event_path).unwrap(); + std::fs::write(&event_path.join("enable"), "0").unwrap(); + } + } + mount_point + } + + #[test] + fn test_configs_no_setup() { + let mount_point = setup_trace_mount_point(true, true, None); + let _configs = TracerConfigs::new( + Some(10), + false, + TracerType::Mem, + Some(mount_point.to_str().unwrap().to_owned()), + None, + ) + .unwrap(); + } + + #[test] + fn test_configs_no_setup_no_mount_point() { + let mount_point = setup_trace_mount_point(false, false, None); + assert_eq!( + TracerConfigs::new( + Some(10), + false, + TracerType::Mem, + Some(mount_point.to_str().unwrap().to_owned()), + None, + ) + .unwrap_err() + .to_string(), + format!( + "Failed to setup prefetch: trace mount point doesn't exist: {}", + mount_point.to_str().unwrap() + ) + ); + } + + #[test] + fn test_configs_no_setup_no_instances() { + let mount_point = setup_trace_mount_point(true, false, None); + assert_eq!( + TracerConfigs::new( + Some(10), + false, + TracerType::Mem, + Some(mount_point.to_str().unwrap().to_owned()), + Some("my_instance".to_owned()), + ) + .unwrap_err() + .to_string(), + format!( + "Failed to setup prefetch: trace mount point doesn't exist: {}/instances/my_instance", + mount_point.to_str().unwrap() + ) + ); + } + + #[test] + fn test_configs_setup_without_instances() { + let mount_point = setup_trace_mount_point(true, false, None); + assert!(TracerConfigs::new( + Some(10), + true, + TracerType::Mem, + Some(mount_point.to_str().unwrap().to_owned()), + None + ) + .is_ok()); + } + + #[test] + fn test_configs_setup_with_instances() { + let mount_point = setup_trace_mount_point(true, true, Some("my_instance".to_owned())); + assert!(TracerConfigs::new( + Some(10), + true, + TracerType::Mem, + Some(mount_point.to_str().unwrap().to_owned()), + Some("my_instance".to_owned()) + ) + .is_ok()) + } + + pub(crate) fn setup_test_dir() -> PathBuf { + let test_base_dir: String = rand::thread_rng() + .sample_iter(&rand::distributions::Alphanumeric) + .take(7) + .map(char::from) + .collect(); + let test_base_dir = format!( + "{}/test/{}", + std::fs::read_link("/proc/self/exe").unwrap().parent().unwrap().to_str().unwrap(), + test_base_dir + ); + std::fs::create_dir_all(&test_base_dir).unwrap(); + PathBuf::from(test_base_dir) + } + + fn modify_records_file(rf: &RecordsFile, target: &str) -> RecordsFile { + let mut modified_rf = rf.clone(); + + for inode in modified_rf.inner.inode_map.values_mut() { + let new_paths: Vec = inode + .paths + .iter() + .map(|s| { + let parent = Path::new(s).parent().unwrap().to_str().unwrap(); + s.replace(parent, target) + }) + .collect(); + + inode.paths = new_paths; + } + + modified_rf + } + + struct AlignedBuffer { + ptr: *mut u8, + len: usize, + layout: Layout, + } + + impl AlignedBuffer { + fn new(size: usize, alignment: usize) -> Result { + if size == 0 { + return Err(Error::Custom { error: "cannot allocate zero bytes".to_string() }); + } + + let layout = Layout::from_size_align(size, alignment).unwrap(); + // SAFETY: + // - `size` is a valid non-zero positive integer representing the desired buffer size. + // - The layout is checked for validity using `.unwrap()`. + let ptr = unsafe { std::alloc::alloc(layout) }; + if ptr.is_null() { + return Err(Error::Custom { error: format!("alloc failed: size: {}", size) }); + } + Ok(AlignedBuffer { ptr, len: size, layout }) + } + } + + impl Deref for AlignedBuffer { + type Target = [u8]; + // SAFETY: + // - self.ptr is a valid pointer obtained from a successful allocation in the new() method. + // - self.len is a valid length used for allocation in the new() method. + fn deref(&self) -> &Self::Target { + unsafe { std::slice::from_raw_parts(self.ptr, self.len) } + } + } + + impl DerefMut for AlignedBuffer { + // SAFETY: + // - self.ptr is a valid pointer obtained from a successful allocation in the new() method. + // - self.len is a valid length used for allocation in the new() method. + fn deref_mut(&mut self) -> &mut Self::Target { + unsafe { std::slice::from_raw_parts_mut(self.ptr, self.len) } + } + } + + impl Drop for AlignedBuffer { + fn drop(&mut self) { + // SAFETY: + // - self.ptr is a valid pointer obtained from a successful allocation in the new() method. + // - self.layout is the Layout used to allocate the memory. + unsafe { + std::alloc::dealloc(self.ptr, self.layout); + } + } + } + + // Copies `files` into directory pointed by `base`. + // + // The newly created file's data is potentially uncached - i.e. the new + // files are opened in O_DIRECT. + // + // WARNING: Though this function makes an attempt to copy into uncached files + // but it cannot guarantee as other processes in the system may access the + // files. This may lead to flaky tests or unexpected results. + pub(crate) fn copy_uncached_files_and_record_from( + base: &Path, + files: &mut [(NamedTempFile, Vec>)], + rf: &RecordsFile, + ) -> (RecordsFile, Vec<(PathBuf, Vec>)>) { + let mut new_files = vec![]; + for (in_file, ranges) in files { + let out_path = base.join(in_file.path().file_name().unwrap()); + let mut out_file = OpenOptions::new() + .read(true) + .write(true) + .custom_flags(O_DIRECT) + .create_new(true) + .open(&out_path) + .expect("Can't open"); + let page_size = page_size().unwrap() as u64; + let in_file_size = in_file.metadata().unwrap().len(); + assert_eq!( + in_file_size % page_size, + 0, + "we create files that are aligned to page size" + ); + let out_file_size = in_file_size; + let mut buf = + AlignedBuffer::new(out_file_size.try_into().unwrap(), page_size as usize).unwrap(); + let _ = in_file.read(&mut *buf).unwrap(); + out_file.write_all(&*buf).unwrap(); + + new_files.push((out_path, ranges.clone())); + } + + for inode in rf.inner.inode_map.values() { + for path in &inode.paths { + let in_path = Path::new(&path); + let out_path = base.join(in_path.file_name().unwrap()); + if !out_path.exists() { + let orig_file = + out_path.file_name().unwrap().to_str().unwrap().replace("-symlink", ""); + symlink(orig_file, out_path.to_str().unwrap()).unwrap(); + new_files.push((out_path.to_owned(), vec![])); + } + } + } + let modified_rf = modify_records_file(rf, base.to_str().unwrap()); + (modified_rf, new_files) + } + + // Generates mem trace string from given args. Sometimes injects lines that are of no importance + fn mem_generate_trace_line_for_open(path: &Path, time: u16, _op: Option<&str>) -> Vec { + let op = "mm_filemap_add_to_page_cache"; + let stat = path.metadata().unwrap(); + let major_no = major(stat.st_dev()); + let minor_no = minor(stat.st_dev()); + let inode_number = stat.st_ino(); + + vec![ + // unknown operation + format!( + " SettingsProvide-502 [001] .... {}.{}: {}: dev {}:{} ino {:x} \ + page=000000008b759458 pfn=59827 ofs=0", + time, + (time * 100) + time, + "unknown_operation", + major_no, + minor_no, + inode_number, + ), + // invalid/relative inode + format!( + " SettingsProvide-502 [001] .... {}.{}: {}: dev {}:{} ino {:x} \ + page=000000008b759458 pfn=59827 ofs=0", + time, + (time * 100) + time, + "unknown_operation", + major_no, + minor_no, + inode_number + 100, + ), + // good one + format!( + " BOX_ENTRY_ADDED-3071 [001] .... {}.{}: {}: dev {}:{} ino {:x} \ + page=00000000f936540b pfn=60952 ofs={}", + time, + (time * 100) + time, + op, + major_no, + minor_no, + inode_number, + 0 + ), + // good one + format!( + " BOX_ENTRY_ADDED-3071 [001] .... {}.{}: {}: dev {}:{} ino {:x} \ + page=00000000f936540b pfn=60952 ofs={}", + time, + (time * 100) + time, + op, + major_no, + minor_no, + inode_number, + 10_000, + ), + // good one + format!( + " BOX_ENTRY_ADDED-3071 [001] .... {}.{}: {}: dev {}:{} ino {:x} \ + page=00000000f936540b pfn=60952 ofs={}", + time, + (time * 100) + time, + op, + major_no, + minor_no, + inode_number, + 100_000, + ), + // good one + format!( + " BOX_ENTRY_ADDED-3071 [001] .... {}.{}: {}: dev {}:{} ino {:x} \ + page=00000000f936540b pfn=60952 ofs={}", + time, + (time * 100) + time, + op, + major_no, + minor_no, + inode_number, + 1_000_000, + ), + // invalid operation case + format!( + " SettingsProvide-502 [001] .... {}.{}: {}: dev {}:{} ino {:x} \ + page=000000008b759458 pfn=59827 ofs=0", + time, + (time * 100) + time, + op.to_uppercase(), + major_no, + minor_no, + inode_number, + ), + ] + } + + fn generate_trace_line_for_open( + tracing_type: TracerType, + path: &Path, + time: u16, + op: Option<&str>, + ) -> Vec { + match tracing_type { + TracerType::Mem => mem_generate_trace_line_for_open(path, time, op), + } + } + + // Generates a fake mountinfo file with bunch of fake mount point and + // fakes given path as a mount point. + fn create_fake_mountinfo_for(path: &Path) -> NamedTempFile { + let stat = path.metadata().unwrap(); + let major_no = major(stat.st_dev()); + let minor_no = minor(stat.st_dev()); + let mut mountinfo_path = NamedTempFile::new().unwrap(); + mountinfo_path + .write_all( + "16 15 0:17 / /dev/pts rw,relatime shared:3 - devpts devpts \ + rw,seclabel,mode=600,ptmxmode=000\n" + .as_bytes(), + ) + .unwrap(); + mountinfo_path + .write_all( + "17 26 0:18 / /proc rw,relatime shared:4 - proc proc rw,gid=3009,hidepid=\ + invisible\n" + .as_bytes(), + ) + .unwrap(); + mountinfo_path + .write_all( + format!( + "26 24 {}:{} / {} ro,nodev,noatime shared:1 - ext4 /dev/block/dm-3 ro,\ + seclabel,errors=panic\n", + major_no, + minor_no, + path.to_str().unwrap(), + ) + .as_bytes(), + ) + .unwrap(); + + mountinfo_path + } + + static RECORD_PER_FILE: usize = 4; + + fn create_tracer( + base_dir: &Path, + t: TracerType, + ) -> (Box, Vec) { + let kb_buffer_size = Some(8388608); + let trace_mount_point = setup_test_dir(); + let mut buffer_size_file = NamedTempFile::new_in(&trace_mount_point).unwrap(); + buffer_size_file + .write_all(format!("{}", kb_buffer_size.as_ref().unwrap()).as_bytes()) + .unwrap(); + + let buffer_size_file_path = buffer_size_file.path().to_str().unwrap().to_string(); + let mut config = TracerConfigs::new( + kb_buffer_size, + false, + t.clone(), + Some(trace_mount_point.to_str().unwrap().to_string()), + None, + ) + .unwrap(); + let mut tempfiles = vec![buffer_size_file]; + ( + match t { + TracerType::Mem => { + let mountinfo_path = + create_fake_mountinfo_for(&base_dir.canonicalize().unwrap()); + config.trace_events = vec![]; + config.buffer_size_file_path = buffer_size_file_path; + config.mountinfo_path = + Some(mountinfo_path.path().to_str().unwrap().to_string()); + tempfiles.push(mountinfo_path); + Box::new(MemTraceSubsystem::create_with_configs(config).unwrap()) + } + }, + tempfiles, + ) + } + + fn test_trace_of_type(tracing_type: TracerType) { + let test_base_dir = setup_test_dir(); + let (_rf, files) = generate_cached_files_and_record( + Some(&test_base_dir), + true, + Some(page_size().unwrap() as u64), + ); + + let mut file = NamedTempFile::new().unwrap(); + let (reader_fd, writer_fd) = pipe().unwrap(); + let reader = File::from(reader_fd); + let mut writer = File::from(writer_fd); + + let (tracer, _temp_files) = create_tracer(&test_base_dir, tracing_type.clone()); + + let mut files_iter = files.iter(); + + for line in generate_trace_line_for_open( + tracing_type.clone(), + files_iter.next().unwrap().0.path(), + 5, + None, + ) { + writeln!(file, "{}", line).unwrap(); + } + file.sync_all().unwrap(); + file.seek(std::io::SeekFrom::Start(0)).unwrap(); + + let (mut tracer, exit_evt) = + Tracer::create_with_config(file.reopen().unwrap(), reader, tracer).unwrap(); + + let thd = thread::spawn(move || tracer.trace(None)); + + for (index, file) in files_iter.enumerate() { + for line in generate_trace_line_for_open(tracing_type.clone(), file.0.path(), 10, None) + { + writeln!(&mut writer, "{}", line).unwrap(); + } + if index == 0 { + // This sleep emulates delay in data arriving over a pipe. This shouldn't cause + // flakes in virtualized environment. + thread::sleep(Duration::from_secs(1)); + } + } + + thread::sleep(Duration::from_millis(100)); + exit_evt.send(()).unwrap(); + writeln!(&mut writer, "line").unwrap(); + + let tracer_rf = thd.join().unwrap().unwrap(); + + let mut found_count = 0; + for file in &files { + let mut found = false; + 'inner: for inode in tracer_rf.inner.inode_map.values() { + for found_path in &inode.paths { + if found_path == file.0.path().canonicalize().unwrap().to_str().unwrap() { + found = true; + break 'inner; + } + } + } + if found { + found_count += 1; + } else { + println!("missing {:?}", file.0.path()); + } + } + assert_eq!(found_count, files.len()); + assert_eq!(tracer_rf.inner.records.len(), files.len() * RECORD_PER_FILE); + } + + #[test] + fn test_trace_mem() { + test_trace_of_type(TracerType::Mem) + } +} From d5c8b0bddf7fd6280c3bb9ffb43b6c4b69859b9b Mon Sep 17 00:00:00 2001 From: Alice Wang Date: Wed, 20 Nov 2024 08:32:40 +0000 Subject: [PATCH 151/183] Remove |ro.hardware.| prefix in KM VM sys property As per comment in aosp/3342288 Bug: 368502791 Test: launch_cvd --secure_hals=guest_keymint_trusty_insecure Test: atest VtsAidlSharedSecretTargetTest Change-Id: I71b6266fbd480c0ebe2a7946adadd88f38afb3e7 --- ...are.security.keymint-service.rust.trusty.system.nonsecure.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc index 410e10a61..e5806510f 100644 --- a/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc +++ b/trusty/keymint/android.hardware.security.keymint-service.rust.trusty.system.nonsecure.rc @@ -11,7 +11,7 @@ service system.keymint.rust-trusty.nonsecure \ # Only starts the non-secure KeyMint HALs when the KeyMint VM feature is enabled # TODO(b/357821690): Start the KeyMint HALs when the KeyMint VM is ready once the Trusty VM # has a mechanism to notify the host. -on late-fs && property:ro.hardware.trusty.security_vm.keymint.enabled=1 && \ +on late-fs && property:trusty.security_vm.keymint.enabled=1 && \ property:trusty.security_vm.vm_cid=* setprop system.keymint.trusty_ipc_dev VSOCK:${trusty.security_vm.vm_cid}:1 start system.keymint.rust-trusty.nonsecure From e2efde3746304d5d1e7857113e99a8d9e5350e4a Mon Sep 17 00:00:00 2001 From: Inseob Kim Date: Wed, 20 Nov 2024 17:56:20 +0900 Subject: [PATCH 152/183] Use genfs labels version library Instead of hard-coding the text path everywhere, this uses a library to get the genfs labels version. As genfs labels affect SELinux, this also adds logs to help debug issues. Bug: 378805380 Test: boot and check log Change-Id: I843c97cbeb0c211c67e0172458a4f0d236cf1f06 --- init/Android.bp | 1 + init/selinux.cpp | 22 +++++----------------- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index 4025a6ba4..4ee3be222 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -176,6 +176,7 @@ libinit_cc_defaults { "libxml2", "lib_apex_manifest_proto_lite", "update_metadata-protos", + "libgenfslabelsversion.ffi", ], shared_libs: [ "libbase", diff --git a/init/selinux.cpp b/init/selinux.cpp index 5ced0b81a..6316b4deb 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -69,6 +69,7 @@ #include #include #include +#include #include #include #include @@ -190,22 +191,6 @@ bool GetVendorMappingVersion(std::string* plat_vers) { return true; } -int GetVendorGenfsVersion() { - std::string line; - if (!ReadFirstLine("/vendor/etc/selinux/genfs_labels_version.txt", &line)) { - PLOG(ERROR) << "Failed to read /vendor/etc/selinux/genfs_labels_version.txt; assuming it's " - "202404"; - return 202404; - } - int version; - if (!ParseInt(line, &version)) { - PLOG(ERROR) << "Failed to parse the genfs labels version " << line - << "; assuming it's 202404"; - return 202404; - } - return version; -} - constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; bool IsSplitPolicyDevice() { @@ -342,11 +327,14 @@ bool OpenSplitPolicy(PolicyFile* policy_file) { std::vector genfs_cil_files; - int vendor_genfs_version = GetVendorGenfsVersion(); + int vendor_genfs_version = get_genfs_labels_version(); std::string genfs_cil_file = std::format("/system/etc/selinux/plat_sepolicy_genfs_{}.cil", vendor_genfs_version); if (access(genfs_cil_file.c_str(), F_OK) != 0) { + LOG(INFO) << "Missing " << genfs_cil_file << "; skipping"; genfs_cil_file.clear(); + } else { + LOG(INFO) << "Using " << genfs_cil_file << " for genfs labels"; } // clang-format off From 3e7c17a8e7ad7275ea3a65642608b1c0becb38ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maciej=20=C5=BBenczykowski?= Date: Wed, 20 Nov 2024 19:37:05 +0000 Subject: [PATCH 153/183] Reapply "libprocessgroup: Remove __BEGIN_DECLS and __END_DECLS" MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This reverts commit fdaaef95238d1de873040482938585cb01f724d6. Reason for revert: should be safe to reapply post https://android-review.git.corp.google.com/c/platform/packages/modules/Connectivity/+/3369257 Test: TreeHugger Bug: 379796721 Signed-off-by: Maciej Å»enczykowski Change-Id: I1a24791713484461345312a34777c2266e443cee --- libprocessgroup/include/processgroup/processgroup.h | 8 -------- 1 file changed, 8 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index d27b56895..6a026a717 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -16,7 +16,6 @@ #pragma once -#include #include #include #include @@ -24,8 +23,6 @@ #include #include -__BEGIN_DECLS - static constexpr std::string CGROUPV2_HIERARCHY_NAME = "cgroup2"; bool CgroupsAvailable(); @@ -39,8 +36,6 @@ bool SetTaskProfiles(pid_t tid, const std::vector& profiles, bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles); bool SetUserProfiles(uid_t uid, const std::vector& profiles); -__END_DECLS - bool SetTaskProfiles(pid_t tid, std::initializer_list profiles, bool use_fd_cache = false); bool SetProcessProfiles(uid_t uid, pid_t pid, std::initializer_list profiles); @@ -50,7 +45,6 @@ bool SetTaskProfiles(pid_t tid, std::span profiles, bool SetProcessProfiles(uid_t uid, pid_t pid, std::span profiles); #endif -__BEGIN_DECLS #ifndef __ANDROID_VNDK__ @@ -96,5 +90,3 @@ bool getAttributePathForTask(const std::string& attr_name, pid_t tid, std::strin bool isProfileValidForProcess(const std::string& profile_name, uid_t uid, pid_t pid); #endif // __ANDROID_VNDK__ - -__END_DECLS From 7bb484d405b42080e3bd08d9890d84d505ca5271 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Wed, 20 Nov 2024 13:07:26 -0800 Subject: [PATCH 154/183] snapuserd: Lock the buffer during snapshot-merge Bug: 377819507 Test: Incremental OTA on Pixel Change-Id: I08fa7129282cc005a565987856166088c092f40a Signed-off-by: Akilesh Kailash --- .../user-space-merge/merge_worker.cpp | 16 +++++++++ .../user-space-merge/snapuserd_core.h | 4 +++ .../user-space-merge/snapuserd_readahead.cpp | 35 +++++++++++-------- 3 files changed, 41 insertions(+), 14 deletions(-) diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp index a0c5c6658..febb4847d 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/merge_worker.cpp @@ -233,6 +233,11 @@ bool MergeWorker::MergeOrderedOpsAsync() { return false; } + std::optional> buffer_lock; + // Acquire the buffer lock at this point so that RA thread + // doesn't step into this buffer. See b/377819507 + buffer_lock.emplace(snapuserd_->GetBufferLock()); + snapuserd_->SetMergeInProgress(ra_block_index_); loff_t offset = 0; @@ -383,6 +388,9 @@ bool MergeWorker::MergeOrderedOpsAsync() { // Mark the block as merge complete snapuserd_->SetMergeCompleted(ra_block_index_); + // Release the buffer lock + buffer_lock.reset(); + // Notify RA thread that the merge thread is ready to merge the next // window snapuserd_->NotifyRAForMergeReady(); @@ -415,6 +423,11 @@ bool MergeWorker::MergeOrderedOps() { return false; } + std::optional> buffer_lock; + // Acquire the buffer lock at this point so that RA thread + // doesn't step into this buffer. See b/377819507 + buffer_lock.emplace(snapuserd_->GetBufferLock()); + snapuserd_->SetMergeInProgress(ra_block_index_); loff_t offset = 0; @@ -468,6 +481,9 @@ bool MergeWorker::MergeOrderedOps() { // Mark the block as merge complete snapuserd_->SetMergeCompleted(ra_block_index_); + // Release the buffer lock + buffer_lock.reset(); + // Notify RA thread that the merge thread is ready to merge the next // window snapuserd_->NotifyRAForMergeReady(); 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 c7de9951f..2340b0b20 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_core.h @@ -186,6 +186,7 @@ class SnapshotHandler : public std::enable_shared_from_this { bool IsIouringSupported(); bool CheckPartitionVerification(); + std::mutex& GetBufferLock() { return buffer_lock_; } private: bool ReadMetadata(); @@ -216,6 +217,9 @@ class SnapshotHandler : public std::enable_shared_from_this { std::mutex lock_; std::condition_variable cv; + // Lock the buffer used for snapshot-merge + std::mutex buffer_lock_; + void* mapped_addr_; size_t total_mapped_addr_length_; diff --git a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp index 3007d45f4..c7ae51926 100644 --- a/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp +++ b/fs_mgr/libsnapshot/snapuserd/user-space-merge/snapuserd_readahead.cpp @@ -706,25 +706,32 @@ bool ReadAhead::ReadAheadIOStart() { return false; } - // Copy the data to scratch space - memcpy(metadata_buffer_, ra_temp_meta_buffer_.get(), snapuserd_->GetBufferMetadataSize()); - memcpy(read_ahead_buffer_, ra_temp_buffer_.get(), total_blocks_merged_ * BLOCK_SZ); + // Acquire buffer lock before doing memcpy to the scratch buffer. Although, + // by now snapshot-merge thread shouldn't be working on this scratch space + // but we take additional measure to ensure that the buffer is not being + // used by the merge thread at this point. see b/377819507 + { + std::lock_guard buffer_lock(snapuserd_->GetBufferLock()); + // Copy the data to scratch space + memcpy(metadata_buffer_, ra_temp_meta_buffer_.get(), snapuserd_->GetBufferMetadataSize()); + memcpy(read_ahead_buffer_, ra_temp_buffer_.get(), total_blocks_merged_ * BLOCK_SZ); - loff_t offset = 0; - std::unordered_map& read_ahead_buffer_map = snapuserd_->GetReadAheadMap(); - read_ahead_buffer_map.clear(); + loff_t offset = 0; + std::unordered_map& read_ahead_buffer_map = snapuserd_->GetReadAheadMap(); + read_ahead_buffer_map.clear(); - for (size_t block_index = 0; block_index < blocks_.size(); block_index++) { - void* bufptr = static_cast((char*)read_ahead_buffer_ + offset); - uint64_t new_block = blocks_[block_index]; + for (size_t block_index = 0; block_index < blocks_.size(); block_index++) { + void* bufptr = static_cast((char*)read_ahead_buffer_ + offset); + uint64_t new_block = blocks_[block_index]; - read_ahead_buffer_map[new_block] = bufptr; - offset += BLOCK_SZ; + read_ahead_buffer_map[new_block] = bufptr; + offset += BLOCK_SZ; + } + + total_ra_blocks_completed_ += total_blocks_merged_; + snapuserd_->SetMergedBlockCountForNextCommit(total_blocks_merged_); } - total_ra_blocks_completed_ += total_blocks_merged_; - snapuserd_->SetMergedBlockCountForNextCommit(total_blocks_merged_); - // Flush the scratch data - Technically, we should flush only for overlapping // blocks; However, since this region is mmap'ed, the dirty pages can still // get flushed to disk at any random point in time. Instead, make sure From 150483e3a1d7e88e6827d8ba11ec7a8b9e3688f7 Mon Sep 17 00:00:00 2001 From: Armelle Laine Date: Thu, 21 Nov 2024 03:11:51 +0000 Subject: [PATCH 155/183] trusty: utils: rpmb_dev: secure storage support for test VM Bug: 367423387 Test: start storageprxyd_test_system Change-Id: Ia9c07d9872a2975c4bd621c16a5df437e8a0736b --- trusty/trusty-storage-cf.mk | 1 + trusty/utils/rpmb_dev/Android.bp | 9 +++ trusty/utils/rpmb_dev/rpmb_dev.test.system.rc | 56 +++++++++++++++++++ 3 files changed, 66 insertions(+) create mode 100644 trusty/utils/rpmb_dev/rpmb_dev.test.system.rc diff --git a/trusty/trusty-storage-cf.mk b/trusty/trusty-storage-cf.mk index 3b46445da..acefd3e99 100644 --- a/trusty/trusty-storage-cf.mk +++ b/trusty/trusty-storage-cf.mk @@ -22,4 +22,5 @@ PRODUCT_PACKAGES += \ storageproxyd.system \ rpmb_dev.system \ + rpmb_dev.test.system \ diff --git a/trusty/utils/rpmb_dev/Android.bp b/trusty/utils/rpmb_dev/Android.bp index ef23cc50f..2f362e8b7 100644 --- a/trusty/utils/rpmb_dev/Android.bp +++ b/trusty/utils/rpmb_dev/Android.bp @@ -58,3 +58,12 @@ cc_binary { "rpmb_dev.wv.system.rc", ], } + +cc_binary { + name: "rpmb_dev.test.system", + defaults: ["rpmb_dev.cc_defaults"], + system_ext_specific: true, + init_rc: [ + "rpmb_dev.test.system.rc", + ], +} diff --git a/trusty/utils/rpmb_dev/rpmb_dev.test.system.rc b/trusty/utils/rpmb_dev/rpmb_dev.test.system.rc new file mode 100644 index 000000000..2127798e1 --- /dev/null +++ b/trusty/utils/rpmb_dev/rpmb_dev.test.system.rc @@ -0,0 +1,56 @@ +service trusty_test_vm /apex/com.android.virt/bin/vm run \ + /data/local/tmp/TrustyTestVM_UnitTests/trusty-test_vm-config.json + disabled + user system + group system + +service storageproxyd_test_system /system_ext/bin/storageproxyd.system \ + -d VSOCK:${trusty.test_vm.vm_cid}:1 \ + -r /dev/socket/rpmb_mock_test_system \ + -p /data/secure_storage_test_system \ + -t sock + disabled + class hal + user system + group system + +service rpmb_mock_init_test_system /system_ext/bin/rpmb_dev.test.system \ + --dev /mnt/secure_storage_rpmb_test_system/persist/RPMB_DATA --init --size 2048 + disabled + user system + group system + oneshot + +service rpmb_mock_test_system /system_ext/bin/rpmb_dev.test.system \ + --dev /mnt/secure_storage_rpmb_test_system/persist/RPMB_DATA \ + --sock rpmb_mock_test_system + disabled + user system + group system + socket rpmb_mock_test_system stream 660 system system + +# RPMB Mock +on post-fs-data + # Create a persistent location for the RPMB data + # (work around lack of RPMb block device on CF). + # file contexts secure_storage_rpmb_system_file + # (only used on Cuttlefish as this is non secure) + mkdir /metadata/secure_storage_rpmb_test_system 0770 system system + mkdir /mnt/secure_storage_rpmb_test_system 0770 system system + symlink /metadata/secure_storage_rpmb_test_system \ + /mnt/secure_storage_rpmb_test_system/persist + # Create a system persist directory in /metadata + # (work around lack of dedicated system persist partition). + # file contexts secure_storage_persist_system_file + mkdir /metadata/secure_storage_persist_test_system 0770 system system + mkdir /mnt/secure_storage_persist_test_system 0770 system system + symlink /metadata/secure_storage_persist_test_system \ + /mnt/secure_storage_persist_test_system/persist + # file contexts secure_storage_system_file + mkdir /data/secure_storage_test_system 0770 root system + symlink /mnt/secure_storage_persist_test_system/persist \ + /data/secure_storage_test_system/persist + chown root system /data/secure_storage_test_system/persist + # setprop storageproxyd_test_system.trusty_ipc_dev VSOCK:${trusty.test_vm.vm_cid}:1 + exec_start rpmb_mock_init_test_system + start rpmb_mock_test_system From b912e3e548c4879a015342be1910c12a629b8dd8 Mon Sep 17 00:00:00 2001 From: Shintaro Kawamura Date: Thu, 21 Nov 2024 16:28:30 +0900 Subject: [PATCH 156/183] Fix permission of zram writeback and idle file The default permission of "/sys/block/zram0/idle" and "/sys/block/zram0/writeback" are "0200". Adding read permission to the files does not make sense because reading those files fail as EIO error. We should keep permission as minimum as possible. Bug: 117682284 Bug: 375432468 Test: ls -la /sys/block/zram0 Change-Id: I11ed5d9eee257002f4698edcd81de39d2c317ea1 --- rootdir/init.rc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index eeafd4c85..82844352a 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1127,9 +1127,9 @@ on boot # System server manages zram writeback chown root system /sys/block/zram0/idle - chmod 0664 /sys/block/zram0/idle + chmod 0220 /sys/block/zram0/idle chown root system /sys/block/zram0/writeback - chmod 0664 /sys/block/zram0/writeback + chmod 0220 /sys/block/zram0/writeback # to access F2FS sysfs on dm- directly mkdir /dev/sys/fs/by-name 0755 system system From 35ab96a4232b5579c96f9c75bd053dfc238f08f4 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Thu, 21 Nov 2024 05:59:54 -0800 Subject: [PATCH 157/183] Add prefetch directory in /metadata Bug: 362507272 Test: Verify directory is created in /metadata Change-Id: Ie1c2312f405d4b41e06a248e4d2b93cd8fc62a93 Signed-off-by: Akilesh Kailash --- rootdir/init.rc | 1 + 1 file changed, 1 insertion(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index eeafd4c85..8ffac2049 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -596,6 +596,7 @@ on post-fs mkdir /metadata/ota/snapshots 0750 root system mkdir /metadata/watchdog 0770 root system mkdir /metadata/tradeinmode 0770 root system + mkdir /metadata/prefetch 0770 root system mkdir /metadata/apex 0700 root system mkdir /metadata/apex/sessions 0700 root system From 589afaa880f36c481cbbdaeac11f7a3fbfd91a44 Mon Sep 17 00:00:00 2001 From: Abdelrahman Daim Date: Thu, 21 Nov 2024 08:13:41 -0800 Subject: [PATCH 158/183] fs_mgr: Support nosymfollow mount option Summary: The nosymfollow mount option was added to Linux 5.10, and the bionic headers support it. Allow mounting with the option set. Updated relevant CTS test too. Test: Successful build on master Change-Id: I0b280287e07ef8c485762b820dbbb26300144982 Signed-off-by: Abdelrahman Daim --- fs_mgr/libfstab/fstab.cpp | 5 +---- fs_mgr/tests/fs_mgr_test.cpp | 1 + init/builtins.cpp | 1 + 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index ca3599059..010fbc81d 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -39,10 +39,6 @@ #include "fstab_priv.h" #include "logging_macros.h" -#if !defined(MS_LAZYTIME) -#define MS_LAZYTIME (1 << 25) -#endif - using android::base::EndsWith; using android::base::ParseByteCount; using android::base::ParseInt; @@ -79,6 +75,7 @@ FlagList kMountFlagsList[] = { {"slave", MS_SLAVE}, {"shared", MS_SHARED}, {"lazytime", MS_LAZYTIME}, + {"nosymfollow", MS_NOSYMFOLLOW}, {"defaults", 0}, }; diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index 6e050cf4b..37a68b8e2 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -334,6 +334,7 @@ TEST(fs_mgr, fs_mgr_read_fstab_file_proc_mounts) { {"slave", MS_SLAVE}, {"shared", MS_SHARED}, {"lazytime", MS_LAZYTIME}, + {"nosymfollow", MS_NOSYMFOLLOW}, {"defaults", 0}, {0, 0}, }; diff --git a/init/builtins.cpp b/init/builtins.cpp index c4af5b503..38aed9c64 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -471,6 +471,7 @@ static struct { { "private", MS_PRIVATE }, { "slave", MS_SLAVE }, { "shared", MS_SHARED }, + { "nosymfollow", MS_NOSYMFOLLOW }, { "defaults", 0 }, { 0, 0 }, }; From 0701fed364e57ba7cb085c297ffe4641449c3d86 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 21 Nov 2024 18:46:28 +0000 Subject: [PATCH 159/183] Remove no longer necessary MS_LAZYTIME definitions. Change-Id: Idf2d947509731715f895518b541d55d55187c43d --- fs_mgr/libfstab/fstab.cpp | 4 ---- fs_mgr/tests/fs_mgr_test.cpp | 4 ---- 2 files changed, 8 deletions(-) diff --git a/fs_mgr/libfstab/fstab.cpp b/fs_mgr/libfstab/fstab.cpp index ca3599059..01e0e3d87 100644 --- a/fs_mgr/libfstab/fstab.cpp +++ b/fs_mgr/libfstab/fstab.cpp @@ -39,10 +39,6 @@ #include "fstab_priv.h" #include "logging_macros.h" -#if !defined(MS_LAZYTIME) -#define MS_LAZYTIME (1 << 25) -#endif - using android::base::EndsWith; using android::base::ParseByteCount; using android::base::ParseInt; diff --git a/fs_mgr/tests/fs_mgr_test.cpp b/fs_mgr/tests/fs_mgr_test.cpp index 6e050cf4b..8004977c9 100644 --- a/fs_mgr/tests/fs_mgr_test.cpp +++ b/fs_mgr/tests/fs_mgr_test.cpp @@ -37,10 +37,6 @@ using namespace android::fs_mgr; using namespace testing; -#if !defined(MS_LAZYTIME) -#define MS_LAZYTIME (1 << 25) -#endif - namespace { const std::string cmdline = From f00efa024227358d477999cb67d6b73a5967007e Mon Sep 17 00:00:00 2001 From: Wei Li Date: Fri, 22 Nov 2024 06:55:05 +0000 Subject: [PATCH 160/183] Remove system/core/METADATA This directory doesn't contain third-party code and it doesn't need a METADATA file. Bug: 380376695 Test: CIs Change-Id: Ie197786da09304476fb002b178c2a77d424f5a53 --- METADATA | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 METADATA diff --git a/METADATA b/METADATA deleted file mode 100644 index d97975ca3..000000000 --- a/METADATA +++ /dev/null @@ -1,3 +0,0 @@ -third_party { - license_type: NOTICE -} From ef3a2c05fe2050defce701d6c72024366ca216d5 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Wed, 20 Nov 2024 15:14:29 -0800 Subject: [PATCH 161/183] libprefetch: Start prefetch service based on build 1: Check the presence of the file 'prefetch_ready'. If it doesn't exist then the device is booting for the first time after wipe. Thus, we would just create the file and exit as we do not want to initiate the record after data wipe primiarly because boot after data wipe is long and the I/O pattern during first boot may not actually match with subsequent boot. 2: If the file 'prefetch_ready' is present: a: Compare the build-finger-print of the device with the one record format is associated with by reading the file 'build_finger_print'. If they match, start the prefetch_replay. b: If they don't match, then the device was updated through OTA. Hence, start a fresh record and delete the build-finger-print file. This should also cover the case of device rollback. c: If the build-finger-print file doesn't exist, then just restart the record from scratch. Bug: 362507272 Test: Prefetch record/replay Change-Id: I90b861ba9381ddba6ab7dedb9930a735e55b0e5d Signed-off-by: Akilesh Kailash --- init/libprefetch/prefetch/prefetch.rc | 16 +++ init/libprefetch/prefetch/src/arch/android.rs | 118 ++++++++++++++++++ init/libprefetch/prefetch/src/args.rs | 4 + .../prefetch/src/args/args_argh.rs | 37 ++++++ init/libprefetch/prefetch/src/lib.rs | 38 +++--- init/libprefetch/prefetch/src/main.rs | 4 + 6 files changed, 195 insertions(+), 22 deletions(-) create mode 100644 init/libprefetch/prefetch/src/arch/android.rs diff --git a/init/libprefetch/prefetch/prefetch.rc b/init/libprefetch/prefetch/prefetch.rc index 9f2cb7f46..fb3fb3b6a 100644 --- a/init/libprefetch/prefetch/prefetch.rc +++ b/init/libprefetch/prefetch/prefetch.rc @@ -1,3 +1,16 @@ +on init && property:ro.prefetch_boot.enabled=true + start prefetch + +service prefetch /system/bin/prefetch start + class main + user root + group root system + disabled + oneshot + +on property:ro.prefetch_boot.record=true + start prefetch_record + service prefetch_record /system/bin/prefetch record --duration ${ro.prefetch_boot.duration_s:-0} class main user root @@ -5,6 +18,9 @@ service prefetch_record /system/bin/prefetch record --duration ${ro.prefetch_boo disabled oneshot +on property:ro.prefetch_boot.replay=true + start prefetch_replay + service prefetch_replay /system/bin/prefetch replay --io-depth ${ro.prefetch_boot.io_depth:-2} --max-fds ${ro.prefetch_boot.max_fds:-128} class main user root diff --git a/init/libprefetch/prefetch/src/arch/android.rs b/init/libprefetch/prefetch/src/arch/android.rs new file mode 100644 index 000000000..c765e38d7 --- /dev/null +++ b/init/libprefetch/prefetch/src/arch/android.rs @@ -0,0 +1,118 @@ +use crate::Error; +use crate::RecordArgs; +use crate::StartArgs; +use log::info; +use log::warn; +use std::fs::File; +use std::fs::OpenOptions; +use std::io::Write; +use std::time::Duration; + +use rustutils::system_properties::error::PropertyWatcherError; +use rustutils::system_properties::PropertyWatcher; + +const PREFETCH_RECORD_PROPERTY: &str = "ro.prefetch_boot.record"; +const PREFETCH_REPLAY_PROPERTY: &str = "ro.prefetch_boot.replay"; +const PREFETCH_RECORD_PROPERTY_STOP: &str = "ro.prefetch_boot.record_stop"; + +fn wait_for_property_true( + property_name: &str, + timeout: Option, +) -> Result<(), PropertyWatcherError> { + let mut prop = PropertyWatcher::new(property_name)?; + prop.wait_for_value("1", timeout)?; + Ok(()) +} + +/// Wait for record to stop +pub fn wait_for_record_stop() { + wait_for_property_true(PREFETCH_RECORD_PROPERTY_STOP, None).unwrap_or_else(|e| { + warn!("failed to wait for {} with error: {}", PREFETCH_RECORD_PROPERTY_STOP, e) + }); +} + +fn start_prefetch_service(property_name: &str) -> Result<(), Error> { + match rustutils::system_properties::write(property_name, "true") { + Ok(_) => {} + Err(_) => { + return Err(Error::Custom { error: "Failed to start prefetch service".to_string() }); + } + } + Ok(()) +} + +/// Start prefetch service +/// +/// 1: Check the presence of the file 'prefetch_ready'. If it doesn't +/// exist then the device is booting for the first time after wipe. +/// Thus, we would just create the file and exit as we do not want +/// to initiate the record after data wipe primiarly because boot +/// after data wipe is long and the I/O pattern during first boot may not actually match +/// with subsequent boot. +/// +/// 2: If the file 'prefetch_ready' is present: +/// +/// a: Compare the build-finger-print of the device with the one record format +/// is associated with by reading the file 'build_finger_print'. If they match, +/// start the prefetch_replay. +/// +/// b: If they don't match, then the device was updated through OTA. Hence, start +/// a fresh record and delete the build-finger-print file. This should also cover +/// the case of device rollback. +/// +/// c: If the build-finger-print file doesn't exist, then just restart the record +/// from scratch. +pub fn start_prefetch(args: &StartArgs) -> Result<(), Error> { + if !args.path.exists() { + match File::create(args.path.clone()) { + Ok(_) => {} + Err(_) => { + return Err(Error::Custom { error: "File Creation failed".to_string() }); + } + } + return Ok(()); + } + + if args.build_fingerprint_path.exists() { + let device_build_fingerprint = rustutils::system_properties::read("ro.build.fingerprint") + .map_err(|e| Error::Custom { + error: format!("Failed to read ro.build.fingerprint: {}", e), + })?; + let pack_build_fingerprint = std::fs::read_to_string(&args.build_fingerprint_path)?; + if pack_build_fingerprint.trim() == device_build_fingerprint.as_deref().unwrap_or_default() + { + info!("Start replay"); + start_prefetch_service(PREFETCH_REPLAY_PROPERTY)?; + } else { + info!("Start record"); + std::fs::remove_file(&args.build_fingerprint_path)?; + start_prefetch_service(PREFETCH_RECORD_PROPERTY)?; + } + } else { + info!("Start record"); + start_prefetch_service(PREFETCH_RECORD_PROPERTY)?; + } + Ok(()) +} + +/// Write build finger print to associate prefetch pack file +pub fn write_build_fingerprint(args: &RecordArgs) -> Result<(), Error> { + let mut build_fingerprint_file = OpenOptions::new() + .write(true) + .create(true) + .truncate(true) + .open(&args.build_fingerprint_path) + .map_err(|source| Error::Create { + source, + path: args.build_fingerprint_path.to_str().unwrap().to_owned(), + })?; + + let device_build_fingerprint = + rustutils::system_properties::read("ro.build.fingerprint").unwrap_or_default(); + let device_build_fingerprint = device_build_fingerprint.unwrap_or_default(); + + build_fingerprint_file.write_all(device_build_fingerprint.as_bytes())?; + build_fingerprint_file.sync_all()?; + + Ok(()) +} diff --git a/init/libprefetch/prefetch/src/args.rs b/init/libprefetch/prefetch/src/args.rs index 4c1e68919..e534210b5 100644 --- a/init/libprefetch/prefetch/src/args.rs +++ b/init/libprefetch/prefetch/src/args.rs @@ -25,6 +25,8 @@ use std::process::exit; pub use args_internal::OutputFormat; pub use args_internal::ReplayArgs; +#[cfg(target_os = "android")] +pub use args_internal::StartArgs; pub use args_internal::TracerType; pub use args_internal::{DumpArgs, MainArgs, RecordArgs, SubCommands}; use serde::Deserialize; @@ -66,6 +68,8 @@ fn verify_and_fix(args: &mut MainArgs) -> Result<(), Error> { SubCommands::Dump(arg) => { ensure_path_exists(&arg.path)?; } + #[cfg(target_os = "android")] + SubCommands::Start(_arg) => return Ok(()), } Ok(()) } diff --git a/init/libprefetch/prefetch/src/args/args_argh.rs b/init/libprefetch/prefetch/src/args/args_argh.rs index 8ac95fce7..65084eeaa 100644 --- a/init/libprefetch/prefetch/src/args/args_argh.rs +++ b/init/libprefetch/prefetch/src/args/args_argh.rs @@ -40,6 +40,38 @@ pub enum SubCommands { Replay(ReplayArgs), /// Dump prefetch data in human readable format Dump(DumpArgs), + /// Start prefetch service if possible + /// If the pack file is present, then prefetch replay is started + /// If the pack file is absent or if the build fingerprint + /// of the current pack file is different, then prefetch record is started. + #[cfg(target_os = "android")] + Start(StartArgs), +} + +#[cfg(target_os = "android")] +fn default_ready_path() -> PathBuf { + PathBuf::from("/metadata/prefetch/prefetch_ready") +} + +#[cfg(target_os = "android")] +fn default_build_finger_print_path() -> PathBuf { + PathBuf::from("/metadata/prefetch/build_finger_print") +} + +#[cfg(target_os = "android")] +#[derive(Eq, PartialEq, Debug, Default, FromArgs)] +/// Start prefetch service based on if pack file is present. +#[argh(subcommand, name = "start")] +pub struct StartArgs { + /// file path to check if prefetch_ready is present. + /// + /// A new file is created at the given path if it's not present. + #[argh(option, default = "default_ready_path()")] + pub path: PathBuf, + + /// file path where build fingerprint is stored + #[argh(option, default = "default_build_finger_print_path()")] + pub build_fingerprint_path: PathBuf, } impl Default for SubCommands { @@ -110,6 +142,11 @@ pub struct RecordArgs { from_str_fn(parse_tracing_instance) )] pub tracing_instance: Option, + + #[cfg(target_os = "android")] + /// store build_finger_print to tie the pack format + #[argh(option, default = "default_build_finger_print_path()")] + pub build_fingerprint_path: PathBuf, } /// Type of tracing subsystem to use. diff --git a/init/libprefetch/prefetch/src/lib.rs b/init/libprefetch/prefetch/src/lib.rs index 4b56b13ee..6564c4bc6 100644 --- a/init/libprefetch/prefetch/src/lib.rs +++ b/init/libprefetch/prefetch/src/lib.rs @@ -20,6 +20,10 @@ mod error; mod format; mod replay; mod tracer; +#[cfg(target_os = "android")] +mod arch { + pub mod android; +} use std::fs::File; use std::fs::OpenOptions; @@ -38,6 +42,8 @@ use log::LevelFilter; pub use args::args_from_env; use args::OutputFormat; pub use args::ReplayArgs; +#[cfg(target_os = "android")] +pub use args::StartArgs; pub use args::{DumpArgs, MainArgs, RecordArgs, SubCommands}; pub use error::Error; pub use format::FileId; @@ -45,29 +51,11 @@ pub use format::InodeInfo; pub use format::Record; pub use format::RecordsFile; use log::info; -#[cfg(target_os = "android")] -use log::warn; pub use replay::Replay; pub use tracer::nanoseconds_since_boot; #[cfg(target_os = "android")] -use rustutils::system_properties; -#[cfg(target_os = "android")] -use rustutils::system_properties::error::PropertyWatcherError; -#[cfg(target_os = "android")] -use rustutils::system_properties::PropertyWatcher; - -#[cfg(target_os = "android")] -fn wait_for_property_true(property_name: &str) -> Result<(), PropertyWatcherError> { - let mut prop = PropertyWatcher::new(property_name)?; - loop { - prop.wait(None)?; - if system_properties::read_bool(property_name, false)? { - break; - } - } - Ok(()) -} +pub use arch::android::*; /// Records prefetch data for the given configuration pub fn record(args: &RecordArgs) -> Result<(), Error> { @@ -85,11 +73,10 @@ pub fn record(args: &RecordArgs) -> Result<(), Error> { thread::sleep(duration); } else { #[cfg(target_os = "android")] - wait_for_property_true("sys.boot_completed").unwrap_or_else(|e| { - warn!("failed to wait for sys.boot_completed with error: {}", e) - }); + wait_for_record_stop(); } + info!("Prefetch record exiting"); // We want to unwrap here on failure to send this signal. Otherwise // tracer will continue generating huge records data. exit_tx.send(()).unwrap(); @@ -107,9 +94,16 @@ pub fn record(args: &RecordArgs) -> Result<(), Error> { std::fs::set_permissions(&args.path, std::fs::Permissions::from_mode(0o644)) .map_err(|source| Error::Create { source, path: args.path.to_str().unwrap().to_owned() })?; + // Write the record file out_file .write_all(&rf.add_checksum_and_serialize()?) .map_err(|source| Error::Write { path: args.path.to_str().unwrap().to_owned(), source })?; + out_file.sync_all()?; + + // Write build-finger-print file + #[cfg(target_os = "android")] + write_build_fingerprint(args)?; + Ok(()) } diff --git a/init/libprefetch/prefetch/src/main.rs b/init/libprefetch/prefetch/src/main.rs index 046e07eda..eab826f25 100644 --- a/init/libprefetch/prefetch/src/main.rs +++ b/init/libprefetch/prefetch/src/main.rs @@ -22,6 +22,8 @@ use prefetch_rs::dump; use prefetch_rs::init_logging; use prefetch_rs::record; use prefetch_rs::replay; +#[cfg(target_os = "android")] +use prefetch_rs::start_prefetch; use prefetch_rs::LogLevel; use prefetch_rs::MainArgs; use prefetch_rs::SubCommands; @@ -33,6 +35,8 @@ fn main() { SubCommands::Record(args) => record(args), SubCommands::Replay(args) => replay(args), SubCommands::Dump(args) => dump(args), + #[cfg(target_os = "android")] + SubCommands::Start(args) => start_prefetch(args), }; if let Err(err) = ret { From fef2dff80a7e44cf23decf0629c7d2dba27bac0b Mon Sep 17 00:00:00 2001 From: Jooyung Han Date: Mon, 25 Nov 2024 08:32:05 +0000 Subject: [PATCH 162/183] Remove /data/apex/hashtree directory This directory is no longer used. Bug: 184914612 Change-Id: Iaa094e2df39c363fe0a5ffd4b27b5c3075bb4f7f Test: (device doesn't have the directory) --- rootdir/init.rc | 1 - 1 file changed, 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 6771c5fde..f00479ece 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -736,7 +736,6 @@ on post-fs-data mkdir /data/apex/active 0755 root system mkdir /data/apex/backup 0700 root system mkdir /data/apex/decompressed 0755 root system encryption=Require - mkdir /data/apex/hashtree 0700 root system mkdir /data/apex/sessions 0700 root system mkdir /data/app-staging 0751 system system encryption=DeleteIfNecessary mkdir /data/apex/ota_reserved 0700 root system encryption=Require From 487584da236d931c4b67d5aaaaf686a6e23a1f4b Mon Sep 17 00:00:00 2001 From: David Drysdale Date: Mon, 25 Nov 2024 12:38:54 +0000 Subject: [PATCH 163/183] Move Trusty C++ KeyMint to v4 - Declare v4 HAL. - Declare version 400 in Package Manager (when unfrozen). - Link to current (V4 when unfrozen) versions of support libraries. - Add `setAdditionalAttestationInfo()` method to HAL service. - Add `SetAdditionalAttestationInfo()` method to implementation, using the common message types. - Add Trusty-specific message code for the `SET_ADDITIONAL_ATTESTATION_INFO` message exchange. Test: VtsAidlKeyMintTargetTest (new test fails until TA updated too) Bug: 369375199 Change-Id: I4699aea3ab8a0723a5c2bc1493f7bbb69cdfd6df --- trusty/keymaster/Android.bp | 11 ++++++----- trusty/keymaster/TrustyKeymaster.cpp | 7 +++++++ .../include/trusty_keymaster/TrustyKeyMintDevice.h | 1 + .../include/trusty_keymaster/TrustyKeymaster.h | 2 ++ .../include/trusty_keymaster/ipc/keymaster_ipc.h | 1 + trusty/keymaster/keymint/TrustyKeyMintDevice.cpp | 14 ++++++++++++++ ...id.hardware.security.keymint-service.trusty.xml | 2 +- 7 files changed, 32 insertions(+), 6 deletions(-) diff --git a/trusty/keymaster/Android.bp b/trusty/keymaster/Android.bp index 5a1e4202d..8ebfc1aeb 100644 --- a/trusty/keymaster/Android.bp +++ b/trusty/keymaster/Android.bp @@ -106,11 +106,11 @@ cc_binary { "keymint/service.cpp", ], shared_libs: [ - "android.hardware.security.keymint-V3-ndk", + "android.hardware.security.keymint-V4-ndk", "android.hardware.security.rkp-V3-ndk", "android.hardware.security.secureclock-V1-ndk", "android.hardware.security.sharedsecret-V1-ndk", - "lib_android_keymaster_keymint_utils_V3", + "lib_android_keymaster_keymint_utils", "libbase", "libbinder_ndk", "libhardware", @@ -120,9 +120,10 @@ cc_binary { "libtrusty", "libutils", ], - required: [ - "android.hardware.hardware_keystore_V3.xml", - ], + required: select(release_flag("RELEASE_AIDL_USE_UNFROZEN"), { + true: ["android.hardware.hardware_keystore.xml"], + default: ["android.hardware.hardware_keystore_V3.xml"], + }), } prebuilt_etc { diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp index b118a2001..723229d03 100644 --- a/trusty/keymaster/TrustyKeymaster.cpp +++ b/trusty/keymaster/TrustyKeymaster.cpp @@ -295,6 +295,13 @@ GetRootOfTrustResponse TrustyKeymaster::GetRootOfTrust(const GetRootOfTrustReque return response; } +SetAdditionalAttestationInfoResponse TrustyKeymaster::SetAdditionalAttestationInfo( + const SetAdditionalAttestationInfoRequest& request) { + SetAdditionalAttestationInfoResponse response(message_version()); + ForwardCommand(KM_SET_ADDITIONAL_ATTESTATION_INFO, request, &response); + return response; +} + GetHwInfoResponse TrustyKeymaster::GetHwInfo() { GetHwInfoResponse response(message_version()); ForwardCommand(KM_GET_HW_INFO, GetHwInfoRequest(message_version()), &response); diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h index c8d8932c4..5e876d3d3 100644 --- a/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h +++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeyMintDevice.h @@ -85,6 +85,7 @@ class TrustyKeyMintDevice : public BnKeyMintDevice { ScopedAStatus getRootOfTrust(const array& challenge, vector* rootOfTrust) override; ScopedAStatus sendRootOfTrust(const vector& rootOfTrust) override; + ScopedAStatus setAdditionalAttestationInfo(const vector& info) override; protected: std::shared_ptr impl_; diff --git a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h index c50178bcf..65d7217e0 100644 --- a/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h +++ b/trusty/keymaster/include/trusty_keymaster/TrustyKeymaster.h @@ -70,6 +70,8 @@ class TrustyKeymaster { ConfigureVendorPatchlevelResponse ConfigureVendorPatchlevel( const ConfigureVendorPatchlevelRequest& request); GetRootOfTrustResponse GetRootOfTrust(const GetRootOfTrustRequest& request); + SetAdditionalAttestationInfoResponse SetAdditionalAttestationInfo( + const SetAdditionalAttestationInfoRequest& request); GetHwInfoResponse GetHwInfo(); uint32_t message_version() const { return message_version_; } diff --git a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h index 822e93334..721315d6f 100644 --- a/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h +++ b/trusty/keymaster/include/trusty_keymaster/ipc/keymaster_ipc.h @@ -62,6 +62,7 @@ enum keymaster_command : uint32_t { KM_GET_ROOT_OF_TRUST = (34 << KEYMASTER_REQ_SHIFT), KM_GET_HW_INFO = (35 << KEYMASTER_REQ_SHIFT), KM_GENERATE_CSR_V2 = (36 << KEYMASTER_REQ_SHIFT), + KM_SET_ADDITIONAL_ATTESTATION_INFO = (37 << KEYMASTER_REQ_SHIFT), // Bootloader/provisioning calls. KM_SET_BOOT_PARAMS = (0x1000 << KEYMASTER_REQ_SHIFT), diff --git a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp index fec4c60fe..154597f99 100644 --- a/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp +++ b/trusty/keymaster/keymint/TrustyKeyMintDevice.cpp @@ -349,4 +349,18 @@ ScopedAStatus TrustyKeyMintDevice::sendRootOfTrust(const vector& /* roo return kmError2ScopedAStatus(KM_ERROR_UNIMPLEMENTED); } +ScopedAStatus TrustyKeyMintDevice::setAdditionalAttestationInfo(const vector& info) { + keymaster::SetAdditionalAttestationInfoRequest request(impl_->message_version()); + request.info.Reinitialize(KmParamSet(info)); + + keymaster::SetAdditionalAttestationInfoResponse response = + impl_->SetAdditionalAttestationInfo(request); + + if (response.error != KM_ERROR_OK) { + return kmError2ScopedAStatus(response.error); + } else { + return ScopedAStatus::ok(); + } +} + } // namespace aidl::android::hardware::security::keymint::trusty diff --git a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml index 3dc9c88ea..f74d21285 100644 --- a/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml +++ b/trusty/keymaster/keymint/android.hardware.security.keymint-service.trusty.xml @@ -1,7 +1,7 @@ android.hardware.security.keymint - 3 + 4 IKeyMintDevice/default From cadad290a79d5b0a30add935aaadab7c1b1ef5e9 Mon Sep 17 00:00:00 2001 From: Eric Biggers Date: Tue, 26 Nov 2024 02:56:24 +0000 Subject: [PATCH 164/183] Fix the dm-verity Merkle tree caches to not expire so quickly Bug: 335233956 Test: cat /sys/module/dm_bufio/parameters/max_age_seconds Change-Id: I20e4df7dd3eb2ac1f462510e900568e946195faf --- rootdir/init.rc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index f00479ece..58f0495e6 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -54,6 +54,10 @@ on early-init mkdir /linkerconfig/bootstrap 0755 mkdir /linkerconfig/default 0755 + # Greatly extend dm-verity's Merkle tree cache timeout. The default timeout + # is much too short and is unnecessary, given that there is also a shrinker. + write /sys/module/dm_bufio/parameters/max_age_seconds 86400 + # Disable dm-verity hash prefetching, since it doesn't help performance # Read more in b/136247322 write /sys/module/dm_verity/parameters/prefetch_cluster 0 From 9731ea7b673edc3a0c914a1bdb3ef81152b61158 Mon Sep 17 00:00:00 2001 From: Eric Lin Date: Tue, 26 Nov 2024 04:24:56 +0000 Subject: [PATCH 165/183] Update comments to point to the new location of event.logtags. event.logtags was moved from system/core/logcat to system/logging/logcat in Android 12 by aosp/1454058. Change-Id: Ia3cedee549145eddb0484ec589a9599a156bea14 BUG: 168791309 Flag: DOCS_ONLY Test: Local build --- libsysutils/EventLogTags.logtags | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsysutils/EventLogTags.logtags b/libsysutils/EventLogTags.logtags index 713f8cd6b..bb06d3433 100644 --- a/libsysutils/EventLogTags.logtags +++ b/libsysutils/EventLogTags.logtags @@ -1,4 +1,4 @@ -# See system/core/logcat/event.logtags for a description of the format of this file. +# See system/logging/logcat/event.logtags for a description of the format of this file. # FrameworkListener dispatchCommand overflow 78001 exp_det_dispatchCommand_overflow From 3df083a4985b5ff88c597db9a586afed6fa3ac96 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Mon, 25 Nov 2024 21:46:56 -0800 Subject: [PATCH 166/183] libprefetch: rename property name Bug: 362507272 Test: Build Change-Id: I39627fdcbbe5458e6fbc9dfaa1aa620844d56f8b Signed-off-by: Akilesh Kailash --- init/libprefetch/prefetch/src/arch/android.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/init/libprefetch/prefetch/src/arch/android.rs b/init/libprefetch/prefetch/src/arch/android.rs index c765e38d7..3404e42b1 100644 --- a/init/libprefetch/prefetch/src/arch/android.rs +++ b/init/libprefetch/prefetch/src/arch/android.rs @@ -11,8 +11,8 @@ use std::time::Duration; use rustutils::system_properties::error::PropertyWatcherError; use rustutils::system_properties::PropertyWatcher; -const PREFETCH_RECORD_PROPERTY: &str = "ro.prefetch_boot.record"; -const PREFETCH_REPLAY_PROPERTY: &str = "ro.prefetch_boot.replay"; +const PREFETCH_RECORD_PROPERTY: &str = "prefetch_boot.record"; +const PREFETCH_REPLAY_PROPERTY: &str = "prefetch_boot.replay"; const PREFETCH_RECORD_PROPERTY_STOP: &str = "ro.prefetch_boot.record_stop"; fn wait_for_property_true( From 52d2446b4e8c208066b4208780b4b0117102c53d Mon Sep 17 00:00:00 2001 From: Dennis Shen Date: Tue, 26 Nov 2024 15:26:52 +0000 Subject: [PATCH 167/183] Deprecate cc_binary aconfigd and the controlling flag cc_binary aconfigd is replaced with rust_binary aconfigd-system. The replacement is flag guarded and is already in TF full for more than a week. Thus delete the flag and deprecate old cc_binary aconfigd. Test: m Change-Id: Ib128adc2ef8178e02222f77e6b89bcc7ac83c1da --- rootdir/init.rc | 8 -------- 1 file changed, 8 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 6771c5fde..6f32ccca4 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1009,16 +1009,8 @@ on post-fs-data wait_for_prop apexd.status activated perform_apex_config - # See flag enable_system_aconfigd_rust, which toggles these processes. - exec_start aconfigd-mainline-init exec_start system_aconfigd_mainline_init - - # system_aconfigd_socket_service is replacing aconfigd: - # - A flag (enable_system_aconfigd_rust) toggles which socket executes. - # - When enabled, aconfigd is a no-op, system_aconfigd_socket_service executes. - # - Conversely, when disabled, aconfigd executes, and system_aconfigd_socket_service is a no-op. start system_aconfigd_socket_service - start aconfigd # Create directories for boot animation. mkdir /data/misc/bootanim 0755 system system From 27dd6f8e62fc587fe7e4c298501ea43888a59914 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Tue, 26 Nov 2024 23:44:17 +0000 Subject: [PATCH 168/183] libutils OWNERS for shayba@ For Looper work, but not scoped down to this unless you want it to be. Bug: N/A Test: N/A Change-Id: I14bf8d21af357ef7b9151cca49b0cf40dde0e3ca --- libutils/OWNERS | 1 + 1 file changed, 1 insertion(+) diff --git a/libutils/OWNERS b/libutils/OWNERS index 40164aae0..4ce689304 100644 --- a/libutils/OWNERS +++ b/libutils/OWNERS @@ -1 +1,2 @@ +shayba@google.com smoreland@google.com From 8366faad18cc853a5bcd44992d6ec1facb1d8833 Mon Sep 17 00:00:00 2001 From: Akhilesh Sanikop Date: Fri, 29 Nov 2024 15:02:21 +0530 Subject: [PATCH 169/183] gatekeeperd_service_fuzzer: Add signal() to handle SIGPIPE Adding signal handler to avoid abort() due to broken pipe. Test: ./gatekeeperd_service_fuzzer Bug: 376201407 Change-Id: Ifca08860d11f56eb8e0d490c6b6956f8774cfa70 --- gatekeeperd/fuzzer/GateKeeperServiceFuzzer.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/gatekeeperd/fuzzer/GateKeeperServiceFuzzer.cpp b/gatekeeperd/fuzzer/GateKeeperServiceFuzzer.cpp index bc0d5fe05..a3cc3f32c 100644 --- a/gatekeeperd/fuzzer/GateKeeperServiceFuzzer.cpp +++ b/gatekeeperd/fuzzer/GateKeeperServiceFuzzer.cpp @@ -22,6 +22,8 @@ using android::fuzzService; using android::GateKeeperProxy; extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + // TODO(b/183141167): need to rewrite 'dump' to avoid SIGPIPE. + signal(SIGPIPE, SIG_IGN); auto gatekeeperService = new GateKeeperProxy(); fuzzService(gatekeeperService, FuzzedDataProvider(data, size)); return 0; From f26b13aeb1a9baec66dc592adee82cac626fcf46 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 26 Nov 2024 00:43:59 +0000 Subject: [PATCH 170/183] libprocessgroup: Remove recovery_available from libcgrouprc ...which no longer appears to be required. Bug: 349105928 Change-Id: I0ad1f44912fdaf98c05b60402c0166c535155775 --- libprocessgroup/cgrouprc/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index 38b2fa31d..c157d9b18 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -21,7 +21,6 @@ cc_library { host_supported: true, ramdisk_available: true, vendor_ramdisk_available: true, - recovery_available: true, // Do not ever mark this as vendor_available; otherwise, vendor modules // that links to the static library will behave unexpectedly. All on-device // modules should use libprocessgroup which links to the LL-NDK library From 62f8723f6764a3d45a48b772691c1e677e90e259 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 26 Nov 2024 00:44:41 +0000 Subject: [PATCH 171/183] libprocessgroup: Remove vendor_ramdisk_available from libcgrouprc ...which no longer appears to be required. Bug: 349105928 Change-Id: I9fc71f9cf3238dcc935da63ce1a3b0b69d9cccc1 --- libprocessgroup/cgrouprc/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index c157d9b18..4007a2344 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -20,7 +20,6 @@ cc_library { name: "libcgrouprc", host_supported: true, ramdisk_available: true, - vendor_ramdisk_available: true, // Do not ever mark this as vendor_available; otherwise, vendor modules // that links to the static library will behave unexpectedly. All on-device // modules should use libprocessgroup which links to the LL-NDK library From 8972ce18d2d8cf1177654c60194083dde00ae617 Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Tue, 26 Nov 2024 00:44:58 +0000 Subject: [PATCH 172/183] libprocessgroup: Remove ramdisk_available from libcgrouprc ...which no longer appears to be required. Bug: 349105928 Change-Id: I0586f76147d9519ef6a520a10164e1b0f5e5c9b8 --- libprocessgroup/cgrouprc/Android.bp | 1 - 1 file changed, 1 deletion(-) diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index 4007a2344..9e46b8e7c 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -19,7 +19,6 @@ package { cc_library { name: "libcgrouprc", host_supported: true, - ramdisk_available: true, // Do not ever mark this as vendor_available; otherwise, vendor modules // that links to the static library will behave unexpectedly. All on-device // modules should use libprocessgroup which links to the LL-NDK library From 00a32314acb08eef5c76439d4535789fe23ed0b0 Mon Sep 17 00:00:00 2001 From: Akilesh Kailash Date: Mon, 2 Dec 2024 10:58:46 -0800 Subject: [PATCH 173/183] libsnapshot: Cleanup temp metadata during rollback Bug: 380471512 Test: Test rollback and check metadata is cleared Change-Id: I4ebd5d9842409fa32c58bb482ffc0066817a5a05 Signed-off-by: Akilesh Kailash --- fs_mgr/libsnapshot/snapshot.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index acabd6770..ecf567eb8 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -2404,6 +2404,9 @@ bool SnapshotManager::NeedSnapshotsInFirstStageMount() { PLOG(ERROR) << "Unable to write rollback indicator: " << path; } else { LOG(INFO) << "Rollback detected, writing rollback indicator to " << path; + if (device_->IsTempMetadata()) { + CleanupScratchOtaMetadataIfPresent(); + } } } LOG(INFO) << "Not booting from new slot. Will not mount snapshots."; From ee7a713757314366023e855a76ff17943b6b9296 Mon Sep 17 00:00:00 2001 From: "Isaac J. Manjarres" Date: Tue, 3 Dec 2024 09:42:56 -0800 Subject: [PATCH 174/183] ashmem: Ensure all memfds have non-executable permissions by default Currently, memfds are created with executable permissions, meaning that one can load a binary into a memfd buffer and use fexecve() to run said binary. This is not desirable for security reasons, and also does not match with the behavior that the ashmem driver currently supports. When the ashmem driver is in use, /dev/ashmem* does not have executable permissions, so fexecve() cannot be used on those buffers. Linux kernels 6.3+ offer MFD_NOEXEC_SEAL as part of the memfd interface, which allows one to create memfds with non-executable permissions. Furthermore, the executable permissions cannot be changed on these memfds. This matches the expected behavior that ashmem provided, so allow memfd usage only if MFD_NOEXEC_SEAL is supported, and create memfds with non-executable permissions by default. Bug: 111903542 Change-Id: Ibb2c2be3c118ead44fc12bcd2b63dcf6f83c9b03 Signed-off-by: Isaac J. Manjarres --- libcutils/ashmem-dev.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp index 46b8ef263..cebfa5d12 100644 --- a/libcutils/ashmem-dev.cpp +++ b/libcutils/ashmem-dev.cpp @@ -114,8 +114,14 @@ static bool __has_memfd_support() { // Check if kernel support exists, otherwise fall back to ashmem. // This code needs to build on old API levels, so we can't use the libc // wrapper. + // + // MFD_NOEXEC_SEAL is used to match the semantics of the ashmem device, + // which did not have executable permissions. This also seals the executable + // permissions of the buffer (i.e. they cannot be changed by fchmod()). + // + // MFD_NOEXEC_SEAL implies MFD_ALLOW_SEALING. android::base::unique_fd fd( - syscall(__NR_memfd_create, "test_android_memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING)); + syscall(__NR_memfd_create, "test_android_memfd", MFD_CLOEXEC | MFD_NOEXEC_SEAL)); if (fd == -1) { ALOGE("memfd_create failed: %s, no memfd support.\n", strerror(errno)); return false; @@ -289,7 +295,13 @@ int ashmem_valid(int fd) static int memfd_create_region(const char* name, size_t size) { // This code needs to build on old API levels, so we can't use the libc // wrapper. - android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_CLOEXEC | MFD_ALLOW_SEALING)); + // + // MFD_NOEXEC_SEAL to match the semantics of the ashmem device, which did + // not have executable permissions. This also seals the executable + // permissions of the buffer (i.e. they cannot be changed by fchmod()). + // + // MFD_NOEXEC_SEAL implies MFD_ALLOW_SEALING. + android::base::unique_fd fd(syscall(__NR_memfd_create, name, MFD_CLOEXEC | MFD_NOEXEC_SEAL)); if (fd == -1) { ALOGE("memfd_create(%s, %zd) failed: %s\n", name, size, strerror(errno)); From 7a1cf9a52d526ed265ce0a3c2ea380fb65e58bcc Mon Sep 17 00:00:00 2001 From: Matt Gilbride Date: Tue, 3 Dec 2024 22:44:52 +0000 Subject: [PATCH 175/183] Update trusty to use secretkeeper hal V1 The HAL has been updated to V2, but the trusty prebuilt implementation does not yet have that code. Update trusty secretkeeper build to use V1 specifically instead of latest until the prebuilt has those changes. Bug: 372223451 Test: TH Change-Id: Ic2e9b578b50685d71b5597d8d34ac7ee36b6ddc9 --- trusty/secretkeeper/Android.bp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/trusty/secretkeeper/Android.bp b/trusty/secretkeeper/Android.bp index 6523edaf6..d399bf86d 100644 --- a/trusty/secretkeeper/Android.bp +++ b/trusty/secretkeeper/Android.bp @@ -27,18 +27,16 @@ rust_binary { "src/hal_main.rs", ], rustlibs: [ + "android.hardware.security.secretkeeper-V1-rust", "libandroid_logger", "libauthgraph_hal", "libauthgraph_wire", "libbinder_rs", "liblibc", "liblog_rust", - "libsecretkeeper_hal", + "libsecretkeeper_hal_v1", "libtrusty-rs", ], - defaults: [ - "secretkeeper_use_latest_hal_aidl_rust", - ], prefer_rlib: true, } From 683e3c07614f452baf3e18f67a1140988709b0f2 Mon Sep 17 00:00:00 2001 From: Dennis Shen Date: Thu, 26 Sep 2024 13:36:18 +0000 Subject: [PATCH 176/183] Start aconfigd socket defined in configinfra mainline module Context: to have better future updatability. The responsiblity of managing mainline module storage files and a socket service for flag overrides will be moved to the configinfra mainline module. Later, aconfigd on /system will only be repsopnsbile for managing platform partition storage files. Bug: b/369810972 Test: m, launch avd and then inspect the logcat log to confirm the service is launched. Change-Id: I490e5aa432fa4afa236689ad0999e5602f7d297e --- rootdir/init.rc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index e487797aa..ae6a6588b 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -1004,6 +1004,11 @@ on post-fs-data exec_start system_aconfigd_mainline_init start system_aconfigd_socket_service + # start mainline aconfigd init, after transition, the above system_aconfigd_mainline_init + # will be deprecated + exec_start mainline_aconfigd_init + start mainline_aconfigd_socket_service + # Create directories for boot animation. mkdir /data/misc/bootanim 0755 system system From 44eca61ab95b304d4cf6a2cc89b2fb4ce1d5aa29 Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Wed, 4 Dec 2024 23:23:22 +0000 Subject: [PATCH 177/183] Replace partition-specific toybox make module with soong modules toybox no longer sets recovery_available property, thus this make module is no longer generated. Thus, replace the entry with the soong modules to prevent missing dependencies make error. This change also specifies `recovery` property in shell_and_utilities_recovery to allow soong generated recovery partition to correctly install the dependencies of the phony module. Test: m nothing Bug: 381888358 Change-Id: I314e8031d23a9f579101ca1d5499969af4e3a9d3 --- shell_and_utilities/Android.bp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp index 1f5c1795c..0a1f7c5a2 100644 --- a/shell_and_utilities/Android.bp +++ b/shell_and_utilities/Android.bp @@ -43,9 +43,10 @@ phony { required: [ "sh.recovery", "toolbox.recovery", - "toybox.recovery", + "toybox_recovery", "ziptool.recovery", ], + recovery: true, } phony { From 09e7cea7c1b611dd1fffc2d2d3fec94bee4e5218 Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Fri, 6 Dec 2024 01:51:35 +0000 Subject: [PATCH 178/183] Define toolbox.recovery By removing `recovery_available` property from "toolbox" and defining a dedicated recovery-specific module for "toolbox". `recovery_available` property should be used to allow the reverse dependencies recovery modules to depend on the module, not to install the module to the recovery partition. Test: m soong_generated_recovery_filesystem_test Bug: 381888358 Change-Id: I8e1bbf56aaf5ba4a761d84e60afa420ba6f825b9 --- toolbox/Android.bp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/toolbox/Android.bp b/toolbox/Android.bp index 120cc6e16..314254298 100644 --- a/toolbox/Android.bp +++ b/toolbox/Android.bp @@ -68,10 +68,16 @@ cc_defaults { cc_binary { name: "toolbox", defaults: ["toolbox_binary_defaults"], - recovery_available: true, vendor_ramdisk_available: true, } +cc_binary { + name: "toolbox.recovery", + defaults: ["toolbox_binary_defaults"], + recovery: true, + stem: "toolbox", +} + cc_binary { name: "toolbox_vendor", stem: "toolbox", From fdd861ef7e3490ab3c0fa9766ca12a5ce2c7376e Mon Sep 17 00:00:00 2001 From: "T.J. Mercier" Date: Fri, 6 Dec 2024 17:52:29 +0000 Subject: [PATCH 179/183] debuggerd: Use libprocessgroup to unfreeze Cgroup v2 paths are owned by libprocessgroup. Those paths can change based on build flags, so paths generated outside of libprocessgroup may not always be correct. Bug: 382693152 Test: adb shell debuggerd -b Change-Id: I7e486ab6f4068d0fae1be033a91b9a307f54ed42 --- debuggerd/Android.bp | 1 + debuggerd/debuggerd.cpp | 11 +++-------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 3257a2c50..0e62ceb8f 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -505,6 +505,7 @@ cc_binary { "libbase", "libdebuggerd_client", "liblog", + "libprocessgroup", "libprocinfo", ], diff --git a/debuggerd/debuggerd.cpp b/debuggerd/debuggerd.cpp index 0d4b91f75..7a2500c60 100644 --- a/debuggerd/debuggerd.cpp +++ b/debuggerd/debuggerd.cpp @@ -23,11 +23,11 @@ #include #include -#include #include #include #include #include +#include #include #include "util.h" @@ -92,13 +92,8 @@ int main(int argc, char* argv[]) { } // unfreeze if pid is frozen. - const std::string freeze_file = android::base::StringPrintf( - "/sys/fs/cgroup/uid_%d/pid_%d/cgroup.freeze", proc_info.uid, proc_info.pid); - if (std::string freeze_status; - android::base::ReadFileToString(freeze_file, &freeze_status) && freeze_status[0] == '1') { - android::base::WriteStringToFile("0", freeze_file); - // we don't restore the frozen state as this is considered a benign change. - } + SetProcessProfiles(proc_info.uid, proc_info.pid, {"Unfrozen"}); + // we don't restore the frozen state as this is considered a benign change. unique_fd output_fd(fcntl(STDOUT_FILENO, F_DUPFD_CLOEXEC, 0)); if (output_fd.get() == -1) { From 2e581b68c6f171989b656d79457acf0e71364cab Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Fri, 6 Dec 2024 23:18:18 +0000 Subject: [PATCH 180/183] Define reboot.recovery and watchdogd.recovery By removing the "recovery_available" property from "reboot" and "watchdogd" modules. "recovery_available" property should be used to allow the reverse dependencies recovery modules to depend on the module, not to install the module to the recovery partition. Test: m soong_generated_recovery_filesystem_test Bug: 381888358 Change-Id: I48014774714957885f3ad648ac302cc3c13687ae --- reboot/Android.bp | 21 ++++++++++++++++++--- watchdogd/Android.bp | 21 ++++++++++++++++++--- 2 files changed, 36 insertions(+), 6 deletions(-) diff --git a/reboot/Android.bp b/reboot/Android.bp index 7b243bd56..1cca82457 100644 --- a/reboot/Android.bp +++ b/reboot/Android.bp @@ -4,10 +4,25 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } -cc_binary { - name: "reboot", +cc_defaults { + name: "reboot_defaults", srcs: ["reboot.c"], shared_libs: ["libcutils"], cflags: ["-Werror"], - recovery_available: true, +} + +cc_binary { + name: "reboot", + defaults: [ + "reboot_defaults", + ], +} + +cc_binary { + name: "reboot.recovery", + defaults: [ + "reboot_defaults", + ], + recovery: true, + stem: "reboot", } diff --git a/watchdogd/Android.bp b/watchdogd/Android.bp index 03882082f..bc7ffb656 100644 --- a/watchdogd/Android.bp +++ b/watchdogd/Android.bp @@ -2,9 +2,8 @@ package { default_applicable_licenses: ["Android-Apache-2.0"], } -cc_binary { - name: "watchdogd", - recovery_available: true, +cc_defaults { + name: "watchdogd_defaults", srcs: ["watchdogd.cpp"], cflags: [ "-Wall", @@ -16,3 +15,19 @@ cc_binary { misc_undefined: ["signed-integer-overflow"], }, } + +cc_binary { + name: "watchdogd", + defaults: [ + "watchdogd_defaults", + ], +} + +cc_binary { + name: "watchdogd.recovery", + defaults: [ + "watchdogd_defaults", + ], + recovery: true, + stem: "watchdogd", +} From 9b5c6fdce8a142b281ccca5da0a8edbe0a3bd2df Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Fri, 6 Dec 2024 23:33:42 +0000 Subject: [PATCH 181/183] Define init_second_stage.recovery By removing `recovery_available` property from "init_second_stage" and defining a dedicated recovery-specific module for "init_second_stage". `recovery_available` property should be used to allow the reverse dependencies recovery modules to depend on the module, not to install the module to the recovery partition. Test: m soong_generated_recovery_filesystem_test Bug: 381888358 Change-Id: Ie9b93b8453bc1e40f7a28e57f498313d3bc4cedb --- init/Android.bp | 65 ++++++++++++++++++++++++------------------------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index 4ee3be222..ed19b4b86 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -268,7 +268,6 @@ phony { cc_defaults { name: "init_second_stage_defaults", - recovery_available: true, stem: "init", defaults: ["init_defaults"], srcs: ["main.cpp"], @@ -280,37 +279,38 @@ cc_binary { defaults: ["init_second_stage_defaults"], static_libs: ["libinit"], visibility: ["//visibility:any_system_partition"], - target: { - platform: { - required: [ - "init.rc", - "ueventd.rc", - "e2fsdroid", - "extra_free_kbytes", - "make_f2fs", - "mke2fs", - "sload_f2fs", - ], - }, - recovery: { - cflags: ["-DRECOVERY"], - exclude_static_libs: [ - "libxml2", - ], - exclude_shared_libs: [ - "libbinder", - "libutils", - ], - required: [ - "init_recovery.rc", - "ueventd.rc.recovery", - "e2fsdroid.recovery", - "make_f2fs.recovery", - "mke2fs.recovery", - "sload_f2fs.recovery", - ], - }, - }, + required: [ + "init.rc", + "ueventd.rc", + "e2fsdroid", + "extra_free_kbytes", + "make_f2fs", + "mke2fs", + "sload_f2fs", + ], +} + +cc_binary { + name: "init_second_stage.recovery", + defaults: ["init_second_stage_defaults"], + static_libs: ["libinit"], + recovery: true, + cflags: ["-DRECOVERY"], + exclude_static_libs: [ + "libxml2", + ], + exclude_shared_libs: [ + "libbinder", + "libutils", + ], + required: [ + "init_recovery.rc", + "ueventd.rc.recovery", + "e2fsdroid.recovery", + "make_f2fs.recovery", + "mke2fs.recovery", + "sload_f2fs.recovery", + ], } cc_binary { @@ -319,7 +319,6 @@ cc_binary { "avf_build_flags_cc", "init_second_stage_defaults", ], - recovery_available: false, static_libs: ["libinit.microdroid"], cflags: ["-DMICRODROID=1"], no_full_install: true, From f9b38f91ac869e1f9eb9e76120aa695ba26540aa Mon Sep 17 00:00:00 2001 From: Jihoon Kang Date: Fri, 6 Dec 2024 23:53:38 +0000 Subject: [PATCH 182/183] Define ueventd.rc.recovery By removing `recovery_available` property from "ueventd.rc" and defining a dedicated recovery-specific module for "ueventd.rc". `recovery_available` property should be used to allow the reverse dependencies recovery modules to depend on the module, not to install the module to the recovery partition. Test: m soong_generated_recovery_filesystem_test Bug: 381888358 Change-Id: I6921cae72a1757e065003efc9d77241625f645e9 --- rootdir/Android.bp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/rootdir/Android.bp b/rootdir/Android.bp index 44acbbae4..4debbbece 100644 --- a/rootdir/Android.bp +++ b/rootdir/Android.bp @@ -47,7 +47,12 @@ prebuilt_etc { prebuilt_etc { name: "ueventd.rc", src: "ueventd.rc", - recovery_available: true, +} + +prebuilt_etc { + name: "ueventd.rc.recovery", + src: "ueventd.rc", + recovery: true, } filegroup { From d189b8755ad42c334c2ac1c21319d4570a15c4af Mon Sep 17 00:00:00 2001 From: "Pechetty Sravani (xWF)" Date: Mon, 9 Dec 2024 02:46:21 +0000 Subject: [PATCH 183/183] Revert "Define ueventd.rc.recovery" This reverts commit f9b38f91ac869e1f9eb9e76120aa695ba26540aa. Reason for revert: Change-Id: Ib6f759fc3dee7800acf9a2c1e24eea2962730167 --- rootdir/Android.bp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/rootdir/Android.bp b/rootdir/Android.bp index 4debbbece..44acbbae4 100644 --- a/rootdir/Android.bp +++ b/rootdir/Android.bp @@ -47,12 +47,7 @@ prebuilt_etc { prebuilt_etc { name: "ueventd.rc", src: "ueventd.rc", -} - -prebuilt_etc { - name: "ueventd.rc.recovery", - src: "ueventd.rc", - recovery: true, + recovery_available: true, } filegroup {