diff options
Diffstat (limited to 'cmds')
38 files changed, 1098 insertions, 326 deletions
diff --git a/cmds/atrace/README.md b/cmds/atrace/README.md new file mode 100644 index 0000000000..faa43b222f --- /dev/null +++ b/cmds/atrace/README.md @@ -0,0 +1,48 @@ +# Atrace categories + +The atrace command (and the perfetto configuration) allow listing **categories** +to select subsets of events to be traced. + +Each category can include some userspace events and some ftrace events. + +## Vendor categories + +It's possible to extend exiting categories (or to define new categories) from +the /vendor partition in order to add hardware specific ftrace events. + +Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt`, atrace +and perfetto will consider the categories and ftrace events listed there. + +The file contains a list of categories, and for each category (on the following +lines, indented with one or more spaces of time), a list of ftrace events that +should be enabled when the category is enabled. + +Each ftrace event should be a subdirectory in `/sys/kernel/tracing/events/` and +should be of the form `group/event`. Listing a whole group is not supported, +each event needs to be listed explicitly. + +It is not an error if an ftrace event is listed in the file, but not present on +the tracing file system. + +Example: + +``` +gfx + mali/gpu_power_state + mali/mali_pm_status +thermal_tj + thermal_exynos/thermal_cpu_pressure + thermal_exynos/thermal_exynos_arm_update +``` + +The file lists two categories (`gfx` and `thermal_tj`). When the `gfx` category +is enabled, atrace (or perfetto) will enable +`/sys/kernel/tracing/events/mali/gpu_power_state` and +`/sys/kernel/tracing/events/mali/mali_pm_status`. When the `thermal_tj` category +is enabled, atrace (or perfetto) will enable +`/sys/kernel/tracing/events/thermal_exynos/thermal_cpu_pressure` and +`/sys/kernel/tracing/events/thermal_exynos/thermal_exynos_arm_update`. + +Since android 14, if the file `/vendor/etc/atrace/atrace_categories.txt` exists +on the file system, perfetto and atrace do not query the android.hardware.atrace +HAL (which is deprecated). diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp index 6fb9a4d112..81056262c3 100644 --- a/cmds/atrace/atrace.cpp +++ b/cmds/atrace/atrace.cpp @@ -49,6 +49,7 @@ #include <android-base/file.h> #include <android-base/macros.h> #include <android-base/properties.h> +#include <android-base/strings.h> #include <android-base/stringprintf.h> using namespace android; @@ -62,7 +63,7 @@ using hardware::atrace::V1_0::toString; using std::string; -#define MAX_SYS_FILES 12 +#define MAX_SYS_FILES 13 const char* k_traceTagsProperty = "debug.atrace.tags.enableflags"; const char* k_userInitiatedTraceProperty = "debug.atrace.user_initiated"; @@ -73,7 +74,9 @@ const char* k_coreServiceCategory = "core_services"; const char* k_pdxServiceCategory = "pdx"; const char* k_coreServicesProp = "ro.atrace.core.services"; -typedef enum { OPT, REQ } requiredness ; +const char* kVendorCategoriesPath = "/vendor/etc/atrace/atrace_categories.txt"; + +typedef enum { OPT, REQ } requiredness; struct TracingCategory { // The name identifying the category. @@ -189,12 +192,15 @@ static const TracingCategory k_categories[] = { { OPT, "events/f2fs/f2fs_sync_file_exit/enable" }, { OPT, "events/f2fs/f2fs_write_begin/enable" }, { OPT, "events/f2fs/f2fs_write_end/enable" }, + { OPT, "events/f2fs/f2fs_iostat/enable" }, + { OPT, "events/f2fs/f2fs_iostat_latency/enable" }, { OPT, "events/ext4/ext4_da_write_begin/enable" }, { OPT, "events/ext4/ext4_da_write_end/enable" }, { OPT, "events/ext4/ext4_sync_file_enter/enable" }, { OPT, "events/ext4/ext4_sync_file_exit/enable" }, - { REQ, "events/block/block_rq_issue/enable" }, - { REQ, "events/block/block_rq_complete/enable" }, + { OPT, "events/block/block_bio_queue/enable" }, + { OPT, "events/block/block_bio_complete/enable" }, + { OPT, "events/ufs/ufshcd_command/enable" }, } }, { "mmc", "eMMC commands", 0, { { REQ, "events/mmc/enable" }, @@ -252,7 +258,20 @@ static const TracingCategory k_categories[] = { } }, }; -struct TracingVendorCategory { +// A category in the vendor categories file. +struct TracingVendorFileCategory { + // The name identifying the category. + std::string name; + + // If the category is enabled through command. + bool enabled = false; + + // Paths to the ftrace enable files (relative to g_traceFolder). + std::vector<std::string> ftrace_enable_paths; +}; + +// A category in the vendor HIDL HAL. +struct TracingVendorHalCategory { // The name identifying the category. std::string name; @@ -262,11 +281,8 @@ struct TracingVendorCategory { // If the category is enabled through command. bool enabled; - TracingVendorCategory(string &&name, string &&description, bool enabled) - : name(std::move(name)) - , description(std::move(description)) - , enabled(enabled) - {} + TracingVendorHalCategory(string&& name, string&& description, bool enabled) + : name(std::move(name)), description(std::move(description)), enabled(enabled) {} }; /* Command line options */ @@ -286,8 +302,9 @@ static bool g_tracePdx = false; static bool g_traceAborted = false; static bool g_categoryEnables[arraysize(k_categories)] = {}; static std::string g_traceFolder; +static std::vector<TracingVendorFileCategory> g_vendorFileCategories; static sp<IAtraceDevice> g_atraceHal; -static std::vector<TracingVendorCategory> g_vendorCategories; +static std::vector<TracingVendorHalCategory> g_vendorHalCategories; /* Sys file paths */ static const char* k_traceClockPath = @@ -644,6 +661,13 @@ static bool disableKernelTraceEvents() { } } } + for (const TracingVendorFileCategory& c : g_vendorFileCategories) { + for (const std::string& path : c.ftrace_enable_paths) { + if (fileIsWritable(path.c_str())) { + ok &= setKernelOptionEnable(path.c_str(), false); + } + } + } return ok; } @@ -723,7 +747,13 @@ static bool setKernelTraceFuncs(const char* funcs) static bool setCategoryEnable(const char* name) { bool vendor_found = false; - for (auto &c : g_vendorCategories) { + for (auto& c : g_vendorFileCategories) { + if (strcmp(name, c.name.c_str()) == 0) { + c.enabled = true; + vendor_found = true; + } + } + for (auto& c : g_vendorHalCategories) { if (strcmp(name, c.name.c_str()) == 0) { c.enabled = true; vendor_found = true; @@ -869,6 +899,16 @@ static bool setUpKernelTracing() } } + for (const TracingVendorFileCategory& c : g_vendorFileCategories) { + if (c.enabled) { + for (const std::string& path : c.ftrace_enable_paths) { + if (fileIsWritable(path.c_str())) { + ok &= setKernelOptionEnable(path.c_str(), true); + } + } + } + } + return ok; } @@ -1054,7 +1094,10 @@ static void listSupportedCategories() printf(" %10s - %s\n", c.name, c.longname); } } - for (const auto &c : g_vendorCategories) { + for (const auto& c : g_vendorFileCategories) { + printf(" %10s - (VENDOR)\n", c.name.c_str()); + } + for (const auto& c : g_vendorHalCategories) { printf(" %10s - %s (HAL)\n", c.name.c_str(), c.description.c_str()); } } @@ -1113,8 +1156,38 @@ bool findTraceFiles() return true; } -void initVendorCategories() -{ +void initVendorCategoriesFromFile() { + std::ifstream is(kVendorCategoriesPath); + for (std::string line; std::getline(is, line);) { + if (line.empty()) { + continue; + } + if (android::base::StartsWith(line, ' ') || android::base::StartsWith(line, '\t')) { + if (g_vendorFileCategories.empty()) { + fprintf(stderr, "Malformed vendor categories file\n"); + exit(1); + return; + } + std::string_view path = std::string_view(line).substr(1); + while (android::base::StartsWith(path, ' ') || android::base::StartsWith(path, '\t')) { + path.remove_prefix(1); + } + if (path.empty()) { + continue; + } + std::string enable_path = "events/"; + enable_path += path; + enable_path += "/enable"; + g_vendorFileCategories.back().ftrace_enable_paths.push_back(std::move(enable_path)); + } else { + TracingVendorFileCategory cat; + cat.name = line; + g_vendorFileCategories.push_back(std::move(cat)); + } + } +} + +void initVendorCategoriesFromHal() { g_atraceHal = IAtraceDevice::getService(); if (g_atraceHal == nullptr) { @@ -1122,27 +1195,34 @@ void initVendorCategories() return; } - Return<void> ret = g_atraceHal->listCategories( - [](const auto& list) { - g_vendorCategories.reserve(list.size()); - for (const auto& category : list) { - g_vendorCategories.emplace_back(category.name, category.description, false); - } - }); + Return<void> ret = g_atraceHal->listCategories([](const auto& list) { + g_vendorHalCategories.reserve(list.size()); + for (const auto& category : list) { + g_vendorHalCategories.emplace_back(category.name, category.description, false); + } + }); if (!ret.isOk()) { fprintf(stderr, "calling atrace HAL failed: %s\n", ret.description().c_str()); } } -static bool setUpVendorTracing() -{ +void initVendorCategories() { + // If kVendorCategoriesPath exists on the filesystem, do not use the HAL. + if (access(kVendorCategoriesPath, F_OK) != -1) { + initVendorCategoriesFromFile(); + } else { + initVendorCategoriesFromHal(); + } +} + +static bool setUpVendorTracingWithHal() { if (g_atraceHal == nullptr) { // No atrace HAL return true; } std::vector<hidl_string> categories; - for (const auto &c : g_vendorCategories) { + for (const auto& c : g_vendorHalCategories) { if (c.enabled) { categories.emplace_back(c.name); } @@ -1163,15 +1243,14 @@ static bool setUpVendorTracing() return true; } -static bool cleanUpVendorTracing() -{ +static bool cleanUpVendorTracingWithHal() { if (g_atraceHal == nullptr) { // No atrace HAL return true; } - if (!g_vendorCategories.size()) { - // No vendor categories + if (!g_vendorHalCategories.size()) { + // No vendor HAL categories return true; } @@ -1325,7 +1404,7 @@ int main(int argc, char **argv) if (ok && traceStart && !onlyUserspace) { ok &= setUpKernelTracing(); - ok &= setUpVendorTracing(); + ok &= setUpVendorTracingWithHal(); ok &= startTrace(); } @@ -1396,7 +1475,7 @@ int main(int argc, char **argv) if (traceStop) { cleanUpUserspaceTracing(); if (!onlyUserspace) { - cleanUpVendorTracing(); + cleanUpVendorTracingWithHal(); cleanUpKernelTracing(); } } diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc index 5267b0294c..dff4c44671 100644 --- a/cmds/atrace/atrace.rc +++ b/cmds/atrace/atrace.rc @@ -181,6 +181,8 @@ on late-init chmod 0666 /sys/kernel/tracing/events/clk/clk_enable/enable chmod 0666 /sys/kernel/debug/tracing/events/clk/clk_set_rate/enable chmod 0666 /sys/kernel/tracing/events/clk/clk_set_rate/enable + chmod 0666 /sys/kernel/debug/tracing/events/printk/console/enable + chmod 0666 /sys/kernel/tracing/events/printk/console/enable # disk chmod 0666 /sys/kernel/tracing/events/f2fs/f2fs_get_data_block/enable @@ -295,8 +297,18 @@ on late-init write /sys/kernel/debug/tracing/synthetic_events "rss_stat_throttled unsigned int mm_id; unsigned int curr; int member; long size" # allow creating event triggers - chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger chmod 0666 /sys/kernel/tracing/events/kmem/rss_stat/trigger + chmod 0666 /sys/kernel/debug/tracing/events/kmem/rss_stat/trigger + + # allow enabling rss_stat_throttled + chmod 0666 /sys/kernel/tracing/events/synthetic/rss_stat_throttled/enable + chmod 0666 /sys/kernel/debug/tracing/events/synthetic/rss_stat_throttled/enable + +on late-init && property:ro.boot.fastboot.boottrace=enabled + setprop debug.atrace.tags.enableflags 802922 + setprop persist.traced.enable 0 + write /sys/kernel/debug/tracing/tracing_on 1 + write /sys/kernel/tracing/tracing_on 1 # Only create the tracing instance if persist.mm_events.enabled # Attempting to remove the tracing instance after it has been created @@ -386,6 +398,103 @@ on post-fs-data && property:persist.mm_events.enabled=true chmod 0666 /sys/kernel/debug/tracing/instances/mm_events/per_cpu/cpu23/trace chmod 0666 /sys/kernel/tracing/instances/mm_events/per_cpu/cpu23/trace +# Handle hyp tracing instance +on late-init && property:ro.boot.hypervisor.vm.supported=1 + +# Hypervisor tracing instance doesn't support changing trace_clock + chmod 0440 /sys/kernel/debug/tracing/hyp/trace_clock + chmod 0440 /sys/kernel/tracing/hyp/trace_clock + + chmod 0660 /sys/kernel/debug/tracing/hyp/buffer_size_kb + chmod 0660 /sys/kernel/tracing/hyp/buffer_size_kb + + chmod 0660 /sys/kernel/debug/tracing/hyp/tracing_on + chmod 0660 /sys/kernel/tracing/hyp/tracing_on + +# Tracing disabled by default + write /sys/kernel/debug/tracing/hyp/tracing_on 0 + write /sys/kernel/tracing/hyp/tracing_on 0 + +# Read and truncate the hyp trace. + chmod 0660 /sys/kernel/debug/tracing/hyp/trace + chmod 0660 /sys/kernel/tracing/hyp/trace + +# Read and truncate the per-CPU kernel trace. +# Cannot use wildcards in .rc files. Update this if there is a phone with +# TODO(b/249050813, ioffe): introduce per-cpu wildcard + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu0/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu0/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu1/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu1/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu2/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu2/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu3/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu3/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu4/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu4/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu5/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu5/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu6/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu6/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu7/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu7/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu8/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu8/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu9/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu9/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu10/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu10/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu11/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu11/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu12/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu12/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu13/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu13/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu14/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu14/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu15/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu15/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu16/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu16/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu17/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu17/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu18/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu18/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu19/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu19/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu20/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu20/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu21/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu21/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu22/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu22/trace + chmod 0660 /sys/kernel/debug/tracing/hyp/per_cpu/cpu23/trace + chmod 0660 /sys/kernel/tracing/hyp/per_cpu/cpu23/trace + + chmod 0440 /sys/kernel/debug/tracing/hyp/events/header_page + chmod 0440 /sys/kernel/tracing/hyp/events/header_page + +# Hyp events start here + +# hyp_enter event + chmod 0660 /sys/kernel/debug/tracing/hyp/events/hyp/hyp_enter/enable + chmod 0660 /sys/kernel/tracing/hyp/events/hyp/hyp_enter/enable +# TODO(b/249050813): should this be handled in kernel? + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/hyp_enter/format + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/hyp_enter/format + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/hyp_enter/id + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/hyp_enter/id + +# hyp_exit event + chmod 0660 /sys/kernel/debug/tracing/hyp/events/hyp/hyp_exit/enable + chmod 0660 /sys/kernel/tracing/hyp/events/hyp/hyp_exit/enable +# TODO(b/249050813): should this be handled in kernel? + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/hyp_exit/format + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/hyp_exit/format + chmod 0440 /sys/kernel/debug/tracing/hyp/events/hyp/hyp_exit/id + chmod 0440 /sys/kernel/tracing/hyp/events/hyp/hyp_exit/id + + on property:persist.debug.atrace.boottrace=1 start boottrace @@ -393,3 +502,10 @@ on property:persist.debug.atrace.boottrace=1 service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categories disabled oneshot + +on property:sys.boot_completed=1 && property:ro.boot.fastboot.boottrace=enabled + setprop debug.atrace.tags.enableflags 0 + setprop persist.traced.enable 1 + write /sys/kernel/debug/tracing/tracing_on 0 + write /sys/kernel/tracing/tracing_on 0 + diff --git a/cmds/atrace/atrace_userdebug.rc b/cmds/atrace/atrace_userdebug.rc index 9186514d0a..fa7be1816a 100644 --- a/cmds/atrace/atrace_userdebug.rc +++ b/cmds/atrace/atrace_userdebug.rc @@ -18,3 +18,9 @@ on post-fs chmod 0666 /sys/kernel/tracing/events/filemap/enable chmod 0666 /sys/kernel/debug/tracing/events/filemap/enable + # Allow traced_probes to use the raw_syscall filters to trace only a subset + # of syscalls. + chmod 0666 /sys/kernel/tracing/events/raw_syscalls/sys_enter/filter + chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/filter + chmod 0666 /sys/kernel/tracing/events/raw_syscalls/sys_exit/filter + chmod 0666 /sys/kernel/debug/tracing/events/raw_syscalls/sys_exit/filter diff --git a/cmds/bugreportz/readme.md b/cmds/bugreportz/readme.md index eb0d898be1..3606827a4d 100644 --- a/cmds/bugreportz/readme.md +++ b/cmds/bugreportz/readme.md @@ -1,6 +1,6 @@ # bugreportz protocol -`bugreportz` is used to generate a zippped bugreport whose path is passed back to `adb`, using +`bugreportz` is used to generate a zipped bugreport whose path is passed back to `adb`, using the simple protocol defined below. # Version 1.1 diff --git a/cmds/dumpstate/Android.bp b/cmds/dumpstate/Android.bp index a2491e503f..a62bd01a5b 100644 --- a/cmds/dumpstate/Android.bp +++ b/cmds/dumpstate/Android.bp @@ -101,6 +101,7 @@ cc_defaults { "libhidlbase", "liblog", "libutils", + "libvintf", "libbinderdebug", "packagemanager_aidl-cpp", ], @@ -125,6 +126,7 @@ cc_binary { ], required: [ "atrace", + "bugreport_procdump", "dmabuf_dump", "ip", "iptables", diff --git a/cmds/dumpstate/TEST_MAPPING b/cmds/dumpstate/TEST_MAPPING index 839a2c3023..649a13ee1e 100644 --- a/cmds/dumpstate/TEST_MAPPING +++ b/cmds/dumpstate/TEST_MAPPING @@ -9,15 +9,15 @@ ] }, { - "name": "dumpstate_smoke_test" - }, - { "name": "dumpstate_test" } ], "postsubmit": [ { "name": "BugreportManagerTestCases" + }, + { + "name": "dumpstate_smoke_test" } ], "imports": [ diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp index ec1e89bce1..47a513be81 100644 --- a/cmds/dumpstate/dumpstate.cpp +++ b/cmds/dumpstate/dumpstate.cpp @@ -15,6 +15,7 @@ */ #define LOG_TAG "dumpstate" +#define ATRACE_TAG ATRACE_TAG_ALWAYS #include <dirent.h> #include <errno.h> @@ -76,6 +77,7 @@ #include <cutils/native_handle.h> #include <cutils/properties.h> #include <cutils/sockets.h> +#include <cutils/trace.h> #include <debuggerd/client.h> #include <dumpsys.h> #include <dumputils/dump_utils.h> @@ -88,6 +90,7 @@ #include <private/android_logger.h> #include <serviceutils/PriorityDumper.h> #include <utils/StrongPointer.h> +#include <vintf/VintfObject.h> #include "DumpstateInternal.h" #include "DumpstateService.h" #include "dumpstate.h" @@ -167,6 +170,7 @@ void add_mountinfo(); #define RECOVERY_DIR "/cache/recovery" #define RECOVERY_DATA_DIR "/data/misc/recovery" #define UPDATE_ENGINE_LOG_DIR "/data/misc/update_engine_log" +#define UPDATE_ENGINE_PREF_DIR "/data/misc/update_engine/prefs" #define LOGPERSIST_DATA_DIR "/data/misc/logd" #define PREREBOOT_DATA_DIR "/data/misc/prereboot" #define PROFILE_DATA_DIR_CUR "/data/misc/profiles/cur" @@ -180,6 +184,8 @@ void add_mountinfo(); #define PACKAGE_DEX_USE_LIST "/data/system/package-dex-usage.list" #define SYSTEM_TRACE_SNAPSHOT "/data/misc/perfetto-traces/bugreport/systrace.pftrace" #define CGROUPFS_DIR "/sys/fs/cgroup" +#define SDK_EXT_INFO "/apex/com.android.sdkext/bin/derive_sdk" +#define DROPBOX_DIR "/data/system/dropbox" // TODO(narayan): Since this information has to be kept in sync // with tombstoned, we should just put it in a common header. @@ -189,6 +195,8 @@ static const std::string TOMBSTONE_DIR = "/data/tombstones/"; static const std::string TOMBSTONE_FILE_PREFIX = "tombstone_"; static const std::string ANR_DIR = "/data/anr/"; static const std::string ANR_FILE_PREFIX = "anr_"; +static const std::string SHUTDOWN_CHECKPOINTS_DIR = "/data/system/shutdown-checkpoints/"; +static const std::string SHUTDOWN_CHECKPOINTS_FILE_PREFIX = "checkpoints-"; // TODO: temporary variables and functions used during C++ refactoring @@ -230,6 +238,7 @@ static const char* WAKE_LOCK_NAME = "dumpstate_wakelock"; // task and the log title of the duration report. static const std::string DUMP_TRACES_TASK = "DUMP TRACES"; static const std::string DUMP_INCIDENT_REPORT_TASK = "INCIDENT REPORT"; +static const std::string DUMP_NETSTATS_PROTO_TASK = "DUMP NETSTATS PROTO"; static const std::string DUMP_HALS_TASK = "DUMP HALS"; static const std::string DUMP_BOARD_TASK = "dumpstate_board()"; static const std::string DUMP_CHECKINS_TASK = "DUMP CHECKINS"; @@ -516,6 +525,15 @@ static bool skip_not_stat(const char *path) { return strcmp(path + len - sizeof(stat) + 1, stat); /* .../stat? */ } +static bool skip_wtf_strictmode(const char *path) { + if (strstr(path, "_wtf")) { + return true; + } else if (strstr(path, "_strictmode")) { + return true; + } + return false; +} + static bool skip_none(const char* path __attribute__((unused))) { return false; } @@ -762,7 +780,7 @@ uint64_t Dumpstate::ConsentCallback::getElapsedTimeMs() const { } void Dumpstate::PrintHeader() const { - std::string build, fingerprint, radio, bootloader, network; + std::string build, fingerprint, radio, bootloader, network, sdkversion; char date[80]; build = android::base::GetProperty("ro.build.display.id", "(unknown)"); @@ -770,6 +788,7 @@ void Dumpstate::PrintHeader() const { radio = android::base::GetProperty("gsm.version.baseband", "(unknown)"); bootloader = android::base::GetProperty("ro.bootloader", "(unknown)"); network = android::base::GetProperty("gsm.operator.alpha", "(unknown)"); + sdkversion = android::base::GetProperty("ro.build.version.sdk", "(unknown)"); strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", localtime(&now_)); printf("========================================================\n"); @@ -787,9 +806,10 @@ void Dumpstate::PrintHeader() const { if (module_metadata_version != 0) { printf("Module Metadata version: %" PRId64 "\n", module_metadata_version); } - printf("SDK extension versions [r=%s s=%s]\n", - android::base::GetProperty("build.version.extensions.r", "-").c_str(), - android::base::GetProperty("build.version.extensions.s", "-").c_str()); + printf("Android SDK version: %s\n", sdkversion.c_str()); + printf("SDK extensions: "); + RunCommandToFd(STDOUT_FILENO, "", {SDK_EXT_INFO, "--header"}, + CommandOptions::WithTimeout(1).Always().DropRoot().Build()); printf("Kernel: "); DumpFileToFd(STDOUT_FILENO, "", "/proc/version"); @@ -829,7 +849,8 @@ status_t Dumpstate::AddZipEntryFromFd(const std::string& entry_name, int fd, // Logging statement below is useful to time how long each entry takes, but it's too verbose. // MYLOGD("Adding zip entry %s\n", entry_name.c_str()); - int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), ZipWriter::kCompress, + size_t flags = ZipWriter::kCompress | ZipWriter::kDefaultCompression; + int32_t err = zip_writer_->StartEntryWithTime(valid_name.c_str(), flags, get_mtime(fd, ds.now_)); if (err != 0) { MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", valid_name.c_str(), @@ -921,7 +942,8 @@ void Dumpstate::AddDir(const std::string& dir, bool recursive) { bool Dumpstate::AddTextZipEntry(const std::string& entry_name, const std::string& content) { MYLOGD("Adding zip text entry %s\n", entry_name.c_str()); - int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), ZipWriter::kCompress, ds.now_); + size_t flags = ZipWriter::kCompress | ZipWriter::kDefaultCompression; + int32_t err = zip_writer_->StartEntryWithTime(entry_name.c_str(), flags, ds.now_); if (err != 0) { MYLOGE("zip_writer_->StartEntryWithTime(%s): %s\n", entry_name.c_str(), ZipWriter::ErrorCodeString(err)); @@ -1020,7 +1042,7 @@ static void DumpIncidentReport() { MYLOGE("Could not open %s to dump incident report.\n", path.c_str()); return; } - RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(120).Build()); + RunCommandToFd(fd, "", {"incident", "-u"}, CommandOptions::WithTimeout(20).Build()); bool empty = 0 == lseek(fd, 0, SEEK_END); if (!empty) { // Use a different name from "incident.proto" @@ -1033,6 +1055,26 @@ static void DumpIncidentReport() { } } +static void DumpNetstatsProto() { + const std::string path = ds.bugreport_internal_dir_ + "/tmp_netstats_proto"; + auto fd = android::base::unique_fd(TEMP_FAILURE_RETRY(open(path.c_str(), + O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC | O_NOFOLLOW, + S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH))); + if (fd < 0) { + MYLOGE("Could not open %s to dump netstats proto.\n", path.c_str()); + return; + } + RunCommandToFd(fd, "", {"dumpsys", "netstats", "--proto"}, + CommandOptions::WithTimeout(120).Build()); + bool empty = 0 == lseek(fd, 0, SEEK_END); + if (!empty) { + ds.EnqueueAddZipEntryAndCleanupIfNeeded(kProtoPath + "netstats" + kProtoExt, + path); + } else { + unlink(path.c_str()); + } +} + static void MaybeAddSystemTraceToZip() { // This function copies into the .zip the system trace that was snapshotted // by the early call to MaybeSnapshotSystemTrace(), if any background @@ -1058,7 +1100,7 @@ static void DumpVisibleWindowViews() { return; } RunCommandToFd(fd, "", {"cmd", "window", "dump-visible-window-views"}, - CommandOptions::WithTimeout(120).Build()); + CommandOptions::WithTimeout(10).Build()); bool empty = 0 == lseek(fd, 0, SEEK_END); if (!empty) { ds.AddZipEntry("visible_windows.zip", path); @@ -1079,6 +1121,16 @@ static void DumpIpTablesAsRoot() { RunCommand("IP6TABLES RAW", {"ip6tables", "-t", "raw", "-L", "-nvx"}); } +static void DumpShutdownCheckpoints() { + const bool shutdown_checkpoints_dumped = AddDumps( + ds.shutdown_checkpoints_.begin(), ds.shutdown_checkpoints_.end(), + "SHUTDOWN CHECKPOINTS", false /* add_to_zip */); + if (!shutdown_checkpoints_dumped) { + printf("*** NO SHUTDOWN CHECKPOINTS to dump in %s\n\n", + SHUTDOWN_CHECKPOINTS_DIR.c_str()); + } +} + static void DumpDynamicPartitionInfo() { if (!::android::base::GetBoolProperty("ro.boot.dynamic_partitions", false)) { return; @@ -1394,6 +1446,25 @@ static void DumpHals(int out_fd = STDOUT_FILENO) { } } +// Dump all of the files that make up the vendor interface. +// See the files listed in dumpFileList() for the latest list of files. +static void DumpVintf() { + + const std::string sku = android::base::GetProperty("ro.boot.product.hardware.sku", ""); + const auto vintfFiles = android::vintf::details::dumpFileList(sku); + for (const auto vintfFile : vintfFiles) { + struct stat st; + if (stat(vintfFile.c_str(), &st) == 0) { + if (S_ISDIR(st.st_mode)) { + ds.AddDir(vintfFile, true /* recursive */); + } else { + ds.EnqueueAddZipEntryAndCleanupIfNeeded(ZIP_ROOT_DIR + vintfFile, + vintfFile); + } + } + } +} + static void DumpExternalFragmentationInfo() { struct stat st; if (stat("/proc/buddyinfo", &st) != 0) { @@ -1486,7 +1557,6 @@ static void DumpCheckins(int out_fd = STDOUT_FILENO) { dprintf(out_fd, "========================================================\n"); RunDumpsys("CHECKIN BATTERYSTATS", {"batterystats", "-c"}, out_fd); - RunDumpsys("CHECKIN MEMINFO", {"meminfo", "--checkin"}, out_fd); RunDumpsys("CHECKIN NETSTATS", {"netstats", "--checkin"}, out_fd); RunDumpsys("CHECKIN PROCSTATS", {"procstats", "-c"}, out_fd); RunDumpsys("CHECKIN USAGESTATS", {"usagestats", "-c"}, out_fd); @@ -1550,7 +1620,8 @@ static Dumpstate::RunStatus dumpstate() { DurationReporter duration_reporter("DUMPSTATE"); // Enqueue slow functions into the thread pool, if the parallel run is enabled. - std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins; + std::future<std::string> dump_hals, dump_incident_report, dump_board, dump_checkins, + dump_netstats_report; if (ds.dump_pool_) { // Pool was shutdown in DumpstateDefaultAfterCritical method in order to // drop root user. Restarts it with two threads for the parallel run. @@ -1559,6 +1630,8 @@ static Dumpstate::RunStatus dumpstate() { dump_hals = ds.dump_pool_->enqueueTaskWithFd(DUMP_HALS_TASK, &DumpHals, _1); dump_incident_report = ds.dump_pool_->enqueueTask( DUMP_INCIDENT_REPORT_TASK, &DumpIncidentReport); + dump_netstats_report = ds.dump_pool_->enqueueTask( + DUMP_NETSTATS_PROTO_TASK, &DumpNetstatsProto); dump_board = ds.dump_pool_->enqueueTaskWithFd( DUMP_BOARD_TASK, &Dumpstate::DumpstateBoard, &ds, _1); dump_checkins = ds.dump_pool_->enqueueTaskWithFd(DUMP_CHECKINS_TASK, &DumpCheckins, _1); @@ -1574,7 +1647,8 @@ static Dumpstate::RunStatus dumpstate() { RunCommand("CPU INFO", {"top", "-b", "-n", "1", "-H", "-s", "6", "-o", "pid,tid,user,pr,ni,%cpu,s,virt,res,pcy,cmd,name"}); - RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "PROCRANK", {"procrank"}, AS_ROOT_20); + RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "BUGREPORT_PROCDUMP", {"bugreport_procdump"}, + CommandOptions::AS_ROOT); RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(DumpVisibleWindowViews); @@ -1591,9 +1665,6 @@ static Dumpstate::RunStatus dumpstate() { RunCommand("PROCESSES AND THREADS", {"ps", "-A", "-T", "-Z", "-O", "pri,nice,rtprio,sched,pcy,time"}); - RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(RunCommand, "LIBRANK", {"librank"}, - CommandOptions::AS_ROOT); - if (ds.dump_pool_) { WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_hals)); } else { @@ -1619,9 +1690,9 @@ static Dumpstate::RunStatus dumpstate() { do_dmesg(); } - RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT); + DumpVintf(); - RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK(for_each_pid, do_showmap, "SMAPS OF ALL PROCESSES"); + RunCommand("LIST OF OPEN FILES", {"lsof"}, CommandOptions::AS_ROOT); for_each_tid(show_wchan, "BLOCKED PROCESS WAIT-CHANNELS"); for_each_pid(show_showtime, "PROCESS TIMES (pid cmd user system iowait+percentage)"); @@ -1652,6 +1723,8 @@ static Dumpstate::RunStatus dumpstate() { DoKmsg(); + DumpShutdownCheckpoints(); + DumpIpAddrAndRules(); dump_route_tables(); @@ -1755,6 +1828,13 @@ static Dumpstate::RunStatus dumpstate() { dump_frozen_cgroupfs(); if (ds.dump_pool_) { + WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_netstats_report)); + } else { + RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_NETSTATS_PROTO_TASK, + DumpNetstatsProto); + } + + if (ds.dump_pool_) { WAIT_TASK_WITH_CONSENT_CHECK(std::move(dump_incident_report)); } else { RUN_SLOW_FUNCTION_WITH_CONSENT_CHECK_AND_LOG(DUMP_INCIDENT_REPORT_TASK, @@ -1799,11 +1879,14 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { if (!PropertiesHelper::IsDryRun()) { ds.tombstone_data_ = GetDumpFds(TOMBSTONE_DIR, TOMBSTONE_FILE_PREFIX); ds.anr_data_ = GetDumpFds(ANR_DIR, ANR_FILE_PREFIX); + ds.shutdown_checkpoints_ = GetDumpFds( + SHUTDOWN_CHECKPOINTS_DIR, SHUTDOWN_CHECKPOINTS_FILE_PREFIX); } ds.AddDir(RECOVERY_DIR, true); ds.AddDir(RECOVERY_DATA_DIR, true); ds.AddDir(UPDATE_ENGINE_LOG_DIR, true); + ds.AddDir(UPDATE_ENGINE_PREF_DIR, true); ds.AddDir(LOGPERSIST_DATA_DIR, false); if (!PropertiesHelper::IsUserBuild()) { ds.AddDir(PROFILE_DATA_DIR_CUR, true); @@ -1815,6 +1898,11 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { DumpIpTablesAsRoot(); DumpDynamicPartitionInfo(); ds.AddDir(OTA_METADATA_DIR, true); + if (!PropertiesHelper::IsUserBuild()) { + // Include dropbox entry files inside ZIP, but exclude + // noisy WTF and StrictMode entries + dump_files("", DROPBOX_DIR, skip_wtf_strictmode, _add_file_from_fd); + } // Capture any IPSec policies in play. No keys are exposed here. RunCommand("IP XFRM POLICY", {"ip", "xfrm", "policy"}, CommandOptions::WithTimeout(10).Build()); @@ -1836,6 +1924,9 @@ Dumpstate::RunStatus Dumpstate::DumpstateDefaultAfterCritical() { DumpFile("PSI memory", "/proc/pressure/memory"); DumpFile("PSI io", "/proc/pressure/io"); + RunCommand("SDK EXTENSIONS", {SDK_EXT_INFO, "--dump"}, + CommandOptions::WithTimeout(10).Always().DropRoot().Build()); + if (dump_pool_) { RETURN_IF_USER_DENIED_CONSENT(); WaitForTask(std::move(dump_traces)); @@ -2847,6 +2938,7 @@ void Dumpstate::Cancel() { } tombstone_data_.clear(); anr_data_.clear(); + shutdown_checkpoints_.clear(); // Instead of shutdown the pool, we delete temporary files directly since // shutdown blocking the call. @@ -3076,7 +3168,9 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, TEMP_FAILURE_RETRY(dup2(dup_stdout_fd, fileno(stdout))); // Zip the (now complete) .tmp file within the internal directory. + ATRACE_BEGIN("FinalizeFile"); FinalizeFile(); + ATRACE_END(); // Share the final file with the caller if the user has consented or Shell is the caller. Dumpstate::RunStatus status = Dumpstate::RunStatus::OK; @@ -3128,6 +3222,7 @@ Dumpstate::RunStatus Dumpstate::RunInternal(int32_t calling_uid, tombstone_data_.clear(); anr_data_.clear(); + shutdown_checkpoints_.clear(); return (consent_callback_ != nullptr && consent_callback_->getResult() == UserConsentResult::UNAVAILABLE) @@ -3164,15 +3259,7 @@ void Dumpstate::MaybeSnapshotSystemTrace() { } void Dumpstate::MaybeSnapshotWinTrace() { - // Currently WindowManagerService and InputMethodManagerSerivice support WinScope protocol. - for (const auto& service : {"window", "input_method"}) { - RunCommand( - // Empty name because it's not intended to be classified as a bugreport section. - // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport. - "", {"cmd", service, "tracing", "save-for-bugreport"}, - CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); - } - // Additionally, include the proto logging from WMShell. + // Include the proto logging from WMShell. RunCommand( // Empty name because it's not intended to be classified as a bugreport section. // Actual logging files can be found as "/data/misc/wmtrace/shell_log.winscope" @@ -3181,6 +3268,14 @@ void Dumpstate::MaybeSnapshotWinTrace() { "WMShell", "protolog", "save-for-bugreport"}, CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); + // Currently WindowManagerService and InputMethodManagerSerivice support WinScope protocol. + for (const auto& service : {"window", "input_method"}) { + RunCommand( + // Empty name because it's not intended to be classified as a bugreport section. + // Actual tracing files can be found in "/data/misc/wmtrace/" in the bugreport. + "", {"cmd", service, "tracing", "save-for-bugreport"}, + CommandOptions::WithTimeout(10).Always().DropRoot().RedirectStderr().Build()); + } } void Dumpstate::onUiIntensiveBugreportDumpsFinished(int32_t calling_uid) { @@ -3396,6 +3491,9 @@ DurationReporter::DurationReporter(const std::string& title, bool logcat_only, b duration_fd_(duration_fd) { if (!title_.empty()) { started_ = Nanotime(); + if (title_.find("SHOW MAP") == std::string::npos) { + ATRACE_ASYNC_BEGIN(title_.c_str(), 0); + } } } @@ -3410,6 +3508,9 @@ DurationReporter::~DurationReporter() { dprintf(duration_fd_, "------ %.3fs was the duration of '%s' ------\n", elapsed, title_.c_str()); } + if (title_.find("SHOW MAP") == std::string::npos) { + ATRACE_ASYNC_END(title_.c_str(), 0); + } } } @@ -3861,15 +3962,6 @@ void do_dmesg() { return; } -void do_showmap(int pid, const char *name) { - char title[255]; - char arg[255]; - - snprintf(title, sizeof(title), "SHOW MAP %d (%s)", pid, name); - snprintf(arg, sizeof(arg), "%d", pid); - RunCommand(title, {"showmap", "-q", arg}, CommandOptions::AS_ROOT); -} - int Dumpstate::DumpFile(const std::string& title, const std::string& path) { DurationReporter duration_reporter(title); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index ee6b1aee18..7ffe80eba3 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -499,6 +499,9 @@ class Dumpstate { // List of open ANR dump files. std::vector<DumpData> anr_data_; + // List of open shutdown checkpoint files. + std::vector<DumpData> shutdown_checkpoints_; + // A thread pool to execute dump tasks simultaneously if the parallel run is enabled. std::unique_ptr<android::os::dumpstate::DumpPool> dump_pool_; @@ -619,9 +622,6 @@ void show_wchan(int pid, int tid, const char *name); /* Displays a processes times */ void show_showtime(int pid, const char *name); -/* Runs "showmap" for a process */ -void do_showmap(int pid, const char *name); - /* Gets the dmesg output for the kernel */ void do_dmesg(); diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp index 70b4e5c0d8..7234d419d6 100644 --- a/cmds/dumpstate/tests/dumpstate_test.cpp +++ b/cmds/dumpstate/tests/dumpstate_test.cpp @@ -1023,7 +1023,8 @@ class ZippedBugReportStreamTest : public DumpstateBaseTest { }; // Generate a quick LimitedOnly report redirected to a file, open it and verify entry exist. -TEST_F(ZippedBugReportStreamTest, StreamLimitedOnlyReport) { +// TODO: broken test tracked in b/249983726 +TEST_F(ZippedBugReportStreamTest, DISABLED_StreamLimitedOnlyReport) { std::string out_path = kTestDataPath + "StreamLimitedOnlyReportOut.zip"; android::base::unique_fd out_fd; CreateFd(out_path, &out_fd); diff --git a/cmds/dumpsys/tests/dumpsys_test.cpp b/cmds/dumpsys/tests/dumpsys_test.cpp index f0c19b93ec..b8e5ce1a63 100644 --- a/cmds/dumpsys/tests/dumpsys_test.cpp +++ b/cmds/dumpsys/tests/dumpsys_test.cpp @@ -60,6 +60,7 @@ class ServiceManagerMock : public IServiceManager { MOCK_METHOD1(isDeclared, bool(const String16&)); MOCK_METHOD1(getDeclaredInstances, Vector<String16>(const String16&)); MOCK_METHOD1(updatableViaApex, std::optional<String16>(const String16&)); + MOCK_METHOD1(getUpdatableNames, Vector<String16>(const String16&)); MOCK_METHOD1(getConnectionInfo, std::optional<ConnectionInfo>(const String16&)); MOCK_METHOD2(registerForNotifications, status_t(const String16&, const sp<LocalRegistrationCallback>&)); diff --git a/cmds/installd/Android.bp b/cmds/installd/Android.bp index c9f680b266..ac101ecb29 100644 --- a/cmds/installd/Android.bp +++ b/cmds/installd/Android.bp @@ -25,6 +25,7 @@ cc_defaults { "CrateManager.cpp", "InstalldNativeService.cpp", "QuotaUtils.cpp", + "SysTrace.cpp", "dexopt.cpp", "execv_helper.cpp", "globals.cpp", @@ -72,8 +73,6 @@ cc_defaults { }, }, - clang: true, - tidy: true, tidy_checks: [ "-*", @@ -81,8 +80,9 @@ cc_defaults { "cert-*", "-cert-err58-cpp", ], - tidy_flags: [ - "-warnings-as-errors=clang-analyzer-security*,cert-*", + tidy_checks_as_errors: [ + "clang-analyzer-security*", + "cert-*", ], } @@ -127,7 +127,6 @@ cc_library_headers { cc_test_host { name: "run_dex2oat_test", test_suites: ["general-tests"], - clang: true, srcs: [ "run_dex2oat_test.cpp", "run_dex2oat.cpp", @@ -175,7 +174,7 @@ cc_binary { // Needs to be wherever installd is as it's execed by // installd. - required: ["migrate_legacy_obb_data.sh"], + required: ["migrate_legacy_obb_data"], } // OTA chroot tool @@ -187,7 +186,6 @@ cc_binary { "-Wall", "-Werror", ], - clang: true, srcs: [ "otapreopt_chroot.cpp", @@ -302,6 +300,6 @@ sh_binary { // Script to migrate legacy obb data. sh_binary { - name: "migrate_legacy_obb_data.sh", + name: "migrate_legacy_obb_data", src: "migrate_legacy_obb_data.sh", } diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp index 6d3f7c3bab..bb6639e1a8 100644 --- a/cmds/installd/InstalldNativeService.cpp +++ b/cmds/installd/InstalldNativeService.cpp @@ -16,8 +16,6 @@ #include "InstalldNativeService.h" -#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER - #include <errno.h> #include <fts.h> #include <inttypes.h> @@ -75,6 +73,7 @@ #include "CrateManager.h" #include "MatchExtensionGen.h" #include "QuotaUtils.h" +#include "SysTrace.h" #ifndef LOG_TAG #define LOG_TAG "installd" @@ -128,8 +127,6 @@ static std::once_flag flag; namespace { -constexpr const char* kDump = "android.permission.DUMP"; - static binder::Status ok() { return binder::Status::ok(); } @@ -153,19 +150,6 @@ static binder::Status error(uint32_t code, const std::string& msg) { return binder::Status::fromServiceSpecificError(code, String8(msg.c_str())); } -binder::Status checkPermission(const char* permission) { - pid_t pid; - uid_t uid; - - if (checkCallingPermission(String16(permission), reinterpret_cast<int32_t*>(&pid), - reinterpret_cast<int32_t*>(&uid))) { - return ok(); - } else { - return exception(binder::Status::EX_SECURITY, - StringPrintf("UID %d / PID %d lacks permission %s", uid, pid, permission)); - } -} - binder::Status checkUid(uid_t expectedUid) { uid_t uid = IPCThreadState::self()->getCallingUid(); if (uid == expectedUid || uid == AID_ROOT) { @@ -232,6 +216,19 @@ binder::Status checkArgumentPath(const std::optional<std::string>& path) { } } +binder::Status checkArgumentFileName(const std::string& path) { + if (path.empty()) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, "Missing name"); + } + for (const char& c : path) { + if (c == '\0' || c == '\n' || c == '/') { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Name %s is malformed", path.c_str())); + } + } + return ok(); +} + #define ENFORCE_UID(uid) { \ binder::Status status = checkUid((uid)); \ if (!status.isOk()) { \ @@ -268,6 +265,14 @@ binder::Status checkArgumentPath(const std::optional<std::string>& path) { } \ } +#define CHECK_ARGUMENT_FILE_NAME(path) \ + { \ + binder::Status status = checkArgumentFileName((path)); \ + if (!status.isOk()) { \ + return status; \ + } \ + } + #ifdef GRANULAR_LOCKS /** @@ -382,13 +387,7 @@ status_t InstalldNativeService::start() { return android::OK; } -status_t InstalldNativeService::dump(int fd, const Vector<String16> & /* args */) { - const binder::Status dump_permission = checkPermission(kDump); - if (!dump_permission.isOk()) { - dprintf(fd, "%s\n", dump_permission.toString8().c_str()); - return PERMISSION_DENIED; - } - +status_t InstalldNativeService::dump(int fd, const Vector<String16>& /* args */) { { std::lock_guard<std::recursive_mutex> lock(mMountsLock); dprintf(fd, "Storage mounts:\n"); @@ -502,10 +501,6 @@ static int prepare_app_cache_dir(const std::string& parent, const char* name, mo } static bool prepare_app_profile_dir(const std::string& packageName, int32_t appId, int32_t userId) { - if (!property_get_bool("dalvik.vm.usejitprofiles", false)) { - return true; - } - int32_t uid = multiuser_get_uid(userId, appId); int shared_app_gid = multiuser_get_shared_gid(userId, appId); if (shared_app_gid == -1) { @@ -1008,6 +1003,12 @@ binder::Status InstalldNativeService::clearAppProfiles(const std::string& packag const std::string& profileName) { ENFORCE_UID(AID_SYSTEM); CHECK_ARGUMENT_PACKAGE_NAME(packageName); + CHECK_ARGUMENT_FILE_NAME(profileName); + if (!base::EndsWith(profileName, ".prof")) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Profile name %s does not end with .prof", + profileName.c_str())); + } LOCK_PACKAGE(); binder::Status res = ok(); @@ -1302,7 +1303,7 @@ binder::Status InstalldNativeService::fixupAppData(const std::optional<std::stri const char* uuid_ = uuid ? uuid->c_str() : nullptr; for (auto userId : get_known_users(uuid_)) { LOCK_USER(); - ATRACE_BEGIN("fixup user"); + atrace_pm_begin("fixup user"); FTS* fts; FTSENT* p; auto ce_path = create_data_user_ce_path(uuid_, userId); @@ -1392,7 +1393,7 @@ binder::Status InstalldNativeService::fixupAppData(const std::optional<std::stri } } fts_close(fts); - ATRACE_END(); + atrace_pm_end(); } return ok(); } @@ -1871,8 +1872,9 @@ binder::Status InstalldNativeService::destroyUserData(const std::optional<std::s binder::Status res = ok(); if (flags & FLAG_STORAGE_DE) { auto path = create_data_user_de_path(uuid_, userId); - if (delete_dir_contents_and_dir(path, true) != 0) { - res = error("Failed to delete " + path); + // Contents only, as vold is responsible for the user_de dir itself. + if (delete_dir_contents(path, true) != 0) { + res = error("Failed to delete contents of " + path); } auto sdk_sandbox_de_path = create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/false, userId); @@ -1892,8 +1894,9 @@ binder::Status InstalldNativeService::destroyUserData(const std::optional<std::s } if (flags & FLAG_STORAGE_CE) { auto path = create_data_user_ce_path(uuid_, userId); - if (delete_dir_contents_and_dir(path, true) != 0) { - res = error("Failed to delete " + path); + // Contents only, as vold is responsible for the user_ce dir itself. + if (delete_dir_contents(path, true) != 0) { + res = error("Failed to delete contents of " + path); } auto sdk_sandbox_ce_path = create_data_misc_sdk_sandbox_path(uuid_, /*isCeData=*/true, userId); @@ -1901,8 +1904,9 @@ binder::Status InstalldNativeService::destroyUserData(const std::optional<std::s res = error("Failed to delete " + sdk_sandbox_ce_path); } path = findDataMediaPath(uuid, userId); - if (delete_dir_contents_and_dir(path, true) != 0) { - res = error("Failed to delete " + path); + // Contents only, as vold is responsible for the media dir itself. + if (delete_dir_contents(path, true) != 0) { + res = error("Failed to delete contents of " + path); } } return res; @@ -1927,7 +1931,6 @@ binder::Status InstalldNativeService::freeCache(const std::optional<std::string> return error("Failed to determine free space for " + data_path); } - int64_t cleared = 0; int64_t needed = targetFreeBytes - free; if (!defy_target) { LOG(DEBUG) << "Device " << data_path << " has " << free << " free; requested " @@ -1943,7 +1946,7 @@ binder::Status InstalldNativeService::freeCache(const std::optional<std::string> // files from the UIDs which are most over their allocated quota // 1. Create trackers for every known UID - ATRACE_BEGIN("create"); + atrace_pm_begin("create"); const auto users = get_known_users(uuid_); #ifdef GRANULAR_LOCKS std::vector<UserLock> userLocks; @@ -2024,11 +2027,10 @@ binder::Status InstalldNativeService::freeCache(const std::optional<std::string> } fts_close(fts); } - ATRACE_END(); + atrace_pm_end(); // 2. Populate tracker stats and insert into priority queue - ATRACE_BEGIN("populate"); - int64_t cacheTotal = 0; + atrace_pm_begin("populate"); auto cmp = [](std::shared_ptr<CacheTracker> left, std::shared_ptr<CacheTracker> right) { return (left->getCacheRatio() < right->getCacheRatio()); }; @@ -2037,13 +2039,12 @@ binder::Status InstalldNativeService::freeCache(const std::optional<std::string> for (const auto& it : trackers) { it.second->loadStats(); queue.push(it.second); - cacheTotal += it.second->cacheUsed; } - ATRACE_END(); + atrace_pm_end(); // 3. Bounce across the queue, freeing items from whichever tracker is // the most over their assigned quota - ATRACE_BEGIN("bounce"); + atrace_pm_begin("bounce"); std::shared_ptr<CacheTracker> active; while (active || !queue.empty()) { // Only look at apps under quota when explicitly requested @@ -2083,7 +2084,6 @@ binder::Status InstalldNativeService::freeCache(const std::optional<std::string> } active->cacheUsed -= item->size; needed -= item->size; - cleared += item->size; } if (!defy_target) { @@ -2100,7 +2100,7 @@ binder::Status InstalldNativeService::freeCache(const std::optional<std::string> } } } - ATRACE_END(); + atrace_pm_end(); } else { return error("Legacy cache logic no longer supported"); @@ -2445,84 +2445,84 @@ binder::Status InstalldNativeService::getAppSize(const std::optional<std::string flags &= ~FLAG_USE_QUOTA; } - ATRACE_BEGIN("obb"); + atrace_pm_begin("obb"); for (const auto& packageName : packageNames) { auto obbCodePath = create_data_media_package_path(uuid_, userId, "obb", packageName.c_str()); calculate_tree_size(obbCodePath, &extStats.codeSize); } - ATRACE_END(); + atrace_pm_end(); // Calculating the app size of the external storage owning app in a manual way, since // calculating it through quota apis also includes external media storage in the app storage // numbers if (flags & FLAG_USE_QUOTA && appId >= AID_APP_START && !ownsExternalStorage(appId)) { - ATRACE_BEGIN("code"); + atrace_pm_begin("code"); for (const auto& codePath : codePaths) { calculate_tree_size(codePath, &stats.codeSize, -1, multiuser_get_shared_gid(0, appId)); } - ATRACE_END(); + atrace_pm_end(); - ATRACE_BEGIN("quota"); + atrace_pm_begin("quota"); collectQuotaStats(uuidString, userId, appId, &stats, &extStats); - ATRACE_END(); + atrace_pm_end(); } else { - ATRACE_BEGIN("code"); + atrace_pm_begin("code"); for (const auto& codePath : codePaths) { calculate_tree_size(codePath, &stats.codeSize); } - ATRACE_END(); + atrace_pm_end(); for (size_t i = 0; i < packageNames.size(); i++) { const char* pkgname = packageNames[i].c_str(); - ATRACE_BEGIN("data"); + atrace_pm_begin("data"); auto cePath = create_data_user_ce_package_path(uuid_, userId, pkgname, ceDataInodes[i]); collectManualStats(cePath, &stats); auto dePath = create_data_user_de_package_path(uuid_, userId, pkgname); collectManualStats(dePath, &stats); - ATRACE_END(); + atrace_pm_end(); // In case of sdk sandbox storage (e.g. /data/misc_ce/0/sdksandbox/<package-name>), // collect individual stats of each subdirectory (shared, storage of each sdk etc.) if (appId >= AID_APP_START && appId <= AID_APP_END) { - ATRACE_BEGIN("sdksandbox"); + atrace_pm_begin("sdksandbox"); auto sdkSandboxCePath = create_data_misc_sdk_sandbox_package_path(uuid_, true, userId, pkgname); collectManualStatsForSubDirectories(sdkSandboxCePath, &stats); auto sdkSandboxDePath = create_data_misc_sdk_sandbox_package_path(uuid_, false, userId, pkgname); collectManualStatsForSubDirectories(sdkSandboxDePath, &stats); - ATRACE_END(); + atrace_pm_end(); } if (!uuid) { - ATRACE_BEGIN("profiles"); + atrace_pm_begin("profiles"); calculate_tree_size( create_primary_current_profile_package_dir_path(userId, pkgname), &stats.dataSize); calculate_tree_size( create_primary_reference_profile_package_dir_path(pkgname), &stats.codeSize); - ATRACE_END(); + atrace_pm_end(); } - ATRACE_BEGIN("external"); + atrace_pm_begin("external"); auto extPath = create_data_media_package_path(uuid_, userId, "data", pkgname); collectManualStats(extPath, &extStats); auto mediaPath = create_data_media_package_path(uuid_, userId, "media", pkgname); calculate_tree_size(mediaPath, &extStats.dataSize); - ATRACE_END(); + atrace_pm_end(); } if (!uuid) { - ATRACE_BEGIN("dalvik"); + atrace_pm_begin("dalvik"); int32_t sharedGid = multiuser_get_shared_gid(0, appId); if (sharedGid != -1) { calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize, sharedGid, -1); } - ATRACE_END(); + atrace_pm_end(); } } @@ -2668,41 +2668,41 @@ binder::Status InstalldNativeService::getUserSize(const std::optional<std::strin } if (flags & FLAG_USE_QUOTA) { - ATRACE_BEGIN("code"); + atrace_pm_begin("code"); calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize, -1, -1, true); - ATRACE_END(); + atrace_pm_end(); - ATRACE_BEGIN("data"); + atrace_pm_begin("data"); auto cePath = create_data_user_ce_path(uuid_, userId); collectManualStatsForUser(cePath, &stats, true); auto dePath = create_data_user_de_path(uuid_, userId); collectManualStatsForUser(dePath, &stats, true); - ATRACE_END(); + atrace_pm_end(); if (!uuid) { - ATRACE_BEGIN("profile"); + atrace_pm_begin("profile"); auto userProfilePath = create_primary_cur_profile_dir_path(userId); calculate_tree_size(userProfilePath, &stats.dataSize, -1, -1, true); auto refProfilePath = create_primary_ref_profile_dir_path(); calculate_tree_size(refProfilePath, &stats.codeSize, -1, -1, true); - ATRACE_END(); + atrace_pm_end(); } - ATRACE_BEGIN("external"); + atrace_pm_begin("external"); auto sizes = getExternalSizesForUserWithQuota(uuidString, userId, appIds); extStats.dataSize += sizes.totalSize; extStats.codeSize += sizes.obbSize; - ATRACE_END(); + atrace_pm_end(); if (!uuid) { - ATRACE_BEGIN("dalvik"); + atrace_pm_begin("dalvik"); calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize, -1, -1, true); calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize, -1, -1, true); - ATRACE_END(); + atrace_pm_end(); } - ATRACE_BEGIN("quota"); + atrace_pm_begin("quota"); int64_t dataSize = extStats.dataSize; for (auto appId : appIds) { if (appId >= AID_APP_START) { @@ -2714,54 +2714,54 @@ binder::Status InstalldNativeService::getUserSize(const std::optional<std::strin } } extStats.dataSize = dataSize; - ATRACE_END(); + atrace_pm_end(); } else { - ATRACE_BEGIN("obb"); + atrace_pm_begin("obb"); auto obbPath = create_data_path(uuid_) + "/media/obb"; calculate_tree_size(obbPath, &extStats.codeSize); - ATRACE_END(); + atrace_pm_end(); - ATRACE_BEGIN("code"); + atrace_pm_begin("code"); calculate_tree_size(create_data_app_path(uuid_), &stats.codeSize); - ATRACE_END(); + atrace_pm_end(); - ATRACE_BEGIN("data"); + atrace_pm_begin("data"); auto cePath = create_data_user_ce_path(uuid_, userId); collectManualStatsForUser(cePath, &stats); auto dePath = create_data_user_de_path(uuid_, userId); collectManualStatsForUser(dePath, &stats); - ATRACE_END(); + atrace_pm_end(); - ATRACE_BEGIN("sdksandbox"); + atrace_pm_begin("sdksandbox"); auto sdkSandboxCePath = create_data_misc_sdk_sandbox_path(uuid_, true, userId); collectManualStatsForUser(sdkSandboxCePath, &stats, false, true); auto sdkSandboxDePath = create_data_misc_sdk_sandbox_path(uuid_, false, userId); collectManualStatsForUser(sdkSandboxDePath, &stats, false, true); - ATRACE_END(); + atrace_pm_end(); if (!uuid) { - ATRACE_BEGIN("profile"); + atrace_pm_begin("profile"); auto userProfilePath = create_primary_cur_profile_dir_path(userId); calculate_tree_size(userProfilePath, &stats.dataSize); auto refProfilePath = create_primary_ref_profile_dir_path(); calculate_tree_size(refProfilePath, &stats.codeSize); - ATRACE_END(); + atrace_pm_end(); } - ATRACE_BEGIN("external"); + atrace_pm_begin("external"); auto dataMediaPath = create_data_media_path(uuid_, userId); collectManualExternalStatsForUser(dataMediaPath, &extStats); #if MEASURE_DEBUG LOG(DEBUG) << "Measured external data " << extStats.dataSize << " cache " << extStats.cacheSize; #endif - ATRACE_END(); + atrace_pm_end(); if (!uuid) { - ATRACE_BEGIN("dalvik"); + atrace_pm_begin("dalvik"); calculate_tree_size(create_data_dalvik_cache_path(), &stats.codeSize); calculate_tree_size(create_primary_cur_profile_dir_path(userId), &stats.dataSize); - ATRACE_END(); + atrace_pm_end(); } } @@ -2809,16 +2809,16 @@ binder::Status InstalldNativeService::getExternalSize(const std::optional<std::s } if (flags & FLAG_USE_QUOTA) { - ATRACE_BEGIN("quota"); + atrace_pm_begin("quota"); auto sizes = getExternalSizesForUserWithQuota(uuidString, userId, appIds); totalSize = sizes.totalSize; audioSize = sizes.audioSize; videoSize = sizes.videoSize; imageSize = sizes.imageSize; obbSize = sizes.obbSize; - ATRACE_END(); + atrace_pm_end(); - ATRACE_BEGIN("apps"); + atrace_pm_begin("apps"); struct stats extStats; memset(&extStats, 0, sizeof(extStats)); for (auto appId : appIds) { @@ -2827,9 +2827,9 @@ binder::Status InstalldNativeService::getExternalSize(const std::optional<std::s } } appSize = extStats.dataSize; - ATRACE_END(); + atrace_pm_end(); } else { - ATRACE_BEGIN("manual"); + atrace_pm_begin("manual"); FTS *fts; FTSENT *p; auto path = create_data_media_path(uuid_, userId); @@ -2872,13 +2872,16 @@ binder::Status InstalldNativeService::getExternalSize(const std::optional<std::s } } fts_close(fts); - ATRACE_END(); + atrace_pm_end(); - ATRACE_BEGIN("obb"); + atrace_pm_begin("obb"); auto obbPath = StringPrintf("%s/Android/obb", create_data_media_path(uuid_, userId).c_str()); calculate_tree_size(obbPath, &obbSize); - ATRACE_END(); + if (!(flags & FLAG_USE_QUOTA)) { + totalSize -= obbSize; + } + atrace_pm_end(); } std::vector<int64_t> ret; @@ -3021,7 +3024,19 @@ binder::Status InstalldNativeService::copySystemProfile(const std::string& syste int32_t packageUid, const std::string& packageName, const std::string& profileName, bool* _aidl_return) { ENFORCE_UID(AID_SYSTEM); + CHECK_ARGUMENT_PATH(systemProfile); + if (!base::EndsWith(systemProfile, ".prof")) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("System profile path %s does not end with .prof", + systemProfile.c_str())); + } CHECK_ARGUMENT_PACKAGE_NAME(packageName); + CHECK_ARGUMENT_FILE_NAME(profileName); + if (!base::EndsWith(profileName, ".prof")) { + return exception(binder::Status::EX_ILLEGAL_ARGUMENT, + StringPrintf("Profile name %s does not end with .prof", + profileName.c_str())); + } LOCK_PACKAGE(); *_aidl_return = copy_system_profile(systemProfile, packageUid, packageName, profileName); return ok(); @@ -3585,10 +3600,10 @@ binder::Status InstalldNativeService::tryMountDataMirror( return error("Failed to stat " + mirrorVolCePath); } - if (mirrorCeStat.st_ino == ceStat.st_ino) { + if (mirrorCeStat.st_ino == ceStat.st_ino && mirrorCeStat.st_dev == ceStat.st_dev) { // As it's being called by prepareUserStorage, it can be called multiple times. // Hence, we if we mount it already, we should skip it. - LOG(WARNING) << "CE dir is mounted already: " + cePath; + LOG(INFO) << "CE dir is mounted already: " + cePath; return ok(); } @@ -3728,7 +3743,7 @@ binder::Status InstalldNativeService::migrateLegacyObbData() { ENFORCE_UID(AID_SYSTEM); // NOTE: The lint warning doesn't apply to the use of system(3) with // absolute parse and no command line arguments. - if (system("/system/bin/migrate_legacy_obb_data.sh") != 0) { // NOLINT(cert-env33-c) + if (system("/system/bin/migrate_legacy_obb_data") != 0) { // NOLINT(cert-env33-c) LOG(ERROR) << "Unable to migrate legacy obb data"; } diff --git a/cmds/installd/SysTrace.cpp b/cmds/installd/SysTrace.cpp new file mode 100644 index 0000000000..fa65c77a2b --- /dev/null +++ b/cmds/installd/SysTrace.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2022 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. + */ + +#define ATRACE_TAG ATRACE_TAG_PACKAGE_MANAGER + +#include "SysTrace.h" +#include <utils/Trace.h> + +namespace android::installd { +void atrace_pm_begin(const char* name) { + ATRACE_BEGIN(name); +} + +void atrace_pm_end() { + ATRACE_END(); +} +} /* namespace android::installd */ diff --git a/cmds/installd/SysTrace.h b/cmds/installd/SysTrace.h new file mode 100644 index 0000000000..18506a9258 --- /dev/null +++ b/cmds/installd/SysTrace.h @@ -0,0 +1,22 @@ +/* + * Copyright (C) 2022 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 + +namespace android::installd { +void atrace_pm_begin(const char*); +void atrace_pm_end(); +} /* namespace android::installd */ diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp index ebb78913b1..34ea7597b4 100644 --- a/cmds/installd/dexopt.cpp +++ b/cmds/installd/dexopt.cpp @@ -1956,7 +1956,7 @@ int dexopt(const char* dex_path, uid_t uid, const char* pkgname, const char* ins join_fds(context_input_fds), swap_fd.get(), instruction_set, compiler_filter, debuggable, boot_complete, for_restore, target_sdk_version, enable_hidden_api_checks, generate_compact_dex, use_jitzygote_image, - compilation_reason); + background_job_compile, compilation_reason); bool cancelled = false; pid_t pid = dexopt_status_->check_cancellation_and_fork(&cancelled); diff --git a/cmds/installd/installd.rc b/cmds/installd/installd.rc index 240aa495b7..5b08c776ac 100644 --- a/cmds/installd/installd.rc +++ b/cmds/installd/installd.rc @@ -1,6 +1,7 @@ service installd /system/bin/installd class main + capabilities CHOWN DAC_OVERRIDE DAC_READ_SEARCH FOWNER FSETID KILL SETGID SETUID SYS_ADMIN on early-boot mkdir /config/sdcardfs/extensions/1055 diff --git a/cmds/installd/otapreopt.cpp b/cmds/installd/otapreopt.cpp index e978e79d86..6a3120c1b7 100644 --- a/cmds/installd/otapreopt.cpp +++ b/cmds/installd/otapreopt.cpp @@ -27,6 +27,7 @@ #include <sys/prctl.h> #include <sys/stat.h> #include <sys/mman.h> +#include <sys/wait.h> #include <android-base/logging.h> #include <android-base/macros.h> @@ -504,6 +505,11 @@ private: return 0; } + if (WIFSIGNALED(dexopt_result)) { + LOG(WARNING) << "Interrupted by signal " << WTERMSIG(dexopt_result) ; + return dexopt_result; + } + // If this was a profile-guided run, we may have profile version issues. Try to downgrade, // if possible. if ((parameters_.dexopt_flags & DEXOPT_PROFILE_GUIDED) == 0) { diff --git a/cmds/installd/otapreopt.rc b/cmds/installd/otapreopt.rc index 059ae752e7..0bad0c59ab 100644 --- a/cmds/installd/otapreopt.rc +++ b/cmds/installd/otapreopt.rc @@ -5,4 +5,4 @@ on post-fs-data # The dalvik-cache was not moved itself, so as to restrict the rights of otapreopt_slot. # But now the relabeling is annoying as there is no force option available here. So # explicitly list all the ISAs we know. - restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/mips /data/dalvik-cache/mips64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64 + restorecon_recursive /data/dalvik-cache/arm /data/dalvik-cache/arm64 /data/dalvik-cache/riscv64 /data/dalvik-cache/x86 /data/dalvik-cache/x86_64 diff --git a/cmds/installd/run_dex2oat.cpp b/cmds/installd/run_dex2oat.cpp index 51c4589440..4221a3a593 100644 --- a/cmds/installd/run_dex2oat.cpp +++ b/cmds/installd/run_dex2oat.cpp @@ -81,6 +81,7 @@ void RunDex2Oat::Initialize(const UniqueFile& output_oat, bool enable_hidden_api_checks, bool generate_compact_dex, bool use_jitzygote, + bool background_job_compile, const char* compilation_reason) { PrepareBootImageFlags(use_jitzygote); @@ -92,7 +93,8 @@ void RunDex2Oat::Initialize(const UniqueFile& output_oat, debuggable, target_sdk_version, enable_hidden_api_checks, generate_compact_dex, compilation_reason); - PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore); + PrepareCompilerRuntimeAndPerfConfigFlags(post_bootcomplete, for_restore, + background_job_compile); const std::string dex2oat_flags = GetProperty("dalvik.vm.dex2oat-flags", ""); std::vector<std::string> dex2oat_flags_args = SplitBySpaces(dex2oat_flags); @@ -296,7 +298,8 @@ void RunDex2Oat::PrepareCompilerConfigFlags(const UniqueFile& input_vdex, } void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, - bool for_restore) { + bool for_restore, + bool background_job_compile) { // CPU set { std::string cpu_set_format = "--cpu-set=%s"; @@ -306,7 +309,12 @@ void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete "dalvik.vm.restore-dex2oat-cpu-set", "dalvik.vm.dex2oat-cpu-set", cpu_set_format) - : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format)) + : (background_job_compile + ? MapPropertyToArgWithBackup( + "dalvik.vm.background-dex2oat-cpu-set", + "dalvik.vm.dex2oat-cpu-set", + cpu_set_format) + : MapPropertyToArg("dalvik.vm.dex2oat-cpu-set", cpu_set_format))) : MapPropertyToArg("dalvik.vm.boot-dex2oat-cpu-set", cpu_set_format); AddArg(dex2oat_cpu_set_arg); } @@ -320,7 +328,12 @@ void RunDex2Oat::PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete "dalvik.vm.restore-dex2oat-threads", "dalvik.vm.dex2oat-threads", threads_format) - : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format)) + : (background_job_compile + ? MapPropertyToArgWithBackup( + "dalvik.vm.background-dex2oat-threads", + "dalvik.vm.dex2oat-threads", + threads_format) + : MapPropertyToArg("dalvik.vm.dex2oat-threads", threads_format))) : MapPropertyToArg("dalvik.vm.boot-dex2oat-threads", threads_format); AddArg(dex2oat_threads_arg); } diff --git a/cmds/installd/run_dex2oat.h b/cmds/installd/run_dex2oat.h index 559244f2b7..c13e1f1acb 100644 --- a/cmds/installd/run_dex2oat.h +++ b/cmds/installd/run_dex2oat.h @@ -51,6 +51,7 @@ class RunDex2Oat { bool enable_hidden_api_checks, bool generate_compact_dex, bool use_jitzygote, + bool background_job_compile, const char* compilation_reason); void Exec(int exit_code); @@ -76,7 +77,9 @@ class RunDex2Oat { bool enable_hidden_api_checks, bool generate_compact_dex, const char* compilation_reason); - void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, bool for_restore); + void PrepareCompilerRuntimeAndPerfConfigFlags(bool post_bootcomplete, + bool for_restore, + bool background_job_compile); virtual std::string GetProperty(const std::string& key, const std::string& default_value); virtual bool GetBoolProperty(const std::string& key, bool default_value); diff --git a/cmds/installd/run_dex2oat_test.cpp b/cmds/installd/run_dex2oat_test.cpp index 2a8135a037..304ba7b04f 100644 --- a/cmds/installd/run_dex2oat_test.cpp +++ b/cmds/installd/run_dex2oat_test.cpp @@ -115,6 +115,7 @@ class RunDex2OatTest : public testing::Test { bool enable_hidden_api_checks = false; bool generate_compact_dex = true; bool use_jitzygote = false; + bool background_job_compile = false; const char* compilation_reason = nullptr; }; @@ -259,6 +260,7 @@ class RunDex2OatTest : public testing::Test { args->enable_hidden_api_checks, args->generate_compact_dex, args->use_jitzygote, + args->background_job_compile, args->compilation_reason); runner.Exec(/*exit_code=*/ 0); } @@ -375,6 +377,30 @@ TEST_F(RunDex2OatTest, CpuSetPostBootCompleteNotForRestore) { VerifyExpectedFlags(); } +TEST_F(RunDex2OatTest, CpuSetPostBootCompleteBackground) { + setSystemProperty("dalvik.vm.background-dex2oat-cpu-set", "1,3"); + setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2"); + auto args = RunDex2OatArgs::MakeDefaultTestArgs(); + args->post_bootcomplete = true; + args->background_job_compile = true; + CallRunDex2Oat(std::move(args)); + + SetExpectedFlagUsed("--cpu-set", "=1,3"); + VerifyExpectedFlags(); +} + +TEST_F(RunDex2OatTest, CpuSetPostBootCompleteBackground_Backup) { + setSystemProperty("dalvik.vm.background-dex2oat-cpu-set", ""); + setSystemProperty("dalvik.vm.dex2oat-cpu-set", "1,2"); + auto args = RunDex2OatArgs::MakeDefaultTestArgs(); + args->post_bootcomplete = true; + args->background_job_compile = true; + CallRunDex2Oat(std::move(args)); + + SetExpectedFlagUsed("--cpu-set", "=1,2"); + VerifyExpectedFlags(); +} + TEST_F(RunDex2OatTest, CpuSetPostBootCompleteForRestore) { setSystemProperty("dalvik.vm.restore-dex2oat-cpu-set", "1,2"); setSystemProperty("dalvik.vm.dex2oat-cpu-set", "2,3"); @@ -481,6 +507,30 @@ TEST_F(RunDex2OatTest, ThreadsPostBootCompleteNotForRestore) { VerifyExpectedFlags(); } +TEST_F(RunDex2OatTest, ThreadsPostBootCompleteBackground) { + setSystemProperty("dalvik.vm.background-dex2oat-threads", "2"); + setSystemProperty("dalvik.vm.dex2oat-threads", "3"); + auto args = RunDex2OatArgs::MakeDefaultTestArgs(); + args->post_bootcomplete = true; + args->background_job_compile = true; + CallRunDex2Oat(std::move(args)); + + SetExpectedFlagUsed("-j", "2"); + VerifyExpectedFlags(); +} + +TEST_F(RunDex2OatTest, ThreadsPostBootCompleteBackground_Backup) { + setSystemProperty("dalvik.vm.background-dex2oat-threads", ""); + setSystemProperty("dalvik.vm.dex2oat-threads", "3"); + auto args = RunDex2OatArgs::MakeDefaultTestArgs(); + args->post_bootcomplete = true; + args->background_job_compile = true; + CallRunDex2Oat(std::move(args)); + + SetExpectedFlagUsed("-j", "3"); + VerifyExpectedFlags(); +} + TEST_F(RunDex2OatTest, ThreadsPostBootCompleteForRestore) { setSystemProperty("dalvik.vm.restore-dex2oat-threads", "4"); setSystemProperty("dalvik.vm.dex2oat-threads", "5"); diff --git a/cmds/installd/tests/Android.bp b/cmds/installd/tests/Android.bp index b3baca5c41..07f73b9029 100644 --- a/cmds/installd/tests/Android.bp +++ b/cmds/installd/tests/Android.bp @@ -11,7 +11,6 @@ package { cc_test { name: "installd_utils_test", test_suites: ["device-tests"], - clang: true, srcs: ["installd_utils_test.cpp"], cflags: [ "-Wall", @@ -36,7 +35,6 @@ cc_test { cc_test { name: "installd_cache_test", test_suites: ["device-tests"], - clang: true, srcs: ["installd_cache_test.cpp"], cflags: [ "-Wall", @@ -82,7 +80,6 @@ cc_test { cc_test { name: "installd_service_test", test_suites: ["device-tests"], - clang: true, srcs: ["installd_service_test.cpp"], cflags: [ "-Wall", @@ -130,7 +127,6 @@ cc_test { cc_test { name: "installd_dexopt_test", test_suites: ["device-tests"], - clang: true, srcs: ["installd_dexopt_test.cpp"], cflags: [ "-Wall", @@ -177,7 +173,6 @@ cc_test { cc_test { name: "installd_otapreopt_test", test_suites: ["device-tests"], - clang: true, srcs: ["installd_otapreopt_test.cpp"], cflags: [ "-Wall", @@ -198,7 +193,6 @@ cc_test { cc_test { name: "installd_file_test", test_suites: ["device-tests"], - clang: true, srcs: ["installd_file_test.cpp"], cflags: [ "-Wall", diff --git a/cmds/installd/tests/installd_dexopt_test.cpp b/cmds/installd/tests/installd_dexopt_test.cpp index 4eb30e2542..3b589dc581 100644 --- a/cmds/installd/tests/installd_dexopt_test.cpp +++ b/cmds/installd/tests/installd_dexopt_test.cpp @@ -23,6 +23,7 @@ #include <android-base/file.h> #include <android-base/logging.h> +#include <android-base/macros.h> #include <android-base/properties.h> #include <android-base/scopeguard.h> #include <android-base/stringprintf.h> @@ -52,22 +53,7 @@ namespace installd { constexpr int kTimeoutMs = 60000; -// TODO(calin): try to dedup this code. -#if defined(__arm__) -static const std::string kRuntimeIsa = "arm"; -#elif defined(__aarch64__) -static const std::string kRuntimeIsa = "arm64"; -#elif defined(__mips__) && !defined(__LP64__) -static const std::string kRuntimeIsa = "mips"; -#elif defined(__mips__) && defined(__LP64__) -static const std::string kRuntimeIsa = "mips64"; -#elif defined(__i386__) -static const std::string kRuntimeIsa = "x86"; -#elif defined(__x86_64__) -static const std::string kRuntimeIsa = "x86_64"; -#else -static const std::string kRuntimeIsa = "none"; -#endif +static const std::string kRuntimeIsa = ABI_STRING; int get_property(const char *key, char *value, const char *default_value) { return property_get(key, value, default_value); @@ -920,6 +906,11 @@ TEST_F(DexoptTest, ResolveStartupConstStrings) { TEST_F(DexoptTest, DexoptDex2oat64Enabled) { LOG(INFO) << "DexoptDex2oat64Enabled"; + std::string zygote_prop = android::base::GetProperty("ro.zygote", ""); + ASSERT_GT(zygote_prop.size(), 0); + if (zygote_prop != "zygote32_64" && zygote_prop != "zygote64_32") { + GTEST_SKIP() << "DexoptDex2oat64Enabled skipped for single-bitness Zygote."; + } const std::string property = "dalvik.vm.dex2oat64.enabled"; const std::string previous_value = android::base::GetProperty(property, ""); auto restore_property = android::base::make_scope_guard([=]() { @@ -1366,6 +1357,58 @@ TEST_F(ProfileTest, ProfilePrepareFailProfileChangedUid) { /*has_user_id*/ true, /*expected_result*/ false); } +TEST_F(ProfileTest, ClearAppProfilesOk) { + LOG(INFO) << "ClearAppProfilesOk"; + + ASSERT_BINDER_SUCCESS(service_->clearAppProfiles(package_name_, "primary.prof")); + ASSERT_BINDER_SUCCESS(service_->clearAppProfiles(package_name_, "image_editor.split.prof")); +} + +TEST_F(ProfileTest, ClearAppProfilesFailWrongProfileName) { + LOG(INFO) << "ClearAppProfilesFailWrongProfileName"; + + ASSERT_BINDER_FAIL( + service_->clearAppProfiles(package_name_, + "../../../../dalvik-cache/arm64/" + "system@app@SecureElement@SecureElement.apk@classes.vdex")); + ASSERT_BINDER_FAIL(service_->clearAppProfiles(package_name_, "image_editor.split.apk")); +} + +TEST_F(ProfileTest, CopySystemProfileOk) { + LOG(INFO) << "CopySystemProfileOk"; + + bool result; + ASSERT_BINDER_SUCCESS( + service_->copySystemProfile("/data/app/random.string/package.name.random/base.apk.prof", + kTestAppUid, package_name_, "primary.prof", &result)); +} + +TEST_F(ProfileTest, CopySystemProfileFailWrongSystemProfilePath) { + LOG(INFO) << "CopySystemProfileFailWrongSystemProfilePath"; + + bool result; + ASSERT_BINDER_FAIL(service_->copySystemProfile("../../secret.dat", kTestAppUid, package_name_, + "primary.prof", &result)); + ASSERT_BINDER_FAIL(service_->copySystemProfile("/data/user/package.name/secret.data", + kTestAppUid, package_name_, "primary.prof", + &result)); +} + +TEST_F(ProfileTest, CopySystemProfileFailWrongProfileName) { + LOG(INFO) << "CopySystemProfileFailWrongProfileName"; + + bool result; + ASSERT_BINDER_FAIL( + service_->copySystemProfile("/data/app/random.string/package.name.random/base.apk.prof", + kTestAppUid, package_name_, + "../../../../dalvik-cache/arm64/test.vdex", &result)); + ASSERT_BINDER_FAIL( + service_->copySystemProfile("/data/app/random.string/package.name.random/base.apk.prof", + kTestAppUid, package_name_, "/test.prof", &result)); + ASSERT_BINDER_FAIL( + service_->copySystemProfile("/data/app/random.string/package.name.random/base.apk.prof", + kTestAppUid, package_name_, "base.apk", &result)); +} class BootProfileTest : public ProfileTest { public: diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp index 4d9b71016e..ffc082d5b2 100644 --- a/cmds/installd/utils.cpp +++ b/cmds/installd/utils.cpp @@ -523,7 +523,6 @@ int calculate_tree_size(const std::string& path, int64_t* size, */ bool is_valid_package_name(const std::string& packageName) { // This logic is borrowed from PackageParser.java - bool hasSep = false; bool front = true; auto it = packageName.begin(); @@ -539,7 +538,6 @@ bool is_valid_package_name(const std::string& packageName) { } } if (c == '.') { - hasSep = true; front = true; continue; } diff --git a/cmds/lshal/ListCommand.cpp b/cmds/lshal/ListCommand.cpp index ff73c9499f..e54f9d3df7 100644 --- a/cmds/lshal/ListCommand.cpp +++ b/cmds/lshal/ListCommand.cpp @@ -353,8 +353,16 @@ bool ListCommand::addEntryWithInstance(const TableEntry& entry, return false; } + auto vintfFqInstance = vintf::FqInstance::from(fqInstance.string()); + if (!vintfFqInstance.has_value()) { + err() << "Unable to convert " << fqInstance.string() << " to vintf::FqInstance" + << std::endl; + return false; + } + std::string e; - if (!manifest->insertInstance(fqInstance, entry.transport, arch, vintf::HalFormat::HIDL, &e)) { + if (!manifest->insertInstance(*vintfFqInstance, entry.transport, arch, vintf::HalFormat::HIDL, + &e)) { err() << "Warning: Cannot insert '" << fqInstance.string() << ": " << e << std::endl; return false; } diff --git a/cmds/lshal/libprocpartition/Android.bp b/cmds/lshal/libprocpartition/Android.bp index cbfbdc9223..af85666276 100644 --- a/cmds/lshal/libprocpartition/Android.bp +++ b/cmds/lshal/libprocpartition/Android.bp @@ -35,5 +35,6 @@ cc_library_static { ], export_include_dirs: [ "include", - ] + ], + min_sdk_version: "30", } diff --git a/cmds/servicemanager/Access.cpp b/cmds/servicemanager/Access.cpp index b7e520f2f1..711038ce63 100644 --- a/cmds/servicemanager/Access.cpp +++ b/cmds/servicemanager/Access.cpp @@ -30,6 +30,7 @@ constexpr bool kIsVendor = true; constexpr bool kIsVendor = false; #endif +#ifdef __ANDROID__ static std::string getPidcon(pid_t pid) { android_errorWriteLog(0x534e4554, "121035042"); @@ -45,7 +46,6 @@ static std::string getPidcon(pid_t pid) { static struct selabel_handle* getSehandle() { static struct selabel_handle* gSehandle = nullptr; - if (gSehandle != nullptr && selinux_status_updated()) { selabel_close(gSehandle); gSehandle = nullptr; @@ -78,8 +78,10 @@ static int auditCallback(void *data, security_class_t /*cls*/, char *buf, size_t ad->tname->c_str()); return 0; } +#endif Access::Access() { +#ifdef __ANDROID__ union selinux_callback cb; cb.func_audit = auditCallback; @@ -91,6 +93,7 @@ Access::Access() { CHECK(selinux_status_open(true /*fallback*/) >= 0); CHECK(getcon(&mThisProcessContext) == 0); +#endif } Access::~Access() { @@ -98,6 +101,7 @@ Access::~Access() { } Access::CallingContext Access::getCallingContext() { +#ifdef __ANDROID__ IPCThreadState* ipc = IPCThreadState::self(); const char* callingSid = ipc->getCallingSid(); @@ -108,6 +112,9 @@ Access::CallingContext Access::getCallingContext() { .uid = ipc->getCallingUid(), .sid = callingSid ? std::string(callingSid) : getPidcon(callingPid), }; +#else + return CallingContext(); +#endif } bool Access::canFind(const CallingContext& ctx,const std::string& name) { @@ -124,6 +131,7 @@ bool Access::canList(const CallingContext& ctx) { bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const char* perm, const std::string& tname) { +#ifdef __ANDROID__ const char* tclass = "service_manager"; AuditCallbackData data = { @@ -133,9 +141,18 @@ bool Access::actionAllowed(const CallingContext& sctx, const char* tctx, const c return 0 == selinux_check_access(sctx.sid.c_str(), tctx, tclass, perm, reinterpret_cast<void*>(&data)); +#else + (void)sctx; + (void)tctx; + (void)perm; + (void)tname; + + return true; +#endif } bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::string& name, const char *perm) { +#ifdef __ANDROID__ char *tctx = nullptr; if (selabel_lookup(getSehandle(), &tctx, name.c_str(), SELABEL_CTX_ANDROID_SERVICE) != 0) { LOG(ERROR) << "SELinux: No match for " << name << " in service_contexts.\n"; @@ -145,6 +162,14 @@ bool Access::actionAllowedFromLookup(const CallingContext& sctx, const std::stri bool allowed = actionAllowed(sctx, tctx, perm, name); freecon(tctx); return allowed; +#else + (void)sctx; + (void)name; + (void)perm; + (void)kIsVendor; + + return true; +#endif } } // android diff --git a/cmds/servicemanager/Android.bp b/cmds/servicemanager/Android.bp index 32922ca24c..1386660eb6 100644 --- a/cmds/servicemanager/Android.bp +++ b/cmds/servicemanager/Android.bp @@ -44,13 +44,6 @@ cc_binary { defaults: ["servicemanager_defaults"], init_rc: ["servicemanager.rc"], srcs: ["main.cpp"], -} - -cc_binary { - name: "servicemanager.microdroid", - defaults: ["servicemanager_defaults"], - init_rc: ["servicemanager.microdroid.rc"], - srcs: ["main.cpp"], bootstrap: true, } @@ -86,3 +79,22 @@ cc_test { ], static_libs: ["libgmock"], } + +cc_fuzz { + name: "servicemanager_fuzzer", + defaults: [ + "servicemanager_defaults", + "service_fuzzer_defaults", + ], + host_supported: true, + srcs: ["ServiceManagerFuzzer.cpp"], + fuzz_config: { + libfuzzer_options: [ + "max_len=50000", + ], + cc: [ + "smoreland@google.com", + "waghpawan@google.com", + ], + }, +} diff --git a/cmds/servicemanager/ServiceManager.cpp b/cmds/servicemanager/ServiceManager.cpp index 3cfe5297ca..eadf67821f 100644 --- a/cmds/servicemanager/ServiceManager.cpp +++ b/cmds/servicemanager/ServiceManager.cpp @@ -49,14 +49,14 @@ static std::vector<ManifestWithDescription> GetManifestsWithDescription() { #ifdef __ANDROID_RECOVERY__ auto vintfObject = vintf::VintfObjectRecovery::GetInstance(); if (vintfObject == nullptr) { - LOG(ERROR) << "NULL VintfObjectRecovery!"; + ALOGE("NULL VintfObjectRecovery!"); return {}; } return {ManifestWithDescription{vintfObject->getRecoveryHalManifest(), "recovery"}}; #else auto vintfObject = vintf::VintfObject::GetInstance(); if (vintfObject == nullptr) { - LOG(ERROR) << "NULL VintfObject!"; + ALOGE("NULL VintfObject!"); return {}; } return {ManifestWithDescription{vintfObject->getDeviceHalManifest(), "device"}, @@ -68,10 +68,10 @@ static std::vector<ManifestWithDescription> GetManifestsWithDescription() { static bool forEachManifest(const std::function<bool(const ManifestWithDescription&)>& func) { for (const ManifestWithDescription& mwd : GetManifestsWithDescription()) { if (mwd.manifest == nullptr) { - LOG(ERROR) << "NULL VINTF MANIFEST!: " << mwd.description; - // note, we explicitly do not retry here, so that we can detect VINTF - // or other bugs (b/151696835) - continue; + ALOGE("NULL VINTF MANIFEST!: %s", mwd.description); + // note, we explicitly do not retry here, so that we can detect VINTF + // or other bugs (b/151696835) + continue; } if (func(mwd)) return true; } @@ -87,8 +87,9 @@ struct AidlName { size_t firstSlash = name.find('/'); size_t lastDot = name.rfind('.', firstSlash); if (firstSlash == std::string::npos || lastDot == std::string::npos) { - LOG(ERROR) << "VINTF HALs require names in the format type/instance (e.g. " - << "some.package.foo.IFoo/default) but got: " << name; + ALOGE("VINTF HALs require names in the format type/instance (e.g. " + "some.package.foo.IFoo/default) but got: %s", + name.c_str()); return false; } aname->package = name.substr(0, lastDot); @@ -104,7 +105,7 @@ static bool isVintfDeclared(const std::string& name) { bool found = forEachManifest([&](const ManifestWithDescription& mwd) { if (mwd.manifest->hasAidlInstance(aname.package, aname.iface, aname.instance)) { - LOG(INFO) << "Found " << name << " in " << mwd.description << " VINTF manifest."; + ALOGI("Found %s in %s VINTF manifest.", name.c_str(), mwd.description); return true; // break } return false; // continue @@ -113,8 +114,8 @@ static bool isVintfDeclared(const std::string& name) { if (!found) { // Although it is tested, explicitly rebuilding qualified name, in case it // becomes something unexpected. - LOG(INFO) << "Could not find " << aname.package << "." << aname.iface << "/" - << aname.instance << " in the VINTF manifest."; + ALOGI("Could not find %s.%s/%s in the VINTF manifest.", aname.package.c_str(), + aname.iface.c_str(), aname.instance.c_str()); } return found; @@ -135,12 +136,33 @@ static std::optional<std::string> getVintfUpdatableApex(const std::string& name) updatableViaApex = manifestInstance.updatableViaApex(); return false; // break (libvintf uses opposite convention) }); + if (updatableViaApex.has_value()) return true; // break (found match) return false; // continue }); return updatableViaApex; } +static std::vector<std::string> getVintfUpdatableInstances(const std::string& apexName) { + std::vector<std::string> instances; + + forEachManifest([&](const ManifestWithDescription& mwd) { + mwd.manifest->forEachInstance([&](const auto& manifestInstance) { + if (manifestInstance.format() == vintf::HalFormat::AIDL && + manifestInstance.updatableViaApex().has_value() && + manifestInstance.updatableViaApex().value() == apexName) { + std::string aname = manifestInstance.package() + "." + + manifestInstance.interface() + "/" + manifestInstance.instance(); + instances.push_back(aname); + } + return true; // continue (libvintf uses opposite convention) + }); + return false; // continue + }); + + return instances; +} + static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& name) { AidlName aname; if (!AidlName::fill(name, &aname)) return std::nullopt; @@ -173,7 +195,9 @@ static std::optional<ConnectionInfo> getVintfConnectionInfo(const std::string& n static std::vector<std::string> getVintfInstances(const std::string& interface) { size_t lastDot = interface.rfind('.'); if (lastDot == std::string::npos) { - LOG(ERROR) << "VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) but got: " << interface; + ALOGE("VINTF interfaces require names in Java package format (e.g. some.package.foo.IFoo) " + "but got: %s", + interface.c_str()); return {}; } const std::string package = interface.substr(0, lastDot); @@ -198,6 +222,13 @@ static bool meetsDeclarationRequirements(const sp<IBinder>& binder, const std::s } #endif // !VENDORSERVICEMANAGER +ServiceManager::Service::~Service() { + if (!hasClients) { + // only expected to happen on process death + LOG(WARNING) << "a service was removed when there are clients"; + } +} + ServiceManager::ServiceManager(std::unique_ptr<Access>&& access) : mAccess(std::move(access)) { // TODO(b/151696835): reenable performance hack when we solve bug, since with // this hack and other fixes, it is unlikely we will see even an ephemeral @@ -269,8 +300,13 @@ sp<IBinder> ServiceManager::tryGetService(const std::string& name, bool startIfN } if (out) { - // Setting this guarantee each time we hand out a binder ensures that the client-checking - // loop knows about the event even if the client immediately drops the service + // Force onClients to get sent, and then make sure the timerfd won't clear it + // by setting guaranteeClient again. This logic could be simplified by using + // a time-based guarantee. However, forcing onClients(true) to get sent + // right here is always going to be important for processes serving multiple + // lazy interfaces. + service->guaranteeClient = true; + CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false)); service->guaranteeClient = true; } @@ -308,7 +344,7 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi } if (!isValidServiceName(name)) { - LOG(ERROR) << "Invalid service name: " << name; + ALOGE("Invalid service name: %s", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT, "Invalid service name"); } @@ -322,22 +358,51 @@ Status ServiceManager::addService(const std::string& name, const sp<IBinder>& bi // implicitly unlinked when the binder is removed if (binder->remoteBinder() != nullptr && binder->linkToDeath(sp<ServiceManager>::fromExisting(this)) != OK) { - LOG(ERROR) << "Could not linkToDeath when adding " << name; + ALOGE("Could not linkToDeath when adding %s", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE, "linkToDeath failure"); } + auto it = mNameToService.find(name); + if (it != mNameToService.end()) { + const Service& existing = it->second; + + // We could do better than this because if the other service dies, it + // may not have an entry here. However, this case is unlikely. We are + // only trying to detect when two different services are accidentally installed. + + if (existing.ctx.uid != ctx.uid) { + ALOGW("Service '%s' originally registered from UID %u but it is now being registered " + "from UID %u. Multiple instances installed?", + name.c_str(), existing.ctx.uid, ctx.uid); + } + + if (existing.ctx.sid != ctx.sid) { + ALOGW("Service '%s' originally registered from SID %s but it is now being registered " + "from SID %s. Multiple instances installed?", + name.c_str(), existing.ctx.sid.c_str(), ctx.sid.c_str()); + } + + ALOGI("Service '%s' originally registered from PID %d but it is being registered again " + "from PID %d. Bad state? Late death notification? Multiple instances installed?", + name.c_str(), existing.ctx.debugPid, ctx.debugPid); + } + // Overwrite the old service if it exists - mNameToService[name] = Service { - .binder = binder, - .allowIsolated = allowIsolated, - .dumpPriority = dumpPriority, - .debugPid = ctx.debugPid, + mNameToService[name] = Service{ + .binder = binder, + .allowIsolated = allowIsolated, + .dumpPriority = dumpPriority, + .ctx = ctx, }; - auto it = mNameToRegistrationCallback.find(name); - if (it != mNameToRegistrationCallback.end()) { + if (auto it = mNameToRegistrationCallback.find(name); it != mNameToRegistrationCallback.end()) { + // See also getService - handles case where client never gets the service, + // we want the service to quit. + mNameToService[name].guaranteeClient = true; + CHECK(handleServiceClientCallback(2 /* sm + transaction */, name, false)); + mNameToService[name].guaranteeClient = true; + for (const sp<IServiceCallback>& cb : it->second) { - mNameToService[name].guaranteeClient = true; // permission checked in registerForNotifications cb->onRegistration(name, binder); } @@ -381,7 +446,7 @@ Status ServiceManager::registerForNotifications( } if (!isValidServiceName(name)) { - LOG(ERROR) << "Invalid service name: " << name; + ALOGE("Invalid service name: %s", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } @@ -392,7 +457,7 @@ Status ServiceManager::registerForNotifications( if (OK != IInterface::asBinder(callback)->linkToDeath( sp<ServiceManager>::fromExisting(this))) { - LOG(ERROR) << "Could not linkToDeath when adding " << name; + ALOGE("Could not linkToDeath when adding %s", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } @@ -424,7 +489,7 @@ Status ServiceManager::unregisterForNotifications( } if (!found) { - LOG(ERROR) << "Trying to unregister callback, but none exists " << name; + ALOGE("Trying to unregister callback, but none exists %s", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } @@ -485,6 +550,30 @@ Status ServiceManager::updatableViaApex(const std::string& name, return Status::ok(); } +Status ServiceManager::getUpdatableNames([[maybe_unused]] const std::string& apexName, + std::vector<std::string>* outReturn) { + auto ctx = mAccess->getCallingContext(); + + std::vector<std::string> apexUpdatableInstances; +#ifndef VENDORSERVICEMANAGER + apexUpdatableInstances = getVintfUpdatableInstances(apexName); +#endif + + outReturn->clear(); + + for (const std::string& instance : apexUpdatableInstances) { + if (mAccess->canFind(ctx, instance)) { + outReturn->push_back(instance); + } + } + + if (outReturn->size() == 0 && apexUpdatableInstances.size() != 0) { + return Status::fromExceptionCode(Status::EX_SECURITY, "SELinux denial"); + } + + return Status::ok(); +} + Status ServiceManager::getConnectionInfo(const std::string& name, std::optional<ConnectionInfo>* outReturn) { auto ctx = mAccess->getCallingContext(); @@ -541,15 +630,17 @@ void ServiceManager::binderDied(const wp<IBinder>& who) { } void ServiceManager::tryStartService(const std::string& name) { - ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service", + ALOGI("Since '%s' could not be found, trying to start it as a lazy AIDL service. (if it's not " + "configured to be a lazy service, it may be stuck starting or still starting).", name.c_str()); std::thread([=] { if (!base::SetProperty("ctl.interface_start", "aidl/" + name)) { - LOG(INFO) << "Tried to start aidl service " << name - << " as a lazy service, but was unable to. Usually this happens when a " - "service is not installed, but if the service is intended to be used as a " - "lazy service, then it may be configured incorrectly."; + ALOGI("Tried to start aidl service %s as a lazy service, but was unable to. Usually " + "this happens when a " + "service is not installed, but if the service is intended to be used as a " + "lazy service, then it may be configured incorrectly.", + name.c_str()); } }).detach(); } @@ -567,24 +658,25 @@ Status ServiceManager::registerClientCallback(const std::string& name, const sp< auto serviceIt = mNameToService.find(name); if (serviceIt == mNameToService.end()) { - LOG(ERROR) << "Could not add callback for nonexistent service: " << name; + ALOGE("Could not add callback for nonexistent service: %s", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } - if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) { - LOG(WARNING) << "Only a server can register for client callbacks (for " << name << ")"; + if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) { + ALOGW("Only a server can register for client callbacks (for %s)", name.c_str()); return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); } if (serviceIt->second.binder != service) { - LOG(WARNING) << "Tried to register client callback for " << name - << " but a different service is registered under this name."; + ALOGW("Tried to register client callback for %s but a different service is registered " + "under this name.", + name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_ARGUMENT); } if (OK != IInterface::asBinder(cb)->linkToDeath(sp<ServiceManager>::fromExisting(this))) { - LOG(ERROR) << "Could not linkToDeath when adding client callback for " << name; + ALOGE("Could not linkToDeath when adding client callback for %s", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } @@ -621,67 +713,74 @@ ssize_t ServiceManager::Service::getNodeStrongRefCount() { void ServiceManager::handleClientCallbacks() { for (const auto& [name, service] : mNameToService) { - handleServiceClientCallback(name, true); + handleServiceClientCallback(1 /* sm has one refcount */, name, true); } } -ssize_t ServiceManager::handleServiceClientCallback(const std::string& serviceName, - bool isCalledOnInterval) { +bool ServiceManager::handleServiceClientCallback(size_t knownClients, + const std::string& serviceName, + bool isCalledOnInterval) { auto serviceIt = mNameToService.find(serviceName); if (serviceIt == mNameToService.end() || mNameToClientCallback.count(serviceName) < 1) { - return -1; + return true; // return we do have clients a.k.a. DON'T DO ANYTHING } Service& service = serviceIt->second; ssize_t count = service.getNodeStrongRefCount(); - // binder driver doesn't support this feature - if (count == -1) return count; + // binder driver doesn't support this feature, consider we have clients + if (count == -1) return true; - bool hasClients = count > 1; // this process holds a strong count + bool hasKernelReportedClients = static_cast<size_t>(count) > knownClients; if (service.guaranteeClient) { - // we have no record of this client - if (!service.hasClients && !hasClients) { - sendClientCallbackNotifications(serviceName, true); + if (!service.hasClients && !hasKernelReportedClients) { + sendClientCallbackNotifications(serviceName, true, + "service is guaranteed to be in use"); } // guarantee is temporary service.guaranteeClient = false; } - // only send notifications if this was called via the interval checking workflow - if (isCalledOnInterval) { - if (hasClients && !service.hasClients) { - // client was retrieved in some other way - sendClientCallbackNotifications(serviceName, true); - } + // Regardless of this situation, we want to give this notification as soon as possible. + // This way, we have a chance of preventing further thrashing. + if (hasKernelReportedClients && !service.hasClients) { + sendClientCallbackNotifications(serviceName, true, "we now have a record of a client"); + } - // there are no more clients, but the callback has not been called yet - if (!hasClients && service.hasClients) { - sendClientCallbackNotifications(serviceName, false); + // But limit rate of shutting down service. + if (isCalledOnInterval) { + if (!hasKernelReportedClients && service.hasClients) { + sendClientCallbackNotifications(serviceName, false, + "we now have no record of a client"); } } - return count; + // May be different than 'hasKernelReportedClients'. We intentionally delay + // information about clients going away to reduce thrashing. + return service.hasClients; } -void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, bool hasClients) { +void ServiceManager::sendClientCallbackNotifications(const std::string& serviceName, + bool hasClients, const char* context) { auto serviceIt = mNameToService.find(serviceName); if (serviceIt == mNameToService.end()) { - LOG(WARNING) << "sendClientCallbackNotifications could not find service " << serviceName; + ALOGW("sendClientCallbackNotifications could not find service %s when %s", + serviceName.c_str(), context); return; } Service& service = serviceIt->second; - CHECK(hasClients != service.hasClients) << "Record shows: " << service.hasClients - << " so we can't tell clients again that we have client: " << hasClients; + CHECK_NE(hasClients, service.hasClients) << context; - LOG(INFO) << "Notifying " << serviceName << " they have clients: " << hasClients; + ALOGI("Notifying %s they %s (previously: %s) have clients when %s", serviceName.c_str(), + hasClients ? "do" : "don't", service.hasClients ? "do" : "don't", context); auto ccIt = mNameToClientCallback.find(serviceName); CHECK(ccIt != mNameToClientCallback.end()) - << "sendClientCallbackNotifications could not find callbacks for service "; + << "sendClientCallbackNotifications could not find callbacks for service when " + << context; for (const auto& callback : ccIt->second) { callback->onClients(service.binder, hasClients); @@ -702,44 +801,47 @@ Status ServiceManager::tryUnregisterService(const std::string& name, const sp<IB auto serviceIt = mNameToService.find(name); if (serviceIt == mNameToService.end()) { - LOG(WARNING) << "Tried to unregister " << name - << ", but that service wasn't registered to begin with."; + ALOGW("Tried to unregister %s, but that service wasn't registered to begin with.", + name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } - if (serviceIt->second.debugPid != IPCThreadState::self()->getCallingPid()) { - LOG(WARNING) << "Only a server can unregister itself (for " << name << ")"; + if (serviceIt->second.ctx.debugPid != IPCThreadState::self()->getCallingPid()) { + ALOGW("Only a server can unregister itself (for %s)", name.c_str()); return Status::fromExceptionCode(Status::EX_UNSUPPORTED_OPERATION); } sp<IBinder> storedBinder = serviceIt->second.binder; if (binder != storedBinder) { - LOG(WARNING) << "Tried to unregister " << name - << ", but a different service is registered under this name."; + ALOGW("Tried to unregister %s, but a different service is registered under this name.", + name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } + // important because we don't have timer-based guarantees, we don't want to clear + // this if (serviceIt->second.guaranteeClient) { - LOG(INFO) << "Tried to unregister " << name << ", but there is about to be a client."; + ALOGI("Tried to unregister %s, but there is about to be a client.", name.c_str()); return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } - int clients = handleServiceClientCallback(name, false); - - // clients < 0: feature not implemented or other error. Assume clients. - // Otherwise: // - kernel driver will hold onto one refcount (during this transaction) // - servicemanager has a refcount (guaranteed by this transaction) - // So, if clients > 2, then at least one other service on the system must hold a refcount. - if (clients < 0 || clients > 2) { - // client callbacks are either disabled or there are other clients - LOG(INFO) << "Tried to unregister " << name << ", but there are clients: " << clients; - // Set this flag to ensure the clients are acknowledged in the next callback + constexpr size_t kKnownClients = 2; + + if (handleServiceClientCallback(kKnownClients, name, false)) { + ALOGI("Tried to unregister %s, but there are clients.", name.c_str()); + + // Since we had a failed registration attempt, and the HIDL implementation of + // delaying service shutdown for multiple periods wasn't ported here... this may + // help reduce thrashing, but we should be able to remove it. serviceIt->second.guaranteeClient = true; + return Status::fromExceptionCode(Status::EX_ILLEGAL_STATE); } + ALOGI("Unregistering %s", name.c_str()); mNameToService.erase(name); return Status::ok(); @@ -754,7 +856,7 @@ Status ServiceManager::getServiceDebugInfo(std::vector<ServiceDebugInfo>* outRet for (auto const& [name, service] : mNameToService) { ServiceDebugInfo info; info.name = name; - info.debugPid = service.debugPid; + info.debugPid = service.ctx.debugPid; outReturn->push_back(std::move(info)); } @@ -762,4 +864,10 @@ Status ServiceManager::getServiceDebugInfo(std::vector<ServiceDebugInfo>* outRet return Status::ok(); } +void ServiceManager::clear() { + mNameToService.clear(); + mNameToRegistrationCallback.clear(); + mNameToClientCallback.clear(); +} + } // namespace android diff --git a/cmds/servicemanager/ServiceManager.h b/cmds/servicemanager/ServiceManager.h index 5e403194d7..3aa6731eb3 100644 --- a/cmds/servicemanager/ServiceManager.h +++ b/cmds/servicemanager/ServiceManager.h @@ -49,6 +49,8 @@ public: binder::Status getDeclaredInstances(const std::string& interface, std::vector<std::string>* outReturn) override; binder::Status updatableViaApex(const std::string& name, std::optional<std::string>* outReturn) override; + binder::Status getUpdatableNames(const std::string& apexName, + std::vector<std::string>* outReturn) override; binder::Status getConnectionInfo(const std::string& name, std::optional<ConnectionInfo>* outReturn) override; binder::Status registerClientCallback(const std::string& name, const sp<IBinder>& service, @@ -58,6 +60,12 @@ public: void binderDied(const wp<IBinder>& who) override; void handleClientCallbacks(); + /** + * This API is added for debug purposes. It clears members which hold service and callback + * information. + */ + void clear(); + protected: virtual void tryStartService(const std::string& name); @@ -68,10 +76,12 @@ private: int32_t dumpPriority; bool hasClients = false; // notifications sent on true -> false. bool guaranteeClient = false; // forces the client check to true - pid_t debugPid = 0; // the process in which this service runs + Access::CallingContext ctx; // process that originally registers this // the number of clients of the service, including servicemanager itself ssize_t getNodeStrongRefCount(); + + ~Service(); }; using ServiceCallbackMap = std::map<std::string, std::vector<sp<IServiceCallback>>>; @@ -83,9 +93,12 @@ private: void removeRegistrationCallback(const wp<IBinder>& who, ServiceCallbackMap::iterator* it, bool* found); - ssize_t handleServiceClientCallback(const std::string& serviceName, bool isCalledOnInterval); - // Also updates mHasClients (of what the last callback was) - void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients); + // returns whether there are known clients in addition to the count provided + bool handleServiceClientCallback(size_t knownClients, const std::string& serviceName, + bool isCalledOnInterval); + // Also updates mHasClients (of what the last callback was) + void sendClientCallbackNotifications(const std::string& serviceName, bool hasClients, + const char* context); // removes a callback from mNameToClientCallback, deleting the entry if the vector is empty // this updates the iterator to the next location void removeClientCallback(const wp<IBinder>& who, ClientCallbackMap::iterator* it); diff --git a/cmds/servicemanager/ServiceManagerFuzzer.cpp b/cmds/servicemanager/ServiceManagerFuzzer.cpp new file mode 100644 index 0000000000..b76a6bd3cd --- /dev/null +++ b/cmds/servicemanager/ServiceManagerFuzzer.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (C) 2022 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 <fuzzbinder/libbinder_driver.h> +#include <utils/StrongPointer.h> + +#include "Access.h" +#include "ServiceManager.h" + +using ::android::Access; +using ::android::fuzzService; +using ::android::ServiceManager; +using ::android::sp; + +extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { + auto accessPtr = std::make_unique<Access>(); + auto serviceManager = sp<ServiceManager>::make(std::move(accessPtr)); + fuzzService(serviceManager, FuzzedDataProvider(data, size)); + serviceManager->clear(); + + return 0; +} diff --git a/cmds/servicemanager/main.cpp b/cmds/servicemanager/main.cpp index 2fb9c2bc9a..c1a04dde89 100644 --- a/cmds/servicemanager/main.cpp +++ b/cmds/servicemanager/main.cpp @@ -15,6 +15,7 @@ */ #include <android-base/logging.h> +#include <android-base/properties.h> #include <binder/IPCThreadState.h> #include <binder/ProcessState.h> #include <binder/Status.h> @@ -26,15 +27,14 @@ #include "ServiceManager.h" using ::android::Access; -using ::android::sp; +using ::android::IPCThreadState; using ::android::Looper; using ::android::LooperCallback; using ::android::ProcessState; -using ::android::IPCThreadState; -using ::android::ProcessState; using ::android::ServiceManager; -using ::android::os::IServiceManager; using ::android::sp; +using ::android::base::SetProperty; +using ::android::os::IServiceManager; class BinderCallback : public LooperCallback { public: @@ -111,9 +111,7 @@ private: }; int main(int argc, char** argv) { -#ifdef __ANDROID_RECOVERY__ android::base::InitLogging(argv, android::base::KernelLogger); -#endif if (argc > 2) { LOG(FATAL) << "usage: " << argv[0] << " [binder driver]"; @@ -121,6 +119,8 @@ int main(int argc, char** argv) { const char* driver = argc == 2 ? argv[1] : "/dev/binder"; + LOG(INFO) << "Starting sm instance on " << driver; + sp<ProcessState> ps = ProcessState::initWithDriver(driver); ps->setThreadPoolMaxThreadCount(0); ps->setCallRestriction(ProcessState::CallRestriction::FATAL_IF_NOT_ONEWAY); @@ -138,6 +138,12 @@ int main(int argc, char** argv) { BinderCallback::setupTo(looper); ClientCallbackCallback::setupTo(looper, manager); +#ifndef VENDORSERVICEMANAGER + if (!SetProperty("servicemanager.ready", "true")) { + LOG(ERROR) << "Failed to set servicemanager ready property"; + } +#endif + while(true) { looper->pollAll(-1); } diff --git a/cmds/servicemanager/servicemanager.microdroid.rc b/cmds/servicemanager/servicemanager.microdroid.rc deleted file mode 100644 index e01f132c64..0000000000 --- a/cmds/servicemanager/servicemanager.microdroid.rc +++ /dev/null @@ -1,8 +0,0 @@ -service servicemanager /system/bin/servicemanager.microdroid - class core - user system - group system readproc - critical - onrestart restart apexd - task_profiles ServiceCapacityLow - shutdown critical diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc index e5d689ff91..4f92b3a374 100644 --- a/cmds/servicemanager/servicemanager.rc +++ b/cmds/servicemanager/servicemanager.rc @@ -3,7 +3,9 @@ service servicemanager /system/bin/servicemanager user system group system readproc critical - onrestart restart apexd + file /dev/kmsg w + onrestart setprop servicemanager.ready false + onrestart restart --only-if-running apexd onrestart restart audioserver onrestart restart gatekeeperd onrestart class_restart --only-enabled main diff --git a/cmds/servicemanager/servicemanager.recovery.rc b/cmds/servicemanager/servicemanager.recovery.rc index 067faf9c8f..b927c018df 100644 --- a/cmds/servicemanager/servicemanager.recovery.rc +++ b/cmds/servicemanager/servicemanager.recovery.rc @@ -1,4 +1,5 @@ service servicemanager /system/bin/servicemanager disabled group system readproc + onrestart setprop servicemanager.ready false seclabel u:r:servicemanager:s0 diff --git a/cmds/servicemanager/test_sm.cpp b/cmds/servicemanager/test_sm.cpp index 5d5a75e174..0fd8d8ee2a 100644 --- a/cmds/servicemanager/test_sm.cpp +++ b/cmds/servicemanager/test_sm.cpp @@ -14,13 +14,15 @@ * limitations under the License. */ +#include <android-base/properties.h> +#include <android-base/strings.h> #include <android/os/BnServiceCallback.h> #include <binder/Binder.h> -#include <binder/ProcessState.h> #include <binder/IServiceManager.h> +#include <binder/ProcessState.h> #include <cutils/android_filesystem_config.h> -#include <gtest/gtest.h> #include <gmock/gmock.h> +#include <gtest/gtest.h> #include "Access.h" #include "ServiceManager.h" @@ -75,6 +77,11 @@ static sp<ServiceManager> getPermissiveServiceManager() { return sm; } +static bool isCuttlefish() { + return android::base::StartsWith(android::base::GetProperty("ro.product.vendor.device", ""), + "vsoc_"); +} + TEST(AddService, HappyHappy) { auto sm = getPermissiveServiceManager(); EXPECT_TRUE(sm->addService("foo", getBinder(), false /*allowIsolated*/, @@ -306,6 +313,49 @@ TEST(ListServices, CriticalServices) { EXPECT_THAT(out, ElementsAre("sa")); } +TEST(Vintf, UpdatableViaApex) { + if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices"; + + auto sm = getPermissiveServiceManager(); + std::optional<std::string> updatableViaApex; + EXPECT_TRUE(sm->updatableViaApex("android.hardware.camera.provider.ICameraProvider/internal/0", + &updatableViaApex) + .isOk()); + EXPECT_EQ(std::make_optional<std::string>("com.google.emulated.camera.provider.hal"), + updatableViaApex); +} + +TEST(Vintf, UpdatableViaApex_InvalidNameReturnsNullOpt) { + if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices"; + + auto sm = getPermissiveServiceManager(); + std::optional<std::string> updatableViaApex; + EXPECT_TRUE(sm->updatableViaApex("android.hardware.camera.provider.ICameraProvider", + &updatableViaApex) + .isOk()); // missing instance name + EXPECT_EQ(std::nullopt, updatableViaApex); +} + +TEST(Vintf, GetUpdatableNames) { + if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices"; + + auto sm = getPermissiveServiceManager(); + std::vector<std::string> names; + EXPECT_TRUE(sm->getUpdatableNames("com.google.emulated.camera.provider.hal", &names).isOk()); + EXPECT_EQ(std::vector< + std::string>{"android.hardware.camera.provider.ICameraProvider/internal/0"}, + names); +} + +TEST(Vintf, GetUpdatableNames_InvalidApexNameReturnsEmpty) { + if (!isCuttlefish()) GTEST_SKIP() << "Skipping non-Cuttlefish devices"; + + auto sm = getPermissiveServiceManager(); + std::vector<std::string> names; + EXPECT_TRUE(sm->getUpdatableNames("non.existing.apex.name", &names).isOk()); + EXPECT_EQ(std::vector<std::string>{}, names); +} + class CallbackHistorian : public BnServiceCallback { Status onRegistration(const std::string& name, const sp<IBinder>& binder) override { registrations.push_back(name); diff --git a/cmds/servicemanager/vndservicemanager.rc b/cmds/servicemanager/vndservicemanager.rc index c9305a1c60..80af1d1377 100644 --- a/cmds/servicemanager/vndservicemanager.rc +++ b/cmds/servicemanager/vndservicemanager.rc @@ -2,6 +2,7 @@ service vndservicemanager /vendor/bin/vndservicemanager /dev/vndbinder class core user system group system readproc + file /dev/kmsg w task_profiles ServiceCapacityLow onrestart class_restart main onrestart class_restart hal |