summaryrefslogtreecommitdiff
path: root/cmds
diff options
context:
space:
mode:
Diffstat (limited to 'cmds')
-rw-r--r--cmds/atrace/README.md48
-rw-r--r--cmds/atrace/atrace.cpp141
-rw-r--r--cmds/atrace/atrace.rc118
-rw-r--r--cmds/atrace/atrace_userdebug.rc6
-rw-r--r--cmds/bugreportz/readme.md2
-rw-r--r--cmds/dumpstate/Android.bp2
-rw-r--r--cmds/dumpstate/TEST_MAPPING6
-rw-r--r--cmds/dumpstate/dumpstate.cpp160
-rw-r--r--cmds/dumpstate/dumpstate.h6
-rw-r--r--cmds/dumpstate/tests/dumpstate_test.cpp3
-rw-r--r--cmds/dumpsys/tests/dumpsys_test.cpp1
-rw-r--r--cmds/installd/Android.bp14
-rw-r--r--cmds/installd/InstalldNativeService.cpp217
-rw-r--r--cmds/installd/SysTrace.cpp30
-rw-r--r--cmds/installd/SysTrace.h22
-rw-r--r--cmds/installd/dexopt.cpp2
-rw-r--r--cmds/installd/installd.rc1
-rw-r--r--cmds/installd/otapreopt.cpp6
-rw-r--r--cmds/installd/otapreopt.rc2
-rw-r--r--cmds/installd/run_dex2oat.cpp21
-rw-r--r--cmds/installd/run_dex2oat.h5
-rw-r--r--cmds/installd/run_dex2oat_test.cpp50
-rw-r--r--cmds/installd/tests/Android.bp6
-rw-r--r--cmds/installd/tests/installd_dexopt_test.cpp75
-rw-r--r--cmds/installd/utils.cpp2
-rw-r--r--cmds/lshal/ListCommand.cpp10
-rw-r--r--cmds/lshal/libprocpartition/Android.bp3
-rw-r--r--cmds/servicemanager/Access.cpp27
-rw-r--r--cmds/servicemanager/Android.bp26
-rw-r--r--cmds/servicemanager/ServiceManager.cpp270
-rw-r--r--cmds/servicemanager/ServiceManager.h21
-rw-r--r--cmds/servicemanager/ServiceManagerFuzzer.cpp35
-rw-r--r--cmds/servicemanager/main.cpp18
-rw-r--r--cmds/servicemanager/servicemanager.microdroid.rc8
-rw-r--r--cmds/servicemanager/servicemanager.rc4
-rw-r--r--cmds/servicemanager/servicemanager.recovery.rc1
-rw-r--r--cmds/servicemanager/test_sm.cpp54
-rw-r--r--cmds/servicemanager/vndservicemanager.rc1
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