From fb25ddd9c9004de9a9ebb1175a6ceaf7aeec0673 Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Fri, 9 Mar 2018 15:20:56 -0800 Subject: [PATCH 001/221] Fix compilation issue when LMKD_LOG_STATS is defined. Note: The breakage was caused by http://ag/3621623 Test: mmma system/core/lmkd/ Change-Id: I17033aeedb3183d4777dacb89ec84430ff061b3c Bug: 74443701 --- lmkd/lmkd.c | 4 ++-- lmkd/statslog.h | 30 +++++++++++++++++------------- 2 files changed, 19 insertions(+), 15 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 1d8afb484..e2e5c4e37 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -1201,7 +1201,7 @@ int main(int argc __unused, char **argv __unused) { (unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0); #ifdef LMKD_LOG_STATS - statlog_init(); + statslog_init(&log_ctx, &enable_stats_log); #endif // MCL_ONFAULT pins pages as they fault instead of loading @@ -1221,7 +1221,7 @@ int main(int argc __unused, char **argv __unused) { mainloop(); #ifdef LMKD_LOG_STATS - statslog_destroy(); + statslog_destroy(&log_ctx); #endif ALOGI("exiting"); diff --git a/lmkd/statslog.h b/lmkd/statslog.h index b567fbf1c..4cde840ea 100644 --- a/lmkd/statslog.h +++ b/lmkd/statslog.h @@ -17,6 +17,7 @@ #ifndef _STATSLOG_H_ #define _STATSLOG_H_ +#include #include #include @@ -34,17 +35,26 @@ __BEGIN_DECLS #define LMK_STATE_CHANGE_START 1 #define LMK_STATE_CHANGE_STOP 2 -static inline void statslog_init() { - enable_stats_log = property_get_bool("ro.lmk.log_stats", false); +/* + * The single event tag id for all stats logs. + * Keep this in sync with system/core/logcat/event.logtags + */ +const static int kStatsEventTag = 1937006964; - if (enable_stats_log) { - log_ctx = create_android_logger(kStatsEventTag); +static inline void statslog_init(android_log_context* log_ctx, bool* enable_stats_log) { + assert(log_ctx != NULL); + assert(enable_stats_log != NULL); + *enable_stats_log = property_get_bool("ro.lmk.log_stats", false); + + if (*enable_stats_log) { + *log_ctx = create_android_logger(kStatsEventTag); } } -static inline void statslog_destroy() { - if (log_ctx) { - android_log_destroy(&log_ctx); +static inline void statslog_destroy(android_log_context* log_ctx) { + assert(log_ctx != NULL); + if (*log_ctx) { + android_log_destroy(log_ctx); } } @@ -58,12 +68,6 @@ struct memory_stat { #define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat" -/* - * The single event tag id for all stats logs. - * Keep this in sync with system/core/logcat/event.logtags - */ -const static int kStatsEventTag = 1937006964; - /** * Logs the change in LMKD state which is used as start/stop boundaries for logging * LMK_KILL_OCCURRED event. From 9f60e15174a3d2e976587f3f9ead20aa2793a0d4 Mon Sep 17 00:00:00 2001 From: Paul McLean Date: Tue, 14 Mar 2017 15:47:11 -0700 Subject: [PATCH 002/221] (re)ntegrate Native MIDI API into NDK - add libamidi add libamidi to system libs Bug: 30252756 Bug: 37090545 Test: Build and install NativeMidiTestbed app. Run NativMidiTestbed app on DUT. Connect to PreSonus AudioBox 22VSL. Connect MIDI interface to external MIDI synthesizer. Verify connection. Verify MIDI messages sent to external MIDI synthesizer. Verify MIDI messages received from external MIDI synthesizer. Change-Id: Id4bcebbbeb6dc342dbd87b916f1bc78ae32f53db --- rootdir/etc/public.libraries.android.txt | 1 + rootdir/etc/public.libraries.wear.txt | 1 + 2 files changed, 2 insertions(+) diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt index e20b95d0c..2a51d5360 100644 --- a/rootdir/etc/public.libraries.android.txt +++ b/rootdir/etc/public.libraries.android.txt @@ -1,6 +1,7 @@ # See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md libandroid.so libaaudio.so +libamidi.so libc.so libcamera2ndk.so libdl.so diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt index 3c46094a2..56055baad 100644 --- a/rootdir/etc/public.libraries.wear.txt +++ b/rootdir/etc/public.libraries.wear.txt @@ -1,6 +1,7 @@ # See https://android.googlesource.com/platform/ndk/+/master/docs/PlatformApis.md libandroid.so libaaudio.so +libamidi.so libc.so libcamera2ndk.so libdl.so From 083be30783870ce4093d1d5f040f42f9f3c27510 Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Fri, 9 Mar 2018 18:29:44 -0800 Subject: [PATCH 003/221] Use usel_mkd_stats_log build variable while compiling lmkd with stats logging feature. Bug: 74443701 Test: Tested manually Change-Id: Ifa13cc7d1c3ff3ac71a16cf55be5a48ce808ef59 --- lmkd/Android.bp | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/lmkd/Android.bp b/lmkd/Android.bp index 8e6516207..58647f2ff 100644 --- a/lmkd/Android.bp +++ b/lmkd/Android.bp @@ -12,6 +12,13 @@ cc_binary { local_include_dirs: ["include"], cflags: ["-Werror", "-DLMKD_TRACE_KILLS"], init_rc: ["lmkd.rc"], + product_variables: { + use_lmkd_stats_log: { + cflags: [ + "-DLMKD_LOG_STATS" + ], + }, + }, } cc_library_static { From 6bbd521a246c8d07a012a208e04eb3acbb4ae6e7 Mon Sep 17 00:00:00 2001 From: Greg Kaiser Date: Fri, 23 Mar 2018 14:16:12 -0700 Subject: [PATCH 004/221] lmkd: Protect against buffer overflow We're passing a 'line' whose backing buffer is PAGE_MAX in size into memory_stat_parse_line(). We protect overflowing the smaller LINE_MAX 'key' buffer via some C preprocessing macros to assure we limit the size. Test: Local build with LMKD_LOG_STATS set for this file. Bug: 76220622 Change-Id: I9e50d4270f7099e37a9bfc7fb9b9b95cc7adb086 --- lmkd/lmkd.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 937a21821..5a210abab 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -80,6 +80,9 @@ /* Defined as ProcessList.SYSTEM_ADJ in ProcessList.java */ #define SYSTEM_ADJ (-900) +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) +#define STRINGIFY_INTERNAL(x) #x + /* default to old in-kernel interface if no memory pressure events */ static int use_inkernel_interface = 1; static bool has_inkernel_module; @@ -583,10 +586,10 @@ static void ctrl_connect_handler(int data __unused, uint32_t events __unused) { #ifdef LMKD_LOG_STATS static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { - char key[LINE_MAX]; + char key[LINE_MAX + 1]; int64_t value; - sscanf(line,"%s %" SCNd64 "", key, &value); + sscanf(line, "%" STRINGIFY(LINE_MAX) "s %" SCNd64 "", key, &value); if (strcmp(key, "total_") < 0) { return; From f2dd78bb2c9fe0e6482cf012e26664752fc64401 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 26 Mar 2018 15:15:05 -0700 Subject: [PATCH 005/221] storaged: fix divide-by-zero when updating history Bug: 75984894 Test: storaged unit tests on x86/64 platforms Change-Id: I869b3dc6e42aa71100a99a84344dbc30c319d280 --- storaged/include/storaged_info.h | 1 + storaged/storaged_info.cpp | 12 ++++++++---- storaged/tests/storaged_test.cpp | 25 +++++++++++++++++++++++++ 3 files changed, 34 insertions(+), 4 deletions(-) diff --git a/storaged/include/storaged_info.h b/storaged/include/storaged_info.h index 88a53deb2..9c3d0e784 100644 --- a/storaged/include/storaged_info.h +++ b/storaged/include/storaged_info.h @@ -38,6 +38,7 @@ using namespace storaged_proto; class storage_info_t { protected: FRIEND_TEST(storaged_test, storage_info_t); + FRIEND_TEST(storaged_test, storage_info_t_proto); // emmc lifetime uint16_t eol; // pre-eol (end of life) information uint16_t lifetime_a; // device life time estimation (type A) diff --git a/storaged/storaged_info.cpp b/storaged/storaged_info.cpp index 055f3751f..5605f667c 100644 --- a/storaged/storaged_info.cpp +++ b/storaged/storaged_info.cpp @@ -157,11 +157,14 @@ void storage_info_t::update_perf_history(uint32_t bw, return; } - recent_perf.erase(recent_perf.begin() + nr_samples, - recent_perf.end()); + if (nr_samples < recent_perf.size()) { + recent_perf.erase(recent_perf.begin() + nr_samples, recent_perf.end()); + } - uint32_t daily_avg_bw = accumulate(recent_perf.begin(), - recent_perf.begin() + nr_samples, 0) / nr_samples; + uint32_t daily_avg_bw = 0; + if (!recent_perf.empty()) { + daily_avg_bw = accumulate(recent_perf.begin(), recent_perf.end(), 0) / recent_perf.size(); + } day_start_tp = tp - chrono::seconds(duration_cast( tp.time_since_epoch()).count() % DAY_TO_SEC); @@ -176,6 +179,7 @@ void storage_info_t::update_perf_history(uint32_t bw, return; } + DCHECK(nr_days > 0); uint32_t week_avg_bw = accumulate(daily_perf.begin(), daily_perf.begin() + nr_days, 0) / nr_days; diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp index d1fa9ed21..ec47b65ee 100644 --- a/storaged/tests/storaged_test.cpp +++ b/storaged/tests/storaged_test.cpp @@ -416,6 +416,31 @@ TEST(storaged_test, storage_info_t) { } } +TEST(storaged_test, storage_info_t_proto) { + storage_info_t si; + si.day_start_tp = {}; + + IOPerfHistory proto; + proto.set_nr_samples(10); + proto.set_day_start_sec(0); + si.load_perf_history_proto(proto); + + // Skip ahead > 1 day, with no data points in the previous day. + time_point stp; + stp += hours(36); + si.update_perf_history(100, stp); + + vector history = si.get_perf_history(); + EXPECT_EQ(history.size(), 63UL); + EXPECT_EQ(history[0], 1); + EXPECT_EQ(history[1], 7); + EXPECT_EQ(history[2], 52); + EXPECT_EQ(history[3], 100); + for (size_t i = 4; i < history.size(); i++) { + EXPECT_EQ(history[i], 0); + } +} + TEST(storaged_test, uid_monitor) { uid_monitor uidm; From 4cc755dce527434dc4b79c1734185faeab084bac Mon Sep 17 00:00:00 2001 From: Jayant Chowdhary Date: Wed, 28 Mar 2018 18:45:35 -0700 Subject: [PATCH 006/221] Add dummy vndk library libmkbootimg to enable abi checks on boot_img_hdr. Bug: 74763691 Test: m -j libmkbootimg creates libmkbootimg.so.lsdump. Test: make -j64 Change-Id: I8d716c560467aaf090f4f7ee9cfbc53a9405f05d --- fastboot/Android.mk | 3 +- init/Android.bp | 4 +-- mkbootimg/Android.bp | 32 +++++++++++++++++++ .../include/abi_check/mkbootimg_abi_check.h | 28 ++++++++++++++++ mkbootimg/{ => include/bootimg}/bootimg.h | 28 ++++++++-------- mkbootimg/mkbootimg_dummy.cpp | 24 ++++++++++++++ 6 files changed, 101 insertions(+), 18 deletions(-) create mode 100644 mkbootimg/Android.bp create mode 100644 mkbootimg/include/abi_check/mkbootimg_abi_check.h rename mkbootimg/{ => include/bootimg}/bootimg.h (91%) create mode 100644 mkbootimg/mkbootimg_dummy.cpp diff --git a/fastboot/Android.mk b/fastboot/Android.mk index f5bcc264d..944b00b16 100644 --- a/fastboot/Android.mk +++ b/fastboot/Android.mk @@ -22,7 +22,8 @@ LOCAL_CFLAGS += -DFASTBOOT_VERSION="\"$(tool_version)\"" LOCAL_C_INCLUDES := \ $(LOCAL_PATH)/../adb \ - $(LOCAL_PATH)/../mkbootimg \ + +LOCAL_HEADER_LIBRARIES := bootimg_headers LOCAL_SRC_FILES := \ bootimg_utils.cpp \ diff --git a/init/Android.bp b/init/Android.bp index 31c8efb09..70a4ac651 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -127,9 +127,7 @@ cc_library_static { "watchdogd.cpp", ], whole_static_libs: ["libcap"], - include_dirs: [ - "system/core/mkbootimg", - ], + header_libs: ["bootimg_headers"], proto: { type: "lite", export_proto_headers: true, diff --git a/mkbootimg/Android.bp b/mkbootimg/Android.bp new file mode 100644 index 000000000..b49434679 --- /dev/null +++ b/mkbootimg/Android.bp @@ -0,0 +1,32 @@ +// Copyright 2012 The Android Open Source Project + +cc_library_headers { + name: "libmkbootimg_abi_headers", + vendor_available: true, + export_include_dirs: ["include"], +} + +cc_library_headers { + name: "bootimg_headers", + vendor_available: true, + export_include_dirs: ["include/bootimg"], + host_supported: true, + target: { + windows: { + enabled: true, + }, + }, +} + +cc_library { + name: "libmkbootimg_abi_check", + vendor_available: true, + vndk: { + enabled: true, + }, + srcs: [ + "mkbootimg_dummy.cpp", + ], + header_libs: ["libmkbootimg_abi_headers"], + export_header_lib_headers: ["libmkbootimg_abi_headers"], +} diff --git a/mkbootimg/include/abi_check/mkbootimg_abi_check.h b/mkbootimg/include/abi_check/mkbootimg_abi_check.h new file mode 100644 index 000000000..d478aba09 --- /dev/null +++ b/mkbootimg/include/abi_check/mkbootimg_abi_check.h @@ -0,0 +1,28 @@ +/* + * Copyright (C) 2018 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 + +// This header has been created for the following reaons: +// 1) In order for a change in a user defined type to be classified as API / +// ABI breaking, it needs to be referenced by an 'exported interface' +// (in this case the function mkbootimg_dummy). +// 2) Since 'mkbootimg_dummy' needs to be exported, we need to have it +// exposed through a public header. +// 3) It is desirable not to pollute bootimg.h with interfaces which are not +// 'used' in reality by on device binaries. Furthermore, bootimg.h might +// be exported by a library in the future, so we must avoid polluting it. +void mkbootimg_dummy(boot_img_hdr*); diff --git a/mkbootimg/bootimg.h b/mkbootimg/include/bootimg/bootimg.h similarity index 91% rename from mkbootimg/bootimg.h rename to mkbootimg/include/bootimg/bootimg.h index 1be8c229c..4311b46f9 100644 --- a/mkbootimg/bootimg.h +++ b/mkbootimg/include/bootimg/bootimg.h @@ -2,16 +2,16 @@ ** ** Copyright 2007, 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 +** 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 +** 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 +** 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. */ @@ -34,17 +34,17 @@ struct boot_img_hdr_v0 { uint8_t magic[BOOT_MAGIC_SIZE]; - uint32_t kernel_size; /* size in bytes */ - uint32_t kernel_addr; /* physical load addr */ + uint32_t kernel_size; /* size in bytes */ + uint32_t kernel_addr; /* physical load addr */ uint32_t ramdisk_size; /* size in bytes */ uint32_t ramdisk_addr; /* physical load addr */ - uint32_t second_size; /* size in bytes */ - uint32_t second_addr; /* physical load addr */ + uint32_t second_size; /* size in bytes */ + uint32_t second_addr; /* physical load addr */ - uint32_t tags_addr; /* physical addr for kernel tags */ - uint32_t page_size; /* flash page size we assume */ + uint32_t tags_addr; /* physical addr for kernel tags */ + uint32_t page_size; /* flash page size we assume */ /* * version for the boot image header. */ diff --git a/mkbootimg/mkbootimg_dummy.cpp b/mkbootimg/mkbootimg_dummy.cpp new file mode 100644 index 000000000..410d37909 --- /dev/null +++ b/mkbootimg/mkbootimg_dummy.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2018 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 + +void mkbootimg_dummy(boot_img_hdr* hdr) { + // TODO: Hack to trigger abi checks, remove this. + if (hdr) { + hdr--; + } +} From 335fd9a3907e2a5d2cfa1050d01f0c7f22baf408 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 28 Mar 2018 12:43:17 -0700 Subject: [PATCH 007/221] make_f2fs: specify sector size for target image size The total sectors that we want to format is used in different meanings from various users. This notifies its size based on 4096 bytes explicitly. Bug: 76407663 Change-Id: I4e00f2e2289c1381f0238d2a4acb606a0ab551a9 Reported-by: katao@xiaomi.com Signed-off-by: Jaegeuk Kim --- fs_mgr/fs_mgr_format.cpp | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/fs_mgr/fs_mgr_format.cpp b/fs_mgr/fs_mgr_format.cpp index cbd8ffa14..63a6839c5 100644 --- a/fs_mgr/fs_mgr_format.cpp +++ b/fs_mgr/fs_mgr_format.cpp @@ -114,10 +114,19 @@ static int format_f2fs(char *fs_blkdev, uint64_t dev_sz, bool crypt_footer) } std::string size_str = std::to_string(dev_sz / 4096); + // clang-format off const char* const args[] = { - "/system/bin/make_f2fs", "-d1", "-f", - "-O", "encrypt", "-O", "quota", - fs_blkdev, size_str.c_str(), nullptr}; + "/system/bin/make_f2fs", + "-d1", + "-f", + "-O", "encrypt", + "-O", "quota", + "-w", "4096", + fs_blkdev, + size_str.c_str(), + nullptr + }; + // clang-format on return android_fork_execvp_ext(arraysize(args), const_cast(args), NULL, true, LOG_KLOG, true, nullptr, nullptr, 0); From 730728cbb4cf056086d6974d0cd2f7426c607ca9 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Mon, 9 Apr 2018 12:20:48 +0900 Subject: [PATCH 008/221] Mark libziparchive as double_loadable libziparchive is explicitly marked as double_loadable since it is one of the (indirect) dependencies of the LLNDK library libvulkan and at the same time the lib itself is marked as VNDK. Such lib can be double loaded inside a vendor process. Note: even without this change, the library is already capable of being double loaded due to the dependency graph around it. This change is to make it explicit so that double loading of a library is carefully tracked and signed-off by the owner of the lib. Bug: 77155589 Test: m -j Change-Id: Id0a731d553bbb68b84bca421500c94b7b35eca14 --- libziparchive/Android.bp | 1 + 1 file changed, 1 insertion(+) diff --git a/libziparchive/Android.bp b/libziparchive/Android.bp index 075fb86e1..ed1b9bc24 100644 --- a/libziparchive/Android.bp +++ b/libziparchive/Android.bp @@ -61,6 +61,7 @@ cc_library { vndk: { enabled: true, }, + double_loadable: true, defaults: [ "libziparchive_defaults", From d716fe3610aae8cefcc676ade00c7bfd2b823c20 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 13 Apr 2018 12:43:41 -0700 Subject: [PATCH 009/221] lmkd: Optimize frequent file reads by keeping file descriptors open To check system memory state lmkd is using same files every time vmpressure event is received. Instead of opening and closing these files every time we store the file descriptor and use pread() to reread the file from the beginning. Bug: 77299493 Bug: 75322373 Change-Id: I8e27f8b9526e82e3cc313a02fce215c2e4dd3d29 Signed-off-by: Suren Baghdasaryan --- lmkd/lmkd.c | 88 ++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 73 insertions(+), 15 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 9fb521651..7205a95ee 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -176,6 +176,11 @@ struct proc { struct proc *pidhash_next; }; +struct reread_data { + const char* const filename; + int fd; +}; + #ifdef LMKD_LOG_STATS static bool enable_stats_log; static android_log_context log_ctx; @@ -191,12 +196,27 @@ static struct adjslot_list procadjslot_list[ADJTOSLOT(OOM_SCORE_ADJ_MAX) + 1]; /* PAGE_SIZE / 1024 */ static long page_k; +static bool parse_int64(const char* str, int64_t* ret) { + char* endptr; + long long val = strtoll(str, &endptr, 10); + if (str == endptr || val > INT64_MAX) { + return false; + } + *ret = (int64_t)val; + return true; +} + +/* + * Read file content from the beginning up to max_len bytes or EOF + * whichever happens first. + */ static ssize_t read_all(int fd, char *buf, size_t max_len) { ssize_t ret = 0; + off_t offset = 0; while (max_len > 0) { - ssize_t r = read(fd, buf, max_len); + ssize_t r = TEMP_FAILURE_RETRY(pread(fd, buf, max_len, offset)); if (r == 0) { break; } @@ -205,12 +225,44 @@ static ssize_t read_all(int fd, char *buf, size_t max_len) } ret += r; buf += r; + offset += r; max_len -= r; } return ret; } +/* + * Read a new or already opened file from the beginning. + * If the file has not been opened yet data->fd should be set to -1. + * To be used with files which are read often and possibly during high + * memory pressure to minimize file opening which by itself requires kernel + * memory allocation and might result in a stall on memory stressed system. + */ +static int reread_file(struct reread_data *data, char *buf, size_t buf_size) { + ssize_t size; + + if (data->fd == -1) { + data->fd = open(data->filename, O_RDONLY | O_CLOEXEC); + if (data->fd == -1) { + ALOGE("%s open: %s", data->filename, strerror(errno)); + return -1; + } + } + + size = read_all(data->fd, buf, buf_size - 1); + if (size < 0) { + ALOGE("%s read: %s", data->filename, strerror(errno)); + close(data->fd); + data->fd = -1; + return -1; + } + ALOG_ASSERT((size_t)size < buf_size - 1, data->filename " too large"); + buf[size] = 0; + + return 0; +} + static struct proc *pid_lookup(int pid) { struct proc *procp; @@ -472,7 +524,7 @@ static void ctrl_data_close(int dsock_idx) { static int ctrl_data_read(int dsock_idx, char *buf, size_t bufsz) { int ret = 0; - ret = read(data_sock[dsock_idx].sock, buf, bufsz); + ret = TEMP_FAILURE_RETRY(read(data_sock[dsock_idx].sock, buf, bufsz)); if (ret == -1) { ALOGE("control data socket read failed; errno=%d", errno); @@ -833,23 +885,19 @@ static int find_and_kill_processes(enum vmpressure_level level, return pages_freed; } -static int64_t get_memory_usage(const char* path) { +static int64_t get_memory_usage(struct reread_data *file_data) { int ret; int64_t mem_usage; char buf[32]; - int fd = open(path, O_RDONLY | O_CLOEXEC); - if (fd == -1) { - ALOGE("%s open: errno=%d", path, errno); + + if (reread_file(file_data, buf, sizeof(buf)) < 0) { return -1; } - ret = read_all(fd, buf, sizeof(buf) - 1); - close(fd); - if (ret < 0) { - ALOGE("%s error: errno=%d", path, errno); + if (!parse_int64(buf, &mem_usage)) { + ALOGE("%s parse error", file_data->filename); return -1; } - sscanf(buf, "%" SCNd64, &mem_usage); if (mem_usage == 0) { ALOGE("No memory!"); return -1; @@ -909,6 +957,14 @@ static void mp_event_common(int data, uint32_t events __unused) { static struct timeval last_report_tm; static unsigned long skip_count = 0; enum vmpressure_level level = (enum vmpressure_level)data; + static struct reread_data mem_usage_file_data = { + .filename = MEMCG_MEMORY_USAGE, + .fd = -1, + }; + static struct reread_data memsw_usage_file_data = { + .filename = MEMCG_MEMORYSW_USAGE, + .fd = -1, + }; /* * Check all event counters from low to critical @@ -917,7 +973,8 @@ static void mp_event_common(int data, uint32_t events __unused) { */ for (lvl = VMPRESS_LEVEL_LOW; lvl < VMPRESS_LEVEL_COUNT; lvl++) { if (mpevfd[lvl] != -1 && - read(mpevfd[lvl], &evcount, sizeof(evcount)) > 0 && + TEMP_FAILURE_RETRY(read(mpevfd[lvl], + &evcount, sizeof(evcount))) > 0 && evcount > 0 && lvl > level) { level = lvl; } @@ -954,9 +1011,10 @@ static void mp_event_common(int data, uint32_t events __unused) { return; } - mem_usage = get_memory_usage(MEMCG_MEMORY_USAGE); - memsw_usage = get_memory_usage(MEMCG_MEMORYSW_USAGE); - if (memsw_usage < 0 || mem_usage < 0) { + if ((mem_usage = get_memory_usage(&mem_usage_file_data)) < 0) { + goto do_kill; + } + if ((memsw_usage = get_memory_usage(&memsw_usage_file_data)) < 0) { goto do_kill; } From da0bc05b2293095c4e1153268ae7b53773f8f5ed Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 13 Apr 2018 13:11:51 -0700 Subject: [PATCH 010/221] lmkd: Add zoneinfo and meminfo parsing routines /proc/zoneinfo and /proc/meminfo contain information necessary for lmkd to assess system memory state. Add routines to parse these files. Bug: 77299493 Bug: 75322373 Change-Id: Ie7d80bbb81fd0d2fc0629f6f678e6afc97fed1f6 Signed-off-by: Suren Baghdasaryan --- lmkd/lmkd.c | 238 +++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 237 insertions(+), 1 deletion(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 7205a95ee..ca3e2c828 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -68,7 +68,8 @@ #define MEMCG_SYSFS_PATH "/dev/memcg/" #define MEMCG_MEMORY_USAGE "/dev/memcg/memory.usage_in_bytes" #define MEMCG_MEMORYSW_USAGE "/dev/memcg/memory.memsw.usage_in_bytes" - +#define ZONEINFO_PATH "/proc/zoneinfo" +#define MEMINFO_PATH "/proc/meminfo" #define LINE_MAX 128 #define INKERNEL_MINFREE_PATH "/sys/module/lowmemorykiller/parameters/minfree" @@ -156,6 +157,86 @@ static int lowmem_adj[MAX_TARGETS]; static int lowmem_minfree[MAX_TARGETS]; static int lowmem_targets_size; +/* Fields to parse in /proc/zoneinfo */ +enum zoneinfo_field { + ZI_NR_FREE_PAGES = 0, + ZI_NR_FILE_PAGES, + ZI_NR_SHMEM, + ZI_NR_UNEVICTABLE, + ZI_WORKINGSET_REFAULT, + ZI_HIGH, + ZI_FIELD_COUNT +}; + +static const char* const zoneinfo_field_names[ZI_FIELD_COUNT] = { + "nr_free_pages", + "nr_file_pages", + "nr_shmem", + "nr_unevictable", + "workingset_refault", + "high", +}; + +union zoneinfo { + struct { + int64_t nr_free_pages; + int64_t nr_file_pages; + int64_t nr_shmem; + int64_t nr_unevictable; + int64_t workingset_refault; + int64_t high; + /* fields below are calculated rather than read from the file */ + int64_t totalreserve_pages; + } field; + int64_t arr[ZI_FIELD_COUNT]; +}; + +/* Fields to parse in /proc/meminfo */ +enum meminfo_field { + MI_NR_FREE_PAGES = 0, + MI_CACHED, + MI_SWAP_CACHED, + MI_BUFFERS, + MI_SHMEM, + MI_UNEVICTABLE, + MI_FREE_SWAP, + MI_DIRTY, + MI_FIELD_COUNT +}; + +static const char* const meminfo_field_names[MI_FIELD_COUNT] = { + "MemFree:", + "Cached:", + "SwapCached:", + "Buffers:", + "Shmem:", + "Unevictable:", + "SwapFree:", + "Dirty:", +}; + +union meminfo { + struct { + int64_t nr_free_pages; + int64_t cached; + int64_t swap_cached; + int64_t buffers; + int64_t shmem; + int64_t unevictable; + int64_t free_swap; + int64_t dirty; + /* fields below are calculated rather than read from the file */ + int64_t nr_file_pages; + } field; + int64_t arr[MI_FIELD_COUNT]; +}; + +enum field_match_result { + NO_MATCH, + PARSE_FAIL, + PARSE_SUCCESS +}; + struct sysmeminfo { int nr_free_pages; int nr_file_pages; @@ -206,6 +287,22 @@ static bool parse_int64(const char* str, int64_t* ret) { return true; } +static enum field_match_result match_field(const char* cp, const char* ap, + const char* const field_names[], + int field_count, int64_t* field, + int *field_idx) { + int64_t val; + int i; + + for (i = 0; i < field_count; i++) { + if (!strcmp(cp, field_names[i])) { + *field_idx = i; + return parse_int64(ap, field) ? PARSE_SUCCESS : PARSE_FAIL; + } + } + return NO_MATCH; +} + /* * Read file content from the beginning up to max_len bytes or EOF * whichever happens first. @@ -683,6 +780,145 @@ static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) { } #endif +/* /prop/zoneinfo parsing routines */ +static int64_t zoneinfo_parse_protection(char *cp) { + int64_t max = 0; + long long zoneval; + char *save_ptr; + + for (cp = strtok_r(cp, "(), ", &save_ptr); cp; + cp = strtok_r(NULL, "), ", &save_ptr)) { + zoneval = strtoll(cp, &cp, 0); + if (zoneval > max) { + max = (zoneval > INT64_MAX) ? INT64_MAX : zoneval; + } + } + + return max; +} + +static bool zoneinfo_parse_line(char *line, union zoneinfo *zi) { + char *cp = line; + char *ap; + char *save_ptr; + int64_t val; + int field_idx; + + cp = strtok_r(line, " ", &save_ptr); + if (!cp) { + return true; + } + + if (!strcmp(cp, "protection:")) { + ap = strtok_r(NULL, ")", &save_ptr); + } else { + ap = strtok_r(NULL, " ", &save_ptr); + } + + if (!ap) { + return true; + } + + switch (match_field(cp, ap, zoneinfo_field_names, + ZI_FIELD_COUNT, &val, &field_idx)) { + case (PARSE_SUCCESS): + zi->arr[field_idx] += val; + break; + case (NO_MATCH): + if (!strcmp(cp, "protection:")) { + zi->field.totalreserve_pages += + zoneinfo_parse_protection(ap); + } + break; + case (PARSE_FAIL): + default: + return false; + } + return true; +} + +static int zoneinfo_parse(union zoneinfo *zi) { + static struct reread_data file_data = { + .filename = ZONEINFO_PATH, + .fd = -1, + }; + char buf[PAGE_SIZE]; + char *save_ptr; + char *line; + + memset(zi, 0, sizeof(union zoneinfo)); + + if (reread_file(&file_data, buf, sizeof(buf)) < 0) { + return -1; + } + + for (line = strtok_r(buf, "\n", &save_ptr); line; + line = strtok_r(NULL, "\n", &save_ptr)) { + if (!zoneinfo_parse_line(line, zi)) { + ALOGE("%s parse error", file_data.filename); + return -1; + } + } + zi->field.totalreserve_pages += zi->field.high; + + return 0; +} + +/* /prop/meminfo parsing routines */ +static bool meminfo_parse_line(char *line, union meminfo *mi) { + char *cp = line; + char *ap; + char *save_ptr; + int64_t val; + int field_idx; + enum field_match_result match_res; + + cp = strtok_r(line, " ", &save_ptr); + if (!cp) { + return false; + } + + ap = strtok_r(NULL, " ", &save_ptr); + if (!ap) { + return false; + } + + match_res = match_field(cp, ap, meminfo_field_names, MI_FIELD_COUNT, + &val, &field_idx); + if (match_res == PARSE_SUCCESS) { + mi->arr[field_idx] = val / page_k; + } + return (match_res != PARSE_FAIL); +} + +static int meminfo_parse(union meminfo *mi) { + static struct reread_data file_data = { + .filename = MEMINFO_PATH, + .fd = -1, + }; + char buf[PAGE_SIZE]; + char *save_ptr; + char *line; + + memset(mi, 0, sizeof(union meminfo)); + + if (reread_file(&file_data, buf, sizeof(buf)) < 0) { + return -1; + } + + for (line = strtok_r(buf, "\n", &save_ptr); line; + line = strtok_r(NULL, "\n", &save_ptr)) { + if (!meminfo_parse_line(line, mi)) { + ALOGE("%s parse error", file_data.filename); + return -1; + } + } + mi->field.nr_file_pages = mi->field.cached + mi->field.swap_cached + + mi->field.buffers; + + return 0; +} + static int get_free_memory(struct mem_size *ms) { struct sysinfo si; From 9ac54eb2f88a4a8fc84d1da307be93f99573ead4 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 13 Apr 2018 13:41:12 -0700 Subject: [PATCH 011/221] lmkd: Switch to using /proc/meminfo to have access to file cache size Current mechanism of getting system memory state by using sysinfo() is not enough because it does not provide information about file cache size which is needed to correctly assess memory state. Switch to using data from /proc/meminfo that includes information provided by sysinfo() and file cache size in addition to that. Bug: 77299493 Bug: 75322373 Change-Id: I16106fc4f9254f17f776803e60502b7b6474e1b7 Signed-off-by: Suren Baghdasaryan --- lmkd/lmkd.c | 79 ++++++++++++++++++++--------------------------------- 1 file changed, 30 insertions(+), 49 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index ca3e2c828..2003dcc7e 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -102,14 +102,9 @@ static const char *level_name[] = { "critical" }; -struct mem_size { - int free_mem; - int free_swap; -}; - struct { - int min_free; /* recorded but not used yet */ - int max_free; + int64_t min_nr_free_pages; /* recorded but not used yet */ + int64_t max_nr_free_pages; } low_pressure_mem = { -1, -1 }; static int level_oomadj[VMPRESS_LEVEL_COUNT]; @@ -237,13 +232,6 @@ enum field_match_result { PARSE_SUCCESS }; -struct sysmeminfo { - int nr_free_pages; - int nr_file_pages; - int nr_shmem; - int totalreserve_pages; -}; - struct adjslot_list { struct adjslot_list *next; struct adjslot_list *prev; @@ -919,18 +907,6 @@ static int meminfo_parse(union meminfo *mi) { return 0; } -static int get_free_memory(struct mem_size *ms) { - struct sysinfo si; - - if (sysinfo(&si) < 0) - return -1; - - ms->free_mem = (int)(si.freeram * si.mem_unit / PAGE_SIZE); - ms->free_swap = (int)(si.freeswap * si.mem_unit / PAGE_SIZE); - - return 0; -} - static int proc_get_size(int pid) { char path[PATH_MAX]; char line[LINE_MAX]; @@ -1141,29 +1117,30 @@ static int64_t get_memory_usage(struct reread_data *file_data) { return mem_usage; } -void record_low_pressure_levels(struct mem_size *free_mem) { - if (low_pressure_mem.min_free == -1 || - low_pressure_mem.min_free > free_mem->free_mem) { +void record_low_pressure_levels(union meminfo *mi) { + if (low_pressure_mem.min_nr_free_pages == -1 || + low_pressure_mem.min_nr_free_pages > mi->field.nr_free_pages) { if (debug_process_killing) { - ALOGI("Low pressure min memory update from %d to %d", - low_pressure_mem.min_free, free_mem->free_mem); + ALOGI("Low pressure min memory update from %" PRId64 " to %" PRId64, + low_pressure_mem.min_nr_free_pages, mi->field.nr_free_pages); } - low_pressure_mem.min_free = free_mem->free_mem; + low_pressure_mem.min_nr_free_pages = mi->field.nr_free_pages; } /* * Free memory at low vmpressure events occasionally gets spikes, * possibly a stale low vmpressure event with memory already * freed up (no memory pressure should have been reported). - * Ignore large jumps in max_free that would mess up our stats. + * Ignore large jumps in max_nr_free_pages that would mess up our stats. */ - if (low_pressure_mem.max_free == -1 || - (low_pressure_mem.max_free < free_mem->free_mem && - free_mem->free_mem - low_pressure_mem.max_free < low_pressure_mem.max_free * 0.1)) { + if (low_pressure_mem.max_nr_free_pages == -1 || + (low_pressure_mem.max_nr_free_pages < mi->field.nr_free_pages && + mi->field.nr_free_pages - low_pressure_mem.max_nr_free_pages < + low_pressure_mem.max_nr_free_pages * 0.1)) { if (debug_process_killing) { - ALOGI("Low pressure max memory update from %d to %d", - low_pressure_mem.max_free, free_mem->free_mem); + ALOGI("Low pressure max memory update from %" PRId64 " to %" PRId64, + low_pressure_mem.max_nr_free_pages, mi->field.nr_free_pages); } - low_pressure_mem.max_free = free_mem->free_mem; + low_pressure_mem.max_nr_free_pages = mi->field.nr_free_pages; } } @@ -1189,7 +1166,7 @@ static void mp_event_common(int data, uint32_t events __unused) { int64_t mem_usage, memsw_usage; int64_t mem_pressure; enum vmpressure_level lvl; - struct mem_size free_mem; + union meminfo mi; static struct timeval last_report_tm; static unsigned long skip_count = 0; enum vmpressure_level level = (enum vmpressure_level)data; @@ -1233,15 +1210,15 @@ static void mp_event_common(int data, uint32_t events __unused) { skip_count = 0; } - if (get_free_memory(&free_mem) == 0) { - if (level == VMPRESS_LEVEL_LOW) { - record_low_pressure_levels(&free_mem); - } - } else { + if (meminfo_parse(&mi) < 0) { ALOGE("Failed to get free memory!"); return; } + if (level == VMPRESS_LEVEL_LOW) { + record_low_pressure_levels(&mi); + } + if (level_oomadj[level] > OOM_SCORE_ADJ_MAX) { /* Do not monitor this pressure level */ return; @@ -1293,16 +1270,20 @@ do_kill: } } else { /* If pressure level is less than critical and enough free swap then ignore */ - if (level < VMPRESS_LEVEL_CRITICAL && free_mem.free_swap > low_pressure_mem.max_free) { + if (level < VMPRESS_LEVEL_CRITICAL && + mi.field.free_swap > low_pressure_mem.max_nr_free_pages) { if (debug_process_killing) { - ALOGI("Ignoring pressure since %d swap pages are available ", free_mem.free_swap); + ALOGI("Ignoring pressure since %" PRId64 + " swap pages are available ", + mi.field.free_swap); } return; } /* Free up enough memory to downgrate the memory pressure to low level */ - if (free_mem.free_mem < low_pressure_mem.max_free) { - int pages_to_free = low_pressure_mem.max_free - free_mem.free_mem; + if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) { + int pages_to_free = low_pressure_mem.max_nr_free_pages - + mi.field.nr_free_pages; if (debug_process_killing) { ALOGI("Trying to free %d pages", pages_to_free); } From d273b6630d47d6bb32996bcc87e01a73240cb228 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 13 Apr 2018 13:53:43 -0700 Subject: [PATCH 012/221] lmkd: Introduce support for legacy kill algorithm that uses minfree levels Add ability to switch to the algorithm used by lowmemorykiller driver for determining when to kill. It uses minfree levels to decide at which levels of free memory and file cache to kill a process. oom_adj_score is also determined by comparing current memory resources against minfree levels. ro.lmk.use_minfree_levels property is introduces for switching into this mode. By default it is disabled. Bug: 77299493 Bug: 75322373 Change-Id: I6b51972951026854a079fcda33d6786b7ed035e4 Signed-off-by: Suren Baghdasaryan --- lmkd/README.md | 5 +++ lmkd/lmkd.c | 107 +++++++++++++++++++++++++++++++++++++------------ 2 files changed, 86 insertions(+), 26 deletions(-) diff --git a/lmkd/README.md b/lmkd/README.md index ba2e83d06..656a6ea0a 100644 --- a/lmkd/README.md +++ b/lmkd/README.md @@ -29,6 +29,11 @@ properties: ro.config.low_ram: choose between low-memory vs high-performance device. Default = false. + ro.lmk.use_minfree_levels: use free memory and file cache thresholds for + making decisions when to kill. This mode works + the same way kernel lowmemorykiller driver used + to work. Default = false + ro.lmk.low: min oom_adj score for processes eligible to be killed at low vmpressure level. Default = 1001 (disabled) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 2003dcc7e..d45636058 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -116,6 +116,7 @@ static int64_t downgrade_pressure; static bool low_ram_device; static bool kill_heaviest_task; static unsigned long kill_timeout_ms; +static bool use_minfree_levels; /* data required to handle events */ struct event_handler_info { @@ -1049,11 +1050,10 @@ static int kill_one_process(struct proc* procp, int min_score_adj, * Returns the size of the killed processes. */ static int find_and_kill_processes(enum vmpressure_level level, - int pages_to_free) { + int min_score_adj, int pages_to_free) { int i; int killed_size; int pages_freed = 0; - int min_score_adj = level_oomadj[level]; #ifdef LMKD_LOG_STATS if (enable_stats_log) { @@ -1167,9 +1167,14 @@ static void mp_event_common(int data, uint32_t events __unused) { int64_t mem_pressure; enum vmpressure_level lvl; union meminfo mi; + union zoneinfo zi; static struct timeval last_report_tm; static unsigned long skip_count = 0; enum vmpressure_level level = (enum vmpressure_level)data; + long other_free = 0, other_file = 0; + int min_score_adj; + int pages_to_free = 0; + int minfree = 0; static struct reread_data mem_usage_file_data = { .filename = MEMCG_MEMORY_USAGE, .fd = -1, @@ -1210,11 +1215,40 @@ static void mp_event_common(int data, uint32_t events __unused) { skip_count = 0; } - if (meminfo_parse(&mi) < 0) { + if (meminfo_parse(&mi) < 0 || zoneinfo_parse(&zi) < 0) { ALOGE("Failed to get free memory!"); return; } + if (use_minfree_levels) { + int i; + + other_free = mi.field.nr_free_pages - zi.field.totalreserve_pages; + if (mi.field.nr_file_pages > (mi.field.shmem + mi.field.unevictable + mi.field.swap_cached)) { + other_file = (mi.field.nr_file_pages - mi.field.shmem - + mi.field.unevictable - mi.field.swap_cached); + } else { + other_file = 0; + } + + min_score_adj = OOM_SCORE_ADJ_MAX + 1; + for (i = 0; i < lowmem_targets_size; i++) { + minfree = lowmem_minfree[i]; + if (other_free < minfree && other_file < minfree) { + min_score_adj = lowmem_adj[i]; + break; + } + } + + if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) + return; + + /* Free up enough pages to push over the highest minfree level */ + pages_to_free = lowmem_minfree[lowmem_targets_size - 1] - + ((other_free < other_file) ? other_free : other_file); + goto do_kill; + } + if (level == VMPRESS_LEVEL_LOW) { record_low_pressure_levels(&mi); } @@ -1263,39 +1297,58 @@ static void mp_event_common(int data, uint32_t events __unused) { do_kill: if (low_ram_device) { /* For Go devices kill only one task */ - if (find_and_kill_processes(level, 0) == 0) { + if (find_and_kill_processes(level, level_oomadj[level], 0) == 0) { if (debug_process_killing) { ALOGI("Nothing to kill"); } } } else { - /* If pressure level is less than critical and enough free swap then ignore */ - if (level < VMPRESS_LEVEL_CRITICAL && - mi.field.free_swap > low_pressure_mem.max_nr_free_pages) { - if (debug_process_killing) { - ALOGI("Ignoring pressure since %" PRId64 - " swap pages are available ", - mi.field.free_swap); + int pages_freed; + + if (!use_minfree_levels) { + /* If pressure level is less than critical and enough free swap then ignore */ + if (level < VMPRESS_LEVEL_CRITICAL && + mi.field.free_swap > low_pressure_mem.max_nr_free_pages) { + if (debug_process_killing) { + ALOGI("Ignoring pressure since %" PRId64 + " swap pages are available ", + mi.field.free_swap); + } + return; + } + /* Free up enough memory to downgrate the memory pressure to low level */ + if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) { + pages_to_free = low_pressure_mem.max_nr_free_pages - + mi.field.nr_free_pages; + } else { + if (debug_process_killing) { + ALOGI("Ignoring pressure since more memory is " + "available (%" PRId64 ") than watermark (%" PRId64 ")", + mi.field.nr_free_pages, low_pressure_mem.max_nr_free_pages); + } + return; + } + min_score_adj = level_oomadj[level]; + } else { + if (debug_process_killing) { + ALOGI("Killing because cache %ldkB is below " + "limit %ldkB for oom_adj %d\n" + " Free memory is %ldkB %s reserved", + other_file * page_k, minfree * page_k, min_score_adj, + other_free * page_k, other_free >= 0 ? "above" : "below"); } - return; } - /* Free up enough memory to downgrate the memory pressure to low level */ - if (mi.field.nr_free_pages < low_pressure_mem.max_nr_free_pages) { - int pages_to_free = low_pressure_mem.max_nr_free_pages - - mi.field.nr_free_pages; + if (debug_process_killing) { + ALOGI("Trying to free %d pages", pages_to_free); + } + pages_freed = find_and_kill_processes(level, min_score_adj, pages_to_free); + if (pages_freed < pages_to_free) { if (debug_process_killing) { - ALOGI("Trying to free %d pages", pages_to_free); - } - int pages_freed = find_and_kill_processes(level, pages_to_free); - if (pages_freed < pages_to_free) { - if (debug_process_killing) { - ALOGI("Unable to free enough memory (pages freed=%d)", - pages_freed); - } - } else { - gettimeofday(&last_report_tm, NULL); + ALOGI("Unable to free enough memory (pages freed=%d)", pages_freed); } + } else { + gettimeofday(&last_report_tm, NULL); } } } @@ -1505,6 +1558,8 @@ int main(int argc __unused, char **argv __unused) { low_ram_device = property_get_bool("ro.config.low_ram", false); kill_timeout_ms = (unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0); + use_minfree_levels = + property_get_bool("ro.lmk.use_minfree_levels", false); #ifdef LMKD_LOG_STATS statslog_init(&log_ctx, &enable_stats_log); From 3a83098f787dee584eb06c3df965970bc8db86f3 Mon Sep 17 00:00:00 2001 From: Florian Mayer Date: Mon, 16 Apr 2018 13:52:17 +0000 Subject: [PATCH 013/221] Revert "Merge commit '6499e5ec'" This reverts commit dc78851c5f5a19142397423e4d99b9007432d7f8. Reason for revert: Mistakenly merged into wrong branch. Change-Id: I99c0d62197f006abaa1a80cee29b3f0f0cdb1433 From a18fa73bba0669737774962415826d654cb4e548 Mon Sep 17 00:00:00 2001 From: Ralph Nathan Date: Tue, 24 Apr 2018 08:43:59 -0700 Subject: [PATCH 014/221] Update public.libraries.iot.txt to be up to date. Adds amidi to the iot public.libraries.txt so it's up to date with the other files. Bug: 78226207 Test: none Change-Id: I28d1135f5da1c9ec907dd27d5ad8df5ee5d99b8b --- rootdir/etc/public.libraries.iot.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/rootdir/etc/public.libraries.iot.txt b/rootdir/etc/public.libraries.iot.txt index ff0813de3..669077049 100644 --- a/rootdir/etc/public.libraries.iot.txt +++ b/rootdir/etc/public.libraries.iot.txt @@ -2,6 +2,7 @@ libandroid.so libandroidthings.so libaaudio.so +libamidi.so libc.so libcamera2ndk.so libdl.so From 2db565d75f81031ea0dfe5693ab0fe02714c2b88 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 27 Apr 2018 15:03:32 -0700 Subject: [PATCH 015/221] healthd use vintf_fragments This encourages device manufacturers to use service.override over service and to remove healthd on device, because it is one less step to do. Test: make VINTF metadata Bug: 66917623 Bug: 77541952 Change-Id: I1cac3570f64a0308b1f2d465205f98a97e4b4320 --- healthd/Android.bp | 12 +++--------- healthd/manifest_healthd.xml | 11 +++++++++++ 2 files changed, 14 insertions(+), 9 deletions(-) create mode 100644 healthd/manifest_healthd.xml diff --git a/healthd/Android.bp b/healthd/Android.bp index cefe09d5e..49d53503b 100644 --- a/healthd/Android.bp +++ b/healthd/Android.bp @@ -59,15 +59,6 @@ cc_binary { defaults: ["android.hardware.health@2.0-service_defaults"], } -cc_binary { - name: "android.hardware.health@2.0-service.override", - defaults: ["android.hardware.health@2.0-service_defaults"], - - overrides: [ - "healthd", - ], -} - cc_binary { name: "healthd", init_rc: ["healthd.rc"], @@ -101,4 +92,7 @@ cc_binary { "android.hardware.health@2.0", ], + vintf_fragments: [ + "manifest_healthd.xml" + ], } diff --git a/healthd/manifest_healthd.xml b/healthd/manifest_healthd.xml new file mode 100644 index 000000000..097a7d87a --- /dev/null +++ b/healthd/manifest_healthd.xml @@ -0,0 +1,11 @@ + + + android.hardware.health + hwbinder + 2.0 + + IHealth + backup + + + From 28d2fb80b2a370d16aeb872f16d9947d699cc7b2 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 1 May 2018 14:59:43 -0700 Subject: [PATCH 016/221] healthd: overridden by health@2.0-service Test: boots Bug: 79107699 Bug: 77541952 Change-Id: Ida4cf80d3553365b673e30cdd19590c156cb52e0 --- healthd/Android.bp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/healthd/Android.bp b/healthd/Android.bp index 49d53503b..8bd51e730 100644 --- a/healthd/Android.bp +++ b/healthd/Android.bp @@ -57,6 +57,10 @@ cc_defaults { cc_binary { name: "android.hardware.health@2.0-service", defaults: ["android.hardware.health@2.0-service_defaults"], + + overrides: [ + "healthd", + ] } cc_binary { From 530ac5bad143b5281b1c90f2f86380407406e614 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 4 May 2018 13:53:41 -0700 Subject: [PATCH 017/221] healthd: add missing libbatteryservice_headers dep It used to use global header include dirs, which is bad. Test: builds Bug: 68724651 Change-Id: Ib5354c66633499ad57fe5997e2c35283ba5e408f --- healthd/Android.mk | 2 ++ 1 file changed, 2 insertions(+) diff --git a/healthd/Android.mk b/healthd/Android.mk index 86f7cf0d1..f7214c6cd 100644 --- a/healthd/Android.mk +++ b/healthd/Android.mk @@ -24,6 +24,8 @@ else LOCAL_CFLAGS += -DHEALTHD_DRAW_SPLIT_OFFSET=0 endif +LOCAL_HEADER_LIBRARIES := libbatteryservice_headers + include $(BUILD_STATIC_LIBRARY) include $(CLEAR_VARS) From 0b31908912d7a1802ce7e3d0f0857fe6b34d926b Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 4 May 2018 14:20:34 -0700 Subject: [PATCH 018/221] storaged: fix headers. Add missing libbatteryservice_headers dependency. It used to use global header include dirs, which is bad. Add old transitive dependency from libbatteryservice_headers as well. Test: builds Bug: 68724651 Change-Id: Idcc4452160dce70b4f8b48e2d809dcd5744b93b4 --- storaged/Android.bp | 1 + storaged/include/storaged.h | 1 - storaged/include/uid_info.h | 2 ++ storaged/storaged.cpp | 1 + 4 files changed, 4 insertions(+), 1 deletion(-) diff --git a/storaged/Android.bp b/storaged/Android.bp index b478f4a8f..7466728d9 100644 --- a/storaged/Android.bp +++ b/storaged/Android.bp @@ -66,6 +66,7 @@ cc_library_static { ], static_libs: ["libhealthhalutils"], + header_libs: ["libbatteryservice_headers"], logtags: ["EventLogTags.logtags"], diff --git a/storaged/include/storaged.h b/storaged/include/storaged.h index 400e734ca..6f9204879 100644 --- a/storaged/include/storaged.h +++ b/storaged/include/storaged.h @@ -26,7 +26,6 @@ #include #include -#include #include #include diff --git a/storaged/include/uid_info.h b/storaged/include/uid_info.h index 4398a0d57..c5533acb1 100644 --- a/storaged/include/uid_info.h +++ b/storaged/include/uid_info.h @@ -19,6 +19,8 @@ #include #include +#include + namespace android { namespace os { namespace storaged { diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index bf8b448ab..f346c387b 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -30,6 +30,7 @@ #include #include +#include #include #include #include From 16830241dfc6d47fee141511299679a0daef852d Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 18 May 2018 14:42:00 -0700 Subject: [PATCH 019/221] lmkd: Do not set soft_limit_in_bytes on high-end devices Setting memory.soft_limit_in_bytes on high-end devices with large memory reserves affects performance of memory-hungry applications that have large workingsets and keep thrashing because of the memory limits imposed. Limit the usage of memory.soft_limit_in_bytes to low-memory devices only. Add debug messages for future troubleshooting to capture cases when vmpressure events are being ignored. Bug: 78916015 Test: collect vmstat while running a heavy app Change-Id: Ib4434b96d2be802ef89960b573486eae8d12f198 Signed-off-by: Suren Baghdasaryan --- lmkd/lmkd.c | 90 +++++++++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 40 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 6170ce00c..b20f4ef5e 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -484,47 +484,50 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet) { return; } - if (params.oomadj >= 900) { - soft_limit_mult = 0; - } else if (params.oomadj >= 800) { - soft_limit_mult = 0; - } else if (params.oomadj >= 700) { - soft_limit_mult = 0; - } else if (params.oomadj >= 600) { - // Launcher should be perceptible, don't kill it. - params.oomadj = 200; - soft_limit_mult = 1; - } else if (params.oomadj >= 500) { - soft_limit_mult = 0; - } else if (params.oomadj >= 400) { - soft_limit_mult = 0; - } else if (params.oomadj >= 300) { - soft_limit_mult = 1; - } else if (params.oomadj >= 200) { - soft_limit_mult = 2; - } else if (params.oomadj >= 100) { - soft_limit_mult = 10; - } else if (params.oomadj >= 0) { - soft_limit_mult = 20; - } else { - // Persistent processes will have a large - // soft limit 512MB. - soft_limit_mult = 64; + if (low_ram_device) { + if (params.oomadj >= 900) { + soft_limit_mult = 0; + } else if (params.oomadj >= 800) { + soft_limit_mult = 0; + } else if (params.oomadj >= 700) { + soft_limit_mult = 0; + } else if (params.oomadj >= 600) { + // Launcher should be perceptible, don't kill it. + params.oomadj = 200; + soft_limit_mult = 1; + } else if (params.oomadj >= 500) { + soft_limit_mult = 0; + } else if (params.oomadj >= 400) { + soft_limit_mult = 0; + } else if (params.oomadj >= 300) { + soft_limit_mult = 1; + } else if (params.oomadj >= 200) { + soft_limit_mult = 2; + } else if (params.oomadj >= 100) { + soft_limit_mult = 10; + } else if (params.oomadj >= 0) { + soft_limit_mult = 20; + } else { + // Persistent processes will have a large + // soft limit 512MB. + soft_limit_mult = 64; + } + + snprintf(path, sizeof(path), MEMCG_SYSFS_PATH + "apps/uid_%d/pid_%d/memory.soft_limit_in_bytes", + params.uid, params.pid); + snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA); + + /* + * system_server process has no memcg under /dev/memcg/apps but should be + * registered with lmkd. This is the best way so far to identify it. + */ + is_system_server = (params.oomadj == SYSTEM_ADJ && + (pwdrec = getpwnam("system")) != NULL && + params.uid == pwdrec->pw_uid); + writefilestring(path, val, !is_system_server); } - snprintf(path, sizeof(path), MEMCG_SYSFS_PATH "apps/uid_%d/pid_%d/memory.soft_limit_in_bytes", - params.uid, params.pid); - snprintf(val, sizeof(val), "%d", soft_limit_mult * EIGHT_MEGA); - - /* - * system_server process has no memcg under /dev/memcg/apps but should be - * registered with lmkd. This is the best way so far to identify it. - */ - is_system_server = (params.oomadj == SYSTEM_ADJ && - (pwdrec = getpwnam("system")) != NULL && - params.uid == pwdrec->pw_uid); - writefilestring(path, val, !is_system_server); - procp = pid_lookup(params.pid); if (!procp) { procp = malloc(sizeof(struct proc)); @@ -1250,8 +1253,15 @@ static void mp_event_common(int data, uint32_t events __unused) { } } - if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) + if (min_score_adj == OOM_SCORE_ADJ_MAX + 1) { + if (debug_process_killing) { + ALOGI("Ignore %s memory pressure event " + "(free memory=%ldkB, cache=%ldkB, limit=%ldkB)", + level_name[level], other_free * page_k, other_file * page_k, + (long)lowmem_minfree[lowmem_targets_size - 1] * page_k); + } return; + } /* Free up enough pages to push over the highest minfree level */ pages_to_free = lowmem_minfree[lowmem_targets_size - 1] - From 4426d410734279ded7a6bcf70d6b8968be29cc42 Mon Sep 17 00:00:00 2001 From: Andrew Chant Date: Fri, 11 May 2018 10:10:29 -0700 Subject: [PATCH 020/221] Add Hardware Reliabilty metrics to C header Expose Hardware Reliabilty TRON metrics constants for logging via C++ interfaces. Bug: 69978775 Test: Logged events from Pixelstats HAL Change-Id: I9a1c4467d31f64ae3c43e35b0a4cf5a92157c39f (cherry picked from commit 358471f74943c2f1585f523c73f3b73c63fd9f25) --- .../include/metricslogger/metrics_logger.h | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/libmetricslogger/include/metricslogger/metrics_logger.h b/libmetricslogger/include/metricslogger/metrics_logger.h index 860d71d39..c305db2da 100644 --- a/libmetricslogger/include/metricslogger/metrics_logger.h +++ b/libmetricslogger/include/metricslogger/metrics_logger.h @@ -77,10 +77,44 @@ enum { ACTION_BOOT = 1098, FIELD_PLATFORM_REASON = 1099, + FIELD_DURATION_MILLIS = 1304, + + FIELD_END_BATTERY_PERCENT = 1308, + ACTION_HIDDEN_API_ACCESSED = 1391, FIELD_HIDDEN_API_ACCESS_METHOD = 1392, FIELD_HIDDEN_API_ACCESS_DENIED = 1393, FIELD_HIDDEN_API_SIGNATURE = 1394, + + ACTION_USB_CONNECTOR_CONNECTED = 1422, + ACTION_USB_CONNECTOR_DISCONNECTED = 1423, + ACTION_USB_AUDIO_CONNECTED = 1424, + FIELD_USB_AUDIO_VIDPID = 1425, + ACTION_USB_AUDIO_DISCONNECTED = 1426, + ACTION_HARDWARE_FAILED = 1427, + FIELD_HARDWARE_TYPE = 1428, + FIELD_HARDWARE_FAILURE_CODE = 1429, + ACTION_PHYSICAL_DROP = 1430, + FIELD_CONFIDENCE_PERCENT = 1431, + FIELD_ACCEL_MILLI_G = 1432, + ACTION_BATTERY_HEALTH = 1433, + FIELD_BATTERY_HEALTH_SNAPSHOT_TYPE = 1434, + FIELD_BATTERY_TEMPERATURE_DECI_C = 1435, + FIELD_BATTERY_VOLTAGE_UV = 1436, + FIELD_BATTERY_OPEN_CIRCUIT_VOLTAGE_UV = 1437, + ACTION_BATTERY_CHARGE_CYCLES = 1438, + FIELD_BATTERY_CHARGE_CYCLES = 1439, + + ACTION_SLOW_IO = 1442, + FIELD_IO_OPERATION_TYPE = 1443, + FIELD_IO_OPERATION_COUNT = 1444, + ACTION_SPEAKER_IMPEDANCE = 1445, + FIELD_SPEAKER_IMPEDANCE_MILLIOHMS = 1446, + FIELD_SPEAKER_LOCATION = 1447, + FIELD_BATTERY_RESISTANCE_UOHMS = 1448, + FIELD_BATTERY_CURRENT_UA = 1449, + FIELD_HARDWARE_LOCATION = 1450, + ACTION_BATTERY_CAUSED_SHUTDOWN = 1441, }; enum { @@ -94,5 +128,30 @@ enum { ACCESS_METHOD_LINKING = 3, }; +enum HardwareType { + HARDWARE_UNKNOWN = 0, + HARDWARE_MICROPHONE = 1, + HARDWARE_CODEC = 2, + HARDWARE_SPEAKER = 3, + HARDWARE_FINGERPRINT = 4, +}; + +enum HardwareFailureCode { + HARDWARE_FAILURE_UNKNOWN = 0, + HARDWARE_FAILURE_COMPLETE = 1, + HARDWARE_FAILURE_SPEAKER_HIGH_Z = 2, + HARDWARE_FAILURE_SPEAKER_SHORT = 3, + HARDWARE_FAILURE_FINGERPRINT_SENSOR_BROKEN = 4, + HARDWARE_FAILURE_FINGERPRINT_TOO_MANY_DEAD_PIXELS = 5, +}; + +enum IoOperation { + IOOP_UNKNOWN = 0, + IOOP_READ = 1, + IOOP_WRITE = 2, + IOOP_UNMAP = 3, + IOOP_SYNC = 4, +}; + } // namespace metricslogger } // namespace android From 8211515fbe81c49d1e53a903ef890718ff01cadc Mon Sep 17 00:00:00 2001 From: Todd Poynor Date: Fri, 1 Jun 2018 11:09:58 -0700 Subject: [PATCH 021/221] charger: minui error handling fixups Log an error if minui init fails, and avoid subsequent calls to minui in this case (which are likely to crash). Warn if no system text font available. This is now expected on most devices, and the fallback text is not expected to be needed, but just in case. Avoid the attempt to print text if no system font available, log warnings instead. Bug: 80249440 Test: manual: charger mode with no system font Change-Id: Ib0c761d37e41a893b2a192438eebcf48c4827049 --- healthd/healthd_draw.cpp | 202 ++++++++++++++++++++++----------------- healthd/healthd_draw.h | 6 ++ 2 files changed, 118 insertions(+), 90 deletions(-) diff --git a/healthd/healthd_draw.cpp b/healthd/healthd_draw.cpp index ea3d991c0..30f2cf3be 100644 --- a/healthd/healthd_draw.cpp +++ b/healthd/healthd_draw.cpp @@ -21,77 +21,96 @@ #include "healthd_draw.h" #define LOGE(x...) KLOG_ERROR("charger", x); +#define LOGW(x...) KLOG_WARNING("charger", x); #define LOGV(x...) KLOG_DEBUG("charger", x); HealthdDraw::HealthdDraw(animation* anim) : kSplitScreen(HEALTHD_DRAW_SPLIT_SCREEN), kSplitOffset(HEALTHD_DRAW_SPLIT_OFFSET) { - gr_init(); - gr_font_size(gr_sys_font(), &char_width_, &char_height_); + int ret = gr_init(); - screen_width_ = gr_fb_width() / (kSplitScreen ? 2 : 1); - screen_height_ = gr_fb_height(); + if (ret < 0) { + LOGE("gr_init failed\n"); + graphics_available = false; + return; + } - int res; - if (!anim->text_clock.font_file.empty() && - (res = gr_init_font(anim->text_clock.font_file.c_str(), - &anim->text_clock.font)) < 0) { - LOGE("Could not load time font (%d)\n", res); - } - if (!anim->text_percent.font_file.empty() && - (res = gr_init_font(anim->text_percent.font_file.c_str(), - &anim->text_percent.font)) < 0) { - LOGE("Could not load percent font (%d)\n", res); - } + graphics_available = true; + sys_font = gr_sys_font(); + if (sys_font == nullptr) { + LOGW("No system font, screen fallback text not available\n"); + } else { + gr_font_size(sys_font, &char_width_, &char_height_); + } + + screen_width_ = gr_fb_width() / (kSplitScreen ? 2 : 1); + screen_height_ = gr_fb_height(); + + int res; + if (!anim->text_clock.font_file.empty() && + (res = gr_init_font(anim->text_clock.font_file.c_str(), &anim->text_clock.font)) < 0) { + LOGE("Could not load time font (%d)\n", res); + } + if (!anim->text_percent.font_file.empty() && + (res = gr_init_font(anim->text_percent.font_file.c_str(), &anim->text_percent.font)) < 0) { + LOGE("Could not load percent font (%d)\n", res); + } } HealthdDraw::~HealthdDraw() {} void HealthdDraw::redraw_screen(const animation* batt_anim, GRSurface* surf_unknown) { - clear_screen(); + if (!graphics_available) return; + clear_screen(); - /* try to display *something* */ - if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0) - draw_unknown(surf_unknown); - else - draw_battery(batt_anim); - gr_flip(); + /* try to display *something* */ + if (batt_anim->cur_level < 0 || batt_anim->num_frames == 0) + draw_unknown(surf_unknown); + else + draw_battery(batt_anim); + gr_flip(); } -void HealthdDraw::blank_screen(bool blank) { gr_fb_blank(blank); } +void HealthdDraw::blank_screen(bool blank) { + if (!graphics_available) return; + gr_fb_blank(blank); +} void HealthdDraw::clear_screen(void) { - gr_color(0, 0, 0, 255); - gr_clear(); + if (!graphics_available) return; + gr_color(0, 0, 0, 255); + gr_clear(); } int HealthdDraw::draw_surface_centered(GRSurface* surface) { - int w = gr_get_width(surface); - int h = gr_get_height(surface); - int x = (screen_width_ - w) / 2 + kSplitOffset; - int y = (screen_height_ - h) / 2; + if (!graphics_available) return 0; + + int w = gr_get_width(surface); + int h = gr_get_height(surface); + int x = (screen_width_ - w) / 2 + kSplitOffset; + int y = (screen_height_ - h) / 2; - LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y); - gr_blit(surface, 0, 0, w, h, x, y); - if (kSplitScreen) { - x += screen_width_ - 2 * kSplitOffset; LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y); gr_blit(surface, 0, 0, w, h, x, y); - } + if (kSplitScreen) { + x += screen_width_ - 2 * kSplitOffset; + LOGV("drawing surface %dx%d+%d+%d\n", w, h, x, y); + gr_blit(surface, 0, 0, w, h, x, y); + } - return y + h; + return y + h; } int HealthdDraw::draw_text(const GRFont* font, int x, int y, const char* str) { - int str_len_px = gr_measure(font, str); + if (!graphics_available) return 0; + int str_len_px = gr_measure(font, str); - if (x < 0) x = (screen_width_ - str_len_px) / 2; - if (y < 0) y = (screen_height_ - char_height_) / 2; - gr_text(font, x + kSplitOffset, y, str, false /* bold */); - if (kSplitScreen) - gr_text(font, x - kSplitOffset + screen_width_, y, str, false /* bold */); + if (x < 0) x = (screen_width_ - str_len_px) / 2; + if (y < 0) y = (screen_height_ - char_height_) / 2; + gr_text(font, x + kSplitOffset, y, str, false /* bold */); + if (kSplitScreen) gr_text(font, x - kSplitOffset + screen_width_, y, str, false /* bold */); - return y + char_height_; + return y + char_height_; } void HealthdDraw::determine_xy(const animation::text_field& field, @@ -119,77 +138,80 @@ void HealthdDraw::determine_xy(const animation::text_field& field, } void HealthdDraw::draw_clock(const animation* anim) { - static constexpr char CLOCK_FORMAT[] = "%H:%M"; - static constexpr int CLOCK_LENGTH = 6; + static constexpr char CLOCK_FORMAT[] = "%H:%M"; + static constexpr int CLOCK_LENGTH = 6; - const animation::text_field& field = anim->text_clock; + const animation::text_field& field = anim->text_clock; - if (field.font == nullptr || field.font->char_width == 0 || - field.font->char_height == 0) - return; + if (!graphics_available || field.font == nullptr || field.font->char_width == 0 || + field.font->char_height == 0) + return; - time_t rawtime; - time(&rawtime); - tm* time_info = localtime(&rawtime); + time_t rawtime; + time(&rawtime); + tm* time_info = localtime(&rawtime); - char clock_str[CLOCK_LENGTH]; - size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info); - if (length != CLOCK_LENGTH - 1) { - LOGE("Could not format time\n"); - return; - } + char clock_str[CLOCK_LENGTH]; + size_t length = strftime(clock_str, CLOCK_LENGTH, CLOCK_FORMAT, time_info); + if (length != CLOCK_LENGTH - 1) { + LOGE("Could not format time\n"); + return; + } - int x, y; - determine_xy(field, length, &x, &y); + int x, y; + determine_xy(field, length, &x, &y); - LOGV("drawing clock %s %d %d\n", clock_str, x, y); - gr_color(field.color_r, field.color_g, field.color_b, field.color_a); - draw_text(field.font, x, y, clock_str); + LOGV("drawing clock %s %d %d\n", clock_str, x, y); + gr_color(field.color_r, field.color_g, field.color_b, field.color_a); + draw_text(field.font, x, y, clock_str); } void HealthdDraw::draw_percent(const animation* anim) { - int cur_level = anim->cur_level; - if (anim->cur_status == BATTERY_STATUS_FULL) { - cur_level = 100; - } + if (!graphics_available) return; + int cur_level = anim->cur_level; + if (anim->cur_status == BATTERY_STATUS_FULL) { + cur_level = 100; + } - if (cur_level <= 0) return; + if (cur_level <= 0) return; - const animation::text_field& field = anim->text_percent; - if (field.font == nullptr || field.font->char_width == 0 || - field.font->char_height == 0) { - return; - } + const animation::text_field& field = anim->text_percent; + if (field.font == nullptr || field.font->char_width == 0 || field.font->char_height == 0) { + return; + } - std::string str = base::StringPrintf("%d%%", cur_level); + std::string str = base::StringPrintf("%d%%", cur_level); - int x, y; - determine_xy(field, str.size(), &x, &y); + int x, y; + determine_xy(field, str.size(), &x, &y); - LOGV("drawing percent %s %d %d\n", str.c_str(), x, y); - gr_color(field.color_r, field.color_g, field.color_b, field.color_a); - draw_text(field.font, x, y, str.c_str()); + LOGV("drawing percent %s %d %d\n", str.c_str(), x, y); + gr_color(field.color_r, field.color_g, field.color_b, field.color_a); + draw_text(field.font, x, y, str.c_str()); } void HealthdDraw::draw_battery(const animation* anim) { - const animation::frame& frame = anim->frames[anim->cur_frame]; + if (!graphics_available) return; + const animation::frame& frame = anim->frames[anim->cur_frame]; - if (anim->num_frames != 0) { - draw_surface_centered(frame.surface); - LOGV("drawing frame #%d min_cap=%d time=%d\n", anim->cur_frame, - frame.min_level, frame.disp_time); - } - draw_clock(anim); - draw_percent(anim); + if (anim->num_frames != 0) { + draw_surface_centered(frame.surface); + LOGV("drawing frame #%d min_cap=%d time=%d\n", anim->cur_frame, frame.min_level, + frame.disp_time); + } + draw_clock(anim); + draw_percent(anim); } void HealthdDraw::draw_unknown(GRSurface* surf_unknown) { int y; if (surf_unknown) { - draw_surface_centered(surf_unknown); + draw_surface_centered(surf_unknown); + } else if (sys_font) { + gr_color(0xa4, 0xc6, 0x39, 255); + y = draw_text(sys_font, -1, -1, "Charging!"); + draw_text(sys_font, -1, y + 25, "?\?/100"); } else { - gr_color(0xa4, 0xc6, 0x39, 255); - y = draw_text(gr_sys_font(), -1, -1, "Charging!"); - draw_text(gr_sys_font(), -1, y + 25, "?\?/100"); + LOGW("Charging, level unknown\n"); } } diff --git a/healthd/healthd_draw.h b/healthd/healthd_draw.h index 6a6ba7655..7c847bdbf 100644 --- a/healthd/healthd_draw.h +++ b/healthd/healthd_draw.h @@ -70,6 +70,12 @@ class HealthdDraw { const bool kSplitScreen; // Pixels to offset graphics towards center split. const int kSplitOffset; + + // system text font, may be nullptr + const GRFont* sys_font; + + // true if minui init'ed OK, false if minui init failed + bool graphics_available; }; #endif // HEALTHD_DRAW_H From f80341693f98b5fce965535cb1e904adbd676e77 Mon Sep 17 00:00:00 2001 From: Marissa Wall Date: Tue, 5 Jun 2018 17:22:32 +0000 Subject: [PATCH 022/221] Revert "sync: remove legacy sync info API" This reverts commit 798ba95bda14f9f28561a2a27ba406537f8bb8a8. Brodcom uses the sync_fence_info_data directly. https://android-build.googleplex.com/builds/submitted/4821789/elfin-userdebug/latest/view/logs/build_error.log Change-Id: I72fed683397e9b10007b71253e20ded43726d377 (cherry picked from commit eed25df46a22a143a0341113759894c23a9b6cbf) --- libsync/include/android/sync.h | 20 ++++++++++++++++++++ libsync/sync.c | 23 ----------------------- libsync/tests/sync_test.cpp | 29 ----------------------------- 3 files changed, 20 insertions(+), 52 deletions(-) diff --git a/libsync/include/android/sync.h b/libsync/include/android/sync.h index 32bb878ba..68f74a0b2 100644 --- a/libsync/include/android/sync.h +++ b/libsync/include/android/sync.h @@ -41,8 +41,28 @@ __BEGIN_DECLS +struct sync_fence_info_data { + uint32_t len; + char name[32]; + int32_t status; + uint8_t pt_info[0]; +}; + +struct sync_pt_info { + uint32_t len; + char obj_name[32]; + char driver_name[32]; + int32_t status; + uint64_t timestamp_ns; + uint8_t driver_data[0]; +}; + /* timeout in msecs */ int sync_wait(int fd, int timeout); +struct sync_fence_info_data *sync_fence_info(int fd); +struct sync_pt_info *sync_pt_info(struct sync_fence_info_data *info, + struct sync_pt_info *itr); +void sync_fence_info_free(struct sync_fence_info_data *info); __END_DECLS diff --git a/libsync/sync.c b/libsync/sync.c index b8c48c7f7..6b187faed 100644 --- a/libsync/sync.c +++ b/libsync/sync.c @@ -30,29 +30,6 @@ #include -/* Prototypes for deprecated functions that used to be declared in the legacy - * android/sync.h. They've been moved here to make sure new code does not use - * them, but the functions are still defined to avoid breaking existing - * binaries. Eventually they can be removed altogether. - */ -struct sync_fence_info_data { - uint32_t len; - char name[32]; - int32_t status; - uint8_t pt_info[0]; -}; -struct sync_pt_info { - uint32_t len; - char obj_name[32]; - char driver_name[32]; - int32_t status; - uint64_t timestamp_ns; - uint8_t driver_data[0]; -}; -struct sync_fence_info_data* sync_fence_info(int fd); -struct sync_pt_info* sync_pt_info(struct sync_fence_info_data* info, struct sync_pt_info* itr); -void sync_fence_info_free(struct sync_fence_info_data* info); - /* Legacy Sync API */ struct sync_legacy_merge_data { diff --git a/libsync/tests/sync_test.cpp b/libsync/tests/sync_test.cpp index 011b09d00..0fb86d6fc 100644 --- a/libsync/tests/sync_test.cpp +++ b/libsync/tests/sync_test.cpp @@ -15,35 +15,6 @@ #include #include -/* These deprecated declarations were in the legacy android/sync.h. They've been removed to - * encourage code to move to the modern equivalents. But they are still implemented in libsync.so - * to avoid breaking existing binaries; as long as that's true we should keep testing them here. - * That means making local copies of the declarations. - */ -extern "C" { - -struct sync_fence_info_data { - uint32_t len; - char name[32]; - int32_t status; - uint8_t pt_info[0]; -}; - -struct sync_pt_info { - uint32_t len; - char obj_name[32]; - char driver_name[32]; - int32_t status; - uint64_t timestamp_ns; - uint8_t driver_data[0]; -}; - -struct sync_fence_info_data* sync_fence_info(int fd); -struct sync_pt_info* sync_pt_info(struct sync_fence_info_data* info, struct sync_pt_info* itr); -void sync_fence_info_free(struct sync_fence_info_data* info); - -} // extern "C" - // TODO: better stress tests? // Handle more than 64 fd's simultaneously, i.e. fix sync_fence_info's 4k limit. // Handle wraparound in timelines like nvidia. From dbb650dd81d51ad6b3a0a3865c5a2e24f4b8ae94 Mon Sep 17 00:00:00 2001 From: Elliott Hughes Date: Thu, 14 Jun 2018 10:59:09 -0700 Subject: [PATCH 023/221] bootstat: remove the only caller of liblogcat. We need to make progress both on adding the real interface for battery level and cleaning up logging. This stands in the way of both. Bug: http://b/77725702 Test: builds Change-Id: Ia457e497606c2c7965d6895baebb26eef17857c9 --- bootstat/Android.bp | 1 - bootstat/bootstat.cpp | 82 +------------------------------------------ 2 files changed, 1 insertion(+), 82 deletions(-) diff --git a/bootstat/Android.bp b/bootstat/Android.bp index 3ddadbc24..5e2d171ff 100644 --- a/bootstat/Android.bp +++ b/bootstat/Android.bp @@ -64,7 +64,6 @@ cc_binary { defaults: ["bootstat_defaults"], static_libs: ["libbootstat"], shared_libs: [ - "liblogcat", "libstatslog" ], init_rc: ["bootstat.rc"], diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp index 4be102c71..8c8d92183 100644 --- a/bootstat/bootstat.cpp +++ b/bootstat/bootstat.cpp @@ -43,7 +43,6 @@ #include #include #include -#include #include #include @@ -871,86 +870,7 @@ std::string BootReasonStrToReason(const std::string& boot_reason) { } } - // The following battery test should migrate to a default system health HAL - - // Let us not worry if the reboot command was issued, for the cases of - // reboot -p, reboot , reboot cold, reboot warm and reboot hard. - // Same for bootloader and ro.boot.bootreasons of this set, but a dead - // battery could conceivably lead to these, so worthy of override. - if (isBluntRebootReason(ret)) { - // Heuristic to determine if shutdown possibly because of a dead battery? - // Really a hail-mary pass to find it in last klog content ... - static const int battery_dead_threshold = 2; // percent - static const char battery[] = "healthd: battery l="; - const pstoreConsole console(content); - size_t pos = console.rfind(battery); // last one - std::string digits; - if (pos != std::string::npos) { - digits = content.substr(pos + strlen(battery), strlen("100 ")); - // correct common errors - correctForBitError(digits, "100 "); - if (digits[0] == '!') digits[0] = '1'; - if (digits[1] == '!') digits[1] = '1'; - } - const char* endptr = digits.c_str(); - unsigned level = 0; - while (::isdigit(*endptr)) { - level *= 10; - level += *endptr++ - '0'; - // make sure no leading zeros, except zero itself, and range check. - if ((level == 0) || (level > 100)) break; - } - // example bit error rate issues for 10% - // 'l=10 ' no bits in error - // 'l=00 ' single bit error (fails above) - // 'l=1 ' single bit error - // 'l=0 ' double bit error - // There are others, not typically critical because of 2% - // battery_dead_threshold. KISS check, make sure second - // character after digit sequence is not a space. - if ((level <= 100) && (endptr != digits.c_str()) && (endptr[0] == ' ') && (endptr[1] != ' ')) { - LOG(INFO) << "Battery level at shutdown " << level << "%"; - if (level <= battery_dead_threshold) { - ret = "shutdown,battery"; - } - } else { // Most likely - digits = ""; // reset digits - - // Content buffer no longer will have console data. Beware if more - // checks added below, that depend on parsing console content. - content = ""; - - LOG(DEBUG) << "Can not find last low battery in last console messages"; - android_logcat_context ctx = create_android_logcat(); - FILE* fp = android_logcat_popen(&ctx, "logcat -b kernel -v brief -d"); - if (fp != nullptr) { - android::base::ReadFdToString(fileno(fp), &content); - } - android_logcat_pclose(&ctx, fp); - static const char logcat_battery[] = "W/healthd ( 0): battery l="; - - pos = content.find(logcat_battery); // The first one it finds. - if (pos != std::string::npos) { - digits = content.substr(pos + strlen(logcat_battery), strlen("100 ")); - } - endptr = digits.c_str(); - level = 0; - while (::isdigit(*endptr)) { - level *= 10; - level += *endptr++ - '0'; - // make sure no leading zeros, except zero itself, and range check. - if ((level == 0) || (level > 100)) break; - } - if ((level <= 100) && (endptr != digits.c_str()) && (*endptr == ' ')) { - LOG(INFO) << "Battery level at startup " << level << "%"; - if (level <= battery_dead_threshold) { - ret = "shutdown,battery"; - } - } else { - LOG(DEBUG) << "Can not find first battery level in dmesg or logcat"; - } - } - } + // TODO: use the HAL to get battery level (http://b/77725702). // Is there a controlled shutdown hint in last_reboot_reason_property? if (isBluntRebootReason(ret)) { From aba4d2b72516a2a6a9082b90883bdfd4d0157f3b Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Tue, 19 Jun 2018 18:38:12 -0700 Subject: [PATCH 024/221] lmkd: Disable memory.stat usage when per-application memcgs are not used Per-application memory.stat files are not available when per-application memcgs are not used (per_app_memcg=false). Disable its usage based on ro.config.per_app_memcg property. minchan: * correct indentation of memory_stat_parse * move per_app_memcg check into memory_stat_parse inside * change low_ram_device to per_app_memcg Bug: 110384555 Test: manual test to see lkmd log message with memory hogger Change-Id: Ib6dd7586d3ef1c64cb04d16e2d2b21fa9c8e6a3a Signed-off-by: Minchan Kim Signed-off-by: Suren Baghdasaryan --- lmkd/lmkd.c | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index b20f4ef5e..c09324634 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -118,6 +118,7 @@ static bool low_ram_device; static bool kill_heaviest_task; static unsigned long kill_timeout_ms; static bool use_minfree_levels; +static bool per_app_memcg; /* data required to handle events */ struct event_handler_info { @@ -484,7 +485,7 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet) { return; } - if (low_ram_device) { + if (per_app_memcg) { if (params.oomadj >= 900) { soft_limit_mult = 0; } else if (params.oomadj >= 800) { @@ -754,24 +755,31 @@ static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { } static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) { - FILE *fp; - char buf[PATH_MAX]; + FILE *fp; + char buf[PATH_MAX]; - snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid); + /* + * Per-application memory.stat files are available only when + * per-application memcgs are enabled. + */ + if (!per_app_memcg) + return -1; - fp = fopen(buf, "r"); + snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid); - if (fp == NULL) { - ALOGE("%s open failed: %s", buf, strerror(errno)); - return -1; - } + fp = fopen(buf, "r"); - while (fgets(buf, PAGE_SIZE, fp) != NULL ) { - memory_stat_parse_line(buf, mem_st); - } - fclose(fp); + if (fp == NULL) { + ALOGE("%s open failed: %s", buf, strerror(errno)); + return -1; + } - return 0; + while (fgets(buf, PAGE_SIZE, fp) != NULL ) { + memory_stat_parse_line(buf, mem_st); + } + fclose(fp); + + return 0; } #endif @@ -1580,6 +1588,8 @@ int main(int argc __unused, char **argv __unused) { (unsigned long)property_get_int32("ro.lmk.kill_timeout_ms", 0); use_minfree_levels = property_get_bool("ro.lmk.use_minfree_levels", false); + per_app_memcg = + property_get_bool("ro.config.per_app_memcg", low_ram_device); #ifdef LMKD_LOG_STATS statslog_init(&log_ctx, &enable_stats_log); From 0e317d787307dafd8b38961d21ad5f95480eb06a Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 10 Jul 2018 13:02:18 -0700 Subject: [PATCH 025/221] healthd: libbatterymonitor: recovery_available Bug: 80132328 Test: builds Change-Id: I4d5ac73431fb002cc839fed2d97b1acff3fde263 --- healthd/Android.bp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/healthd/Android.bp b/healthd/Android.bp index 8bd51e730..eb8dbe6ce 100644 --- a/healthd/Android.bp +++ b/healthd/Android.bp @@ -1,6 +1,7 @@ cc_library_headers { name: "libhealthd_headers", vendor_available: true, + recovery_available: true, export_include_dirs: ["include"], header_libs: ["libbatteryservice_headers"], export_header_lib_headers: ["libbatteryservice_headers"], @@ -11,6 +12,7 @@ cc_library_static { srcs: ["BatteryMonitor.cpp"], cflags: ["-Wall", "-Werror"], vendor_available: true, + recovery_available: true, export_include_dirs: ["include"], shared_libs: [ "libutils", From aacfc68acfb6f9432e741fa25a68d9336cc7c401 Mon Sep 17 00:00:00 2001 From: Jerry Zhang Date: Fri, 15 Jun 2018 17:40:54 -0700 Subject: [PATCH 026/221] Use more shared libraries in adb and init. fs_mgr is used by several different processes in both system and recovery, so it makes sense for it to be a shared library to save space. libadbd is used by adbd, recovery (as minadbd) and fastbootd so it should be shared as well. Bug: 78793464 Test: compiles Change-Id: I4225f4d1a44e6e5811c68a55595d1f94f0773114 --- adb/Android.bp | 53 ++++++++++++++++++++++------------------- adb/transport_local.cpp | 8 +++---- fs_mgr/Android.bp | 21 ++++++++++------ fs_mgr/libdm/Android.bp | 8 +++---- init/Android.bp | 17 ++++++------- 5 files changed, 60 insertions(+), 47 deletions(-) diff --git a/adb/Android.bp b/adb/Android.bp index 2a9a57985..d35c3a381 100644 --- a/adb/Android.bp +++ b/adb/Android.bp @@ -277,7 +277,7 @@ cc_binary_host { }, } -cc_library_static { +cc_library { name: "libadbd", defaults: ["adb_defaults"], recovery_available: true, @@ -288,16 +288,36 @@ cc_library_static { "daemon/auth.cpp", "daemon/usb.cpp", "daemon/jdwp_service.cpp", + "daemon/mdns.cpp", + "daemon/file_sync_service.cpp", + "daemon/framebuffer_service.cpp", + "daemon/remount_service.cpp", + "daemon/set_verity_enable_state_service.cpp", + "daemon/shell_service.cpp", + "shell_service_protocol.cpp", ], static_libs: [ + "libavb_user", + "libdiagnose_usb", + "libfec", + "libfec_rs", + "libfs_mgr", + "libmdnssd", + "libqemu_pipe", + "libsquashfs_utils", + "libselinux", + ], + + shared_libs: [ "libasyncio", "libbootloader_message", + "libbase", "libcrypto_utils", "libcrypto", - "libdiagnose_usb", - "libqemu_pipe", - "libbase", + "libcutils", + "libext4_utils", + "liblog", ], export_include_dirs: [ @@ -313,13 +333,6 @@ cc_binary { srcs: [ "daemon/main.cpp", - "daemon/mdns.cpp", - "daemon/file_sync_service.cpp", - "daemon/framebuffer_service.cpp", - "daemon/remount_service.cpp", - "daemon/set_verity_enable_state_service.cpp", - "daemon/shell_service.cpp", - "shell_service_protocol.cpp", ], cflags: [ @@ -331,27 +344,19 @@ cc_binary { keep_symbols: true, }, - static_libs: [ + shared_libs: [ "libadbd", "libasyncio", - "libavb_user", + "libbase", "libbootloader_message", + "libcap", "libcrypto_utils", "libcrypto", - "libdiagnose_usb", - "libfec", - "libfec_rs", - "libfs_mgr", - "liblog", + "libcutils", "libext4_utils", - "libmdnssd", + "liblog", "libminijail", "libselinux", - "libsquashfs_utils", - "libqemu_pipe", - - "libbase", - "libcutils", ], } diff --git a/adb/transport_local.cpp b/adb/transport_local.cpp index fa3823854..abd2c312f 100644 --- a/adb/transport_local.cpp +++ b/adb/transport_local.cpp @@ -428,6 +428,10 @@ void local_init(int port) std::thread(func, port).detach(); } +std::string getEmulatorSerialString(int console_port) { + return android::base::StringPrintf("emulator-%d", console_port); +} + #if ADB_HOST struct EmulatorConnection : public FdConnection { EmulatorConnection(unique_fd fd, int local_port) @@ -462,10 +466,6 @@ static atransport* find_emulator_transport_by_adb_port_locked(int adb_port) return it->second; } -std::string getEmulatorSerialString(int console_port) { - return android::base::StringPrintf("emulator-%d", console_port); -} - atransport* find_emulator_transport_by_adb_port(int adb_port) { std::lock_guard lock(local_transports_lock); return find_emulator_transport_by_adb_port_locked(adb_port); diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index a3ce879a9..ce1595ed9 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -30,7 +30,7 @@ cc_defaults { ], } -cc_library_static { +cc_library { name: "libfs_mgr", defaults: ["fs_mgr_defaults"], recovery_available: true, @@ -44,18 +44,24 @@ cc_library_static { "fs_mgr_avb_ops.cpp", "fs_mgr_dm_linear.cpp", ], - static_libs: [ + shared_libs: [ "libfec", "libfec_rs", "libbase", "libcrypto_utils", "libcrypto", + "libcutils", "libext4_utils", + "libkeyutils", + "liblog", + "liblogwrap", "libsquashfs_utils", "libselinux", + ], + static_libs: [ "libavb", - "libfstab", "libdm", + "libfstab", "liblp", ], export_static_lib_headers: [ @@ -65,9 +71,8 @@ cc_library_static { ], whole_static_libs: [ "liblp", - "liblogwrap", - "libdm", "libfstab", + "libdm", ], cppflags: [ "-DALLOW_ADBD_DISABLE_VERITY=0", @@ -82,7 +87,7 @@ cc_library_static { }, } -cc_library_static { +cc_library { name: "libfstab", vendor_available: true, recovery_available: true, @@ -93,5 +98,7 @@ cc_library_static { "fs_mgr_slotselect.cpp", ], export_include_dirs: ["include_fstab"], - header_libs: ["libbase_headers"], + shared_libs: [ + "libbase", + ], } diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp index 22af1238e..8a3a34ffd 100644 --- a/fs_mgr/libdm/Android.bp +++ b/fs_mgr/libdm/Android.bp @@ -14,7 +14,7 @@ // limitations under the License. // -cc_library_static { +cc_library { name: "libdm", defaults: ["fs_mgr_defaults"], recovery_available: true, @@ -32,9 +32,9 @@ cc_library_static { "loop_control.cpp", ], - header_libs: [ - "libbase_headers", - "liblog_headers", + shared_libs: [ + "libbase", + "liblog", ], } diff --git a/init/Android.bp b/init/Android.bp index 5bbb7a09c..094d914bd 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -59,17 +59,9 @@ cc_defaults { }, }, static_libs: [ - "libbootloader_message", - "libfs_mgr", - "libfec", - "libfec_rs", "libhidl-gen-utils", "libsquashfs_utils", - "liblogwrap", - "libext4_utils", "libseccomp_policy", - "libcrypto_utils", - "libsparse", "libprocessgroup", "libavb", "libkeyutils", @@ -78,13 +70,22 @@ cc_defaults { "libpropertyinfoparser", ], shared_libs: [ + "libbootloader_message", + "libcrypto_utils", "libcutils", "libbase", "libc", + "libext4_utils", + "libfs_mgr", + "libfec", + "libfec_rs", "liblog", + "liblogwrap", "libcrypto", "libc++", "libdl", + "libselinux", + "libsparse", "libz", "libselinux", ], From 423046bbf603875e9c118a90b47e5fb51fe7fbba Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 26 Jul 2018 13:20:26 -0700 Subject: [PATCH 027/221] storaged: Fix-up private variable names in uid_monitor. Bug: N/A Test: storaged builds Change-Id: Ifd21e25baa7b1c6ce41c5e0ec5247f47ba716e6e --- storaged/include/storaged_uid_monitor.h | 24 +++--- storaged/storaged_uid_monitor.cpp | 102 ++++++++++++------------ storaged/tests/storaged_test.cpp | 43 +++++----- 3 files changed, 86 insertions(+), 83 deletions(-) diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h index 3a718fa60..b56e71aac 100644 --- a/storaged/include/storaged_uid_monitor.h +++ b/storaged/include/storaged_uid_monitor.h @@ -68,31 +68,31 @@ struct uid_io_usage { struct uid_record { string name; - struct uid_io_usage ios; + uid_io_usage ios; }; struct uid_records { uint64_t start_ts; - vector entries; + vector entries; }; class uid_monitor { private: FRIEND_TEST(storaged_test, uid_monitor); // last dump from /proc/uid_io/stats, uid -> uid_info - unordered_map last_uid_io_stats; + unordered_map last_uid_io_stats_; // current io usage for next report, app name -> uid_io_usage - unordered_map curr_io_stats; + unordered_map curr_io_stats_; // io usage records, end timestamp -> {start timestamp, vector of records} - map io_history; + map io_history_; // charger ON/OFF - charger_stat_t charger_stat; + charger_stat_t charger_stat_; // protects curr_io_stats, last_uid_io_stats, records and charger_stat - Mutex uidm_mutex; + Mutex uidm_mutex_; // start time for IO records - uint64_t start_ts; + uint64_t start_ts_; // true if UID_IO_STATS_PATH is accessible - const bool enable; + const bool enabled_; // reads from /proc/uid_io/stats unordered_map get_uid_io_stats_locked(); @@ -110,16 +110,18 @@ public: // called by storaged -u unordered_map get_uid_io_stats(); // called by dumpsys - map dump( + map dump( double hours, uint64_t threshold, bool force_report); // called by battery properties listener void set_charger_state(charger_stat_t stat); // called by storaged periodic_chore or dump with force_report - bool enabled() { return enable; }; + bool enabled() { return enabled_; }; void report(unordered_map* protos); // restores io_history from protobuf void load_uid_io_proto(const UidIOUsage& proto); void clear_user_history(userid_t user_id); + + map& io_history() { return io_history_; } }; #endif /* _STORAGED_UID_MONITOR_H_ */ diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp index 5745782b2..32b1568de 100644 --- a/storaged/storaged_uid_monitor.cpp +++ b/storaged/storaged_uid_monitor.cpp @@ -50,7 +50,7 @@ const char* UID_IO_STATS_PATH = "/proc/uid_io/stats"; std::unordered_map uid_monitor::get_uid_io_stats() { - Mutex::Autolock _l(uidm_mutex); + Mutex::Autolock _l(uidm_mutex_); return get_uid_io_stats_locked(); }; @@ -178,10 +178,10 @@ std::unordered_map uid_monitor::get_uid_io_stats_locked() uid_io_stats[u.uid].name = std::to_string(u.uid); uids.push_back(u.uid); uid_names.push_back(&uid_io_stats[u.uid].name); - if (last_uid_io_stats.find(u.uid) == last_uid_io_stats.end()) { + if (last_uid_io_stats_.find(u.uid) == last_uid_io_stats_.end()) { refresh_uid_names = true; } else { - uid_io_stats[u.uid].name = last_uid_io_stats[u.uid].name; + uid_io_stats[u.uid].name = last_uid_io_stats_[u.uid].name; } } else { task_info t; @@ -218,12 +218,12 @@ void uid_monitor::add_records_locked(uint64_t curr_ts) { // remove records more than 5 days old if (curr_ts > 5 * DAY_TO_SEC) { - auto it = io_history.lower_bound(curr_ts - 5 * DAY_TO_SEC); - io_history.erase(io_history.begin(), it); + auto it = io_history_.lower_bound(curr_ts - 5 * DAY_TO_SEC); + io_history_.erase(io_history_.begin(), it); } struct uid_records new_records; - for (const auto& p : curr_io_stats) { + for (const auto& p : curr_io_stats_) { struct uid_record record = {}; record.name = p.first; if (!p.second.uid_ios.is_zero()) { @@ -237,23 +237,23 @@ void uid_monitor::add_records_locked(uint64_t curr_ts) } } - curr_io_stats.clear(); - new_records.start_ts = start_ts; - start_ts = curr_ts; + curr_io_stats_.clear(); + new_records.start_ts = start_ts_; + start_ts_ = curr_ts; if (new_records.entries.empty()) return; // make some room for new records - ssize_t overflow = history_size(io_history) + + ssize_t overflow = history_size(io_history_) + new_records.entries.size() - MAX_UID_RECORDS_SIZE; - while (overflow > 0 && io_history.size() > 0) { - auto del_it = io_history.begin(); + while (overflow > 0 && io_history_.size() > 0) { + auto del_it = io_history_.begin(); overflow -= del_it->second.entries.size(); - io_history.erase(io_history.begin()); + io_history_.erase(io_history_.begin()); } - io_history[curr_ts] = new_records; + io_history_[curr_ts] = new_records; } std::map uid_monitor::dump( @@ -263,7 +263,7 @@ std::map uid_monitor::dump( report(nullptr); } - Mutex::Autolock _l(uidm_mutex); + Mutex::Autolock _l(uidm_mutex_); std::map dump_records; uint64_t first_ts = 0; @@ -272,7 +272,7 @@ std::map uid_monitor::dump( first_ts = time(NULL) - hours * HOUR_TO_SEC; } - for (auto it = io_history.lower_bound(first_ts); it != io_history.end(); ++it) { + for (auto it = io_history_.lower_bound(first_ts); it != io_history_.end(); ++it) { const std::vector& recs = it->second.entries; struct uid_records filtered; @@ -311,29 +311,29 @@ void uid_monitor::update_curr_io_stats_locked() for (const auto& it : uid_io_stats) { const uid_info& uid = it.second; - if (curr_io_stats.find(uid.name) == curr_io_stats.end()) { - curr_io_stats[uid.name] = {}; + if (curr_io_stats_.find(uid.name) == curr_io_stats_.end()) { + curr_io_stats_[uid.name] = {}; } - struct uid_io_usage& usage = curr_io_stats[uid.name]; + struct uid_io_usage& usage = curr_io_stats_[uid.name]; usage.user_id = multiuser_get_user_id(uid.uid); int64_t fg_rd_delta = uid.io[FOREGROUND].read_bytes - - last_uid_io_stats[uid.uid].io[FOREGROUND].read_bytes; + last_uid_io_stats_[uid.uid].io[FOREGROUND].read_bytes; int64_t bg_rd_delta = uid.io[BACKGROUND].read_bytes - - last_uid_io_stats[uid.uid].io[BACKGROUND].read_bytes; + last_uid_io_stats_[uid.uid].io[BACKGROUND].read_bytes; int64_t fg_wr_delta = uid.io[FOREGROUND].write_bytes - - last_uid_io_stats[uid.uid].io[FOREGROUND].write_bytes; + last_uid_io_stats_[uid.uid].io[FOREGROUND].write_bytes; int64_t bg_wr_delta = uid.io[BACKGROUND].write_bytes - - last_uid_io_stats[uid.uid].io[BACKGROUND].write_bytes; + last_uid_io_stats_[uid.uid].io[BACKGROUND].write_bytes; - usage.uid_ios.bytes[READ][FOREGROUND][charger_stat] += + usage.uid_ios.bytes[READ][FOREGROUND][charger_stat_] += (fg_rd_delta < 0) ? 0 : fg_rd_delta; - usage.uid_ios.bytes[READ][BACKGROUND][charger_stat] += + usage.uid_ios.bytes[READ][BACKGROUND][charger_stat_] += (bg_rd_delta < 0) ? 0 : bg_rd_delta; - usage.uid_ios.bytes[WRITE][FOREGROUND][charger_stat] += + usage.uid_ios.bytes[WRITE][FOREGROUND][charger_stat_] += (fg_wr_delta < 0) ? 0 : fg_wr_delta; - usage.uid_ios.bytes[WRITE][BACKGROUND][charger_stat] += + usage.uid_ios.bytes[WRITE][BACKGROUND][charger_stat_] += (bg_wr_delta < 0) ? 0 : bg_wr_delta; for (const auto& task_it : uid.tasks) { @@ -341,34 +341,34 @@ void uid_monitor::update_curr_io_stats_locked() const pid_t pid = task_it.first; const std::string& comm = task_it.second.comm; int64_t task_fg_rd_delta = task.io[FOREGROUND].read_bytes - - last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].read_bytes; + last_uid_io_stats_[uid.uid].tasks[pid].io[FOREGROUND].read_bytes; int64_t task_bg_rd_delta = task.io[BACKGROUND].read_bytes - - last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].read_bytes; + last_uid_io_stats_[uid.uid].tasks[pid].io[BACKGROUND].read_bytes; int64_t task_fg_wr_delta = task.io[FOREGROUND].write_bytes - - last_uid_io_stats[uid.uid].tasks[pid].io[FOREGROUND].write_bytes; + last_uid_io_stats_[uid.uid].tasks[pid].io[FOREGROUND].write_bytes; int64_t task_bg_wr_delta = task.io[BACKGROUND].write_bytes - - last_uid_io_stats[uid.uid].tasks[pid].io[BACKGROUND].write_bytes; + last_uid_io_stats_[uid.uid].tasks[pid].io[BACKGROUND].write_bytes; io_usage& task_usage = usage.task_ios[comm]; - task_usage.bytes[READ][FOREGROUND][charger_stat] += + task_usage.bytes[READ][FOREGROUND][charger_stat_] += (task_fg_rd_delta < 0) ? 0 : task_fg_rd_delta; - task_usage.bytes[READ][BACKGROUND][charger_stat] += + task_usage.bytes[READ][BACKGROUND][charger_stat_] += (task_bg_rd_delta < 0) ? 0 : task_bg_rd_delta; - task_usage.bytes[WRITE][FOREGROUND][charger_stat] += + task_usage.bytes[WRITE][FOREGROUND][charger_stat_] += (task_fg_wr_delta < 0) ? 0 : task_fg_wr_delta; - task_usage.bytes[WRITE][BACKGROUND][charger_stat] += + task_usage.bytes[WRITE][BACKGROUND][charger_stat_] += (task_bg_wr_delta < 0) ? 0 : task_bg_wr_delta; } } - last_uid_io_stats = uid_io_stats; + last_uid_io_stats_ = uid_io_stats; } void uid_monitor::report(unordered_map* protos) { if (!enabled()) return; - Mutex::Autolock _l(uidm_mutex); + Mutex::Autolock _l(uidm_mutex_); update_curr_io_stats_locked(); add_records_locked(time(NULL)); @@ -408,7 +408,7 @@ void get_io_usage_proto(io_usage* usage, const IOUsage& io_proto) void uid_monitor::update_uid_io_proto(unordered_map* protos) { - for (const auto& item : io_history) { + for (const auto& item : io_history_) { const uint64_t& end_ts = item.first; const struct uid_records& recs = item.second; unordered_map user_items; @@ -448,9 +448,9 @@ void uid_monitor::update_uid_io_proto(unordered_map* protos) void uid_monitor::clear_user_history(userid_t user_id) { - Mutex::Autolock _l(uidm_mutex); + Mutex::Autolock _l(uidm_mutex_); - for (auto& item : io_history) { + for (auto& item : io_history_) { vector* entries = &item.second.entries; entries->erase( remove_if(entries->begin(), entries->end(), @@ -459,9 +459,9 @@ void uid_monitor::clear_user_history(userid_t user_id) entries->end()); } - for (auto it = io_history.begin(); it != io_history.end(); ) { + for (auto it = io_history_.begin(); it != io_history_.end(); ) { if (it->second.entries.empty()) { - it = io_history.erase(it); + it = io_history_.erase(it); } else { it++; } @@ -472,11 +472,11 @@ void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto) { if (!enabled()) return; - Mutex::Autolock _l(uidm_mutex); + Mutex::Autolock _l(uidm_mutex_); for (const auto& item_proto : uid_io_proto.uid_io_items()) { const UidIORecords& records_proto = item_proto.records(); - struct uid_records* recs = &io_history[item_proto.end_ts()]; + struct uid_records* recs = &io_history_[item_proto.end_ts()]; recs->start_ts = records_proto.start_ts(); for (const auto& rec_proto : records_proto.entries()) { @@ -497,24 +497,24 @@ void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto) void uid_monitor::set_charger_state(charger_stat_t stat) { - Mutex::Autolock _l(uidm_mutex); + Mutex::Autolock _l(uidm_mutex_); - if (charger_stat == stat) { + if (charger_stat_ == stat) { return; } update_curr_io_stats_locked(); - charger_stat = stat; + charger_stat_ = stat; } void uid_monitor::init(charger_stat_t stat) { - charger_stat = stat; + charger_stat_ = stat; - start_ts = time(NULL); - last_uid_io_stats = get_uid_io_stats(); + start_ts_ = time(NULL); + last_uid_io_stats_ = get_uid_io_stats(); } uid_monitor::uid_monitor() - : enable(!access(UID_IO_STATS_PATH, R_OK)) { + : enabled_(!access(UID_IO_STATS_PATH, R_OK)) { } diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp index ec47b65ee..e08c9ee6c 100644 --- a/storaged/tests/storaged_test.cpp +++ b/storaged/tests/storaged_test.cpp @@ -443,8 +443,9 @@ TEST(storaged_test, storage_info_t_proto) { TEST(storaged_test, uid_monitor) { uid_monitor uidm; + auto& io_history = uidm.io_history(); - uidm.io_history[200] = { + io_history[200] = { .start_ts = 100, .entries = { { "app1", { @@ -466,7 +467,7 @@ TEST(storaged_test, uid_monitor) { }, }; - uidm.io_history[300] = { + io_history[300] = { .start_ts = 200, .entries = { { "app1", { @@ -526,9 +527,9 @@ TEST(storaged_test, uid_monitor) { EXPECT_EQ(user_1_item_1.records().entries(0).user_id(), 1UL); EXPECT_EQ(user_1_item_1.records().entries(0).uid_io().wr_fg_chg_off(), 1000UL); - uidm.io_history.clear(); + io_history.clear(); - uidm.io_history[300] = { + io_history[300] = { .start_ts = 200, .entries = { { "app1", { @@ -539,7 +540,7 @@ TEST(storaged_test, uid_monitor) { }, }; - uidm.io_history[400] = { + io_history[400] = { .start_ts = 300, .entries = { { "app1", { @@ -553,13 +554,13 @@ TEST(storaged_test, uid_monitor) { uidm.load_uid_io_proto(protos[0].uid_io_usage()); uidm.load_uid_io_proto(protos[1].uid_io_usage()); - EXPECT_EQ(uidm.io_history.size(), 3UL); - EXPECT_EQ(uidm.io_history.count(200), 1UL); - EXPECT_EQ(uidm.io_history.count(300), 1UL); - EXPECT_EQ(uidm.io_history.count(400), 1UL); + EXPECT_EQ(io_history.size(), 3UL); + EXPECT_EQ(io_history.count(200), 1UL); + EXPECT_EQ(io_history.count(300), 1UL); + EXPECT_EQ(io_history.count(400), 1UL); - EXPECT_EQ(uidm.io_history[200].start_ts, 100UL); - const vector& entries_0 = uidm.io_history[200].entries; + EXPECT_EQ(io_history[200].start_ts, 100UL); + const vector& entries_0 = io_history[200].entries; EXPECT_EQ(entries_0.size(), 3UL); EXPECT_EQ(entries_0[0].name, "app1"); EXPECT_EQ(entries_0[0].ios.user_id, 0UL); @@ -572,8 +573,8 @@ TEST(storaged_test, uid_monitor) { EXPECT_EQ(entries_0[2].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON], 1000UL); EXPECT_EQ(entries_0[2].ios.uid_ios.bytes[READ][FOREGROUND][CHARGER_ON], 1000UL); - EXPECT_EQ(uidm.io_history[300].start_ts, 200UL); - const vector& entries_1 = uidm.io_history[300].entries; + EXPECT_EQ(io_history[300].start_ts, 200UL); + const vector& entries_1 = io_history[300].entries; EXPECT_EQ(entries_1.size(), 3UL); EXPECT_EQ(entries_1[0].name, "app1"); EXPECT_EQ(entries_1[0].ios.user_id, 0UL); @@ -585,8 +586,8 @@ TEST(storaged_test, uid_monitor) { EXPECT_EQ(entries_1[2].ios.user_id, 1UL); EXPECT_EQ(entries_1[2].ios.uid_ios.bytes[WRITE][FOREGROUND][CHARGER_OFF], 1000UL); - EXPECT_EQ(uidm.io_history[400].start_ts, 300UL); - const vector& entries_2 = uidm.io_history[400].entries; + EXPECT_EQ(io_history[400].start_ts, 300UL); + const vector& entries_2 = io_history[400].entries; EXPECT_EQ(entries_2.size(), 1UL); EXPECT_EQ(entries_2[0].name, "app1"); EXPECT_EQ(entries_2[0].ios.user_id, 0UL); @@ -615,14 +616,14 @@ TEST(storaged_test, uid_monitor) { uidm.clear_user_history(0); - EXPECT_EQ(uidm.io_history.size(), 2UL); - EXPECT_EQ(uidm.io_history.count(200), 1UL); - EXPECT_EQ(uidm.io_history.count(300), 1UL); + EXPECT_EQ(uidm.io_history_.size(), 2UL); + EXPECT_EQ(uidm.io_history_.count(200), 1UL); + EXPECT_EQ(uidm.io_history_.count(300), 1UL); - EXPECT_EQ(uidm.io_history[200].entries.size(), 1UL); - EXPECT_EQ(uidm.io_history[300].entries.size(), 1UL); + EXPECT_EQ(uidm.io_history_[200].entries.size(), 1UL); + EXPECT_EQ(uidm.io_history_[300].entries.size(), 1UL); uidm.clear_user_history(1); - EXPECT_EQ(uidm.io_history.size(), 0UL); + EXPECT_EQ(uidm.io_history_.size(), 0UL); } From 21f20feec999779b07d830d62432e70e120371bd Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 26 Jul 2018 14:30:35 -0700 Subject: [PATCH 028/221] storaged: Don't duplicate uid_records from proto files. It is possible for storaged to load the same saved proto file multiple times, for example, if system_server crashes. In this case we do not want to fill io_history with duplicate entries. This patch elides records for which an app+userid record already exists for the same timestamp. Bug: 111578975 Test: gtest storaged_test.load_uid_io_proto Change-Id: I87bc3e37d6464079cece03b5852285d79067b935 --- storaged/include/storaged_uid_monitor.h | 4 ++- storaged/storaged.cpp | 2 +- storaged/storaged_uid_monitor.cpp | 18 ++++++++++- storaged/tests/storaged_test.cpp | 41 +++++++++++++++++++++++-- 4 files changed, 60 insertions(+), 5 deletions(-) diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h index b56e71aac..0c03402a0 100644 --- a/storaged/include/storaged_uid_monitor.h +++ b/storaged/include/storaged_uid_monitor.h @@ -79,6 +79,8 @@ struct uid_records { class uid_monitor { private: FRIEND_TEST(storaged_test, uid_monitor); + FRIEND_TEST(storaged_test, load_uid_io_proto); + // last dump from /proc/uid_io/stats, uid -> uid_info unordered_map last_uid_io_stats_; // current io usage for next report, app name -> uid_io_usage @@ -118,7 +120,7 @@ public: bool enabled() { return enabled_; }; void report(unordered_map* protos); // restores io_history from protobuf - void load_uid_io_proto(const UidIOUsage& proto); + void load_uid_io_proto(userid_t user_id, const UidIOUsage& proto); void clear_user_history(userid_t user_id); map& io_history() { return io_history_; } diff --git a/storaged/storaged.cpp b/storaged/storaged.cpp index f346c387b..77c6167de 100644 --- a/storaged/storaged.cpp +++ b/storaged/storaged.cpp @@ -194,7 +194,7 @@ void storaged_t::load_proto(userid_t user_id) { return; } - mUidm.load_uid_io_proto(proto.uid_io_usage()); + mUidm.load_uid_io_proto(user_id, proto.uid_io_usage()); if (user_id == USER_SYSTEM) { storage_info->load_perf_history_proto(proto.perf_history()); diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp index 32b1568de..d5f2fe09f 100644 --- a/storaged/storaged_uid_monitor.cpp +++ b/storaged/storaged_uid_monitor.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include @@ -468,7 +469,7 @@ void uid_monitor::clear_user_history(userid_t user_id) } } -void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto) +void uid_monitor::load_uid_io_proto(userid_t user_id, const UidIOUsage& uid_io_proto) { if (!enabled()) return; @@ -478,8 +479,23 @@ void uid_monitor::load_uid_io_proto(const UidIOUsage& uid_io_proto) const UidIORecords& records_proto = item_proto.records(); struct uid_records* recs = &io_history_[item_proto.end_ts()]; + // It's possible that the same uid_io_proto file gets loaded more than + // once, for example, if system_server crashes. In this case we avoid + // adding duplicate entries, so we build a quick way to check for + // duplicates. + std::unordered_set existing_uids; + for (const auto& rec : recs->entries) { + if (rec.ios.user_id == user_id) { + existing_uids.emplace(rec.name); + } + } + recs->start_ts = records_proto.start_ts(); for (const auto& rec_proto : records_proto.entries()) { + if (existing_uids.find(rec_proto.uid_name()) != existing_uids.end()) { + continue; + } + struct uid_record record; record.name = rec_proto.uid_name(); record.ios.user_id = rec_proto.user_id(); diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp index e08c9ee6c..d66746dee 100644 --- a/storaged/tests/storaged_test.cpp +++ b/storaged/tests/storaged_test.cpp @@ -551,8 +551,8 @@ TEST(storaged_test, uid_monitor) { }, }; - uidm.load_uid_io_proto(protos[0].uid_io_usage()); - uidm.load_uid_io_proto(protos[1].uid_io_usage()); + uidm.load_uid_io_proto(0, protos[0].uid_io_usage()); + uidm.load_uid_io_proto(1, protos[1].uid_io_usage()); EXPECT_EQ(io_history.size(), 3UL); EXPECT_EQ(io_history.count(200), 1UL); @@ -627,3 +627,40 @@ TEST(storaged_test, uid_monitor) { EXPECT_EQ(uidm.io_history_.size(), 0UL); } + +TEST(storaged_test, load_uid_io_proto) { + uid_monitor uidm; + + uidm.io_history_[200] = { + .start_ts = 100, + .entries = { + { "app1", { + .user_id = 0, + .uid_ios.bytes[WRITE][FOREGROUND][CHARGER_ON] = 1000, + } + }, + { "app2", { + .user_id = 0, + .uid_ios.bytes[READ][FOREGROUND][CHARGER_OFF] = 2000, + } + }, + { "app3", { + .user_id = 0, + .uid_ios.bytes[READ][FOREGROUND][CHARGER_OFF] = 3000, + } + }, + }, + }; + + unordered_map protos; + uidm.update_uid_io_proto(&protos); + ASSERT_EQ(protos.size(), size_t(1)); + + // Loading the same proto many times should not add duplicate entries. + const UidIOUsage& user_0 = protos[0].uid_io_usage(); + for (size_t i = 0; i < 10000; i++) { + uidm.load_uid_io_proto(0, user_0); + } + ASSERT_EQ(uidm.io_history_.size(), size_t(1)); + ASSERT_EQ(uidm.io_history_[200].entries.size(), size_t(3)); +} From 379003e77fe6ba6601b34494b57d20c5bfb8062d Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 26 Jul 2018 18:01:03 -0700 Subject: [PATCH 029/221] storaged: Cap io_history when loading stats from disk. Similar to add_record_locked, load_uid_io_proto should respect the maximum number of records. Bug: 111578975 Test: storaged_test.load_uid_io_proto Change-Id: Ic3c5095cdd09d2184f436813b5ab50d3ee0007b2 --- storaged/include/storaged_uid_monitor.h | 6 ++++ storaged/storaged_uid_monitor.cpp | 19 ++++++++---- storaged/tests/storaged_test.cpp | 40 ++++++++++++++++++------- 3 files changed, 49 insertions(+), 16 deletions(-) diff --git a/storaged/include/storaged_uid_monitor.h b/storaged/include/storaged_uid_monitor.h index 0c03402a0..fffb3d2c8 100644 --- a/storaged/include/storaged_uid_monitor.h +++ b/storaged/include/storaged_uid_monitor.h @@ -105,6 +105,10 @@ private: // writes io_history to protobuf void update_uid_io_proto(unordered_map* protos); + // Ensure that io_history_ can append |n| items without exceeding + // MAX_UID_RECORDS_SIZE in size. + void maybe_shrink_history_for_items(size_t nitems); + public: uid_monitor(); // called by storaged main thread @@ -124,6 +128,8 @@ public: void clear_user_history(userid_t user_id); map& io_history() { return io_history_; } + + static constexpr int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours }; #endif /* _STORAGED_UID_MONITOR_H_ */ diff --git a/storaged/storaged_uid_monitor.cpp b/storaged/storaged_uid_monitor.cpp index d5f2fe09f..55380ba25 100644 --- a/storaged/storaged_uid_monitor.cpp +++ b/storaged/storaged_uid_monitor.cpp @@ -201,8 +201,6 @@ std::unordered_map uid_monitor::get_uid_io_stats_locked() namespace { -const int MAX_UID_RECORDS_SIZE = 1000 * 48; // 1000 uids in 48 hours - inline size_t history_size( const std::map& history) { @@ -246,15 +244,18 @@ void uid_monitor::add_records_locked(uint64_t curr_ts) return; // make some room for new records - ssize_t overflow = history_size(io_history_) + - new_records.entries.size() - MAX_UID_RECORDS_SIZE; + maybe_shrink_history_for_items(new_records.entries.size()); + + io_history_[curr_ts] = new_records; +} + +void uid_monitor::maybe_shrink_history_for_items(size_t nitems) { + ssize_t overflow = history_size(io_history_) + nitems - MAX_UID_RECORDS_SIZE; while (overflow > 0 && io_history_.size() > 0) { auto del_it = io_history_.begin(); overflow -= del_it->second.entries.size(); io_history_.erase(io_history_.begin()); } - - io_history_[curr_ts] = new_records; } std::map uid_monitor::dump( @@ -508,6 +509,12 @@ void uid_monitor::load_uid_io_proto(userid_t user_id, const UidIOUsage& uid_io_p } recs->entries.push_back(record); } + + // We already added items, so this will just cull down to the maximum + // length. We do not remove anything if there is only one entry. + if (io_history_.size() > 1) { + maybe_shrink_history_for_items(0); + } } } diff --git a/storaged/tests/storaged_test.cpp b/storaged/tests/storaged_test.cpp index d66746dee..64009c265 100644 --- a/storaged/tests/storaged_test.cpp +++ b/storaged/tests/storaged_test.cpp @@ -616,22 +616,24 @@ TEST(storaged_test, uid_monitor) { uidm.clear_user_history(0); - EXPECT_EQ(uidm.io_history_.size(), 2UL); - EXPECT_EQ(uidm.io_history_.count(200), 1UL); - EXPECT_EQ(uidm.io_history_.count(300), 1UL); + EXPECT_EQ(io_history.size(), 2UL); + EXPECT_EQ(io_history.count(200), 1UL); + EXPECT_EQ(io_history.count(300), 1UL); - EXPECT_EQ(uidm.io_history_[200].entries.size(), 1UL); - EXPECT_EQ(uidm.io_history_[300].entries.size(), 1UL); + EXPECT_EQ(io_history[200].entries.size(), 1UL); + EXPECT_EQ(io_history[300].entries.size(), 1UL); uidm.clear_user_history(1); - EXPECT_EQ(uidm.io_history_.size(), 0UL); + EXPECT_EQ(io_history.size(), 0UL); } TEST(storaged_test, load_uid_io_proto) { uid_monitor uidm; + auto& io_history = uidm.io_history(); - uidm.io_history_[200] = { + static const uint64_t kProtoTime = 200; + io_history[kProtoTime] = { .start_ts = 100, .entries = { { "app1", { @@ -657,10 +659,28 @@ TEST(storaged_test, load_uid_io_proto) { ASSERT_EQ(protos.size(), size_t(1)); // Loading the same proto many times should not add duplicate entries. - const UidIOUsage& user_0 = protos[0].uid_io_usage(); + UidIOUsage user_0 = protos[0].uid_io_usage(); for (size_t i = 0; i < 10000; i++) { uidm.load_uid_io_proto(0, user_0); } - ASSERT_EQ(uidm.io_history_.size(), size_t(1)); - ASSERT_EQ(uidm.io_history_[200].entries.size(), size_t(3)); + ASSERT_EQ(io_history.size(), size_t(1)); + ASSERT_EQ(io_history[kProtoTime].entries.size(), size_t(3)); + + // Create duplicate entries until we go over the limit. + auto record = io_history[kProtoTime]; + io_history.clear(); + for (size_t i = 0; i < uid_monitor::MAX_UID_RECORDS_SIZE * 2; i++) { + if (i == kProtoTime) { + continue; + } + io_history[i] = record; + } + ASSERT_GT(io_history.size(), size_t(uid_monitor::MAX_UID_RECORDS_SIZE)); + + // After loading, the history should be truncated. + for (auto& item : *user_0.mutable_uid_io_items()) { + item.set_end_ts(io_history.size()); + } + uidm.load_uid_io_proto(0, user_0); + ASSERT_LE(io_history.size(), size_t(uid_monitor::MAX_UID_RECORDS_SIZE)); } From c30e0709bb2ce123a3aa33297ca57ce034811e6f Mon Sep 17 00:00:00 2001 From: Jae Shin Date: Wed, 25 Jul 2018 18:01:29 +0900 Subject: [PATCH 030/221] Build ld.config.txt for older VNDK versions Until now, the ld.config.$VER.txt for $VER older than PLATFORM_VNDK_VERSION was installed from a prebuilt stored under /prebuilts/vndk/v$VER. At runtime, the VNDK version needed by the vendor partition (ro.vndk.version) determines which ld.config.$VER.txt is loaded and this configuration is used for both system and vendor processes. In a system-only-upgrade scenario, where the system partition is a newer Android version than the vendor partition, this is a problem because the prebuilt linker config file will not reflect the most recent system partition related changes made in the newer Android version. To fix this problem, this change builds ld.config.$VER.txt for older VNDK versions from the source tree by getting the lists of VNDK libraries from the /prebuilts/vndk/v{VER} directory. Test: m -j ld.config.txt ld.config.28.txt ld.config.vndk_lite.txt Bug: 74658756 Change-Id: I1fa2469fc0bce2f2aab507104cd9717b6112d738 --- rootdir/Android.mk | 110 +++++++-------------- rootdir/update_and_install_ld_config.mk | 123 ++++++++++++++++++++++++ 2 files changed, 159 insertions(+), 74 deletions(-) create mode 100644 rootdir/update_and_install_ld_config.mk diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 3a6a5e8af..0312859e4 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -162,66 +162,6 @@ $(strip \ ) endef -# Update namespace configuration file with library lists and VNDK version -# -# $(1): Input source file (ld.config.txt) -# $(2): Output built module -# $(3): VNDK version suffix -# $(4): true if libz must be included in llndk not in vndk-sp -define update_and_install_ld_config -# If $(4) is true, move libz to llndk from vndk-sp. -$(if $(filter true,$(4)),\ - $(eval llndk_libraries_list := $(LLNDK_LIBRARIES) libz) \ - $(eval vndksp_libraries_list := $(filter-out libz,$(VNDK_SAMEPROCESS_LIBRARIES))),\ - $(eval llndk_libraries_list := $(LLNDK_LIBRARIES)) \ - $(eval vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES))) - -llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\ - $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(llndk_libraries_list)))) -private_llndk_libraries := $(call normalize-path-list,$(addsuffix .so,\ - $(filter $(VNDK_PRIVATE_LIBRARIES),$(llndk_libraries_list)))) -vndk_sameprocess_libraries := $(call normalize-path-list,$(addsuffix .so,\ - $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(vndksp_libraries_list)))) -vndk_core_libraries := $(call normalize-path-list,$(addsuffix .so,\ - $(filter-out $(VNDK_PRIVATE_LIBRARIES),$(VNDK_CORE_LIBRARIES)))) -sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\ - $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \ - $(UBSAN_RUNTIME_LIBRARY) \ - $(TSAN_RUNTIME_LIBRARY) \ - $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \ - $(2ND_UBSAN_RUNTIME_LIBRARY) \ - $(2ND_TSAN_RUNTIME_LIBRARY))) -# If BOARD_VNDK_VERSION is not defined, VNDK version suffix will not be used. -vndk_version_suffix := $(if $(strip $(3)),-$(strip $(3))) - -$(2): PRIVATE_LLNDK_LIBRARIES := $$(llndk_libraries) -$(2): PRIVATE_PRIVATE_LLNDK_LIBRARIES := $$(private_llndk_libraries) -$(2): PRIVATE_VNDK_SAMEPROCESS_LIBRARIES := $$(vndk_sameprocess_libraries) -$(2): PRIVATE_VNDK_CORE_LIBRARIES := $$(vndk_core_libraries) -$(2): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $$(sanitizer_runtime_libraries) -$(2): PRIVATE_VNDK_VERSION := $$(vndk_version_suffix) -$(2): $(1) - @echo "Generate: $$< -> $$@" - @mkdir -p $$(dir $$@) - $$(hide) sed -e 's?%LLNDK_LIBRARIES%?$$(PRIVATE_LLNDK_LIBRARIES)?g' $$< >$$@ - $$(hide) sed -i -e 's?%PRIVATE_LLNDK_LIBRARIES%?$$(PRIVATE_PRIVATE_LLNDK_LIBRARIES)?g' $$@ - $$(hide) sed -i -e 's?%VNDK_SAMEPROCESS_LIBRARIES%?$$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES)?g' $$@ - $$(hide) sed -i -e 's?%VNDK_CORE_LIBRARIES%?$$(PRIVATE_VNDK_CORE_LIBRARIES)?g' $$@ - $$(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $$@ - $$(hide) sed -i -e 's?%VNDK_VER%?$$(PRIVATE_VNDK_VERSION)?g' $$@ - $$(hide) sed -i -e 's?%PRODUCT%?$$(TARGET_COPY_OUT_PRODUCT)?g' $$@ - $$(hide) sed -i -e 's?%PRODUCTSERVICES%?$$(TARGET_COPY_OUT_PRODUCTSERVICES)?g' $$@ - -llndk_libraries_list := -vndksp_libraries_list := -llndk_libraries := -private_llndk_libraries := -vndk_sameprocess_libraries := -vndk_core_libraries := -sanitizer_runtime_libraries := -vndk_version_suffix := -endef # update_and_install_ld_config - ####################################### # ld.config.txt selection variables @@ -265,21 +205,19 @@ ifeq ($(_enforce_vndk_at_runtime),true) # for VNDK enforced devices LOCAL_MODULE_STEM := $(call append_vndk_version,$(LOCAL_MODULE)) include $(BUILD_SYSTEM)/base_rules.mk -$(eval $(call update_and_install_ld_config,\ - $(LOCAL_PATH)/etc/ld.config.txt,\ - $(LOCAL_BUILT_MODULE),\ - $(PLATFORM_VNDK_VERSION))) +ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt +vndk_version := $(PLATFORM_VNDK_VERSION) +include $(LOCAL_PATH)/update_and_install_ld_config.mk else ifeq ($(_enforce_vndk_lite_at_runtime),true) # for treblized but VNDK lightly enforced devices LOCAL_MODULE_STEM := ld.config.vndk_lite.txt include $(BUILD_SYSTEM)/base_rules.mk -$(eval $(call update_and_install_ld_config,\ - $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\ - $(LOCAL_BUILT_MODULE),\ - $(PLATFORM_VNDK_VERSION),\ - true)) +ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt +vndk_version := $(PLATFORM_VNDK_VERSION) +libz_is_llndk := true +include $(LOCAL_PATH)/update_and_install_ld_config.mk else @@ -290,6 +228,31 @@ include $(BUILD_PREBUILT) endif # ifeq ($(_enforce_vndk_at_runtime),true) +# ld.config.txt for VNDK versions older than PLATFORM_VNDK_VERSION +# are built with the VNDK libraries lists under /prebuilts/vndk. +# +# ld.config.$(VER).txt is built and installed for all VNDK versions +# listed in PRODUCT_EXTRA_VNDK_VERSIONS. +# +# $(1): VNDK version +define build_versioned_ld_config +include $(CLEAR_VARS) +LOCAL_MODULE := ld.config.$(1).txt +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +LOCAL_MODULE_STEM := $$(LOCAL_MODULE) +include $(BUILD_SYSTEM)/base_rules.mk +ld_config_template := $(LOCAL_PATH)/etc/ld.config.txt +vndk_version := $(1) +lib_list_from_prebuilts := true +include $(LOCAL_PATH)/update_and_install_ld_config.mk +endef + +# For VNDK snapshot versions prior to 28, ld.config.txt is installed from the +# prebuilt under /prebuilts/vndk +supported_vndk_snapshot_versions := 28 +$(eval $(foreach ver,$(supported_vndk_snapshot_versions),\ + $(call build_versioned_ld_config,$(ver)))) ####################################### # ld.config.vndk_lite.txt @@ -304,11 +267,10 @@ LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) LOCAL_MODULE_STEM := $(LOCAL_MODULE) include $(BUILD_SYSTEM)/base_rules.mk -$(eval $(call update_and_install_ld_config,\ - $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt,\ - $(LOCAL_BUILT_MODULE),\ - $(PLATFORM_VNDK_VERSION),\ - true)) +ld_config_template := $(LOCAL_PATH)/etc/ld.config.vndk_lite.txt +vndk_version := $(PLATFORM_VNDK_VERSION) +libz_is_llndk := true +include $(LOCAL_PATH)/update_and_install_ld_config.mk endif # ifeq ($(_enforce_vndk_lite_at_runtime),false) diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk new file mode 100644 index 000000000..06e04e7dd --- /dev/null +++ b/rootdir/update_and_install_ld_config.mk @@ -0,0 +1,123 @@ +##################################################################### +# Builds linker config file, ld.config.txt, from the specified template +# under $(LOCAL_PATH)/etc/*. +# +# Inputs: +# (expected to follow an include of $(BUILD_SYSTEM)/base_rules.mk) +# ld_config_template: template linker config file to use, +# e.g. $(LOCAL_PATH)/etc/ld.config.txt +# vndk_version: version of the VNDK library lists used to update the +# template linker config file, e.g. 28 +# lib_list_from_prebuilts: should be set to 'true' if the VNDK library +# lists should be read from /prebuilts/vndk/* +# libz_is_llndk: should be set to 'true' if libz must be included in +# llndk and not in vndk-sp +# Outputs: +# Builds and installs ld.config.$VER.txt or ld.config.vndk_lite.txt +##################################################################### + +# Read inputs +ld_config_template := $(strip $(ld_config_template)) +vndk_version := $(strip $(vndk_version)) +lib_list_from_prebuilts := $(strip $(lib_list_from_prebuilts)) +libz_is_llndk := $(strip $(libz_is_llndk)) + +intermediates_dir := $(call intermediates-dir-for,ETC,$(LOCAL_MODULE)) +library_lists_dir := $(intermediates_dir) +ifeq ($(lib_list_from_prebuilts),true) + library_lists_dir := prebuilts/vndk/v$(vndk_version)/$(TARGET_ARCH)/configs +endif + +llndk_libraries_file := $(library_lists_dir)/llndk.libraries.$(vndk_version).txt +vndksp_libraries_file := $(library_lists_dir)/vndksp.libraries.$(vndk_version).txt +vndkcore_libraries_file := $(library_lists_dir)/vndkcore.libraries.txt +vndkprivate_libraries_file := $(library_lists_dir)/vndkprivate.libraries.txt + +sanitizer_runtime_libraries := $(call normalize-path-list,$(addsuffix .so,\ + $(ADDRESS_SANITIZER_RUNTIME_LIBRARY) \ + $(UBSAN_RUNTIME_LIBRARY) \ + $(TSAN_RUNTIME_LIBRARY) \ + $(2ND_ADDRESS_SANITIZER_RUNTIME_LIBRARY) \ + $(2ND_UBSAN_RUNTIME_LIBRARY) \ + $(2ND_TSAN_RUNTIME_LIBRARY))) +# If BOARD_VNDK_VERSION is not defined, VNDK version suffix will not be used. +vndk_version_suffix := $(if $(vndk_version),-$(vndk_version)) + +ifneq ($(lib_list_from_prebuilts),true) +ifeq ($(libz_is_llndk),true) + llndk_libraries_list := $(LLNDK_LIBRARIES) libz + vndksp_libraries_list := $(filter-out libz,$(VNDK_SAMEPROCESS_LIBRARIES)) +else + llndk_libraries_list := $(LLNDK_LIBRARIES) + vndksp_libraries_list := $(VNDK_SAMEPROCESS_LIBRARIES) +endif + +# $(1): list of libraries +# $(2): output file to write the list of libraries to +define write-libs-to-file +$(2): PRIVATE_LIBRARIES := $(1) +$(2): + echo -n > $$@ && $$(foreach lib,$$(PRIVATE_LIBRARIES),echo $$(lib).so >> $$@;) +endef +$(eval $(call write-libs-to-file,$(llndk_libraries_list),$(llndk_libraries_file))) +$(eval $(call write-libs-to-file,$(vndksp_libraries_list),$(vndksp_libraries_file))) +$(eval $(call write-libs-to-file,$(VNDK_CORE_LIBRARIES),$(vndkcore_libraries_file))) +$(eval $(call write-libs-to-file,$(VNDK_PRIVATE_LIBRARIES),$(vndkprivate_libraries_file))) +endif # ifneq ($(lib_list_from_prebuilts),true) + +# Given a file with a list of libs, filter-out the VNDK private libraries +# and write resulting list to a new file in "a:b:c" format +# +# $(1): libs file from which to filter-out VNDK private libraries +# $(2): output file with the filtered list of lib names +$(LOCAL_BUILT_MODULE): private-filter-out-private-libs = \ + paste -sd ":" $(1) > $(2) && \ + cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | xargs -n 1 -I privatelib bash -c "sed -i 's/privatelib//' $(2)" && \ + sed -i -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(2) +$(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES_FILE := $(llndk_libraries_file) +$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SP_LIBRARIES_FILE := $(vndksp_libraries_file) +$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES_FILE := $(vndkcore_libraries_file) +$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE := $(vndkprivate_libraries_file) +$(LOCAL_BUILT_MODULE): PRIVATE_SANITIZER_RUNTIME_LIBRARIES := $(sanitizer_runtime_libraries) +$(LOCAL_BUILT_MODULE): PRIVATE_VNDK_VERSION_SUFFIX := $(vndk_version_suffix) +$(LOCAL_BUILT_MODULE): PRIVATE_INTERMEDIATES_DIR := $(intermediates_dir) +deps := $(llndk_libraries_file) $(vndksp_libraries_file) $(vndkcore_libraries_file) \ + $(vndkprivate_libraries_file) + +$(LOCAL_BUILT_MODULE): $(ld_config_template) $(deps) + @echo "Generate: $< -> $@" + @mkdir -p $(dir $@) + $(call private-filter-out-private-libs,$(PRIVATE_LLNDK_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered) + $(hide) sed -e "s?%LLNDK_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)?g" $< >$@ + $(call private-filter-out-private-libs,$(PRIVATE_VNDK_SP_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered) + $(hide) sed -i -e "s?%VNDK_SAMEPROCESS_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)?g" $@ + $(call private-filter-out-private-libs,$(PRIVATE_VNDK_CORE_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered) + $(hide) sed -i -e "s?%VNDK_CORE_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)?g" $@ + + $(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \ + cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | \ + xargs -n 1 -I privatelib bash -c "(grep privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk" && \ + paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \ + sed -i -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@ + + $(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@ + $(hide) sed -i -e 's?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g' $@ + $(hide) sed -i -e 's?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g' $@ + $(hide) sed -i -e 's?%PRODUCTSERVICES%?$(TARGET_COPY_OUT_PRODUCTSERVICES)?g' $@ + +ld_config_template := +vndk_version := +lib_list_from_prebuilts := +libz_is_llndk := +intermediates_dir := +library_lists_dir := +llndk_libraries_file := +vndksp_libraries_file := +vndkcore_libraries_file := +vndkprivate_libraries_file := +deps := +sanitizer_runtime_libraries := +vndk_version_suffix := +llndk_libraries_list := +vndksp_libraries_list := +write-libs-to-file := From 6009d874aa430d1fc8eb632e78e91052e5793b96 Mon Sep 17 00:00:00 2001 From: Justin Yun Date: Sat, 11 Aug 2018 08:23:49 +0900 Subject: [PATCH 031/221] Add '.bak' for sed -i that is required by BSD sed BSD version of sed requires a parameter for '-i' option. Add '.bak' for back up and remove the back up file at the end of the sed command Bug: 112478836 Test: checkbuild on a mac machine Change-Id: Iedc93c2b5239004d2bbb8011488041c54b29996b --- rootdir/update_and_install_ld_config.mk | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/rootdir/update_and_install_ld_config.mk b/rootdir/update_and_install_ld_config.mk index 06e04e7dd..1b42c3205 100644 --- a/rootdir/update_and_install_ld_config.mk +++ b/rootdir/update_and_install_ld_config.mk @@ -72,8 +72,9 @@ endif # ifneq ($(lib_list_from_prebuilts),true) # $(2): output file with the filtered list of lib names $(LOCAL_BUILT_MODULE): private-filter-out-private-libs = \ paste -sd ":" $(1) > $(2) && \ - cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | xargs -n 1 -I privatelib bash -c "sed -i 's/privatelib//' $(2)" && \ - sed -i -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(2) + cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | xargs -n 1 -I privatelib bash -c "sed -i.bak 's/privatelib//' $(2)" && \ + sed -i.bak -e 's/::\+/:/g ; s/^:\+// ; s/:\+$$//' $(2) && \ + rm -f $(2).bak $(LOCAL_BUILT_MODULE): PRIVATE_LLNDK_LIBRARIES_FILE := $(llndk_libraries_file) $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_SP_LIBRARIES_FILE := $(vndksp_libraries_file) $(LOCAL_BUILT_MODULE): PRIVATE_VNDK_CORE_LIBRARIES_FILE := $(vndkcore_libraries_file) @@ -90,20 +91,21 @@ $(LOCAL_BUILT_MODULE): $(ld_config_template) $(deps) $(call private-filter-out-private-libs,$(PRIVATE_LLNDK_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered) $(hide) sed -e "s?%LLNDK_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/llndk_filtered)?g" $< >$@ $(call private-filter-out-private-libs,$(PRIVATE_VNDK_SP_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered) - $(hide) sed -i -e "s?%VNDK_SAMEPROCESS_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)?g" $@ + $(hide) sed -i.bak -e "s?%VNDK_SAMEPROCESS_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndksp_filtered)?g" $@ $(call private-filter-out-private-libs,$(PRIVATE_VNDK_CORE_LIBRARIES_FILE),$(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered) - $(hide) sed -i -e "s?%VNDK_CORE_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)?g" $@ + $(hide) sed -i.bak -e "s?%VNDK_CORE_LIBRARIES%?$$(cat $(PRIVATE_INTERMEDIATES_DIR)/vndkcore_filtered)?g" $@ $(hide) echo -n > $(PRIVATE_INTERMEDIATES_DIR)/private_llndk && \ cat $(PRIVATE_VNDK_PRIVATE_LIBRARIES_FILE) | \ xargs -n 1 -I privatelib bash -c "(grep privatelib $(PRIVATE_LLNDK_LIBRARIES_FILE) || true) >> $(PRIVATE_INTERMEDIATES_DIR)/private_llndk" && \ paste -sd ":" $(PRIVATE_INTERMEDIATES_DIR)/private_llndk | \ - sed -i -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@ + sed -i.bak -e "s?%PRIVATE_LLNDK_LIBRARIES%?$$(cat -)?g" $@ - $(hide) sed -i -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@ - $(hide) sed -i -e 's?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g' $@ - $(hide) sed -i -e 's?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g' $@ - $(hide) sed -i -e 's?%PRODUCTSERVICES%?$(TARGET_COPY_OUT_PRODUCTSERVICES)?g' $@ + $(hide) sed -i.bak -e 's?%SANITIZER_RUNTIME_LIBRARIES%?$(PRIVATE_SANITIZER_RUNTIME_LIBRARIES)?g' $@ + $(hide) sed -i.bak -e 's?%VNDK_VER%?$(PRIVATE_VNDK_VERSION_SUFFIX)?g' $@ + $(hide) sed -i.bak -e 's?%PRODUCT%?$(TARGET_COPY_OUT_PRODUCT)?g' $@ + $(hide) sed -i.bak -e 's?%PRODUCTSERVICES%?$(TARGET_COPY_OUT_PRODUCTSERVICES)?g' $@ + $(hide) rm -f $@.bak ld_config_template := vndk_version := From baeaaf94296cf3d6202362eb1ea46c8acdf8955a Mon Sep 17 00:00:00 2001 From: Jae Shin Date: Fri, 10 Aug 2018 15:49:17 +0900 Subject: [PATCH 032/221] Parse the list of supported vndk snapshot versions This allows the target, ld.config.$VER.txt, to be defined for all $VERs for which a VNDK snapshot exists under /prebuilts/vndk/v$VER. With this fix, 1) supported_vndk_snaphsot_versions do not need to be manually updated everytime a new VNDK snapshot is added and, 2) ld.config.$VER.txt will not be ill-defined in a tree that does not have the required dependency files under /prebuilts/vndk/v$VER. Test: m -j ld.config.28.txt Bug: 74658756 Change-Id: Idb056c21412d4cb7c7a7cb3c247b1d82a4a759ff --- rootdir/Android.mk | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 0312859e4..2429b490b 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -250,10 +250,16 @@ endef # For VNDK snapshot versions prior to 28, ld.config.txt is installed from the # prebuilt under /prebuilts/vndk -supported_vndk_snapshot_versions := 28 +vndk_snapshots := $(wildcard prebuilts/vndk/*) +supported_vndk_snapshot_versions := \ + $(strip $(foreach ver,$(patsubst prebuilts/vndk/v%,%,$(vndk_snapshots)),\ + $(if $(call math_gt_or_eq,$(ver),28),$(ver),))) $(eval $(foreach ver,$(supported_vndk_snapshot_versions),\ $(call build_versioned_ld_config,$(ver)))) +vndk_snapshots := +supported_vndk_snapshot_versions := + ####################################### # ld.config.vndk_lite.txt # From 69071b9143c5447d12996c0b9fb5b931a9c6c4ca Mon Sep 17 00:00:00 2001 From: Dario Freni Date: Fri, 17 Aug 2018 01:01:25 +0100 Subject: [PATCH 033/221] s/product-services/product_services/g Attempting to reduce the number of different spellings we have for "product services" partition in the codebase. Bug: 112431447 Test: m Change-Id: I1a87d7e040a8b1f91f973ac7d90d6360b5b54f71 --- fastboot/fastboot.cpp | 6 +++--- init/init.cpp | 4 ++-- init/property_service.cpp | 2 +- libcutils/fs_config.cpp | 2 +- rootdir/Android.mk | 4 ++-- rootdir/etc/ld.config.txt | 4 ++-- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index dc94952ba..db6d5d657 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -122,9 +122,9 @@ static struct { { "dts", "dt.img", "dt.sig", "dts", true, false }, { "odm", "odm.img", "odm.sig", "odm", true, false }, { "product", "product.img", "product.sig", "product", true, false }, - { "product-services", - "product-services.img", - "product-services.sig", + { "product_services", + "product_services.img", + "product_services.sig", "product_services", true, true }, { "recovery", "recovery.img", "recovery.sig", "recovery", true, false }, diff --git a/init/init.cpp b/init/init.cpp index b550f1b74..16564f459 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -114,8 +114,8 @@ static void LoadBootScripts(ActionManager& action_manager, ServiceList& service_ if (!parser.ParseConfig("/product/etc/init")) { late_import_paths.emplace_back("/product/etc/init"); } - if (!parser.ParseConfig("/product-services/etc/init")) { - late_import_paths.emplace_back("/product-services/etc/init"); + if (!parser.ParseConfig("/product_services/etc/init")) { + late_import_paths.emplace_back("/product_services/etc/init"); } if (!parser.ParseConfig("/odm/etc/init")) { late_import_paths.emplace_back("/odm/etc/init"); diff --git a/init/property_service.cpp b/init/property_service.cpp index cd2f630ca..5c8b92a34 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -692,7 +692,7 @@ void property_load_boot_defaults() { } } load_properties_from_file("/product/build.prop", NULL); - load_properties_from_file("/product-services/build.prop", NULL); + load_properties_from_file("/product_services/build.prop", NULL); load_properties_from_file("/odm/default.prop", NULL); load_properties_from_file("/vendor/default.prop", NULL); diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index af8f0a2f2..bd5f26fe9 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -149,7 +149,7 @@ static const struct fs_path_config android_files[] = { { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_dir + 1 }, { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_file + 1 }, { 00600, AID_ROOT, AID_ROOT, 0, "product/build.prop" }, - { 00600, AID_ROOT, AID_ROOT, 0, "product-services/build.prop" }, + { 00600, AID_ROOT, AID_ROOT, 0, "product_services/build.prop" }, { 00750, AID_ROOT, AID_SHELL, 0, "sbin/fs_mgr" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump32" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/bin/crash_dump64" }, diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 2429b490b..fcc2d5011 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -94,9 +94,9 @@ else LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product $(TARGET_ROOT_OUT)/product endif ifdef BOARD_USES_PRODUCT_SERVICESIMAGE - LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/product-services + LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/product_services else - LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product-services $(TARGET_ROOT_OUT)/product-services + LOCAL_POST_INSTALL_CMD += ; ln -sf /system/product_services $(TARGET_ROOT_OUT)/product_services endif ifdef BOARD_USES_METADATA_PARTITION LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/metadata diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt index 7d22a3acc..c336115b0 100644 --- a/rootdir/etc/ld.config.txt +++ b/rootdir/etc/ld.config.txt @@ -79,8 +79,8 @@ namespace.default.asan.search.paths = /data/asan/system/${LIB} namespace.default.asan.search.paths += /system/${LIB} namespace.default.asan.search.paths += /data/asan/product/${LIB} namespace.default.asan.search.paths += /product/${LIB} -namespace.default.asan.search.paths += /data/asan/product-services/${LIB} -namespace.default.asan.search.paths += /product-services/${LIB} +namespace.default.asan.search.paths += /data/asan/product_services/${LIB} +namespace.default.asan.search.paths += /product_services/${LIB} namespace.default.asan.permitted.paths = /data namespace.default.asan.permitted.paths += /system/${LIB}/drm From ad3a40bf76b670878760738765154448772243fb Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Mon, 20 Aug 2018 16:15:33 -0700 Subject: [PATCH 034/221] Add a function to allow statslog caller to log a log failure. + Record all types of failures which lead to log loss + Only record eventual failure after the retries to get a accurate log loss count. Bug: 80538532 Test: manually tested Change-Id: I23a55e62e140bf22ae5aa9e6c40539d51149cd66 --- libstats/include/stats_event_list.h | 1 + libstats/stats_event_list.c | 4 ++++ libstats/statsd_writer.c | 22 +++++++++++++--------- libstats/statsd_writer.h | 2 ++ 4 files changed, 20 insertions(+), 9 deletions(-) diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h index 5d174ae03..28da27072 100644 --- a/libstats/include/stats_event_list.h +++ b/libstats/include/stats_event_list.h @@ -24,6 +24,7 @@ extern "C" { #endif void reset_log_context(android_log_context ctx); int write_to_logger(android_log_context context, log_id_t id); +void note_log_drop(); #ifdef __cplusplus } diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c index 3d746db18..51408e071 100644 --- a/libstats/stats_event_list.c +++ b/libstats/stats_event_list.c @@ -119,6 +119,10 @@ int write_to_logger(android_log_context ctx, log_id_t id) { return retValue; } +void note_log_drop() { + statsdLoggerWrite.noteDrop(); +} + /* log_init_lock assumed */ static int __write_to_statsd_initialize_locked() { if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) { diff --git a/libstats/statsd_writer.c b/libstats/statsd_writer.c index 9953bba2e..afe401f5c 100644 --- a/libstats/statsd_writer.c +++ b/libstats/statsd_writer.c @@ -38,6 +38,7 @@ #define min(x, y) ((y) ^ (((x) ^ (y)) & -((x) < (y)))) static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; +static atomic_int dropped = 0; void statsd_writer_init_lock() { /* @@ -59,14 +60,16 @@ static int statsdAvailable(); static int statsdOpen(); static void statsdClose(); static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr); +static void statsdNoteDrop(); struct android_log_transport_write statsdLoggerWrite = { - .name = "statsd", - .sock = -EBADF, - .available = statsdAvailable, - .open = statsdOpen, - .close = statsdClose, - .write = statsdWrite, + .name = "statsd", + .sock = -EBADF, + .available = statsdAvailable, + .open = statsdOpen, + .close = statsdClose, + .write = statsdWrite, + .noteDrop = statsdNoteDrop, }; /* log_init_lock assumed */ @@ -131,6 +134,10 @@ static int statsdAvailable() { return 1; } +static void statsdNoteDrop() { + atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed); +} + static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { ssize_t ret; int sock; @@ -138,7 +145,6 @@ static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { struct iovec newVec[nr + headerLength]; android_log_header_t header; size_t i, payloadSize; - static atomic_int dropped; sock = atomic_load(&statsdLoggerWrite.sock); if (sock < 0) switch (sock) { @@ -252,8 +258,6 @@ static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { if (ret > (ssize_t)sizeof(header)) { ret -= sizeof(header); - } else if (ret == -EAGAIN) { - atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed); } return ret; diff --git a/libstats/statsd_writer.h b/libstats/statsd_writer.h index 82e14e04f..728944153 100644 --- a/libstats/statsd_writer.h +++ b/libstats/statsd_writer.h @@ -38,6 +38,8 @@ struct android_log_transport_write { void (*close)(); /* free up resources */ /* write log to transport, returns number of bytes propagated, or -errno */ int (*write)(struct timespec* ts, struct iovec* vec, size_t nr); + /* note one log drop */ + void (*noteDrop)(); }; #endif // ANDROID_STATS_LOG_STATS_WRITER_H From fbeb8e8c46da4b6f378a04b4d3848b4d052e3383 Mon Sep 17 00:00:00 2001 From: Steven Moreland Date: Wed, 29 Aug 2018 21:44:35 -0700 Subject: [PATCH 035/221] Add libbinder_ndk to public.libraries.* Bug: 111445392 Test: atest android.binder.cts.NdkBinderTest Change-Id: I8ccb1f74654dcb925cd3ac20042cbffd2f594bb9 (cherry picked from commit fd0dad6825c09b8cc043fd54f679f7782fbf2c26) --- rootdir/etc/public.libraries.android.txt | 1 + rootdir/etc/public.libraries.iot.txt | 1 + rootdir/etc/public.libraries.wear.txt | 1 + 3 files changed, 3 insertions(+) diff --git a/rootdir/etc/public.libraries.android.txt b/rootdir/etc/public.libraries.android.txt index 2a51d5360..27e855fb7 100644 --- a/rootdir/etc/public.libraries.android.txt +++ b/rootdir/etc/public.libraries.android.txt @@ -2,6 +2,7 @@ libandroid.so libaaudio.so libamidi.so +libbinder_ndk.so libc.so libcamera2ndk.so libdl.so diff --git a/rootdir/etc/public.libraries.iot.txt b/rootdir/etc/public.libraries.iot.txt index 669077049..b56534070 100644 --- a/rootdir/etc/public.libraries.iot.txt +++ b/rootdir/etc/public.libraries.iot.txt @@ -3,6 +3,7 @@ libandroid.so libandroidthings.so libaaudio.so libamidi.so +libbinder_ndk.so libc.so libcamera2ndk.so libdl.so diff --git a/rootdir/etc/public.libraries.wear.txt b/rootdir/etc/public.libraries.wear.txt index 56055baad..7cbda0812 100644 --- a/rootdir/etc/public.libraries.wear.txt +++ b/rootdir/etc/public.libraries.wear.txt @@ -2,6 +2,7 @@ libandroid.so libaaudio.so libamidi.so +libbinder_ndk.so libc.so libcamera2ndk.so libdl.so From 993b4edb0f33ac4f46cd4da932ba5fb033c06328 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Fri, 14 Sep 2018 13:58:21 -0700 Subject: [PATCH 036/221] Pass OEM commands to HAL Bug: 78793464 Bug: 79480454 Test: fastboot oem command Change-Id: Ibaabef6ea725857102f7531997fcff2a1dbdc1ca --- fastboot/constants.h | 1 + fastboot/device/commands.cpp | 21 +++++++++++++++++++++ fastboot/device/commands.h | 1 + fastboot/device/fastboot_device.cpp | 17 ++++++++++++++--- 4 files changed, 37 insertions(+), 3 deletions(-) diff --git a/fastboot/constants.h b/fastboot/constants.h index 57e25fc59..2a68a2b03 100644 --- a/fastboot/constants.h +++ b/fastboot/constants.h @@ -32,6 +32,7 @@ #define FB_CMD_DELETE_PARTITION "delete-logical-partition" #define FB_CMD_RESIZE_PARTITION "resize-logical-partition" #define FB_CMD_UPDATE_SUPER "update-super" +#define FB_CMD_OEM "oem" #define RESPONSE_OKAY "OKAY" #define RESPONSE_FAIL "FAIL" diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index 0ec09945b..48c935a73 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -40,6 +40,9 @@ using ::android::hardware::hidl_string; using ::android::hardware::boot::V1_0::BoolResult; using ::android::hardware::boot::V1_0::CommandResult; using ::android::hardware::boot::V1_0::Slot; +using ::android::hardware::fastboot::V1_0::Result; +using ::android::hardware::fastboot::V1_0::Status; + using namespace android::fs_mgr; struct VariableHandlers { @@ -133,6 +136,24 @@ bool EraseHandler(FastbootDevice* device, const std::vector& args) return device->WriteStatus(FastbootResult::FAIL, "Erasing failed"); } +bool OemCmdHandler(FastbootDevice* device, const std::vector& args) { + auto fastboot_hal = device->fastboot_hal(); + if (!fastboot_hal) { + return device->WriteStatus(FastbootResult::FAIL, "Unable to open fastboot HAL"); + } + + Result ret; + auto ret_val = fastboot_hal->doOemCommand(args[0], [&](Result result) { ret = result; }); + if (!ret_val.isOk()) { + return device->WriteStatus(FastbootResult::FAIL, "Unable to do OEM command"); + } + if (ret.status != Status::SUCCESS) { + return device->WriteStatus(FastbootResult::FAIL, ret.message); + } + + return device->WriteStatus(FastbootResult::OKAY, ret.message); +} + bool DownloadHandler(FastbootDevice* device, const std::vector& args) { if (args.size() < 2) { return device->WriteStatus(FastbootResult::FAIL, "size argument unspecified"); diff --git a/fastboot/device/commands.h b/fastboot/device/commands.h index 4778d2350..9df43a90c 100644 --- a/fastboot/device/commands.h +++ b/fastboot/device/commands.h @@ -45,3 +45,4 @@ bool CreatePartitionHandler(FastbootDevice* device, const std::vector& args); bool ResizePartitionHandler(FastbootDevice* device, const std::vector& args); bool UpdateSuperHandler(FastbootDevice* device, const std::vector& args); +bool OemCmdHandler(FastbootDevice* device, const std::vector& args); diff --git a/fastboot/device/fastboot_device.cpp b/fastboot/device/fastboot_device.cpp index ae2e7a607..6862741b6 100644 --- a/fastboot/device/fastboot_device.cpp +++ b/fastboot/device/fastboot_device.cpp @@ -48,6 +48,7 @@ FastbootDevice::FastbootDevice() {FB_CMD_DELETE_PARTITION, DeletePartitionHandler}, {FB_CMD_RESIZE_PARTITION, ResizePartitionHandler}, {FB_CMD_UPDATE_SUPER, UpdateSuperHandler}, + {FB_CMD_OEM, OemCmdHandler}, }), transport_(std::make_unique()), boot_control_hal_(IBootControl::getService()), @@ -120,10 +121,20 @@ void FastbootDevice::ExecuteCommands() { command[bytes_read] = '\0'; LOG(INFO) << "Fastboot command: " << command; - auto args = android::base::Split(command, ":"); - auto found_command = kCommandMap.find(args[0]); + + std::vector args; + std::string cmd_name; + if (android::base::StartsWith(command, "oem ")) { + args = {command}; + cmd_name = "oem"; + } else { + args = android::base::Split(command, ":"); + cmd_name = args[0]; + } + + auto found_command = kCommandMap.find(cmd_name); if (found_command == kCommandMap.end()) { - WriteStatus(FastbootResult::FAIL, "Unrecognized command"); + WriteStatus(FastbootResult::FAIL, "Unrecognized command " + args[0]); continue; } if (!found_command->second(this, args)) { From 4785287a0043ddea2f784433d8a4fc8a168efc79 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Wed, 26 Sep 2018 13:08:16 -0700 Subject: [PATCH 037/221] Support fastboot variable 'variant'. Bug: 79480454 Bug: 78793464 Test: fastboot getvar variant Change-Id: Iefef82c147d8405318c793ad0a73f00674bbb63d --- fastboot/constants.h | 1 + fastboot/device/commands.cpp | 1 + fastboot/device/variables.cpp | 21 +++++++++++++++++++++ fastboot/device/variables.h | 1 + 4 files changed, 24 insertions(+) diff --git a/fastboot/constants.h b/fastboot/constants.h index 2a68a2b03..ad2e1a173 100644 --- a/fastboot/constants.h +++ b/fastboot/constants.h @@ -60,3 +60,4 @@ #define FB_VAR_IS_LOGICAL "is-logical" #define FB_VAR_IS_USERSPACE "is-userspace" #define FB_VAR_HW_REVISION "hw-revision" +#define FB_VAR_VARIANT "variant" diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index 48c935a73..f69f06bc5 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -82,6 +82,7 @@ bool GetVarHandler(FastbootDevice* device, const std::vector& args) {FB_VAR_VERSION_BASEBAND, {GetBasebandVersion, nullptr}}, {FB_VAR_PRODUCT, {GetProduct, nullptr}}, {FB_VAR_SERIALNO, {GetSerial, nullptr}}, + {FB_VAR_VARIANT, {GetVariant, nullptr}}, {FB_VAR_SECURE, {GetSecure, nullptr}}, {FB_VAR_UNLOCKED, {GetUnlocked, nullptr}}, {FB_VAR_MAX_DOWNLOAD_SIZE, {GetMaxDownloadSize, nullptr}}, diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp index 75352489e..9fcabb76c 100644 --- a/fastboot/device/variables.cpp +++ b/fastboot/device/variables.cpp @@ -74,6 +74,27 @@ bool GetSecure(FastbootDevice* /* device */, const std::vector& /* return true; } +bool GetVariant(FastbootDevice* device, const std::vector& /* args */, + std::string* message) { + auto fastboot_hal = device->fastboot_hal(); + if (!fastboot_hal) { + *message = "Fastboot HAL not found"; + return false; + } + + Result ret; + auto ret_val = fastboot_hal->getVariant([&](std::string device_variant, Result result) { + *message = device_variant; + ret = result; + }); + if (!ret_val.isOk() || ret.status != Status::SUCCESS) { + *message = "Unable to get device variant"; + return false; + } + + return true; +} + bool GetCurrentSlot(FastbootDevice* device, const std::vector& /* args */, std::string* message) { std::string suffix = device->GetCurrentSlot(); diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h index 63f267024..0546942a8 100644 --- a/fastboot/device/variables.h +++ b/fastboot/device/variables.h @@ -52,6 +52,7 @@ bool GetIsUserspace(FastbootDevice* device, const std::vector& args std::string* message); bool GetHardwareRevision(FastbootDevice* device, const std::vector& args, std::string* message); +bool GetVariant(FastbootDevice* device, const std::vector& args, std::string* message); // Helpers for getvar all. std::vector> GetAllPartitionArgsWithSlot(FastbootDevice* device); From b05d278696cbb25e14085362651999204aa51b40 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Thu, 27 Sep 2018 10:41:01 -0700 Subject: [PATCH 038/221] Add support to read fastboot variable 'off-mode-charge' Bug: 78793464 Bug: 79480454 Test: fastboot getvar off-mode-charge Change-Id: I4c40847be292e8e2e420340f81bb624b247bc11b --- fastboot/constants.h | 1 + fastboot/device/commands.cpp | 1 + fastboot/device/variables.cpp | 22 ++++++++++++++++++++++ fastboot/device/variables.h | 2 ++ 4 files changed, 26 insertions(+) diff --git a/fastboot/constants.h b/fastboot/constants.h index ad2e1a173..c11d9defa 100644 --- a/fastboot/constants.h +++ b/fastboot/constants.h @@ -61,3 +61,4 @@ #define FB_VAR_IS_USERSPACE "is-userspace" #define FB_VAR_HW_REVISION "hw-revision" #define FB_VAR_VARIANT "variant" +#define FB_VAR_OFF_MODE_CHARGE_STATE "off-mode-charge" diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index e70de1b6d..4fa114821 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -95,6 +95,7 @@ bool GetVarHandler(FastbootDevice* device, const std::vector& args) {FB_VAR_PARTITION_TYPE, {GetPartitionType, GetAllPartitionArgsWithSlot}}, {FB_VAR_IS_LOGICAL, {GetPartitionIsLogical, GetAllPartitionArgsWithSlot}}, {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}}, + {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}}, {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}}}; if (args.size() < 2) { diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp index 77cd4bc25..bcf13a540 100644 --- a/fastboot/device/variables.cpp +++ b/fastboot/device/variables.cpp @@ -95,6 +95,28 @@ bool GetVariant(FastbootDevice* device, const std::vector& /* args return true; } +bool GetOffModeChargeState(FastbootDevice* device, const std::vector& /* args */, + std::string* message) { + auto fastboot_hal = device->fastboot_hal(); + if (!fastboot_hal) { + *message = "Fastboot HAL not found"; + return false; + } + + Result ret; + auto ret_val = + fastboot_hal->getOffModeChargeState([&](bool off_mode_charging_state, Result result) { + *message = off_mode_charging_state ? "1" : "0"; + ret = result; + }); + if (!ret_val.isOk() || (ret.status != Status::SUCCESS)) { + *message = "Unable to get off mode charge state"; + return false; + } + + return true; +} + bool GetCurrentSlot(FastbootDevice* device, const std::vector& /* args */, std::string* message) { std::string suffix = device->GetCurrentSlot(); diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h index 0546942a8..b06881ead 100644 --- a/fastboot/device/variables.h +++ b/fastboot/device/variables.h @@ -53,6 +53,8 @@ bool GetIsUserspace(FastbootDevice* device, const std::vector& args bool GetHardwareRevision(FastbootDevice* device, const std::vector& args, std::string* message); bool GetVariant(FastbootDevice* device, const std::vector& args, std::string* message); +bool GetOffModeChargeState(FastbootDevice* device, const std::vector& args, + std::string* message); // Helpers for getvar all. std::vector> GetAllPartitionArgsWithSlot(FastbootDevice* device); From 5b63e2704a3d0dd23ff3ef9900639d5bb51aca61 Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Tue, 2 Oct 2018 10:51:49 -0700 Subject: [PATCH 039/221] Add an API to release stats logger resources. Test: tested with ag/5112579 Change-Id: I271b7574beab1baa9886d31bc1cf25c40c2fae23 --- libstats/include/stats_event_list.h | 1 + libstats/stats_event_list.c | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h index 28da27072..a9832db29 100644 --- a/libstats/include/stats_event_list.h +++ b/libstats/include/stats_event_list.h @@ -25,6 +25,7 @@ extern "C" { void reset_log_context(android_log_context ctx); int write_to_logger(android_log_context context, log_id_t id); void note_log_drop(); +void stats_log_close(); #ifdef __cplusplus } diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c index 51408e071..735088a37 100644 --- a/libstats/stats_event_list.c +++ b/libstats/stats_event_list.c @@ -123,6 +123,14 @@ void note_log_drop() { statsdLoggerWrite.noteDrop(); } +void stats_log_close() { + statsd_writer_init_lock(); + if (statsdLoggerWrite.close) { + (*statsdLoggerWrite.close)(); + } + statsd_writer_init_unlock(); +} + /* log_init_lock assumed */ static int __write_to_statsd_initialize_locked() { if (!statsdLoggerWrite.open || ((*statsdLoggerWrite.open)() < 0)) { From 9a1203b7acf7cf3a09ccec022c4698c994143bbd Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Wed, 3 Oct 2018 15:53:22 -0700 Subject: [PATCH 040/221] Support fastboot variable battery-soc-ok Bug: 79480454 Test: fastboot getvar battery-soc-ok Change-Id: Icfd70a71f1598e437316d4b8f895fd851516febb --- fastboot/constants.h | 1 + fastboot/device/commands.cpp | 1 + fastboot/device/variables.cpp | 75 ++++++++++++++++++++++++++--------- fastboot/device/variables.h | 3 ++ 4 files changed, 61 insertions(+), 19 deletions(-) diff --git a/fastboot/constants.h b/fastboot/constants.h index 2eaf00687..705da333b 100644 --- a/fastboot/constants.h +++ b/fastboot/constants.h @@ -63,3 +63,4 @@ #define FB_VAR_VARIANT "variant" #define FB_VAR_OFF_MODE_CHARGE_STATE "off-mode-charge" #define FB_VAR_BATTERY_VOLTAGE "battery-voltage" +#define FB_VAR_BATTERY_SOC_OK "battery-soc-ok" diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index b02d968c5..51585b3c2 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -97,6 +97,7 @@ bool GetVarHandler(FastbootDevice* device, const std::vector& args) {FB_VAR_IS_USERSPACE, {GetIsUserspace, nullptr}}, {FB_VAR_OFF_MODE_CHARGE_STATE, {GetOffModeChargeState, nullptr}}, {FB_VAR_BATTERY_VOLTAGE, {GetBatteryVoltage, nullptr}}, + {FB_VAR_BATTERY_SOC_OK, {GetBatterySoCOk, nullptr}}, {FB_VAR_HW_REVISION, {GetHardwareRevision, nullptr}}}; if (args.size() < 2) { diff --git a/fastboot/device/variables.cpp b/fastboot/device/variables.cpp index 01415d72b..2de79b18d 100644 --- a/fastboot/device/variables.cpp +++ b/fastboot/device/variables.cpp @@ -96,6 +96,56 @@ bool GetVariant(FastbootDevice* device, const std::vector& /* args return true; } +bool GetBatteryVoltageHelper(FastbootDevice* device, int32_t* battery_voltage) { + using android::hardware::health::V2_0::HealthInfo; + using android::hardware::health::V2_0::Result; + + auto health_hal = device->health_hal(); + if (!health_hal) { + return false; + } + + Result ret; + auto ret_val = health_hal->getHealthInfo([&](Result result, HealthInfo info) { + *battery_voltage = info.legacy.batteryVoltage; + ret = result; + }); + if (!ret_val.isOk() || (ret != Result::SUCCESS)) { + return false; + } + + return true; +} + +bool GetBatterySoCOk(FastbootDevice* device, const std::vector& /* args */, + std::string* message) { + int32_t battery_voltage = 0; + if (!GetBatteryVoltageHelper(device, &battery_voltage)) { + *message = "Unable to read battery voltage"; + return false; + } + + auto fastboot_hal = device->fastboot_hal(); + if (!fastboot_hal) { + *message = "Fastboot HAL not found"; + return false; + } + + Result ret; + auto ret_val = fastboot_hal->getBatteryVoltageFlashingThreshold( + [&](int32_t voltage_threshold, Result result) { + *message = battery_voltage >= voltage_threshold ? "yes" : "no"; + ret = result; + }); + + if (!ret_val.isOk() || ret.status != Status::SUCCESS) { + *message = "Unable to get battery voltage flashing threshold"; + return false; + } + + return true; +} + bool GetOffModeChargeState(FastbootDevice* device, const std::vector& /* args */, std::string* message) { auto fastboot_hal = device->fastboot_hal(); @@ -120,26 +170,13 @@ bool GetOffModeChargeState(FastbootDevice* device, const std::vector& /* args */, std::string* message) { - using android::hardware::health::V2_0::HealthInfo; - using android::hardware::health::V2_0::Result; - - auto health_hal = device->health_hal(); - if (!health_hal) { - *message = "Health HAL not found"; - return false; + int32_t battery_voltage = 0; + if (GetBatteryVoltageHelper(device, &battery_voltage)) { + *message = std::to_string(battery_voltage); + return true; } - - Result ret; - auto ret_val = health_hal->getHealthInfo([&](Result result, HealthInfo info) { - *message = std::to_string(info.legacy.batteryVoltage); - ret = result; - }); - if (!ret_val.isOk() || (ret != Result::SUCCESS)) { - *message = "Unable to get battery voltage"; - return false; - } - - return true; + *message = "Unable to get battery voltage"; + return false; } bool GetCurrentSlot(FastbootDevice* device, const std::vector& /* args */, diff --git a/fastboot/device/variables.h b/fastboot/device/variables.h index e7c3c7c83..59b71e836 100644 --- a/fastboot/device/variables.h +++ b/fastboot/device/variables.h @@ -57,6 +57,9 @@ bool GetOffModeChargeState(FastbootDevice* device, const std::vector& args, std::string* message); +bool GetBatterySoCOk(FastbootDevice* device, const std::vector& args, + std::string* message); + // Helpers for getvar all. std::vector> GetAllPartitionArgsWithSlot(FastbootDevice* device); std::vector> GetAllPartitionArgsNoSlot(FastbootDevice* device); From 0301683e49ab255769b15469487feaab3466167a Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Fri, 5 Oct 2018 12:34:59 -0700 Subject: [PATCH 041/221] Read memory stats from /proc/pid/stat file. Bug: 117333340 Test: Manual testing using alloc-stress tool Change-Id: Ie555933aafa6a6b7aa1dbf5518ebe804376e0afd --- lmkd/lmkd.c | 59 ++++++++++++++++++++++++++++++++++++++++--------- lmkd/statslog.h | 3 +++ 2 files changed, 51 insertions(+), 11 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 1980dc660..8b68dcad2 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -822,7 +822,7 @@ static void ctrl_connect_handler(int data __unused, uint32_t events __unused) { } #ifdef LMKD_LOG_STATS -static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { +static void memory_stat_parse_line(char* line, struct memory_stat* mem_st) { char key[LINE_MAX + 1]; int64_t value; @@ -844,17 +844,10 @@ static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { mem_st->swap_in_bytes = value; } -static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) { +static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid) { FILE *fp; char buf[PATH_MAX]; - /* - * Per-application memory.stat files are available only when - * per-application memcgs are enabled. - */ - if (!per_app_memcg) - return -1; - snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid); fp = fopen(buf, "r"); @@ -864,13 +857,50 @@ static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) { return -1; } - while (fgets(buf, PAGE_SIZE, fp) != NULL ) { + while (fgets(buf, PAGE_SIZE, fp) != NULL) { memory_stat_parse_line(buf, mem_st); } fclose(fp); return 0; } + +static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) { + char path[PATH_MAX]; + char buffer[PROC_STAT_BUFFER_SIZE]; + int fd, ret; + + snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid); + if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) { + ALOGE("%s open failed: %s", path, strerror(errno)); + return -1; + } + + ret = read(fd, buffer, sizeof(buffer)); + if (ret < 0) { + ALOGE("%s read failed: %s", path, strerror(errno)); + close(fd); + return -1; + } + close(fd); + + // field 10 is pgfault + // field 12 is pgmajfault + // field 24 is rss_in_pages + int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0; + if (sscanf(buffer, + "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d " + "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d " + "%*d %*d %" SCNd64 "", + &pgfault, &pgmajfault, &rss_in_pages) != 3) { + return -1; + } + mem_st->pgfault = pgfault; + mem_st->pgmajfault = pgmajfault; + mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE); + + return 0; +} #endif /* /prop/zoneinfo parsing routines */ @@ -1125,7 +1155,11 @@ static int kill_one_process(struct proc* procp) { #ifdef LMKD_LOG_STATS if (enable_stats_log) { - memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid); + if (per_app_memcg) { + memory_stat_parse_result = memory_stat_from_cgroup(&mem_st, pid, uid); + } else { + memory_stat_parse_result = memory_stat_from_procfs(&mem_st, pid); + } } #endif @@ -1148,6 +1182,9 @@ static int kill_one_process(struct proc* procp) { stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes, mem_st.cache_in_bytes, mem_st.swap_in_bytes); + } else if (enable_stats_log) { + stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, + -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1); } #endif return tasksize; diff --git a/lmkd/statslog.h b/lmkd/statslog.h index edebb195b..84584805d 100644 --- a/lmkd/statslog.h +++ b/lmkd/statslog.h @@ -67,6 +67,9 @@ struct memory_stat { }; #define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat" +#define PROC_STAT_FILE_PATH "/proc/%d/stat" +#define PROC_STAT_BUFFER_SIZE 1024 +#define BYTES_IN_KILOBYTE 1024 /** * Logs the change in LMKD state which is used as start/stop boundaries for logging From 97cdd8776fe82d27fe293e8a43454ca2c9f7ccdc Mon Sep 17 00:00:00 2001 From: Srinivas Paladugu Date: Tue, 9 Oct 2018 14:21:10 -0700 Subject: [PATCH 042/221] lmkd: increase the soft limit for keyboard lmkd sets the soft limit parameters for Go devices. The limit for apps in the perceptible group is set to 16M. However this limit is not sufficient for the keyboard app to prevent pages from being re-claimed quickly. The mem usage of the keyboard app is around 55M most cases with some occasional spikes to 70-80M. Increasing the limit to 64M improves the warm startup latency for keyboard. It is still lower than the limits set for foreground and visible apps. Test: Go device (1G) Bug: 117517805 Change-Id: Id50e49327cfd76126e41ef6503971845f29196af --- lmkd/lmkd.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 8b68dcad2..a8598ef06 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -559,7 +559,7 @@ static void cmd_procprio(LMKD_CTRL_PACKET packet) { } else if (params.oomadj >= 300) { soft_limit_mult = 1; } else if (params.oomadj >= 200) { - soft_limit_mult = 2; + soft_limit_mult = 8; } else if (params.oomadj >= 100) { soft_limit_mult = 10; } else if (params.oomadj >= 0) { From ead88bc88e567182b3c6ae5fd2f17730f55ec3f3 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 26 Oct 2018 11:22:40 -0700 Subject: [PATCH 043/221] Update for v4.19 kernel headers. Add new trap type TRAP_UNK. Test: Unit tests pass. Change-Id: I2b9cb8ddd1d993aa4819831aaca34f8da4286b52 --- debuggerd/libdebuggerd/utility.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 8bdc02f90..d0c5234d3 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -382,6 +382,8 @@ const char* get_sigcode(const siginfo_t* si) { case TRAP_TRACE: return "TRAP_TRACE"; case TRAP_BRANCH: return "TRAP_BRANCH"; case TRAP_HWBKPT: return "TRAP_HWBKPT"; + case TRAP_UNK: + return "TRAP_UNDIAGNOSED"; } if ((si->si_code & 0xff) == SIGTRAP) { switch ((si->si_code >> 8) & 0xff) { @@ -403,7 +405,7 @@ const char* get_sigcode(const siginfo_t* si) { return "PTRACE_EVENT_STOP"; } } - static_assert(NSIGTRAP == TRAP_HWBKPT, "missing TRAP_* si_code"); + static_assert(NSIGTRAP == TRAP_UNK, "missing TRAP_* si_code"); break; } // Then the other codes... From 61926875917fe3d0dd456b319d0c9aebeca59f1a Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Tue, 6 Nov 2018 14:26:49 -0800 Subject: [PATCH 044/221] run-as: allow running cmds for apps profileable from shell. So we can run simpleperf on released apps with profileableFromShell flag. Bug: 118835348 Test: build and test manually on marlin. Test: run CtsSimpleperfTestCases. Change-Id: I58e208391f7ef1a9871e6e772947ce5c99ecb9b8 --- .../packagelistparser/packagelistparser.h | 1 + libpackagelistparser/packagelistparser.c | 17 +++++++++++++++++ run-as/run-as.cpp | 9 +++++---- 3 files changed, 23 insertions(+), 4 deletions(-) diff --git a/libpackagelistparser/include/packagelistparser/packagelistparser.h b/libpackagelistparser/include/packagelistparser/packagelistparser.h index d602c26dc..8bcc1e225 100644 --- a/libpackagelistparser/include/packagelistparser/packagelistparser.h +++ b/libpackagelistparser/include/packagelistparser/packagelistparser.h @@ -53,6 +53,7 @@ struct pkg_info { char *seinfo; gid_list gids; void *private_data; + bool profileable_from_shell; }; /** diff --git a/libpackagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c index 3e1a3d193..4ce2363df 100644 --- a/libpackagelistparser/packagelistparser.c +++ b/libpackagelistparser/packagelistparser.c @@ -223,6 +223,23 @@ extern bool packagelist_parse(pfn_on_package callback, void *userdata) } } + cur = strsep(&next, " \t\r\n"); + if (cur) { + tmp = strtoul(cur, &endptr, 10); + if (*endptr != '\0') { + errmsg = "Could not convert field \"profileable_from_shell\" to integer value"; + goto err; + } + + /* should be a valid boolean of 1 or 0 */ + if (!(tmp == 0 || tmp == 1)) { + errmsg = "Field \"profileable_from_shell\" is not 0 or 1 boolean value"; + goto err; + } + + pkg_info->profileable_from_shell = (bool)tmp; + } + rc = callback(pkg_info, userdata); if (rc == false) { /* diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp index f49bdf720..dea191d83 100644 --- a/run-as/run-as.cpp +++ b/run-as/run-as.cpp @@ -45,7 +45,7 @@ // // - that the ro.boot.disable_runas property is not set // - that it is invoked from the 'shell' or 'root' user (abort otherwise) -// - that '' is the name of an installed and debuggable package +// - that '' is the name of an installed and debuggable/profileableFromShell package // - that the package's data directory is well-formed // // If so, it will drop to the application's user id / group id, cd to the @@ -57,6 +57,7 @@ // during development. // // - Run the 'gdbserver' binary executable to allow native debugging +// - Run simpleperf to allow native profiling // static bool packagelist_parse_callback(pkg_info* this_package, void* userdata) { @@ -196,9 +197,9 @@ int main(int argc, char* argv[]) { error(1, 0, "package not an application: %s", pkgname); } - // Reject any non-debuggable package. - if (!info.debuggable) { - error(1, 0, "package not debuggable: %s", pkgname); + // Reject packages that are neither debuggable nor profileable from shell. + if (!info.debuggable && !info.profileable_from_shell) { + error(1, 0, "package is neither debuggable nor profileable from shell: %s", pkgname); } // Check that the data directory path is valid. From 524a03caf5b679e6574f728f1a985868422ee2a6 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Thu, 8 Nov 2018 22:39:43 -0800 Subject: [PATCH 045/221] Enable the APEX support on the device side. Test: on device Change-Id: Ic6e237556fa059e02cf9c55d1c034947b7dfb405 --- adb/transport.cpp | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/adb/transport.cpp b/adb/transport.cpp index c2d4917ea..76a31cee0 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -1009,14 +1009,11 @@ size_t atransport::get_max_payload() const { const FeatureSet& supported_features() { // Local static allocation to avoid global non-POD variables. static const FeatureSet* features = new FeatureSet{ - kFeatureShell2, kFeatureCmd, kFeatureStat2, kFeatureFixedPushMkdir, -#if ADB_HOST - kFeatureApex -#endif - // Increment ADB_SERVER_VERSION when adding a feature that adbd needs - // to know about. Otherwise, the client can be stuck running an old - // version of the server even after upgrading their copy of adb. - // (http://b/24370690) + kFeatureShell2, kFeatureCmd, kFeatureStat2, kFeatureFixedPushMkdir, kFeatureApex + // Increment ADB_SERVER_VERSION when adding a feature that adbd needs + // to know about. Otherwise, the client can be stuck running an old + // version of the server even after upgrading their copy of adb. + // (http://b/24370690) }; return *features; From cb3527794cadfb828589e338602a08f464e40f83 Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Thu, 8 Nov 2018 15:41:01 -0800 Subject: [PATCH 046/221] Log the last error code of StatsLog failures Test: builds and manual test Bug: 80538532 Change-Id: I7f9d0e22b7ad4295dd787f6cb409bfb3342a7b27 --- libstats/include/stats_event_list.h | 2 +- libstats/stats_event_list.c | 4 ++-- libstats/statsd_writer.c | 7 +++++-- libstats/statsd_writer.h | 2 +- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h index a9832db29..153ec270a 100644 --- a/libstats/include/stats_event_list.h +++ b/libstats/include/stats_event_list.h @@ -24,7 +24,7 @@ extern "C" { #endif void reset_log_context(android_log_context ctx); int write_to_logger(android_log_context context, log_id_t id); -void note_log_drop(); +void note_log_drop(int error); void stats_log_close(); #ifdef __cplusplus diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c index 72770d48a..f38887117 100644 --- a/libstats/stats_event_list.c +++ b/libstats/stats_event_list.c @@ -120,8 +120,8 @@ int write_to_logger(android_log_context ctx, log_id_t id) { return retValue; } -void note_log_drop() { - statsdLoggerWrite.noteDrop(); +void note_log_drop(int error) { + statsdLoggerWrite.noteDrop(error); } void stats_log_close() { diff --git a/libstats/statsd_writer.c b/libstats/statsd_writer.c index 88f7d443a..f00fc2d89 100644 --- a/libstats/statsd_writer.c +++ b/libstats/statsd_writer.c @@ -48,6 +48,7 @@ static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; static atomic_int dropped = 0; +static atomic_int log_error = 0; void statsd_writer_init_lock() { /* @@ -150,8 +151,9 @@ static int statsdAvailable() { return 1; } -static void statsdNoteDrop() { +static void statsdNoteDrop(int error) { atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed); + atomic_exchange_explicit(&log_error, error, memory_order_relaxed); } static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { @@ -202,7 +204,8 @@ static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { if (snapshot) { android_log_event_int_t buffer; header.id = LOG_ID_STATS; - buffer.header.tag = htole32(LIBLOG_LOG_TAG); + // store the last log error in the tag field. This tag field is not used by statsd. + buffer.header.tag = htole32(atomic_load(&log_error)); buffer.payload.type = EVENT_TYPE_INT; buffer.payload.data = htole32(snapshot); diff --git a/libstats/statsd_writer.h b/libstats/statsd_writer.h index 728944153..4fc3f8bc2 100644 --- a/libstats/statsd_writer.h +++ b/libstats/statsd_writer.h @@ -39,7 +39,7 @@ struct android_log_transport_write { /* write log to transport, returns number of bytes propagated, or -errno */ int (*write)(struct timespec* ts, struct iovec* vec, size_t nr); /* note one log drop */ - void (*noteDrop)(); + void (*noteDrop)(int error); }; #endif // ANDROID_STATS_LOG_STATS_WRITER_H From a01f8ed295cbdccf921dc3e12708c2af694965f1 Mon Sep 17 00:00:00 2001 From: Yabin Cui Date: Mon, 12 Nov 2018 23:41:31 +0000 Subject: [PATCH 047/221] Revert "run-as: allow running cmds for apps profileable from shell." This reverts commit 61926875917fe3d0dd456b319d0c9aebeca59f1a. Reason for revert: needs security review. Bug: 118835348 Change-Id: I89dc98ac5464960430abd318c47e30788fee1565 --- .../packagelistparser/packagelistparser.h | 1 - libpackagelistparser/packagelistparser.c | 17 ----------------- run-as/run-as.cpp | 9 ++++----- 3 files changed, 4 insertions(+), 23 deletions(-) diff --git a/libpackagelistparser/include/packagelistparser/packagelistparser.h b/libpackagelistparser/include/packagelistparser/packagelistparser.h index 8bcc1e225..d602c26dc 100644 --- a/libpackagelistparser/include/packagelistparser/packagelistparser.h +++ b/libpackagelistparser/include/packagelistparser/packagelistparser.h @@ -53,7 +53,6 @@ struct pkg_info { char *seinfo; gid_list gids; void *private_data; - bool profileable_from_shell; }; /** diff --git a/libpackagelistparser/packagelistparser.c b/libpackagelistparser/packagelistparser.c index 4ce2363df..3e1a3d193 100644 --- a/libpackagelistparser/packagelistparser.c +++ b/libpackagelistparser/packagelistparser.c @@ -223,23 +223,6 @@ extern bool packagelist_parse(pfn_on_package callback, void *userdata) } } - cur = strsep(&next, " \t\r\n"); - if (cur) { - tmp = strtoul(cur, &endptr, 10); - if (*endptr != '\0') { - errmsg = "Could not convert field \"profileable_from_shell\" to integer value"; - goto err; - } - - /* should be a valid boolean of 1 or 0 */ - if (!(tmp == 0 || tmp == 1)) { - errmsg = "Field \"profileable_from_shell\" is not 0 or 1 boolean value"; - goto err; - } - - pkg_info->profileable_from_shell = (bool)tmp; - } - rc = callback(pkg_info, userdata); if (rc == false) { /* diff --git a/run-as/run-as.cpp b/run-as/run-as.cpp index dea191d83..f49bdf720 100644 --- a/run-as/run-as.cpp +++ b/run-as/run-as.cpp @@ -45,7 +45,7 @@ // // - that the ro.boot.disable_runas property is not set // - that it is invoked from the 'shell' or 'root' user (abort otherwise) -// - that '' is the name of an installed and debuggable/profileableFromShell package +// - that '' is the name of an installed and debuggable package // - that the package's data directory is well-formed // // If so, it will drop to the application's user id / group id, cd to the @@ -57,7 +57,6 @@ // during development. // // - Run the 'gdbserver' binary executable to allow native debugging -// - Run simpleperf to allow native profiling // static bool packagelist_parse_callback(pkg_info* this_package, void* userdata) { @@ -197,9 +196,9 @@ int main(int argc, char* argv[]) { error(1, 0, "package not an application: %s", pkgname); } - // Reject packages that are neither debuggable nor profileable from shell. - if (!info.debuggable && !info.profileable_from_shell) { - error(1, 0, "package is neither debuggable nor profileable from shell: %s", pkgname); + // Reject any non-debuggable package. + if (!info.debuggable) { + error(1, 0, "package not debuggable: %s", pkgname); } // Check that the data directory path is valid. From b087c01c374fe117409b79f6684e40fcd9e40fa7 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Tue, 20 Nov 2018 12:59:21 -0800 Subject: [PATCH 048/221] fs_mgr: overlayfs: resize scratch should it be too small If scratch gets made too small (eg: fastboot flash scratch small-file) it can not recover without a workaround. The workaround is not intuitive, (adb enable-verity then adb disable-verity to erase and re-establish the proper sized scratch. This needs to be automatic. If we detect it is too small to support a filesystem, resize it to an more appropriate size if it exists. Alter unit test to check for fastboot characteristics and assumptions associated with the scratch partition, and a test case to flash the partition. Test: adb-remount-test.sh Bug: 109821005 Change-Id: Icfceaa461c2bf13ca5a7dd4e34675dde8a4d251f --- fs_mgr/fs_mgr_overlayfs.cpp | 87 +++++++++++++++++----------- fs_mgr/tests/adb-remount-test.sh | 99 ++++++++++++++++++++++++++------ 2 files changed, 134 insertions(+), 52 deletions(-) diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index a1de005a5..23e9c519a 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -432,7 +432,7 @@ bool fs_mgr_overlayfs_teardown_scratch(const std::string& overlay, bool* change) if (change) *change = true; if (!DestroyLogicalPartition(partition_name, 0s)) return false; } else { - PERROR << "delete partition " << overlay; + LERROR << "delete partition " << overlay; return false; } errno = save_errno; @@ -647,49 +647,65 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { if (fs_mgr_overlayfs_already_mounted(kScratchMountPoint, false)) return true; auto mnt_type = fs_mgr_overlayfs_scratch_mount_type(); auto scratch_device = fs_mgr_overlayfs_scratch_device(); - auto partition_exists = fs_mgr_rw_access(scratch_device); + auto partition_create = !fs_mgr_rw_access(scratch_device); + auto slot_number = fs_mgr_overlayfs_slot_number(); + auto super_device = fs_mgr_overlayfs_super_device(slot_number); + if (!fs_mgr_rw_access(super_device)) return false; + if (!fs_mgr_overlayfs_has_logical(fstab)) return false; + auto builder = MetadataBuilder::New(super_device, slot_number); + if (!builder) { + LERROR << "open " << super_device << " metadata"; + return false; + } + const auto partition_name = android::base::Basename(kScratchMountPoint); + auto partition = builder->FindPartition(partition_name); + auto partition_exists = partition != nullptr; + auto changed = false; if (!partition_exists) { - auto slot_number = fs_mgr_overlayfs_slot_number(); - auto super_device = fs_mgr_overlayfs_super_device(slot_number); - if (!fs_mgr_rw_access(super_device)) return false; - if (!fs_mgr_overlayfs_has_logical(fstab)) return false; - auto builder = MetadataBuilder::New(super_device, slot_number); - if (!builder) { - PERROR << "open " << super_device << " metadata"; + partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE); + if (!partition) { + LERROR << "create " << partition_name; return false; } - const auto partition_name = android::base::Basename(kScratchMountPoint); - partition_exists = builder->FindPartition(partition_name) != nullptr; - if (!partition_exists) { - auto partition = builder->AddPartition(partition_name, LP_PARTITION_ATTR_NONE); - if (!partition) { - PERROR << "create " << partition_name; - return false; + changed = true; + } + // Take half of free space, minimum 512MB or free space - 256KB margin. + static constexpr auto kMinimumSize = uint64_t(512 * 1024 * 1024); + static constexpr auto kMarginSize = uint64_t(256 * 1024); + if (partition->size() < kMinimumSize) { + auto partition_size = + builder->AllocatableSpace() - builder->UsedSpace() + partition->size(); + if ((partition_size > kMinimumSize) || !partition->size()) { + partition_size = std::max(std::min(kMinimumSize, partition_size - kMarginSize), + partition_size / 2); + if (partition_size > partition->size()) { + if (!builder->ResizePartition(partition, partition_size)) { + LERROR << "resize " << partition_name; + return false; + } + if (!partition_create) DestroyLogicalPartition(partition_name, 10s); + changed = true; + partition_exists = false; } - auto partition_size = builder->AllocatableSpace() - builder->UsedSpace(); - // 512MB or half the remaining available space, whichever is greater. - partition_size = std::max(uint64_t(512 * 1024 * 1024), partition_size / 2); - if (!builder->ResizePartition(partition, partition_size)) { - PERROR << "resize " << partition_name; - return false; - } - - auto metadata = builder->Export(); - if (!metadata) { - LERROR << "generate new metadata " << partition_name; - return false; - } - if (!UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { - LERROR << "update " << partition_name; - return false; - } - - if (change) *change = true; + } + } + // land the update back on to the partition + if (changed) { + auto metadata = builder->Export(); + if (!metadata || !UpdatePartitionTable(super_device, *metadata.get(), slot_number)) { + LERROR << "add partition " << partition_name; + return false; } + if (change) *change = true; + } + + if (changed || partition_create) { if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s, &scratch_device)) return false; + + if (change) *change = true; } if (partition_exists) { @@ -709,6 +725,7 @@ bool fs_mgr_overlayfs_setup_scratch(const fstab* fstab, bool* change) { } else if (mnt_type == "ext4") { command = kMkExt4 + " -b 4096 -t ext4 -m 0 -O has_journal -M " + kScratchMountPoint; } else { + errno = ESRCH; LERROR << mnt_type << " has no mkfs cookbook"; return false; } diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh index 7a0019452..3bc6d403d 100755 --- a/fs_mgr/tests/adb-remount-test.sh +++ b/fs_mgr/tests/adb-remount-test.sh @@ -63,6 +63,7 @@ adb_date() { Returns: the logcat output" ] adb_logcat() { + echo "${RED}[ INFO ]${NORMAL} logcat ${@}" >&2 && adb logcat "${@}" /dev/null + fi >/dev/null 2>/dev/null || + inFastboot +} + [ "USAGE: adb_root Returns: true if device in root state" ] adb_root() { - adb root >/dev/null /dev/null && - sleep 1 && - adb_wait && - sleep 1 + adb root >/dev/null /dev/null + sleep 2 + adb_wait 2m && + [ `adb_sh echo '${USER}'` = root ] +} + +[ "USAGE: fastboot_getvar var expected + +Returns: true if var output matches expected" ] +fastboot_getvar() { + O=`fastboot getvar ${1} 2>&1` + err=${?} + O="${O#< waiting for * >?}" + O="${O%%?Finished. Total time: *}" + if [ 0 -ne ${err} ]; then + echo ${O} >&2 + false + return + fi + if [ -n "${2}" -a "${1}: ${2}" != "${O}" ]; then + echo "${2} != ${O}" >&2 + false + return + fi + echo ${O} >&2 } [ "USAGE: die [-t ] [message] >/dev/stderr @@ -233,8 +270,7 @@ adb_sh ls -d /sys/module/overlay /dev/null && adb_su ls /sys/module/overlay/parameters/override_creds /dev/null && echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 || die "overlay module can not be used on ANDROID" -adb_root && - adb_wait || +adb_root || die "initial setup" reboot=false OVERLAYFS_BACKING="cache mnt/scratch" @@ -250,8 +286,7 @@ if ${reboot}; then echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2 adb_reboot && adb_wait 2m && - adb_root && - adb_wait || + adb_root || die "reboot after wipe" fi D=`adb_sh df -k /dev/null || T=`adb_date` adb_root && - adb_wait && adb remount && D=`adb_sh df -k &2 +fastboot erase scratch && + die "fastbootd can erase scratch" +fastboot reboot || + die "can not reboot out of fastbootd" +echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes" adb_wait 2m || die "did not reboot after flash" adb_root && - adb_wait && D=`adb_sh df -k /dev/null && B="`adb_cat /system/hello`" || die "re-read system hello after flash vendor" check_eq "${A}" "${B}" system after flash vendor -adb_root && - adb_wait || +adb_root || die "adb root" B="`adb_cat /vendor/hello`" && die "re-read vendor hello after flash vendor" @@ -384,4 +426,27 @@ B="`adb_cat /vendor/hello`" && die "re-read vendor hello after rm" check_eq "cat: /vendor/hello: No such file or directory" "${B}" after flash rm +adb reboot-fastboot && + dd if=/dev/zero of=adb-remount-test.img bs=4096 count=16 && + fastboot_wait 2m || + die "reboot into fastbootd" +fastboot flash scratch adb-remount-test.img +err=${?} +rm adb-remount-test.img +[ 0 -eq ${err} ] || + die "fastbootd flash scratch" +fastboot reboot || + die "can not reboot out of fastbootd" +adb_wait 2m && + adb_root || + die "did not reboot after flash" +T=`adb_date` +D=`adb disable-verity 2>&1` +err=${?} +echo "${D}" +[ ${err} = 0 ] && + [ X"${D}" = X"${D##*setup failed}" ] && + [ X"${D}" != X"${D##*using overlayfs}" ] || + die -t ${T} "setup for overlayfs" + echo "${GREEN}[ PASSED ]${NORMAL} adb remount" >&2 From 34c3cb84a0a330ba16391a9d3ebb7d719cf56580 Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 21 Nov 2018 16:22:36 +0000 Subject: [PATCH 049/221] Add start time to LmkKillOccurred This is to measure an application's behavior with respect to being LMKed (the longer an app lives before being LMKed, the better). Bug: 119854389 Test: Manual Change-Id: I4ef6433391c8758626334731d2b5de038e4468ae --- lmkd/lmkd.c | 13 +++++++------ lmkd/statslog.c | 6 +++++- lmkd/statslog.h | 3 ++- 3 files changed, 14 insertions(+), 8 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index c9c9e8e51..7794f81fa 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -1018,19 +1018,20 @@ static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) { // field 10 is pgfault // field 12 is pgmajfault + // field 22 is starttime // field 24 is rss_in_pages - int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0; + int64_t pgfault = 0, pgmajfault = 0, starttime = 0, rss_in_pages = 0; if (sscanf(buffer, "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d " "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d " - "%*d %*d %" SCNd64 "", - &pgfault, &pgmajfault, &rss_in_pages) != 3) { + "%" SCNd64 " %*d %" SCNd64 "", + &pgfault, &pgmajfault, &starttime, &rss_in_pages) != 4) { return -1; } mem_st->pgfault = pgfault; mem_st->pgmajfault = pgmajfault; mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE); - + mem_st->process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK)); return 0; } #endif @@ -1316,10 +1317,10 @@ static int kill_one_process(struct proc* procp) { if (memory_stat_parse_result == 0) { stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes, - mem_st.cache_in_bytes, mem_st.swap_in_bytes); + mem_st.cache_in_bytes, mem_st.swap_in_bytes, mem_st.process_start_time_ns); } else if (enable_stats_log) { stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, - -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1); + -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1, -1); } #endif result = tasksize; diff --git a/lmkd/statslog.c b/lmkd/statslog.c index 66d11647b..689e8aebe 100644 --- a/lmkd/statslog.c +++ b/lmkd/statslog.c @@ -65,7 +65,7 @@ int stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid, char const* process_name, int32_t oom_score, int64_t pgfault, int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes, - int64_t swap_in_bytes) { + int64_t swap_in_bytes, int64_t process_start_time_ns) { assert(ctx != NULL); int ret = -EINVAL; if (!ctx) { @@ -113,5 +113,9 @@ stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid return ret; } + if ((ret = android_log_write_int64(ctx, process_start_time_ns)) < 0) { + return ret; + } + return write_to_logger(ctx, LOG_ID_STATS); } diff --git a/lmkd/statslog.h b/lmkd/statslog.h index 84584805d..f3abe1103 100644 --- a/lmkd/statslog.h +++ b/lmkd/statslog.h @@ -64,6 +64,7 @@ struct memory_stat { int64_t rss_in_bytes; int64_t cache_in_bytes; int64_t swap_in_bytes; + int64_t process_start_time_ns; }; #define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat" @@ -87,7 +88,7 @@ int stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid, char const* process_name, int32_t oom_score, int64_t pgfault, int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes, - int64_t swap_in_bytes); + int64_t swap_in_bytes, int64_t process_start_time_ns); __END_DECLS From 52bd22a8789dca0ac9cede4e82cfc33e6b4cd015 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 27 Nov 2018 20:19:26 -0800 Subject: [PATCH 050/221] fastboot: do not die if ANDROID_PRODUCT_OUT undefined When checking for existence of "super_empty.img" to determine if flash image product set is meant for logical partitions, we die if ANDROID_PRODUCT_OUT environment is unset or empty. This check is done before we look at the flash image name to determine if it is a candidate to look at the logical metadata. Instead, allow this check to conservatively fail for now. Test: export ANDROID_PRODUCT_OUT= fastboot flash bootloader Bug: 120041144 Change-Id: I43f124015f9d26c79a0feb9123522432fe937343 --- fastboot/fastboot.cpp | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index e066bfff7..d5e88a792 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -162,9 +162,17 @@ static Image images[] = { // clang-format on }; -static std::string find_item_given_name(const std::string& img_name) { +static char* get_android_product_out() { char* dir = getenv("ANDROID_PRODUCT_OUT"); if (dir == nullptr || dir[0] == '\0') { + return nullptr; + } + return dir; +} + +static std::string find_item_given_name(const std::string& img_name) { + char* dir = get_android_product_out(); + if (!dir) { die("ANDROID_PRODUCT_OUT not set"); } return std::string(dir) + "/" + img_name; @@ -1508,6 +1516,9 @@ failed: } static bool should_flash_in_userspace(const std::string& partition_name) { + if (!get_android_product_out()) { + return false; + } auto path = find_item_given_name("super_empty.img"); if (path.empty()) { return false; From 28136850573a2e1ee6aa969ba6ce619f11dc30de Mon Sep 17 00:00:00 2001 From: Adam Seaton Date: Wed, 28 Nov 2018 11:47:19 -0800 Subject: [PATCH 051/221] Manually Revert aog/836840 in qt-release (cherry picked from commit da122d6a13d02fd7dbc9390322d7f8e24cad2c9b) Change-Id: I9d456ae854b15db5a121e03a89ea2572a452a6ad --- rootdir/ueventd.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc index d47506c44..2f85dec07 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc @@ -72,7 +72,7 @@ subsystem sound /dev/diag_arm9 0660 radio radio /dev/ttyMSM0 0600 bluetooth bluetooth /dev/uhid 0660 uhid uhid -/dev/uinput 0660 uhid uhid +/dev/uinput 0660 system bluetooth /dev/alarm 0664 system radio /dev/rtc0 0640 system system /dev/tty0 0660 root system From 182b69212454d7f34ea03a3f46a3b417c6c098a4 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Tue, 20 Nov 2018 11:04:15 -0800 Subject: [PATCH 052/221] fastboot: propagate error for format command (cherry pick commit a30b6964d69886a2f8786a760eea962e90c10f79) If fastboot format command fails, return error. Test: adb-remount-test.sh Bug: 109821005 Change-Id: Ic4e1a1dea8861028f19ac7f9c834d26e8adba56c --- fastboot/fastboot.cpp | 18 ++++++++---------- fs_mgr/tests/adb-remount-test.sh | 3 +++ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index d5e88a792..0978ec13e 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1474,15 +1474,13 @@ static void fb_perform_format( fprintf(stderr, "File system type %s not supported.\n", partition_type.c_str()); return; } - fprintf(stderr, "Formatting is not supported for file system with type '%s'.\n", - partition_type.c_str()); - return; + die("Formatting is not supported for file system with type '%s'.", + partition_type.c_str()); } int64_t size; if (!android::base::ParseInt(partition_size, &size)) { - fprintf(stderr, "Couldn't parse partition size '%s'.\n", partition_size.c_str()); - return; + die("Couldn't parse partition size '%s'.", partition_size.c_str()); } unsigned eraseBlkSize, logicalBlkSize; @@ -1492,17 +1490,14 @@ static void fb_perform_format( if (fs_generator_generate(gen, output.path, size, initial_dir, eraseBlkSize, logicalBlkSize)) { die("Cannot generate image for %s", partition.c_str()); - return; } fd.reset(open(output.path, O_RDONLY)); if (fd == -1) { - fprintf(stderr, "Cannot open generated image: %s\n", strerror(errno)); - return; + die("Cannot open generated image: %s", strerror(errno)); } if (!load_buf_fd(fd.release(), &buf)) { - fprintf(stderr, "Cannot read image: %s\n", strerror(errno)); - return; + die("Cannot read image: %s", strerror(errno)); } flash_buf(partition, &buf); return; @@ -1513,6 +1508,9 @@ failed: if (errMsg) fprintf(stderr, "%s", errMsg); } fprintf(stderr, "FAILED (%s)\n", fb->Error().c_str()); + if (!skip_if_not_supported) { + die("Command failed"); + } } static bool should_flash_in_userspace(const std::string& partition_name) { diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh index 3bc6d403d..d9e017c2a 100755 --- a/fs_mgr/tests/adb-remount-test.sh +++ b/fs_mgr/tests/adb-remount-test.sh @@ -390,6 +390,9 @@ fastboot_getvar partition-type:scratch raw && echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot erase scratch to fail" >&2 fastboot erase scratch && die "fastbootd can erase scratch" +echo "${ORANGE}[ INFO ]${NORMAL} expect fastboot format scratch to fail" >&2 +fastboot format scratch && + die "fastbootd can format scratch" fastboot reboot || die "can not reboot out of fastbootd" echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot ... waiting 2 minutes" From c7359b5ddc64dba0aa1afcb2fd88bf7caf4c848c Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Wed, 5 Dec 2018 14:54:26 -0800 Subject: [PATCH 053/221] Fix /init -> /system/bin/init symlink creation race A symlink for TARGET_ROOT_OUT as a post install command of a package that is also installed to TARGET_ROOT_OUT. We hijack init.rc which satisfies this requirement for this symlink. Bug: 120402274 Bug: 120460755 Bug: 120509320 Bug: 120554662 Test: symlink is created Test: make bootimage && ls -la $OUT/root/init Change-Id: I6f1ac06ef152c36d7d7db4618d49a008338da39b (cherry picked from commit c12e205ec52bc03b907bfeb3adc64f6745f6e556) --- init/Android.mk | 1 - rootdir/Android.mk | 4 ++++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/init/Android.mk b/init/Android.mk index 0e6ee0b59..bdd03018a 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -104,7 +104,6 @@ LOCAL_MODULE := init_system LOCAL_REQUIRED_MODULES := \ init_second_stage \ -LOCAL_POST_INSTALL_CMD := ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init include $(BUILD_PHONY_PACKAGE) include $(CLEAR_VARS) diff --git a/rootdir/Android.mk b/rootdir/Android.mk index aad00ad30..f88f6b945 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -9,6 +9,10 @@ LOCAL_SRC_FILES := $(LOCAL_MODULE) LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_ROOT_OUT) +# The init symlink must be a post install command of a file that is to TARGET_ROOT_OUT. +# Since init.rc is required for init and satisfies that requirement, we hijack it to create the symlink. +LOCAL_POST_INSTALL_CMD := ln -sf /system/bin/init $(TARGET_ROOT_OUT)/init + include $(BUILD_PREBUILT) ####################################### From 8e188412163c280f7fad57f63847406f40ad52be Mon Sep 17 00:00:00 2001 From: Andy Hung Date: Tue, 11 Dec 2018 04:10:34 +0000 Subject: [PATCH 054/221] Revert "Remove obsolete ueventd.rc rules." This reverts commit d3b0b2708bf4dfcbda5614ea336a5d040cd7c95d. Reason for revert: Regression in USB audio handling Test: USB audio playback on Crosshatch Bug: 120795549 Change-Id: Ibd05cd9b419f3e7988ce24a45f800d4bfe91ef6a (cherry picked from commit 3fddf924656b54aca3757130f9d3487ddb155929) --- rootdir/ueventd.rc | 70 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 70 insertions(+) diff --git a/rootdir/ueventd.rc b/rootdir/ueventd.rc index d90a1ceea..a9658a46a 100644 --- a/rootdir/ueventd.rc +++ b/rootdir/ueventd.rc @@ -1,6 +1,9 @@ firmware_directories /etc/firmware/ /odm/firmware/ /vendor/firmware/ /firmware/image/ uevent_socket_rcvbuf_size 16M +subsystem adf + devname uevent_devname + subsystem graphics devname uevent_devpath dirname /dev/graphics @@ -9,10 +12,26 @@ subsystem drm devname uevent_devpath dirname /dev/dri +subsystem oncrpc + devname uevent_devpath + dirname /dev/oncrpc + +subsystem adsp + devname uevent_devpath + dirname /dev/adsp + +subsystem msm_camera + devname uevent_devpath + dirname /dev/msm_camera + subsystem input devname uevent_devpath dirname /dev/input +subsystem mtd + devname uevent_devpath + dirname /dev/mtd + subsystem sound devname uevent_devpath dirname /dev/snd @@ -40,25 +59,73 @@ subsystem sound /dev/pmsg0 0222 root log +# the msm hw3d client device node is world writable/readable. +/dev/msm_hw3dc 0666 root root + +# gpu driver for adreno200 is globally accessible +/dev/kgsl 0666 root root + # kms driver for drm based gpu /dev/dri/* 0666 root graphics # these should not be world writable /dev/diag 0660 radio radio +/dev/diag_arm9 0660 radio radio /dev/ttyMSM0 0600 bluetooth bluetooth /dev/uhid 0660 uhid uhid /dev/uinput 0660 uhid uhid +/dev/alarm 0664 system radio /dev/rtc0 0640 system system /dev/tty0 0660 root system /dev/graphics/* 0660 root graphics +/dev/msm_hw3dm 0660 system graphics /dev/input/* 0660 root input /dev/v4l-touch* 0660 root input +/dev/eac 0660 root audio +/dev/cam 0660 root camera +/dev/pmem 0660 system graphics +/dev/pmem_adsp* 0660 system audio +/dev/pmem_camera* 0660 system camera +/dev/oncrpc/* 0660 root system +/dev/adsp/* 0660 system audio /dev/snd/* 0660 system audio +/dev/mt9t013 0660 system system +/dev/msm_camera/* 0660 system system +/dev/akm8976_daemon 0640 compass system +/dev/akm8976_aot 0640 compass system +/dev/akm8973_daemon 0640 compass system +/dev/akm8973_aot 0640 compass system +/dev/bma150 0640 compass system +/dev/cm3602 0640 compass system +/dev/akm8976_pffd 0640 compass system +/dev/lightsensor 0640 system system +/dev/msm_pcm_out* 0660 system audio +/dev/msm_pcm_in* 0660 system audio +/dev/msm_pcm_ctl* 0660 system audio +/dev/msm_snd* 0660 system audio /dev/msm_mp3* 0660 system audio +/dev/audience_a1026* 0660 system audio +/dev/tpa2018d1* 0660 system audio +/dev/msm_audpre 0660 system audio +/dev/msm_audio_ctl 0660 system audio +/dev/htc-acoustic 0660 system audio +/dev/vdec 0660 system audio +/dev/q6venc 0660 system audio +/dev/snd/dsp 0660 system audio +/dev/snd/dsp1 0660 system audio +/dev/snd/mixer 0660 system audio +/dev/smd0 0640 radio radio +/dev/qmi 0640 radio radio +/dev/qmi0 0640 radio radio +/dev/qmi1 0640 radio radio +/dev/qmi2 0640 radio radio +/dev/bus/usb/* 0660 root usb +/dev/mtp_usb 0660 root mtp /dev/usb_accessory 0660 root usb /dev/tun 0660 system vpn # CDMA radio interface MUX +/dev/ts0710mux* 0640 radio radio /dev/ppp 0660 radio vpn # sysfs properties @@ -68,3 +135,6 @@ subsystem sound /sys/devices/virtual/usb_composite/* enable 0664 root system /sys/devices/system/cpu/cpu* cpufreq/scaling_max_freq 0664 system system /sys/devices/system/cpu/cpu* cpufreq/scaling_min_freq 0664 system system + +# DVB API device nodes +/dev/dvb* 0660 root system From fb5e79318ff677bea7d9dcb341ab9f3335c6554e Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Thu, 13 Dec 2018 10:56:33 -0800 Subject: [PATCH 055/221] relax /system/bin directory permissions In commit f4fc922f0b863659ca8e97c1f5fa522fafc7deb6, we tightened the permissions on various bin directories. Please see https://android-review.googlesource.com/c/platform/system/core/+/822955 for details. This change causes the Chase banking app to crash. This is because the Chase app is using inotify_add_watch() on the /system/bin directory and not checking the return value. The Android Security model guarantees the immutability of files in /system/bin, so the inotify watch is unnecessary. Until the Chase app fixes their bug, we need to relax the permissions on the /system/bin directory. Conceptually, this is a partial revert of f4fc922f0b863659ca8e97c1f5fa522fafc7deb6. Bug: 119605322 Test: compiles Change-Id: Ic72dd24cb27cff677093963bdfd0ae09bf132e08 (cherry picked from commit 53842f8a9044db84109ee84dbacef09491be15c2) --- libcutils/fs_config.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index db59569f8..1490fbce6 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -84,7 +84,7 @@ static const struct fs_path_config android_dirs[] = { { 00750, AID_ROOT, AID_SHELL, 0, "sbin" }, { 00777, AID_ROOT, AID_ROOT, 0, "sdcard" }, { 00751, AID_ROOT, AID_SDCARD_R, 0, "storage" }, - { 00751, AID_ROOT, AID_SHELL, 0, "system/bin" }, + { 00755, AID_ROOT, AID_SHELL, 0, "system/bin" }, { 00755, AID_ROOT, AID_ROOT, 0, "system/etc/ppp" }, { 00755, AID_ROOT, AID_SHELL, 0, "system/vendor" }, { 00751, AID_ROOT, AID_SHELL, 0, "system/xbin" }, From 59ec6057297a19efba9dab1af87d163284c5172a Mon Sep 17 00:00:00 2001 From: Adam Seaton Date: Mon, 17 Dec 2018 21:45:33 +0000 Subject: [PATCH 056/221] Revert "Merge "Use libdexfile external API in libunwindstack." am: 1d6969ccb9 am: 6b2cd22482" This reverts commit fab5637b4bdda94bb490e00bd7a4e46c82a49230. Reason for revert: Need to Cherry-pick revert to QT-Release Branch Change-Id: I50652bda22c4b89f9f0734f8cfe484bda4d6eff5 (cherry picked from commit 744d9a990dbd334aefb2a95c600795b844392ec8) --- debuggerd/Android.bp | 23 +- libunwindstack/Android.bp | 14 +- libunwindstack/DexFile.cpp | 198 +++++++++++++----- libunwindstack/DexFile.h | 33 +-- libunwindstack/DexFiles.cpp | 13 +- libunwindstack/include/unwindstack/DexFiles.h | 2 +- libunwindstack/tests/DexFileTest.cpp | 66 ++++-- 7 files changed, 231 insertions(+), 118 deletions(-) diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 516748176..d9fae5275 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -116,21 +116,14 @@ cc_library_static { "libdebuggerd", "libbacktrace", "libunwindstack", - "libdexfile", // libunwindstack dependency - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency + "libdexfile", "liblzma", "libcutils", ], target: { recovery: { cflags: ["-DNO_LIBDEXFILE_SUPPORT"], - exclude_static_libs: [ - "libartbase", - "libdexfile", - "libdexfile_external", - "libdexfile_support", - ], + exclude_static_libs: ["libdexfile"], }, }, @@ -177,22 +170,12 @@ cc_library_static { static_libs: [ "libbacktrace", - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency "libunwindstack", "liblzma", "libbase", "libcutils", "liblog", ], - target: { - recovery: { - exclude_static_libs: [ - "libdexfile_external", - "libdexfile_support", - ], - }, - }, } cc_test { @@ -233,8 +216,6 @@ cc_test { static_libs: [ "libdebuggerd", - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency "libunwindstack", ], diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 89d4fc0e8..4e0470e38 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -94,10 +94,7 @@ cc_library { "DexFile.cpp", "DexFiles.cpp", ], - exclude_shared_libs: [ - "libdexfile_external", - "libdexfile_support", - ], + exclude_shared_libs: ["libdexfile"], }, recovery: { cflags: ["-DNO_LIBDEXFILE_SUPPORT"], @@ -105,10 +102,7 @@ cc_library { "DexFile.cpp", "DexFiles.cpp", ], - exclude_shared_libs: [ - "libdexfile_external", - "libdexfile_support", - ], + exclude_shared_libs: ["libdexfile"], }, }, @@ -133,8 +127,7 @@ cc_library { shared_libs: [ "libbase", - "libdexfile_external", - "libdexfile_support", + "libdexfile", "liblog", "liblzma", ], @@ -222,7 +215,6 @@ cc_test { "liblzma", "libunwindstack", "libdexfile", - "libdexfile_support", ], static_libs: [ diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp index 9b0b2328f..8ec560c3b 100644 --- a/libunwindstack/DexFile.cpp +++ b/libunwindstack/DexFile.cpp @@ -23,7 +23,13 @@ #include #include -#include + +#include +#include +#include +#include +#include +#include #include #include @@ -32,71 +38,169 @@ namespace unwindstack { -std::unique_ptr DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, - MapInfo* info) { +DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) { if (!info->name.empty()) { - std::unique_ptr dex_file = - DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name); - if (dex_file) { - return dex_file; + std::unique_ptr dex_file(new DexFileFromFile); + if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) { + return dex_file.release(); } } - return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name); + + std::unique_ptr dex_file(new DexFileFromMemory); + if (dex_file->Open(dex_file_offset_in_memory, memory)) { + return dex_file.release(); + } + return nullptr; +} + +DexFileFromFile::~DexFileFromFile() { + if (size_ != 0) { + munmap(mapped_memory_, size_); + } } bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset) { - art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset); - if (method_info.offset == 0) { + if (dex_file_ == nullptr) { return false; } - *method_name = method_info.name; - *method_offset = dex_offset - method_info.offset; - return true; + + if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) { + return false; // The DEX offset is not within the bytecode of this dex file. + } + + if (dex_file_->IsCompactDexFile()) { + // The data section of compact dex files might be shared. + // Check the subrange unique to this compact dex. + const auto& cdex_header = dex_file_->AsCompactDexFile()->GetHeader(); + uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin(); + uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd(); + if (dex_offset < begin || dex_offset >= end) { + return false; // The DEX offset is not within the bytecode of this dex file. + } + } + + // The method data is cached in a std::map indexed by method end offset and + // contains the start offset and the method member index. + // Only cache the method data as it is searched. Do not read the entire + // set of method data into the cache at once. + // This is done because many unwinds only find a single frame with dex file + // info, so reading the entire method data is wasteful. However, still cache + // the data so that anything doing multiple unwinds will have this data + // cached for future use. + + // First look in the method cache. + auto entry = method_cache_.upper_bound(dex_offset); + if (entry != method_cache_.end() && dex_offset >= entry->second.first) { + *method_name = dex_file_->PrettyMethod(entry->second.second, false); + *method_offset = dex_offset - entry->second.first; + return true; + } + + // Check the methods we haven't cached. + for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) { + art::ClassAccessor accessor(*dex_file_, dex_file_->GetClassDef(class_def_index_)); + + for (const art::ClassAccessor::Method& method : accessor.GetMethods()) { + art::CodeItemInstructionAccessor code = method.GetInstructions(); + if (!code.HasCodeItem()) { + continue; + } + uint32_t offset = reinterpret_cast(code.Insns()) - dex_file_->Begin(); + uint32_t offset_end = offset + code.InsnsSizeInBytes(); + uint32_t member_index = method.GetIndex(); + method_cache_[offset_end] = std::make_pair(offset, member_index); + if (offset <= dex_offset && dex_offset < offset_end) { + *method_name = dex_file_->PrettyMethod(member_index, false); + *method_offset = dex_offset - offset; + return true; + } + } + } + return false; } -std::unique_ptr DexFileFromFile::Create(uint64_t dex_file_offset_in_file, - const std::string& file) { +bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC))); if (fd == -1) { - return nullptr; + return false; + } + struct stat buf; + if (fstat(fd, &buf) == -1) { + return false; + } + uint64_t length; + if (buf.st_size < 0 || + __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) || + static_cast(buf.st_size) < length) { + return false; } + mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (mapped_memory_ == MAP_FAILED) { + return false; + } + size_ = buf.st_size; + + uint8_t* memory = reinterpret_cast(mapped_memory_); + + art::DexFile::Header* header = + reinterpret_cast(&memory[dex_file_offset_in_file]); + if (!art::StandardDexFile::IsMagicValid(header->magic_) && + !art::CompactDexFile::IsMagicValid(header->magic_)) { + return false; + } + + if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) || + static_cast(buf.st_size) < length) { + return false; + } + + art::DexFileLoader loader; std::string error_msg; - std::unique_ptr art_dex_file = - OpenFromFd(fd, dex_file_offset_in_file, file, &error_msg); - if (art_dex_file == nullptr) { - return nullptr; - } - - return std::unique_ptr(new DexFileFromFile(std::move(*art_dex_file.release()))); + auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr, + false, false, &error_msg); + dex_file_.reset(dex.release()); + return dex_file_ != nullptr; } -std::unique_ptr DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory, - Memory* memory, - const std::string& name) { - std::vector backing_memory; - - for (size_t size = 0;;) { - std::string error_msg; - std::unique_ptr art_dex_file = - OpenFromMemory(backing_memory.data(), &size, name, &error_msg); - - if (art_dex_file != nullptr) { - return std::unique_ptr( - new DexFileFromMemory(std::move(*art_dex_file.release()), std::move(backing_memory))); - } - - if (!error_msg.empty()) { - return nullptr; - } - - backing_memory.resize(size); - if (!memory->ReadFully(dex_file_offset_in_memory, backing_memory.data(), - backing_memory.size())) { - return nullptr; - } +bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) { + memory_.resize(sizeof(art::DexFile::Header)); + if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { + return false; } + + art::DexFile::Header* header = reinterpret_cast(memory_.data()); + uint32_t file_size = header->file_size_; + if (art::CompactDexFile::IsMagicValid(header->magic_)) { + // Compact dex file store data section separately so that it can be shared. + // Therefore we need to extend the read memory range to include it. + // TODO: This might be wasteful as we might read data in between as well. + // In practice, this should be fine, as such sharing only happens on disk. + uint32_t computed_file_size; + if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) { + return false; + } + if (computed_file_size > file_size) { + file_size = computed_file_size; + } + } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) { + return false; + } + + memory_.resize(file_size); + if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { + return false; + } + + header = reinterpret_cast(memory_.data()); + + art::DexFileLoader loader; + std::string error_msg; + auto dex = + loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg); + dex_file_.reset(dex.release()); + return dex_file_ != nullptr; } } // namespace unwindstack diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h index 5797deec6..c123158ef 100644 --- a/libunwindstack/DexFile.h +++ b/libunwindstack/DexFile.h @@ -25,41 +25,48 @@ #include #include -#include +#include namespace unwindstack { -class DexFile : protected art_api::dex::DexFile { +class DexFile { public: + DexFile() = default; virtual ~DexFile() = default; bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); - static std::unique_ptr Create(uint64_t dex_file_offset_in_memory, Memory* memory, - MapInfo* info); + static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info); protected: - DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {} + void Init(); + + std::unique_ptr dex_file_; + std::map> method_cache_; // dex offset to method index. + + uint32_t class_def_index_ = 0; }; class DexFileFromFile : public DexFile { public: - static std::unique_ptr Create(uint64_t dex_file_offset_in_file, - const std::string& file); + DexFileFromFile() = default; + virtual ~DexFileFromFile(); + + bool Open(uint64_t dex_file_offset_in_file, const std::string& name); private: - DexFileFromFile(art_api::dex::DexFile&& art_dex_file) : DexFile(std::move(art_dex_file)) {} + void* mapped_memory_ = nullptr; + size_t size_ = 0; }; class DexFileFromMemory : public DexFile { public: - static std::unique_ptr Create(uint64_t dex_file_offset_in_memory, - Memory* memory, const std::string& name); + DexFileFromMemory() = default; + virtual ~DexFileFromMemory() = default; + + bool Open(uint64_t dex_file_offset_in_memory, Memory* memory); private: - DexFileFromMemory(art_api::dex::DexFile&& art_dex_file, std::vector&& memory) - : DexFile(std::move(art_dex_file)), memory_(std::move(memory)) {} - std::vector memory_; }; diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp index 63a77e50f..451a0b90d 100644 --- a/libunwindstack/DexFiles.cpp +++ b/libunwindstack/DexFiles.cpp @@ -48,7 +48,11 @@ DexFiles::DexFiles(std::shared_ptr& memory) : Global(memory) {} DexFiles::DexFiles(std::shared_ptr& memory, std::vector& search_libs) : Global(memory, search_libs) {} -DexFiles::~DexFiles() {} +DexFiles::~DexFiles() { + for (auto& entry : files_) { + delete entry.second; + } +} void DexFiles::ProcessArch() { switch (arch()) { @@ -133,11 +137,10 @@ DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { DexFile* dex_file; auto entry = files_.find(dex_file_offset); if (entry == files_.end()) { - std::unique_ptr new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); - dex_file = new_dex_file.get(); - files_[dex_file_offset] = std::move(new_dex_file); + dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); + files_[dex_file_offset] = dex_file; } else { - dex_file = entry->second.get(); + dex_file = entry->second; } return dex_file; } diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h index 033617362..c202a334d 100644 --- a/libunwindstack/include/unwindstack/DexFiles.h +++ b/libunwindstack/include/unwindstack/DexFiles.h @@ -66,7 +66,7 @@ class DexFiles : public Global { std::mutex lock_; bool initialized_ = false; - std::unordered_map> files_; + std::unordered_map files_; uint64_t entry_addr_ = 0; uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr; diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp index 21ca47b52..95d217631 100644 --- a/libunwindstack/tests/DexFileTest.cpp +++ b/libunwindstack/tests/DexFileTest.cpp @@ -21,37 +21,44 @@ #include #include -#include -#include + #include #include +#include +#include + +#include + #include "DexFile.h" + #include "DexFileData.h" #include "MemoryFake.h" namespace unwindstack { TEST(DexFileTest, from_file_open_non_exist) { - EXPECT_TRUE(DexFileFromFile::Create(0, "/file/does/not/exist") == nullptr); + DexFileFromFile dex_file; + ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist")); } TEST(DexFileTest, from_file_open_too_small) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); - ASSERT_EQ(sizeof(art::DexFile::Header) - 1, + ASSERT_EQ(sizeof(art::DexFile::Header) - 2, static_cast( - TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1)))); + TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2))); // Header too small. - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr); + DexFileFromFile dex_file; + ASSERT_FALSE(dex_file.Open(0, tf.path)); // Header correct, file too small. ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); ASSERT_EQ(sizeof(art::DexFile::Header), static_cast(TEMP_FAILURE_RETRY(write( tf.fd, kDexData, sizeof(art::DexFile::Header))))); - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr); + ASSERT_FALSE(dex_file.Open(0, tf.path)); } TEST(DexFileTest, from_file_open) { @@ -61,7 +68,8 @@ TEST(DexFileTest, from_file_open) { ASSERT_EQ(sizeof(kDexData), static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) != nullptr); + DexFileFromFile dex_file; + ASSERT_TRUE(dex_file.Open(0, tf.path)); } TEST(DexFileTest, from_file_open_non_zero_offset) { @@ -72,31 +80,35 @@ TEST(DexFileTest, from_file_open_non_zero_offset) { ASSERT_EQ(sizeof(kDexData), static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - EXPECT_TRUE(DexFileFromFile::Create(0x100, tf.path) != nullptr); + DexFileFromFile dex_file; + ASSERT_TRUE(dex_file.Open(0x100, tf.path)); } TEST(DexFileTest, from_memory_fail_too_small_for_header) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr); + ASSERT_FALSE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, from_memory_fail_too_small_for_data) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr); + ASSERT_FALSE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, from_memory_open) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(kDexData)); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr); + ASSERT_TRUE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, create_using_file) { @@ -109,7 +121,8 @@ TEST(DexFileTest, create_using_file) { MemoryFake memory; MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x500, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x500, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_file_non_zero_start) { @@ -122,7 +135,8 @@ TEST(DexFileTest, create_using_file_non_zero_start) { MemoryFake memory; MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x600, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x600, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_file_non_zero_offset) { @@ -135,21 +149,24 @@ TEST(DexFileTest, create_using_file_non_zero_offset) { MemoryFake memory; MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x400, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x400, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_empty_file) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); - EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_file_does_not_exist) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist"); - EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_file_is_malformed) { @@ -162,13 +179,22 @@ TEST(DexFileTest, create_using_memory_file_is_malformed) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist"); - std::unique_ptr dex_file = DexFile::Create(0x4000, &memory, &info); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); // Check it came from memory by clearing memory and verifying it fails. memory.Clear(); - dex_file = DexFile::Create(0x4000, &memory, &info); - EXPECT_TRUE(dex_file == nullptr); + dex_file.reset(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file == nullptr); +} + +TEST(DexFileTest, get_method_not_opened) { + std::string method("something"); + uint64_t method_offset = 100; + DexFile dex_file; + dex_file.GetMethodInformation(0x100, &method, &method_offset); + EXPECT_EQ("something", method); + EXPECT_EQ(100U, method_offset); } TEST(DexFileTest, get_method) { From 8568dcb057d63023feca09b031e456592c133f0e Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 17 Dec 2018 17:07:34 -0800 Subject: [PATCH 057/221] fastbootd: Only flash slots listed by the boot control HAL. Bug: N/A Test: flash when metadata slot count is >2 Change-Id: I67481be0de162cab5da8d32c2e318489427f1932 --- fastboot/device/commands.cpp | 6 ++++-- fastboot/device/flashing.cpp | 2 +- fastboot/device/utility.cpp | 10 ++++++++-- fastboot/device/utility.h | 2 +- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/fastboot/device/commands.cpp b/fastboot/device/commands.cpp index 71d2a1d61..e91598d01 100644 --- a/fastboot/device/commands.cpp +++ b/fastboot/device/commands.cpp @@ -329,12 +329,14 @@ class PartitionBuilder { MetadataBuilder* operator->() const { return builder_.get(); } private: + FastbootDevice* device_; std::string super_device_; uint32_t slot_number_; std::unique_ptr builder_; }; -PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name) { +PartitionBuilder::PartitionBuilder(FastbootDevice* device, const std::string& partition_name) + : device_(device) { std::string slot_suffix = GetSuperSlotSuffix(device, partition_name); slot_number_ = SlotNumberForSlotSuffix(slot_suffix); auto super_device = FindPhysicalPartition(fs_mgr_get_super_partition_name(slot_number_)); @@ -350,7 +352,7 @@ bool PartitionBuilder::Write() { if (!metadata) { return false; } - return UpdateAllPartitionMetadata(super_device_, *metadata.get()); + return UpdateAllPartitionMetadata(device_, super_device_, *metadata.get()); } bool CreatePartitionHandler(FastbootDevice* device, const std::vector& args) { diff --git a/fastboot/device/flashing.cpp b/fastboot/device/flashing.cpp index fbba63122..963916cf9 100644 --- a/fastboot/device/flashing.cpp +++ b/fastboot/device/flashing.cpp @@ -184,7 +184,7 @@ bool UpdateSuper(FastbootDevice* device, const std::string& super_name, bool wip } // Write the new table to every metadata slot. - if (!UpdateAllPartitionMetadata(super_name, *new_metadata.get())) { + if (!UpdateAllPartitionMetadata(device, super_name, *new_metadata.get())) { return device->WriteFail("Unable to write new partition table"); } fs_mgr_overlayfs_teardown(); diff --git a/fastboot/device/utility.cpp b/fastboot/device/utility.cpp index 2ae9ac55b..2ebd57d12 100644 --- a/fastboot/device/utility.cpp +++ b/fastboot/device/utility.cpp @@ -200,10 +200,16 @@ bool GetDeviceLockStatus() { return cmdline.find("androidboot.verifiedbootstate=orange") == std::string::npos; } -bool UpdateAllPartitionMetadata(const std::string& super_name, +bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name, const android::fs_mgr::LpMetadata& metadata) { + size_t num_slots = 1; + auto boot_control_hal = device->boot_control_hal(); + if (boot_control_hal) { + num_slots = boot_control_hal->getNumberSlots(); + } + bool ok = true; - for (size_t i = 0; i < metadata.geometry.metadata_slot_count; i++) { + for (size_t i = 0; i < num_slots; i++) { ok &= UpdatePartitionTable(super_name, metadata, i); } return ok; diff --git a/fastboot/device/utility.h b/fastboot/device/utility.h index 4c6aa07ad..bfeeb742f 100644 --- a/fastboot/device/utility.h +++ b/fastboot/device/utility.h @@ -68,5 +68,5 @@ std::vector ListPartitions(FastbootDevice* device); bool GetDeviceLockStatus(); // Update all copies of metadata. -bool UpdateAllPartitionMetadata(const std::string& super_name, +bool UpdateAllPartitionMetadata(FastbootDevice* device, const std::string& super_name, const android::fs_mgr::LpMetadata& metadata); From 7a7fd14b7721f003ef1b2822e243c2e36fc5a9a4 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Tue, 18 Dec 2018 17:30:32 +0000 Subject: [PATCH 058/221] Revert "Snap for 5187456 from 9638c086ee0c5a0f75e7c76522a0ecb5b5956d78 to qt-release" This partially reverts commit b71447238ef4aa1e4aeac4e9a0b61ab70b35cd5a. Reason for revert: Breaks loading of libRS_internal.so. Change-Id: I43e010b342f31e6019f0b8736793a7d504d9f124 (cherry picked from commit 25798ba30af628c43328e8d9879ab90d6581d028) --- debuggerd/Android.bp | 23 +- libunwindstack/Android.bp | 14 +- libunwindstack/DexFile.cpp | 198 +++++++++++++----- libunwindstack/DexFile.h | 33 +-- libunwindstack/DexFiles.cpp | 13 +- libunwindstack/include/unwindstack/DexFiles.h | 2 +- libunwindstack/tests/DexFileTest.cpp | 66 ++++-- 7 files changed, 231 insertions(+), 118 deletions(-) diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 516748176..d9fae5275 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -116,21 +116,14 @@ cc_library_static { "libdebuggerd", "libbacktrace", "libunwindstack", - "libdexfile", // libunwindstack dependency - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency + "libdexfile", "liblzma", "libcutils", ], target: { recovery: { cflags: ["-DNO_LIBDEXFILE_SUPPORT"], - exclude_static_libs: [ - "libartbase", - "libdexfile", - "libdexfile_external", - "libdexfile_support", - ], + exclude_static_libs: ["libdexfile"], }, }, @@ -177,22 +170,12 @@ cc_library_static { static_libs: [ "libbacktrace", - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency "libunwindstack", "liblzma", "libbase", "libcutils", "liblog", ], - target: { - recovery: { - exclude_static_libs: [ - "libdexfile_external", - "libdexfile_support", - ], - }, - }, } cc_test { @@ -233,8 +216,6 @@ cc_test { static_libs: [ "libdebuggerd", - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency "libunwindstack", ], diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 89d4fc0e8..4e0470e38 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -94,10 +94,7 @@ cc_library { "DexFile.cpp", "DexFiles.cpp", ], - exclude_shared_libs: [ - "libdexfile_external", - "libdexfile_support", - ], + exclude_shared_libs: ["libdexfile"], }, recovery: { cflags: ["-DNO_LIBDEXFILE_SUPPORT"], @@ -105,10 +102,7 @@ cc_library { "DexFile.cpp", "DexFiles.cpp", ], - exclude_shared_libs: [ - "libdexfile_external", - "libdexfile_support", - ], + exclude_shared_libs: ["libdexfile"], }, }, @@ -133,8 +127,7 @@ cc_library { shared_libs: [ "libbase", - "libdexfile_external", - "libdexfile_support", + "libdexfile", "liblog", "liblzma", ], @@ -222,7 +215,6 @@ cc_test { "liblzma", "libunwindstack", "libdexfile", - "libdexfile_support", ], static_libs: [ diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp index 9b0b2328f..8ec560c3b 100644 --- a/libunwindstack/DexFile.cpp +++ b/libunwindstack/DexFile.cpp @@ -23,7 +23,13 @@ #include #include -#include + +#include +#include +#include +#include +#include +#include #include #include @@ -32,71 +38,169 @@ namespace unwindstack { -std::unique_ptr DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, - MapInfo* info) { +DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) { if (!info->name.empty()) { - std::unique_ptr dex_file = - DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name); - if (dex_file) { - return dex_file; + std::unique_ptr dex_file(new DexFileFromFile); + if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) { + return dex_file.release(); } } - return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name); + + std::unique_ptr dex_file(new DexFileFromMemory); + if (dex_file->Open(dex_file_offset_in_memory, memory)) { + return dex_file.release(); + } + return nullptr; +} + +DexFileFromFile::~DexFileFromFile() { + if (size_ != 0) { + munmap(mapped_memory_, size_); + } } bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset) { - art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset); - if (method_info.offset == 0) { + if (dex_file_ == nullptr) { return false; } - *method_name = method_info.name; - *method_offset = dex_offset - method_info.offset; - return true; + + if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) { + return false; // The DEX offset is not within the bytecode of this dex file. + } + + if (dex_file_->IsCompactDexFile()) { + // The data section of compact dex files might be shared. + // Check the subrange unique to this compact dex. + const auto& cdex_header = dex_file_->AsCompactDexFile()->GetHeader(); + uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin(); + uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd(); + if (dex_offset < begin || dex_offset >= end) { + return false; // The DEX offset is not within the bytecode of this dex file. + } + } + + // The method data is cached in a std::map indexed by method end offset and + // contains the start offset and the method member index. + // Only cache the method data as it is searched. Do not read the entire + // set of method data into the cache at once. + // This is done because many unwinds only find a single frame with dex file + // info, so reading the entire method data is wasteful. However, still cache + // the data so that anything doing multiple unwinds will have this data + // cached for future use. + + // First look in the method cache. + auto entry = method_cache_.upper_bound(dex_offset); + if (entry != method_cache_.end() && dex_offset >= entry->second.first) { + *method_name = dex_file_->PrettyMethod(entry->second.second, false); + *method_offset = dex_offset - entry->second.first; + return true; + } + + // Check the methods we haven't cached. + for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) { + art::ClassAccessor accessor(*dex_file_, dex_file_->GetClassDef(class_def_index_)); + + for (const art::ClassAccessor::Method& method : accessor.GetMethods()) { + art::CodeItemInstructionAccessor code = method.GetInstructions(); + if (!code.HasCodeItem()) { + continue; + } + uint32_t offset = reinterpret_cast(code.Insns()) - dex_file_->Begin(); + uint32_t offset_end = offset + code.InsnsSizeInBytes(); + uint32_t member_index = method.GetIndex(); + method_cache_[offset_end] = std::make_pair(offset, member_index); + if (offset <= dex_offset && dex_offset < offset_end) { + *method_name = dex_file_->PrettyMethod(member_index, false); + *method_offset = dex_offset - offset; + return true; + } + } + } + return false; } -std::unique_ptr DexFileFromFile::Create(uint64_t dex_file_offset_in_file, - const std::string& file) { +bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC))); if (fd == -1) { - return nullptr; + return false; + } + struct stat buf; + if (fstat(fd, &buf) == -1) { + return false; + } + uint64_t length; + if (buf.st_size < 0 || + __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) || + static_cast(buf.st_size) < length) { + return false; } + mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (mapped_memory_ == MAP_FAILED) { + return false; + } + size_ = buf.st_size; + + uint8_t* memory = reinterpret_cast(mapped_memory_); + + art::DexFile::Header* header = + reinterpret_cast(&memory[dex_file_offset_in_file]); + if (!art::StandardDexFile::IsMagicValid(header->magic_) && + !art::CompactDexFile::IsMagicValid(header->magic_)) { + return false; + } + + if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) || + static_cast(buf.st_size) < length) { + return false; + } + + art::DexFileLoader loader; std::string error_msg; - std::unique_ptr art_dex_file = - OpenFromFd(fd, dex_file_offset_in_file, file, &error_msg); - if (art_dex_file == nullptr) { - return nullptr; - } - - return std::unique_ptr(new DexFileFromFile(std::move(*art_dex_file.release()))); + auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr, + false, false, &error_msg); + dex_file_.reset(dex.release()); + return dex_file_ != nullptr; } -std::unique_ptr DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory, - Memory* memory, - const std::string& name) { - std::vector backing_memory; - - for (size_t size = 0;;) { - std::string error_msg; - std::unique_ptr art_dex_file = - OpenFromMemory(backing_memory.data(), &size, name, &error_msg); - - if (art_dex_file != nullptr) { - return std::unique_ptr( - new DexFileFromMemory(std::move(*art_dex_file.release()), std::move(backing_memory))); - } - - if (!error_msg.empty()) { - return nullptr; - } - - backing_memory.resize(size); - if (!memory->ReadFully(dex_file_offset_in_memory, backing_memory.data(), - backing_memory.size())) { - return nullptr; - } +bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) { + memory_.resize(sizeof(art::DexFile::Header)); + if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { + return false; } + + art::DexFile::Header* header = reinterpret_cast(memory_.data()); + uint32_t file_size = header->file_size_; + if (art::CompactDexFile::IsMagicValid(header->magic_)) { + // Compact dex file store data section separately so that it can be shared. + // Therefore we need to extend the read memory range to include it. + // TODO: This might be wasteful as we might read data in between as well. + // In practice, this should be fine, as such sharing only happens on disk. + uint32_t computed_file_size; + if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) { + return false; + } + if (computed_file_size > file_size) { + file_size = computed_file_size; + } + } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) { + return false; + } + + memory_.resize(file_size); + if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { + return false; + } + + header = reinterpret_cast(memory_.data()); + + art::DexFileLoader loader; + std::string error_msg; + auto dex = + loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg); + dex_file_.reset(dex.release()); + return dex_file_ != nullptr; } } // namespace unwindstack diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h index 5797deec6..c123158ef 100644 --- a/libunwindstack/DexFile.h +++ b/libunwindstack/DexFile.h @@ -25,41 +25,48 @@ #include #include -#include +#include namespace unwindstack { -class DexFile : protected art_api::dex::DexFile { +class DexFile { public: + DexFile() = default; virtual ~DexFile() = default; bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); - static std::unique_ptr Create(uint64_t dex_file_offset_in_memory, Memory* memory, - MapInfo* info); + static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info); protected: - DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {} + void Init(); + + std::unique_ptr dex_file_; + std::map> method_cache_; // dex offset to method index. + + uint32_t class_def_index_ = 0; }; class DexFileFromFile : public DexFile { public: - static std::unique_ptr Create(uint64_t dex_file_offset_in_file, - const std::string& file); + DexFileFromFile() = default; + virtual ~DexFileFromFile(); + + bool Open(uint64_t dex_file_offset_in_file, const std::string& name); private: - DexFileFromFile(art_api::dex::DexFile&& art_dex_file) : DexFile(std::move(art_dex_file)) {} + void* mapped_memory_ = nullptr; + size_t size_ = 0; }; class DexFileFromMemory : public DexFile { public: - static std::unique_ptr Create(uint64_t dex_file_offset_in_memory, - Memory* memory, const std::string& name); + DexFileFromMemory() = default; + virtual ~DexFileFromMemory() = default; + + bool Open(uint64_t dex_file_offset_in_memory, Memory* memory); private: - DexFileFromMemory(art_api::dex::DexFile&& art_dex_file, std::vector&& memory) - : DexFile(std::move(art_dex_file)), memory_(std::move(memory)) {} - std::vector memory_; }; diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp index 63a77e50f..451a0b90d 100644 --- a/libunwindstack/DexFiles.cpp +++ b/libunwindstack/DexFiles.cpp @@ -48,7 +48,11 @@ DexFiles::DexFiles(std::shared_ptr& memory) : Global(memory) {} DexFiles::DexFiles(std::shared_ptr& memory, std::vector& search_libs) : Global(memory, search_libs) {} -DexFiles::~DexFiles() {} +DexFiles::~DexFiles() { + for (auto& entry : files_) { + delete entry.second; + } +} void DexFiles::ProcessArch() { switch (arch()) { @@ -133,11 +137,10 @@ DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { DexFile* dex_file; auto entry = files_.find(dex_file_offset); if (entry == files_.end()) { - std::unique_ptr new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); - dex_file = new_dex_file.get(); - files_[dex_file_offset] = std::move(new_dex_file); + dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); + files_[dex_file_offset] = dex_file; } else { - dex_file = entry->second.get(); + dex_file = entry->second; } return dex_file; } diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h index 033617362..c202a334d 100644 --- a/libunwindstack/include/unwindstack/DexFiles.h +++ b/libunwindstack/include/unwindstack/DexFiles.h @@ -66,7 +66,7 @@ class DexFiles : public Global { std::mutex lock_; bool initialized_ = false; - std::unordered_map> files_; + std::unordered_map files_; uint64_t entry_addr_ = 0; uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr; diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp index 21ca47b52..95d217631 100644 --- a/libunwindstack/tests/DexFileTest.cpp +++ b/libunwindstack/tests/DexFileTest.cpp @@ -21,37 +21,44 @@ #include #include -#include -#include + #include #include +#include +#include + +#include + #include "DexFile.h" + #include "DexFileData.h" #include "MemoryFake.h" namespace unwindstack { TEST(DexFileTest, from_file_open_non_exist) { - EXPECT_TRUE(DexFileFromFile::Create(0, "/file/does/not/exist") == nullptr); + DexFileFromFile dex_file; + ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist")); } TEST(DexFileTest, from_file_open_too_small) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); - ASSERT_EQ(sizeof(art::DexFile::Header) - 1, + ASSERT_EQ(sizeof(art::DexFile::Header) - 2, static_cast( - TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1)))); + TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2))); // Header too small. - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr); + DexFileFromFile dex_file; + ASSERT_FALSE(dex_file.Open(0, tf.path)); // Header correct, file too small. ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); ASSERT_EQ(sizeof(art::DexFile::Header), static_cast(TEMP_FAILURE_RETRY(write( tf.fd, kDexData, sizeof(art::DexFile::Header))))); - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr); + ASSERT_FALSE(dex_file.Open(0, tf.path)); } TEST(DexFileTest, from_file_open) { @@ -61,7 +68,8 @@ TEST(DexFileTest, from_file_open) { ASSERT_EQ(sizeof(kDexData), static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) != nullptr); + DexFileFromFile dex_file; + ASSERT_TRUE(dex_file.Open(0, tf.path)); } TEST(DexFileTest, from_file_open_non_zero_offset) { @@ -72,31 +80,35 @@ TEST(DexFileTest, from_file_open_non_zero_offset) { ASSERT_EQ(sizeof(kDexData), static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - EXPECT_TRUE(DexFileFromFile::Create(0x100, tf.path) != nullptr); + DexFileFromFile dex_file; + ASSERT_TRUE(dex_file.Open(0x100, tf.path)); } TEST(DexFileTest, from_memory_fail_too_small_for_header) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr); + ASSERT_FALSE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, from_memory_fail_too_small_for_data) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr); + ASSERT_FALSE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, from_memory_open) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(kDexData)); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr); + ASSERT_TRUE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, create_using_file) { @@ -109,7 +121,8 @@ TEST(DexFileTest, create_using_file) { MemoryFake memory; MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x500, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x500, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_file_non_zero_start) { @@ -122,7 +135,8 @@ TEST(DexFileTest, create_using_file_non_zero_start) { MemoryFake memory; MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x600, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x600, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_file_non_zero_offset) { @@ -135,21 +149,24 @@ TEST(DexFileTest, create_using_file_non_zero_offset) { MemoryFake memory; MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x400, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x400, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_empty_file) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); - EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_file_does_not_exist) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist"); - EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_file_is_malformed) { @@ -162,13 +179,22 @@ TEST(DexFileTest, create_using_memory_file_is_malformed) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist"); - std::unique_ptr dex_file = DexFile::Create(0x4000, &memory, &info); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); // Check it came from memory by clearing memory and verifying it fails. memory.Clear(); - dex_file = DexFile::Create(0x4000, &memory, &info); - EXPECT_TRUE(dex_file == nullptr); + dex_file.reset(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file == nullptr); +} + +TEST(DexFileTest, get_method_not_opened) { + std::string method("something"); + uint64_t method_offset = 100; + DexFile dex_file; + dex_file.GetMethodInformation(0x100, &method, &method_offset); + EXPECT_EQ("something", method); + EXPECT_EQ(100U, method_offset); } TEST(DexFileTest, get_method) { From 8595c201cf4c1ad8dae5439fff3ec24d3ab93234 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Wed, 19 Dec 2018 13:40:11 +0000 Subject: [PATCH 059/221] Revert "Snap for 5189750 from 8051c86223527fb65325f514069bcdc42ce6afd0 to qt-release" This partially reverts commit ef04bcfc65f31c18d7abd3aee85d3f84d5d51434. Reason for revert: Revert change breaking renderscript on marlin and sailfish that has already been reverted upstream (aosp/853492). Bug: 121110092 Change-Id: I01d9309a5f650c8e5fd5125196cb533ffbc49720 (cherry picked from commit 381f046c36f4e998c24fe6e6540c893b88554843) --- debuggerd/Android.bp | 23 +- libunwindstack/Android.bp | 14 +- libunwindstack/DexFile.cpp | 198 +++++++++++++----- libunwindstack/DexFile.h | 33 +-- libunwindstack/DexFiles.cpp | 13 +- libunwindstack/include/unwindstack/DexFiles.h | 2 +- libunwindstack/tests/DexFileTest.cpp | 66 ++++-- 7 files changed, 231 insertions(+), 118 deletions(-) diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 516748176..d9fae5275 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -116,21 +116,14 @@ cc_library_static { "libdebuggerd", "libbacktrace", "libunwindstack", - "libdexfile", // libunwindstack dependency - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency + "libdexfile", "liblzma", "libcutils", ], target: { recovery: { cflags: ["-DNO_LIBDEXFILE_SUPPORT"], - exclude_static_libs: [ - "libartbase", - "libdexfile", - "libdexfile_external", - "libdexfile_support", - ], + exclude_static_libs: ["libdexfile"], }, }, @@ -177,22 +170,12 @@ cc_library_static { static_libs: [ "libbacktrace", - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency "libunwindstack", "liblzma", "libbase", "libcutils", "liblog", ], - target: { - recovery: { - exclude_static_libs: [ - "libdexfile_external", - "libdexfile_support", - ], - }, - }, } cc_test { @@ -233,8 +216,6 @@ cc_test { static_libs: [ "libdebuggerd", - "libdexfile_external", // libunwindstack dependency - "libdexfile_support", // libunwindstack dependency "libunwindstack", ], diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index 89d4fc0e8..4e0470e38 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -94,10 +94,7 @@ cc_library { "DexFile.cpp", "DexFiles.cpp", ], - exclude_shared_libs: [ - "libdexfile_external", - "libdexfile_support", - ], + exclude_shared_libs: ["libdexfile"], }, recovery: { cflags: ["-DNO_LIBDEXFILE_SUPPORT"], @@ -105,10 +102,7 @@ cc_library { "DexFile.cpp", "DexFiles.cpp", ], - exclude_shared_libs: [ - "libdexfile_external", - "libdexfile_support", - ], + exclude_shared_libs: ["libdexfile"], }, }, @@ -133,8 +127,7 @@ cc_library { shared_libs: [ "libbase", - "libdexfile_external", - "libdexfile_support", + "libdexfile", "liblog", "liblzma", ], @@ -222,7 +215,6 @@ cc_test { "liblzma", "libunwindstack", "libdexfile", - "libdexfile_support", ], static_libs: [ diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp index 9b0b2328f..8ec560c3b 100644 --- a/libunwindstack/DexFile.cpp +++ b/libunwindstack/DexFile.cpp @@ -23,7 +23,13 @@ #include #include -#include + +#include +#include +#include +#include +#include +#include #include #include @@ -32,71 +38,169 @@ namespace unwindstack { -std::unique_ptr DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, - MapInfo* info) { +DexFile* DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) { if (!info->name.empty()) { - std::unique_ptr dex_file = - DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name); - if (dex_file) { - return dex_file; + std::unique_ptr dex_file(new DexFileFromFile); + if (dex_file->Open(dex_file_offset_in_memory - info->start + info->offset, info->name)) { + return dex_file.release(); } } - return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name); + + std::unique_ptr dex_file(new DexFileFromMemory); + if (dex_file->Open(dex_file_offset_in_memory, memory)) { + return dex_file.release(); + } + return nullptr; +} + +DexFileFromFile::~DexFileFromFile() { + if (size_ != 0) { + munmap(mapped_memory_, size_); + } } bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset) { - art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset); - if (method_info.offset == 0) { + if (dex_file_ == nullptr) { return false; } - *method_name = method_info.name; - *method_offset = dex_offset - method_info.offset; - return true; + + if (!dex_file_->IsInDataSection(dex_file_->Begin() + dex_offset)) { + return false; // The DEX offset is not within the bytecode of this dex file. + } + + if (dex_file_->IsCompactDexFile()) { + // The data section of compact dex files might be shared. + // Check the subrange unique to this compact dex. + const auto& cdex_header = dex_file_->AsCompactDexFile()->GetHeader(); + uint32_t begin = cdex_header.data_off_ + cdex_header.OwnedDataBegin(); + uint32_t end = cdex_header.data_off_ + cdex_header.OwnedDataEnd(); + if (dex_offset < begin || dex_offset >= end) { + return false; // The DEX offset is not within the bytecode of this dex file. + } + } + + // The method data is cached in a std::map indexed by method end offset and + // contains the start offset and the method member index. + // Only cache the method data as it is searched. Do not read the entire + // set of method data into the cache at once. + // This is done because many unwinds only find a single frame with dex file + // info, so reading the entire method data is wasteful. However, still cache + // the data so that anything doing multiple unwinds will have this data + // cached for future use. + + // First look in the method cache. + auto entry = method_cache_.upper_bound(dex_offset); + if (entry != method_cache_.end() && dex_offset >= entry->second.first) { + *method_name = dex_file_->PrettyMethod(entry->second.second, false); + *method_offset = dex_offset - entry->second.first; + return true; + } + + // Check the methods we haven't cached. + for (; class_def_index_ < dex_file_->NumClassDefs(); class_def_index_++) { + art::ClassAccessor accessor(*dex_file_, dex_file_->GetClassDef(class_def_index_)); + + for (const art::ClassAccessor::Method& method : accessor.GetMethods()) { + art::CodeItemInstructionAccessor code = method.GetInstructions(); + if (!code.HasCodeItem()) { + continue; + } + uint32_t offset = reinterpret_cast(code.Insns()) - dex_file_->Begin(); + uint32_t offset_end = offset + code.InsnsSizeInBytes(); + uint32_t member_index = method.GetIndex(); + method_cache_[offset_end] = std::make_pair(offset, member_index); + if (offset <= dex_offset && dex_offset < offset_end) { + *method_name = dex_file_->PrettyMethod(member_index, false); + *method_offset = dex_offset - offset; + return true; + } + } + } + return false; } -std::unique_ptr DexFileFromFile::Create(uint64_t dex_file_offset_in_file, - const std::string& file) { +bool DexFileFromFile::Open(uint64_t dex_file_offset_in_file, const std::string& file) { android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(file.c_str(), O_RDONLY | O_CLOEXEC))); if (fd == -1) { - return nullptr; + return false; + } + struct stat buf; + if (fstat(fd, &buf) == -1) { + return false; + } + uint64_t length; + if (buf.st_size < 0 || + __builtin_add_overflow(dex_file_offset_in_file, sizeof(art::DexFile::Header), &length) || + static_cast(buf.st_size) < length) { + return false; } + mapped_memory_ = mmap(nullptr, buf.st_size, PROT_READ, MAP_PRIVATE, fd, 0); + if (mapped_memory_ == MAP_FAILED) { + return false; + } + size_ = buf.st_size; + + uint8_t* memory = reinterpret_cast(mapped_memory_); + + art::DexFile::Header* header = + reinterpret_cast(&memory[dex_file_offset_in_file]); + if (!art::StandardDexFile::IsMagicValid(header->magic_) && + !art::CompactDexFile::IsMagicValid(header->magic_)) { + return false; + } + + if (__builtin_add_overflow(dex_file_offset_in_file, header->file_size_, &length) || + static_cast(buf.st_size) < length) { + return false; + } + + art::DexFileLoader loader; std::string error_msg; - std::unique_ptr art_dex_file = - OpenFromFd(fd, dex_file_offset_in_file, file, &error_msg); - if (art_dex_file == nullptr) { - return nullptr; - } - - return std::unique_ptr(new DexFileFromFile(std::move(*art_dex_file.release()))); + auto dex = loader.Open(&memory[dex_file_offset_in_file], header->file_size_, "", 0, nullptr, + false, false, &error_msg); + dex_file_.reset(dex.release()); + return dex_file_ != nullptr; } -std::unique_ptr DexFileFromMemory::Create(uint64_t dex_file_offset_in_memory, - Memory* memory, - const std::string& name) { - std::vector backing_memory; - - for (size_t size = 0;;) { - std::string error_msg; - std::unique_ptr art_dex_file = - OpenFromMemory(backing_memory.data(), &size, name, &error_msg); - - if (art_dex_file != nullptr) { - return std::unique_ptr( - new DexFileFromMemory(std::move(*art_dex_file.release()), std::move(backing_memory))); - } - - if (!error_msg.empty()) { - return nullptr; - } - - backing_memory.resize(size); - if (!memory->ReadFully(dex_file_offset_in_memory, backing_memory.data(), - backing_memory.size())) { - return nullptr; - } +bool DexFileFromMemory::Open(uint64_t dex_file_offset_in_memory, Memory* memory) { + memory_.resize(sizeof(art::DexFile::Header)); + if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { + return false; } + + art::DexFile::Header* header = reinterpret_cast(memory_.data()); + uint32_t file_size = header->file_size_; + if (art::CompactDexFile::IsMagicValid(header->magic_)) { + // Compact dex file store data section separately so that it can be shared. + // Therefore we need to extend the read memory range to include it. + // TODO: This might be wasteful as we might read data in between as well. + // In practice, this should be fine, as such sharing only happens on disk. + uint32_t computed_file_size; + if (__builtin_add_overflow(header->data_off_, header->data_size_, &computed_file_size)) { + return false; + } + if (computed_file_size > file_size) { + file_size = computed_file_size; + } + } else if (!art::StandardDexFile::IsMagicValid(header->magic_)) { + return false; + } + + memory_.resize(file_size); + if (!memory->ReadFully(dex_file_offset_in_memory, memory_.data(), memory_.size())) { + return false; + } + + header = reinterpret_cast(memory_.data()); + + art::DexFileLoader loader; + std::string error_msg; + auto dex = + loader.Open(memory_.data(), header->file_size_, "", 0, nullptr, false, false, &error_msg); + dex_file_.reset(dex.release()); + return dex_file_ != nullptr; } } // namespace unwindstack diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h index 5797deec6..c123158ef 100644 --- a/libunwindstack/DexFile.h +++ b/libunwindstack/DexFile.h @@ -25,41 +25,48 @@ #include #include -#include +#include namespace unwindstack { -class DexFile : protected art_api::dex::DexFile { +class DexFile { public: + DexFile() = default; virtual ~DexFile() = default; bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); - static std::unique_ptr Create(uint64_t dex_file_offset_in_memory, Memory* memory, - MapInfo* info); + static DexFile* Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info); protected: - DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {} + void Init(); + + std::unique_ptr dex_file_; + std::map> method_cache_; // dex offset to method index. + + uint32_t class_def_index_ = 0; }; class DexFileFromFile : public DexFile { public: - static std::unique_ptr Create(uint64_t dex_file_offset_in_file, - const std::string& file); + DexFileFromFile() = default; + virtual ~DexFileFromFile(); + + bool Open(uint64_t dex_file_offset_in_file, const std::string& name); private: - DexFileFromFile(art_api::dex::DexFile&& art_dex_file) : DexFile(std::move(art_dex_file)) {} + void* mapped_memory_ = nullptr; + size_t size_ = 0; }; class DexFileFromMemory : public DexFile { public: - static std::unique_ptr Create(uint64_t dex_file_offset_in_memory, - Memory* memory, const std::string& name); + DexFileFromMemory() = default; + virtual ~DexFileFromMemory() = default; + + bool Open(uint64_t dex_file_offset_in_memory, Memory* memory); private: - DexFileFromMemory(art_api::dex::DexFile&& art_dex_file, std::vector&& memory) - : DexFile(std::move(art_dex_file)), memory_(std::move(memory)) {} - std::vector memory_; }; diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp index 63a77e50f..451a0b90d 100644 --- a/libunwindstack/DexFiles.cpp +++ b/libunwindstack/DexFiles.cpp @@ -48,7 +48,11 @@ DexFiles::DexFiles(std::shared_ptr& memory) : Global(memory) {} DexFiles::DexFiles(std::shared_ptr& memory, std::vector& search_libs) : Global(memory, search_libs) {} -DexFiles::~DexFiles() {} +DexFiles::~DexFiles() { + for (auto& entry : files_) { + delete entry.second; + } +} void DexFiles::ProcessArch() { switch (arch()) { @@ -133,11 +137,10 @@ DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { DexFile* dex_file; auto entry = files_.find(dex_file_offset); if (entry == files_.end()) { - std::unique_ptr new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); - dex_file = new_dex_file.get(); - files_[dex_file_offset] = std::move(new_dex_file); + dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); + files_[dex_file_offset] = dex_file; } else { - dex_file = entry->second.get(); + dex_file = entry->second; } return dex_file; } diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h index 033617362..c202a334d 100644 --- a/libunwindstack/include/unwindstack/DexFiles.h +++ b/libunwindstack/include/unwindstack/DexFiles.h @@ -66,7 +66,7 @@ class DexFiles : public Global { std::mutex lock_; bool initialized_ = false; - std::unordered_map> files_; + std::unordered_map files_; uint64_t entry_addr_ = 0; uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr; diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp index 21ca47b52..95d217631 100644 --- a/libunwindstack/tests/DexFileTest.cpp +++ b/libunwindstack/tests/DexFileTest.cpp @@ -21,37 +21,44 @@ #include #include -#include -#include + #include #include +#include +#include + +#include + #include "DexFile.h" + #include "DexFileData.h" #include "MemoryFake.h" namespace unwindstack { TEST(DexFileTest, from_file_open_non_exist) { - EXPECT_TRUE(DexFileFromFile::Create(0, "/file/does/not/exist") == nullptr); + DexFileFromFile dex_file; + ASSERT_FALSE(dex_file.Open(0, "/file/does/not/exist")); } TEST(DexFileTest, from_file_open_too_small) { TemporaryFile tf; ASSERT_TRUE(tf.fd != -1); - ASSERT_EQ(sizeof(art::DexFile::Header) - 1, + ASSERT_EQ(sizeof(art::DexFile::Header) - 2, static_cast( - TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1)))); + TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)) - 2))); // Header too small. - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr); + DexFileFromFile dex_file; + ASSERT_FALSE(dex_file.Open(0, tf.path)); // Header correct, file too small. ASSERT_EQ(0, lseek(tf.fd, 0, SEEK_SET)); ASSERT_EQ(sizeof(art::DexFile::Header), static_cast(TEMP_FAILURE_RETRY(write( tf.fd, kDexData, sizeof(art::DexFile::Header))))); - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) == nullptr); + ASSERT_FALSE(dex_file.Open(0, tf.path)); } TEST(DexFileTest, from_file_open) { @@ -61,7 +68,8 @@ TEST(DexFileTest, from_file_open) { ASSERT_EQ(sizeof(kDexData), static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - EXPECT_TRUE(DexFileFromFile::Create(0, tf.path) != nullptr); + DexFileFromFile dex_file; + ASSERT_TRUE(dex_file.Open(0, tf.path)); } TEST(DexFileTest, from_file_open_non_zero_offset) { @@ -72,31 +80,35 @@ TEST(DexFileTest, from_file_open_non_zero_offset) { ASSERT_EQ(sizeof(kDexData), static_cast(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData))))); - EXPECT_TRUE(DexFileFromFile::Create(0x100, tf.path) != nullptr); + DexFileFromFile dex_file; + ASSERT_TRUE(dex_file.Open(0x100, tf.path)); } TEST(DexFileTest, from_memory_fail_too_small_for_header) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(art::DexFile::Header) - 1); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr); + ASSERT_FALSE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, from_memory_fail_too_small_for_data) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(kDexData) - 2); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") == nullptr); + ASSERT_FALSE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, from_memory_open) { MemoryFake memory; memory.SetMemory(0x1000, kDexData, sizeof(kDexData)); + DexFileFromMemory dex_file; - EXPECT_TRUE(DexFileFromMemory::Create(0x1000, &memory, "") != nullptr); + ASSERT_TRUE(dex_file.Open(0x1000, &memory)); } TEST(DexFileTest, create_using_file) { @@ -109,7 +121,8 @@ TEST(DexFileTest, create_using_file) { MemoryFake memory; MapInfo info(nullptr, 0, 0x10000, 0, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x500, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x500, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_file_non_zero_start) { @@ -122,7 +135,8 @@ TEST(DexFileTest, create_using_file_non_zero_start) { MemoryFake memory; MapInfo info(nullptr, 0x100, 0x10000, 0, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x600, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x600, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_file_non_zero_offset) { @@ -135,21 +149,24 @@ TEST(DexFileTest, create_using_file_non_zero_offset) { MemoryFake memory; MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, tf.path); - EXPECT_TRUE(DexFile::Create(0x400, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x400, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_empty_file) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, ""); - EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_file_does_not_exist) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x100, 0x10000, 0x200, 0x5, "/does/not/exist"); - EXPECT_TRUE(DexFile::Create(0x4000, &memory, &info) != nullptr); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file != nullptr); } TEST(DexFileTest, create_using_memory_file_is_malformed) { @@ -162,13 +179,22 @@ TEST(DexFileTest, create_using_memory_file_is_malformed) { MemoryFake memory; memory.SetMemory(0x4000, kDexData, sizeof(kDexData)); MapInfo info(nullptr, 0x4000, 0x10000, 0x200, 0x5, "/does/not/exist"); - std::unique_ptr dex_file = DexFile::Create(0x4000, &memory, &info); + std::unique_ptr dex_file(DexFile::Create(0x4000, &memory, &info)); ASSERT_TRUE(dex_file != nullptr); // Check it came from memory by clearing memory and verifying it fails. memory.Clear(); - dex_file = DexFile::Create(0x4000, &memory, &info); - EXPECT_TRUE(dex_file == nullptr); + dex_file.reset(DexFile::Create(0x4000, &memory, &info)); + ASSERT_TRUE(dex_file == nullptr); +} + +TEST(DexFileTest, get_method_not_opened) { + std::string method("something"); + uint64_t method_offset = 100; + DexFile dex_file; + dex_file.GetMethodInformation(0x100, &method, &method_offset); + EXPECT_EQ("something", method); + EXPECT_EQ(100U, method_offset); } TEST(DexFileTest, get_method) { From 61e68cb8d7483636ef89ac45b937fdd90ddd8870 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?M=C3=A5rten=20Kongstad?= Date: Mon, 3 Dec 2018 12:56:49 +0100 Subject: [PATCH 060/221] Add systrace tag for RRO Introduce a new systrace tag, TRACE_TAG_RRO, for use with runtime resource overlay. Bug: 119761810 Test: builds Change-Id: I7b883d107a9ae2b12bbda04b74001a68e2a904aa --- libcutils/include/cutils/trace.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/libcutils/include/cutils/trace.h b/libcutils/include/cutils/trace.h index 58b9f0946..79b4b355b 100644 --- a/libcutils/include/cutils/trace.h +++ b/libcutils/include/cutils/trace.h @@ -75,7 +75,8 @@ __BEGIN_DECLS #define ATRACE_TAG_VIBRATOR (1<<23) #define ATRACE_TAG_AIDL (1<<24) #define ATRACE_TAG_NNAPI (1<<25) -#define ATRACE_TAG_LAST ATRACE_TAG_NNAPI +#define ATRACE_TAG_RRO (1<<26) +#define ATRACE_TAG_LAST ATRACE_TAG_RRO // Reserved for initialization. #define ATRACE_TAG_NOT_READY (1ULL<<63) From 5b4015d9083802003351ddf6472fe145c3f441cb Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Sun, 13 Jan 2019 19:39:46 -0800 Subject: [PATCH 061/221] meminfo: Fix ProcMemInfo ForEachVmaFromFile Caused by passing invalid parameters to getline(3) and the test failure went unnoticed. Bug: 111694435 Test: libmeminfo_test 1 --gtest_filter=TestProcMemInfo.ForEachVmaFromFileTest Change-Id: Ideb39604c58f89237b05d2f7c8edb67c5ae65768 Signed-off-by: Sandeep Patil --- libmeminfo/libmeminfo_test.cpp | 5 +++++ libmeminfo/procmeminfo.cpp | 3 ++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp index 20ed3bf41..2529bd76c 100644 --- a/libmeminfo/libmeminfo_test.cpp +++ b/libmeminfo/libmeminfo_test.cpp @@ -374,6 +374,9 @@ TEST(TestProcMemInfo, ForEachVmaFromFileTest) { auto collect_vmas = [&](const Vma& v) { vmas.push_back(v); }; ASSERT_TRUE(ForEachVmaFromFile(path, collect_vmas)); + // We should get a total of 6 vmas + ASSERT_EQ(vmas.size(), 6); + // Expect values to be equal to what we have in testdata1/smaps_short // Check for sizes first ASSERT_EQ(vmas[0].usage.vss, 32768); @@ -468,6 +471,8 @@ TEST(TestProcMemInfo, SmapsTest) { auto vmas = proc_mem.Smaps(path); ASSERT_FALSE(vmas.empty()); + // We should get a total of 6 vmas + ASSERT_EQ(vmas.size(), 6); // Expect values to be equal to what we have in testdata1/smaps_short // Check for sizes first diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp index 1f8db1a04..18ae9784a 100644 --- a/libmeminfo/procmeminfo.cpp +++ b/libmeminfo/procmeminfo.cpp @@ -338,8 +338,9 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) { char* line = nullptr; bool parsing_vma = false; ssize_t line_len; + size_t line_alloc = 0; Vma vma; - while ((line_len = getline(&line, 0, fp.get())) > 0) { + while ((line_len = getline(&line, &line_alloc, fp.get())) > 0) { // Make sure the line buffer terminates like a C string for ReadMapFile line[line_len] = '\0'; From 1a0d0afefb7674d5fdec381baa66b51b73c4b7f7 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Sat, 12 Jan 2019 21:29:19 -0800 Subject: [PATCH 062/221] meminfo: Remove unnecessary working set stats The Vma and ProcMemInfo objects do not need separate stats objects for storing working set. The Vma either has working set or memory usage information and never both. Bug: 111694435 Test: libmeminfo_test 1 Change-Id: I2df05f7e750bbba4325474633e705d6d68dd2ccb Signed-off-by: Sandeep Patil --- libmeminfo/include/meminfo/meminfo.h | 7 +--- libmeminfo/include/meminfo/procmeminfo.h | 1 - libmeminfo/procmeminfo.cpp | 43 ++++++++---------------- libmeminfo/tools/procmem.cpp | 12 +++---- libmeminfo/tools/procrank.cpp | 2 +- 5 files changed, 22 insertions(+), 43 deletions(-) diff --git a/libmeminfo/include/meminfo/meminfo.h b/libmeminfo/include/meminfo/meminfo.h index 5ee32d45f..2fc78670a 100644 --- a/libmeminfo/include/meminfo/meminfo.h +++ b/libmeminfo/include/meminfo/meminfo.h @@ -72,15 +72,10 @@ struct Vma { : start(s), end(e), offset(off), flags(f), name(n) {} ~Vma() = default; - void clear() { - memset(&usage, 0, sizeof(usage)); - memset(&wss, 0, sizeof(wss)); - } + void clear() { memset(&usage, 0, sizeof(usage)); } // Memory usage of this mapping. MemUsage usage; - // Working set within this mapping. - MemUsage wss; }; } // namespace meminfo diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h index 0bfd80f2f..c5f8c3c11 100644 --- a/libmeminfo/include/meminfo/procmeminfo.h +++ b/libmeminfo/include/meminfo/procmeminfo.h @@ -82,7 +82,6 @@ class ProcMemInfo final { std::vector maps_; MemUsage usage_; - MemUsage wss_; std::vector swap_offsets_; }; diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp index 18ae9784a..9345bda90 100644 --- a/libmeminfo/procmeminfo.cpp +++ b/libmeminfo/procmeminfo.cpp @@ -157,14 +157,14 @@ const MemUsage& ProcMemInfo::Wss() { if (!get_wss_) { LOG(WARNING) << "Trying to read process working set for " << pid_ << " using invalid object"; - return wss_; + return usage_; } if (maps_.empty() && !ReadMaps(get_wss_)) { LOG(ERROR) << "Failed to get working set for Process " << pid_; } - return wss_; + return usage_; } bool ProcMemInfo::ForEachVma(const VmaCallback& callback) { @@ -228,11 +228,7 @@ bool ProcMemInfo::ReadMaps(bool get_wss) { maps_.clear(); return false; } - if (get_wss) { - add_mem_usage(&wss_, vma.wss); - } else { - add_mem_usage(&usage_, vma.usage); - } + add_mem_usage(&usage_, vma.usage); } return true; @@ -300,31 +296,20 @@ bool ProcMemInfo::ReadVmaStats(int pagemap_fd, Vma& vma, bool get_wss) { // This effectively makes vss = rss for the working set is requested. // The libpagemap implementation returns vss > rss for // working set, which doesn't make sense. - vma.wss.vss += pagesz; - vma.wss.rss += pagesz; - vma.wss.uss += is_private ? pagesz : 0; - vma.wss.pss += pagesz / pg_counts[i]; - if (is_private) { - vma.wss.private_dirty += is_dirty ? pagesz : 0; - vma.wss.private_clean += is_dirty ? 0 : pagesz; - } else { - vma.wss.shared_dirty += is_dirty ? pagesz : 0; - vma.wss.shared_clean += is_dirty ? 0 : pagesz; - } + vma.usage.vss += pagesz; + } + + vma.usage.rss += pagesz; + vma.usage.uss += is_private ? pagesz : 0; + vma.usage.pss += pagesz / pg_counts[i]; + if (is_private) { + vma.usage.private_dirty += is_dirty ? pagesz : 0; + vma.usage.private_clean += is_dirty ? 0 : pagesz; } else { - vma.usage.rss += pagesz; - vma.usage.uss += is_private ? pagesz : 0; - vma.usage.pss += pagesz / pg_counts[i]; - if (is_private) { - vma.usage.private_dirty += is_dirty ? pagesz : 0; - vma.usage.private_clean += is_dirty ? 0 : pagesz; - } else { - vma.usage.shared_dirty += is_dirty ? pagesz : 0; - vma.usage.shared_clean += is_dirty ? 0 : pagesz; - } + vma.usage.shared_dirty += is_dirty ? pagesz : 0; + vma.usage.shared_clean += is_dirty ? 0 : pagesz; } } - return true; } diff --git a/libmeminfo/tools/procmem.cpp b/libmeminfo/tools/procmem.cpp index b9b174db8..47881ed5b 100644 --- a/libmeminfo/tools/procmem.cpp +++ b/libmeminfo/tools/procmem.cpp @@ -98,7 +98,7 @@ static int show(const MemUsage& proc_stats, const std::vector& maps) { std::stringstream ss; print_header(ss); for (auto& vma : maps) { - const MemUsage& vma_stats = show_wss ? vma.wss : vma.usage; + const MemUsage& vma_stats = vma.usage; if (hide_zeroes && vma_stats.rss == 0) { continue; } @@ -116,14 +116,14 @@ static int show(const MemUsage& proc_stats, const std::vector& maps) { int main(int argc, char* argv[]) { int opt; auto pss_sort = [](const Vma& a, const Vma& b) { - uint64_t pss_a = show_wss ? a.wss.pss : a.usage.pss; - uint64_t pss_b = show_wss ? b.wss.pss : b.usage.pss; + uint64_t pss_a = a.usage.pss; + uint64_t pss_b = b.usage.pss; return pss_a > pss_b; }; auto uss_sort = [](const Vma& a, const Vma& b) { - uint64_t uss_a = show_wss ? a.wss.uss : a.usage.uss; - uint64_t uss_b = show_wss ? b.wss.uss : b.usage.uss; + uint64_t uss_a = a.usage.uss; + uint64_t uss_b = b.usage.uss; return uss_a > uss_b; }; @@ -182,7 +182,7 @@ int main(int argc, char* argv[]) { } ProcMemInfo proc(pid, show_wss); - const MemUsage& proc_stats = show_wss ? proc.Wss() : proc.Usage(); + const MemUsage& proc_stats = proc.Usage(); std::vector maps(proc.Maps()); if (sort_func != nullptr) { std::sort(maps.begin(), maps.end(), sort_func); diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp index a75172220..21a684c5c 100644 --- a/libmeminfo/tools/procrank.cpp +++ b/libmeminfo/tools/procrank.cpp @@ -465,7 +465,7 @@ int main(int argc, char* argv[]) { } // Skip processes with no memory mappings - uint64_t vss = show_wss ? proc.Wss().vss : proc.Usage().vss; + uint64_t vss = proc.Usage().vss; if (vss == 0) return true; // collect swap_offset counts from all processes in 1st pass From 4646a76d4f23355d18906160086d5f84fe9ccdc8 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Sun, 13 Jan 2019 16:47:20 -0800 Subject: [PATCH 063/221] meminfo: Add SmapsOrRollupPss Adds SmapsOrRollup parsing methods to only read Pss of the process fomr /proc//{smaps, smaps_rollup}. Bug: 111694435 Test: libmeminfo_test 1 --gtest_filter=TestProcMemInfo.* Change-Id: I31b982ae5ff2bb5b165ea33f6c57755ee34cbbc7 Signed-off-by: Sandeep Patil --- libmeminfo/include/meminfo/procmeminfo.h | 10 ++++++ libmeminfo/libmeminfo_test.cpp | 44 ++++++++++++++++++++++++ libmeminfo/procmeminfo.cpp | 23 +++++++++++++ 3 files changed, 77 insertions(+) diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h index c5f8c3c11..4cce133ae 100644 --- a/libmeminfo/include/meminfo/procmeminfo.h +++ b/libmeminfo/include/meminfo/procmeminfo.h @@ -66,6 +66,11 @@ class ProcMemInfo final { // All other fields of MemUsage are zeroed. bool SmapsOrRollup(bool use_rollup, MemUsage* stats) const; + // Used to parse either of /proc//{smaps, smaps_rollup} and record the process's + // Pss. The 'use_rollup' parameter decides which file is to be tried. + // Returns 'true' on success and the value of Pss in the out parameter. + bool SmapsOrRollupPss(bool use_rollup, uint64_t* pss) const; + const std::vector& SwapOffsets(); ~ProcMemInfo() = default; @@ -94,5 +99,10 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback); // or /proc//smaps_rollup bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats); +// Same as ProcMemInfo::SmapsOrRollupPss but reads the statistics directly +// from a file and returns total Pss in kB. The file MUST be in the same format +// as /proc//smaps or /proc//smaps_rollup +bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss); + } // namespace meminfo } // namespace android diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp index 2529bd76c..796a7d0fe 100644 --- a/libmeminfo/libmeminfo_test.cpp +++ b/libmeminfo/libmeminfo_test.cpp @@ -365,6 +365,50 @@ VmFlags: rd wr mr mw me ac EXPECT_EQ(stats.swap_pss, 70); } +TEST(TestProcMemInfo, SmapsOrRollupPssRollupTest) { + // This is a made up smaps for the test + std::string smaps = + R"smaps(12c00000-13440000 rw-p 00000000 00:00 0 [anon:dalvik-main space (region space)] +Name: [anon:dalvik-main space (region space)] +Size: 8448 kB +KernelPageSize: 4 kB +MMUPageSize: 4 kB +Rss: 2652 kB +Pss: 2652 kB +Shared_Clean: 840 kB +Shared_Dirty: 40 kB +Private_Clean: 84 kB +Private_Dirty: 2652 kB +Referenced: 2652 kB +Anonymous: 2652 kB +AnonHugePages: 0 kB +ShmemPmdMapped: 0 kB +Shared_Hugetlb: 0 kB +Private_Hugetlb: 0 kB +Swap: 102 kB +SwapPss: 70 kB +Locked: 2652 kB +VmFlags: rd wr mr mw me ac +)smaps"; + + TemporaryFile tf; + ASSERT_TRUE(tf.fd != -1); + ASSERT_TRUE(::android::base::WriteStringToFd(smaps, tf.fd)); + + uint64_t pss; + ASSERT_EQ(SmapsOrRollupPssFromFile(tf.path, &pss), true); + EXPECT_EQ(pss, 2652); +} + +TEST(TestProcMemInfo, SmapsOrRollupPssSmapsTest) { + std::string exec_dir = ::android::base::GetExecutableDirectory(); + std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str()); + + uint64_t pss; + ASSERT_EQ(SmapsOrRollupPssFromFile(path, &pss), true); + EXPECT_EQ(pss, 19119); +} + TEST(TestProcMemInfo, ForEachVmaFromFileTest) { std::string exec_dir = ::android::base::GetExecutableDirectory(); std::string path = ::android::base::StringPrintf("%s/testdata1/smaps_short", exec_dir.c_str()); diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp index 9345bda90..f72d46964 100644 --- a/libmeminfo/procmeminfo.cpp +++ b/libmeminfo/procmeminfo.cpp @@ -178,6 +178,12 @@ bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const { return SmapsOrRollupFromFile(path, stats); }; +bool ProcMemInfo::SmapsOrRollupPss(bool use_rollup, uint64_t* pss) const { + std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_, + use_rollup ? "smaps_rollup" : "smaps"); + return SmapsOrRollupPssFromFile(path, pss); +} + const std::vector& ProcMemInfo::SwapOffsets() { if (get_wss_) { LOG(WARNING) << "Trying to read process swap offsets for " << pid_ @@ -412,5 +418,22 @@ bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) { return true; } +bool SmapsOrRollupPssFromFile(const std::string& path, uint64_t* pss) { + auto fp = std::unique_ptr{fopen(path.c_str(), "re"), fclose}; + if (fp == nullptr) { + return false; + } + *pss = 0; + char line[1024]; + while (fgets(line, sizeof(line), fp.get()) != nullptr) { + uint64_t v; + if (sscanf(line, "Pss: %" SCNu64 " kB", &v) == 1) { + *pss += v; + } + } + + return true; +} + } // namespace meminfo } // namespace android From 7a6b5e820826cb7b824078b51d3959d91bfbff2f Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Sun, 13 Jan 2019 17:39:08 -0800 Subject: [PATCH 064/221] meminfo: Add IsSmapsRollupSupported Api Consolidate the checking of /proc//smaps_rollup support in libmeminfo and do it in a thread safe way. Use the API in ProcMemInfo as well to eliminate the extra parameters passed to SmapsOrRollup* methods. Bug: 111694435 Test: libmeminfo_test 1 --gtest_filter=TestProcMemInfo.IsSmapsSupportedTest Test: Tested with and without the smaps_rollup support in kernel. Change-Id: I992057f06b54569025fa0cdade9618da2675d1de Signed-off-by: Sandeep Patil --- libmeminfo/include/meminfo/procmeminfo.h | 12 +++++-- libmeminfo/libmeminfo_test.cpp | 11 ++++++- libmeminfo/procmeminfo.cpp | 40 +++++++++++++++++++----- 3 files changed, 52 insertions(+), 11 deletions(-) diff --git a/libmeminfo/include/meminfo/procmeminfo.h b/libmeminfo/include/meminfo/procmeminfo.h index 4cce133ae..0b66074aa 100644 --- a/libmeminfo/include/meminfo/procmeminfo.h +++ b/libmeminfo/include/meminfo/procmeminfo.h @@ -64,12 +64,12 @@ class ProcMemInfo final { // private_dirty // SwapPss // All other fields of MemUsage are zeroed. - bool SmapsOrRollup(bool use_rollup, MemUsage* stats) const; + bool SmapsOrRollup(MemUsage* stats) const; // Used to parse either of /proc//{smaps, smaps_rollup} and record the process's - // Pss. The 'use_rollup' parameter decides which file is to be tried. + // Pss. // Returns 'true' on success and the value of Pss in the out parameter. - bool SmapsOrRollupPss(bool use_rollup, uint64_t* pss) const; + bool SmapsOrRollupPss(uint64_t* pss) const; const std::vector& SwapOffsets(); @@ -94,6 +94,12 @@ class ProcMemInfo final { // same format as /proc//smaps. Returns 'false' if the file is malformed. bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback); +// Returns if the kernel supports /proc//smaps_rollup. Assumes that the +// calling process has access to the /proc//smaps_rollup. +// Returns 'false' if the calling process has no permission to read the file if it exists +// of if the file doesn't exist. +bool IsSmapsRollupSupported(pid_t pid); + // Same as ProcMemInfo::SmapsOrRollup but reads the statistics directly // from a file. The file MUST be in the same format as /proc//smaps // or /proc//smaps_rollup diff --git a/libmeminfo/libmeminfo_test.cpp b/libmeminfo/libmeminfo_test.cpp index 796a7d0fe..e689a2679 100644 --- a/libmeminfo/libmeminfo_test.cpp +++ b/libmeminfo/libmeminfo_test.cpp @@ -284,13 +284,22 @@ TEST(TestProcMemInfo, SwapOffsetsEmpty) { EXPECT_EQ(swap_offsets.size(), 0); } +TEST(TestProcMemInfo, IsSmapsSupportedTest) { + std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); + bool supported = IsSmapsRollupSupported(pid); + EXPECT_EQ(!access(path.c_str(), F_OK | R_OK), supported); + // Second call must return what the first one returned regardless of the pid parameter. + // So, deliberately pass invalid pid. + EXPECT_EQ(supported, IsSmapsRollupSupported(-1)); +} + TEST(TestProcMemInfo, SmapsOrRollupReturn) { // if /proc//smaps_rollup file exists, .SmapsRollup() must return true; // false otherwise std::string path = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); ProcMemInfo proc_mem(pid); MemUsage stats; - EXPECT_EQ(!access(path.c_str(), F_OK), proc_mem.SmapsOrRollup(true, &stats)); + EXPECT_EQ(!access(path.c_str(), F_OK), proc_mem.SmapsOrRollup(&stats)); } TEST(TestProcMemInfo, SmapsOrRollupTest) { diff --git a/libmeminfo/procmeminfo.cpp b/libmeminfo/procmeminfo.cpp index f72d46964..347a293a9 100644 --- a/libmeminfo/procmeminfo.cpp +++ b/libmeminfo/procmeminfo.cpp @@ -21,6 +21,7 @@ #include #include +#include #include #include #include @@ -172,15 +173,15 @@ bool ProcMemInfo::ForEachVma(const VmaCallback& callback) { return ForEachVmaFromFile(path, callback); } -bool ProcMemInfo::SmapsOrRollup(bool use_rollup, MemUsage* stats) const { - std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_, - use_rollup ? "smaps_rollup" : "smaps"); +bool ProcMemInfo::SmapsOrRollup(MemUsage* stats) const { + std::string path = ::android::base::StringPrintf( + "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps"); return SmapsOrRollupFromFile(path, stats); -}; +} -bool ProcMemInfo::SmapsOrRollupPss(bool use_rollup, uint64_t* pss) const { - std::string path = ::android::base::StringPrintf("/proc/%d/%s", pid_, - use_rollup ? "smaps_rollup" : "smaps"); +bool ProcMemInfo::SmapsOrRollupPss(uint64_t* pss) const { + std::string path = ::android::base::StringPrintf( + "/proc/%d/%s", pid_, IsSmapsRollupSupported(pid_) ? "smaps_rollup" : "smaps"); return SmapsOrRollupPssFromFile(path, pss); } @@ -374,6 +375,31 @@ bool ForEachVmaFromFile(const std::string& path, const VmaCallback& callback) { return true; } +enum smaps_rollup_support { UNTRIED, SUPPORTED, UNSUPPORTED }; + +static std::atomic g_rollup_support = UNTRIED; + +bool IsSmapsRollupSupported(pid_t pid) { + // Similar to OpenSmapsOrRollup checks from android_os_Debug.cpp, except + // the method only checks if rollup is supported and returns the status + // right away. + enum smaps_rollup_support rollup_support = g_rollup_support.load(std::memory_order_relaxed); + if (rollup_support != UNTRIED) { + return rollup_support == SUPPORTED; + } + std::string rollup_file = ::android::base::StringPrintf("/proc/%d/smaps_rollup", pid); + if (access(rollup_file.c_str(), F_OK | R_OK)) { + // No check for errno = ENOENT necessary here. The caller MUST fallback to + // using /proc//smaps instead anyway. + g_rollup_support.store(UNSUPPORTED, std::memory_order_relaxed); + return false; + } + + g_rollup_support.store(SUPPORTED, std::memory_order_relaxed); + LOG(INFO) << "Using smaps_rollup for pss collection"; + return true; +} + bool SmapsOrRollupFromFile(const std::string& path, MemUsage* stats) { auto fp = std::unique_ptr{fopen(path.c_str(), "re"), fclose}; if (fp == nullptr) { From c4e6cb6145a6f19f1a540b2aaba48b4877d3f397 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Mon, 14 Jan 2019 16:57:55 -0800 Subject: [PATCH 065/221] Add libprocessgroup into VNDK Include libprocessgroup into vndk in preparation for sched_policy functions to be moved into it. Bug: 111307099 Test: builds, boots Change-Id: I09a528cac8821df3201c2428b151fd2eaece3ccb Signed-off-by: Suren Baghdasaryan --- libprocessgroup/Android.bp | 3 +++ libprocessgroup/processgroup.cpp | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index c38279df4..05397292c 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -3,7 +3,10 @@ cc_library { name: "libprocessgroup", host_supported: true, recovery_available: true, + vendor_available: true, shared_libs: ["libbase"], + // for cutils/android_filesystem_config.h + header_libs: [ "libcutils_headers" ], export_include_dirs: ["include"], cflags: [ "-Wall", diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 9df8dd96f..8d2ac3d57 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -42,7 +42,7 @@ #include #include #include -#include +#include #include From e1d970df09af55bbab9d9df438ff71088c7842d7 Mon Sep 17 00:00:00 2001 From: Nicolas Geoffray Date: Sat, 12 Jan 2019 15:01:20 +0000 Subject: [PATCH 066/221] Move to C API of libnativeloader. Test: m Bug: 119840313 Bug: 122710865 Change-Id: Id5b08ef5de0d38cb678a50e45d38dfb8107c4a1c --- libnativeloader/Android.bp | 16 +++++ .../include/nativeloader/dlext_namespaces.h | 16 +++-- .../include/nativeloader/native_loader.h | 50 ++++++++------- libnativeloader/libnativeloader.map.txt | 31 ++++++++++ libnativeloader/native_loader.cpp | 61 ++++++++----------- libnativeloader/test/Android.bp | 11 ++++ libnativeloader/test/api_test.c | 25 ++++++++ 7 files changed, 144 insertions(+), 66 deletions(-) create mode 100644 libnativeloader/libnativeloader.map.txt create mode 100644 libnativeloader/test/api_test.c diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp index 17983bc14..8903b72c7 100644 --- a/libnativeloader/Android.bp +++ b/libnativeloader/Android.bp @@ -23,4 +23,20 @@ cc_library { "llndk.libraries.txt", "vndksp.libraries.txt", ], + target: { + android: { + version_script: "libnativeloader.map.txt", + }, + }, + stubs: { + symbol_file: "libnativeloader.map.txt", + versions: ["1"], + }, +} + +cc_library_headers { + name: "libnativeloader-dummy-headers", + + host_supported: true, + export_include_dirs: ["include"], } diff --git a/libnativeloader/include/nativeloader/dlext_namespaces.h b/libnativeloader/include/nativeloader/dlext_namespaces.h index 43c932978..ca026b3be 100644 --- a/libnativeloader/include/nativeloader/dlext_namespaces.h +++ b/libnativeloader/include/nativeloader/dlext_namespaces.h @@ -18,6 +18,7 @@ #define __ANDROID_DLEXT_NAMESPACES_H__ #include +#include __BEGIN_DECLS @@ -84,12 +85,9 @@ enum { * If a library or any of its dependencies are outside of the permitted_when_isolated_path * and search_path, and it is not part of the public namespace dlopen will fail. */ -extern struct android_namespace_t* android_create_namespace(const char* name, - const char* ld_library_path, - const char* default_library_path, - uint64_t type, - const char* permitted_when_isolated_path, - android_namespace_t* parent); +extern struct android_namespace_t* android_create_namespace( + const char* name, const char* ld_library_path, const char* default_library_path, uint64_t type, + const char* permitted_when_isolated_path, struct android_namespace_t* parent); /* * Creates a link between namespaces. Every link has list of sonames of @@ -107,8 +105,8 @@ extern struct android_namespace_t* android_create_namespace(const char* name, * step will not go deeper into linked namespaces for this library but * will do so for DT_NEEDED libraries. */ -extern bool android_link_namespaces(android_namespace_t* from, - android_namespace_t* to, +extern bool android_link_namespaces(struct android_namespace_t* from, + struct android_namespace_t* to, const char* shared_libs_sonames); /* @@ -124,7 +122,7 @@ extern bool android_link_namespaces(android_namespace_t* from, */ extern void android_get_LD_LIBRARY_PATH(char* buffer, size_t buffer_size); -extern android_namespace_t* android_get_exported_namespace(const char* name); +extern struct android_namespace_t* android_get_exported_namespace(const char* name); __END_DECLS diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h index c1d9d2a92..af53dc5a1 100644 --- a/libnativeloader/include/nativeloader/native_loader.h +++ b/libnativeloader/include/nativeloader/native_loader.h @@ -17,14 +17,21 @@ #ifndef NATIVE_LOADER_H_ #define NATIVE_LOADER_H_ -#include "jni.h" +#include #include -#include +#include "jni.h" #if defined(__ANDROID__) #include #endif +#ifdef __cplusplus namespace android { +extern "C" { +#endif // __cplusplus + +// README: the char** error message parameter being passed +// to the methods below need to be freed through calling NativeLoaderFreeErrorMessage. +// It's the caller's responsibility to call that method. __attribute__((visibility("default"))) void InitializeNativeLoader(); @@ -38,42 +45,39 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, jstring library_path, jstring permitted_path); -__attribute__((visibility("default"))) -void* OpenNativeLibrary(JNIEnv* env, - int32_t target_sdk_version, - const char* path, - jobject class_loader, - jstring library_path, - bool* needs_native_bridge, - std::string* error_msg); +__attribute__((visibility("default"))) void* OpenNativeLibrary( + JNIEnv* env, int32_t target_sdk_version, const char* path, jobject class_loader, + jstring library_path, bool* needs_native_bridge, char** error_msg); __attribute__((visibility("default"))) bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, - std::string* error_msg); + char** error_msg); + +__attribute__((visibility("default"))) void NativeLoaderFreeErrorMessage(char* msg); #if defined(__ANDROID__) // Look up linker namespace by class_loader. Returns nullptr if // there is no namespace associated with the class_loader. // TODO(b/79940628): move users to FindNativeLoaderNamespaceByClassLoader and remove this function. -__attribute__((visibility("default"))) -android_namespace_t* FindNamespaceByClassLoader(JNIEnv* env, jobject class_loader); -// That version works with native bridge namespaces, but requires use of OpenNativeLibrary. -class NativeLoaderNamespace; -__attribute__((visibility("default"))) -NativeLoaderNamespace* FindNativeLoaderNamespaceByClassLoader( +__attribute__((visibility("default"))) struct android_namespace_t* FindNamespaceByClassLoader( JNIEnv* env, jobject class_loader); +// That version works with native bridge namespaces, but requires use of OpenNativeLibrary. +struct NativeLoaderNamespace; +__attribute__((visibility("default"))) struct NativeLoaderNamespace* +FindNativeLoaderNamespaceByClassLoader(JNIEnv* env, jobject class_loader); // Load library. Unlinke OpenNativeLibrary above couldn't create namespace on demand, but does // not require access to JNIEnv either. -__attribute__((visibility("default"))) -void* OpenNativeLibrary(NativeLoaderNamespace* ns, - const char* path, - bool* needs_native_bridge, - std::string* error_msg); +__attribute__((visibility("default"))) void* OpenNativeLibraryInNamespace( + struct NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge, + char** error_msg); #endif __attribute__((visibility("default"))) void ResetNativeLoader(); -}; // namespace android +#ifdef __cplusplus +} // extern "C" +} // namespace android +#endif // __cplusplus #endif // NATIVE_BRIDGE_H_ diff --git a/libnativeloader/libnativeloader.map.txt b/libnativeloader/libnativeloader.map.txt new file mode 100644 index 000000000..40c30bd4a --- /dev/null +++ b/libnativeloader/libnativeloader.map.txt @@ -0,0 +1,31 @@ +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# TODO(b/122710865): Prune these uses once the runtime APEX is complete. +LIBNATIVELOADER_1 { + global: + OpenNativeLibrary; + InitializeNativeLoader; + ResetNativeLoader; + CloseNativeLibrary; + OpenNativeLibraryInNamespace; + FindNamespaceByClassLoader; + FindNativeLoaderNamespaceByClassLoader; + CreateClassLoaderNamespace; + NativeLoaderFreeErrorMessage; + local: + *; +}; diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index de7ea0885..f231afa5b 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -52,7 +52,7 @@ using namespace std::string_literals; namespace android { #if defined(__ANDROID__) -class NativeLoaderNamespace { +struct NativeLoaderNamespace { public: NativeLoaderNamespace() : android_ns_(nullptr), native_bridge_ns_(nullptr) { } @@ -151,14 +151,9 @@ class LibraryNamespaces { public: LibraryNamespaces() : initialized_(false) { } - NativeLoaderNamespace* Create(JNIEnv* env, - uint32_t target_sdk_version, - jobject class_loader, - bool is_shared, - bool is_for_vendor, - jstring java_library_path, - jstring java_permitted_path, - std::string* error_msg) { + NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, + bool is_shared, bool is_for_vendor, jstring java_library_path, + jstring java_permitted_path, std::string* error_msg) { std::string library_path; // empty string by default. if (java_library_path != nullptr) { @@ -628,13 +623,9 @@ jstring CreateClassLoaderNamespace(JNIEnv* env, return nullptr; } -void* OpenNativeLibrary(JNIEnv* env, - int32_t target_sdk_version, - const char* path, - jobject class_loader, - jstring library_path, - bool* needs_native_bridge, - std::string* error_msg) { +void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* path, + jobject class_loader, jstring library_path, bool* needs_native_bridge, + char** error_msg) { #if defined(__ANDROID__) UNUSED(target_sdk_version); if (class_loader == nullptr) { @@ -652,19 +643,16 @@ void* OpenNativeLibrary(JNIEnv* env, if ((ns = g_namespaces->FindNamespaceByClassLoader(env, class_loader)) == nullptr) { // This is the case where the classloader was not created by ApplicationLoaders // In this case we create an isolated not-shared namespace for it. - if ((ns = g_namespaces->Create(env, - target_sdk_version, - class_loader, - false /* is_shared */, - false /* is_for_vendor */, - library_path, - nullptr, - error_msg)) == nullptr) { + std::string create_error_msg; + if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, + false /* is_for_vendor */, library_path, nullptr, + &create_error_msg)) == nullptr) { + *error_msg = strdup(create_error_msg.c_str()); return nullptr; } } - return OpenNativeLibrary(ns, path, needs_native_bridge, error_msg); + return OpenNativeLibraryInNamespace(ns, path, needs_native_bridge, error_msg); #else UNUSED(env, target_sdk_version, class_loader); @@ -705,35 +693,40 @@ void* OpenNativeLibrary(JNIEnv* env, if (handle != nullptr) { return handle; } - *error_msg = NativeBridgeGetError(); + *error_msg = strdup(NativeBridgeGetError()); } else { - *error_msg = dlerror(); + *error_msg = strdup(dlerror()); } } return nullptr; #endif } -bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, std::string* error_msg) { +bool CloseNativeLibrary(void* handle, const bool needs_native_bridge, char** error_msg) { bool success; if (needs_native_bridge) { success = (NativeBridgeUnloadLibrary(handle) == 0); if (!success) { - *error_msg = NativeBridgeGetError(); + *error_msg = strdup(NativeBridgeGetError()); } } else { success = (dlclose(handle) == 0); if (!success) { - *error_msg = dlerror(); + *error_msg = strdup(dlerror()); } } return success; } +void NativeLoaderFreeErrorMessage(char* msg) { + // The error messages get allocated through strdup, so we must call free on them. + free(msg); +} + #if defined(__ANDROID__) -void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs_native_bridge, - std::string* error_msg) { +void* OpenNativeLibraryInNamespace(NativeLoaderNamespace* ns, const char* path, + bool* needs_native_bridge, char** error_msg) { if (ns->is_android_namespace()) { android_dlextinfo extinfo; extinfo.flags = ANDROID_DLEXT_USE_NAMESPACE; @@ -741,14 +734,14 @@ void* OpenNativeLibrary(NativeLoaderNamespace* ns, const char* path, bool* needs void* handle = android_dlopen_ext(path, RTLD_NOW, &extinfo); if (handle == nullptr) { - *error_msg = dlerror(); + *error_msg = strdup(dlerror()); } *needs_native_bridge = false; return handle; } else { void* handle = NativeBridgeLoadLibraryExt(path, RTLD_NOW, ns->get_native_bridge_ns()); if (handle == nullptr) { - *error_msg = NativeBridgeGetError(); + *error_msg = strdup(NativeBridgeGetError()); } *needs_native_bridge = true; return handle; diff --git a/libnativeloader/test/Android.bp b/libnativeloader/test/Android.bp index d528f3031..1464e39f3 100644 --- a/libnativeloader/test/Android.bp +++ b/libnativeloader/test/Android.bp @@ -69,3 +69,14 @@ cc_library { "libbase", ], } + +// Build the test for the C API. +cc_test { + name: "libnativeloader-api-tests", + host_supported: true, + test_per_src: true, + srcs: [ + "api_test.c", + ], + header_libs: ["libnativeloader-dummy-headers"], +} diff --git a/libnativeloader/test/api_test.c b/libnativeloader/test/api_test.c new file mode 100644 index 000000000..e7025fd7a --- /dev/null +++ b/libnativeloader/test/api_test.c @@ -0,0 +1,25 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* The main purpose of this test is to ensure this C header compiles in C, so + * that no C++ features inadvertently leak into the C ABI. */ +#include "nativeloader/native_loader.h" + +int main(int argc, char** argv) { + (void)argc; + (void)argv; + return 0; +} From 3a63283affdb32674c06e81da584682da36ba88b Mon Sep 17 00:00:00 2001 From: Srinivas Paladugu Date: Wed, 9 Jan 2019 11:28:59 -0800 Subject: [PATCH 067/221] Allow write access to system_server on zram sysfs System server needs to be able to write to idle and writeback nodes in the zram sysfs directory. Bug: 117682284 Bug: 122674343 Test: Test writeback on go ref device Change-Id: I1cd663b73a7ebb255fe7e459601e720961bbd69e --- rootdir/init.rc | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index 9b2096412..026dbedca 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -643,6 +643,12 @@ on boot chown root system /sys/module/lowmemorykiller/parameters/minfree chmod 0664 /sys/module/lowmemorykiller/parameters/minfree + # System server manages zram writeback + chown root system /sys/block/zram0/idle + chmod 0664 /sys/block/zram0/idle + chown root system /sys/block/zram0/writeback + chmod 0664 /sys/block/zram0/writeback + # Tweak background writeout write /proc/sys/vm/dirty_expire_centisecs 200 write /proc/sys/vm/dirty_background_ratio 5 From d17e357fa156b8063541df2e3be490f043f10874 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 21 Dec 2018 11:34:23 -0800 Subject: [PATCH 068/221] libcutils: Move sched_policy functions into libprocessgroup Move functions operating on cgroups from sched_policy.h in libcutils into sched_policy_ctrl.h under libprocessgroup. This consolidates cgroup-related functionality inside libprocessgroup. Bug: 111307099 Test: builds, boots Change-Id: Iba75f33281162b889989214d0325a5973d53ed2d Signed-off-by: Suren Baghdasaryan --- libcutils/Android.bp | 7 +- libcutils/include/cutils/sched_policy.h | 63 +-------------- libcutils/tests/Android.bp | 1 + libprocessgroup/Android.bp | 33 +++++++- .../include/processgroup/sched_policy.h | 80 +++++++++++++++++++ .../sched_policy.cpp | 2 +- 6 files changed, 121 insertions(+), 65 deletions(-) create mode 100644 libprocessgroup/include/processgroup/sched_policy.h rename {libcutils => libprocessgroup}/sched_policy.cpp (99%) diff --git a/libcutils/Android.bp b/libcutils/Android.bp index 4291212a1..0dbbc3f2f 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -66,7 +66,6 @@ cc_library { "load_file.cpp", "native_handle.cpp", "record_stream.cpp", - "sched_policy.cpp", "sockets.cpp", "strdup16to8.cpp", "strdup8to16.cpp", @@ -178,8 +177,12 @@ cc_library { "libbase_headers", "libcutils_headers", "libutils_headers", + "libprocessgroup_headers", + ], + export_header_lib_headers: [ + "libcutils_headers", + "libprocessgroup_headers", ], - export_header_lib_headers: ["libcutils_headers"], local_include_dirs: ["include"], cflags: [ diff --git a/libcutils/include/cutils/sched_policy.h b/libcutils/include/cutils/sched_policy.h index cf91b76f4..538ff6b9b 100644 --- a/libcutils/include/cutils/sched_policy.h +++ b/libcutils/include/cutils/sched_policy.h @@ -17,67 +17,10 @@ #ifndef __CUTILS_SCHED_POLICY_H #define __CUTILS_SCHED_POLICY_H -#include - -#ifdef __cplusplus -extern "C" { -#endif - /* - * Check if Linux kernel enables CPUSETS feature. - * - * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise. + * For backwards compatibility only + * New users should include processgroup/sched_policy.h directly */ -extern bool cpusets_enabled(); - -/* - * Check if Linux kernel enables SCHEDTUNE feature (only available in Android - * common kernel or Linaro LSK, not in mainline Linux as of v4.9) - * - * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise. - */ -extern bool schedboost_enabled(); - -/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */ -typedef enum { - SP_DEFAULT = -1, - SP_BACKGROUND = 0, - SP_FOREGROUND = 1, - SP_SYSTEM = 2, // can't be used with set_sched_policy() - SP_AUDIO_APP = 3, - SP_AUDIO_SYS = 4, - SP_TOP_APP = 5, - SP_RT_APP = 6, - SP_RESTRICTED = 7, - SP_CNT, - SP_MAX = SP_CNT - 1, - SP_SYSTEM_DEFAULT = SP_FOREGROUND, -} SchedPolicy; - -extern int set_cpuset_policy(int tid, SchedPolicy policy); - -/* Assign thread tid to the cgroup associated with the specified policy. - * If the thread is a thread group leader, that is it's gettid() == getpid(), - * then the other threads in the same thread group are _not_ affected. - * On platforms which support gettid(), zero tid means current thread. - * Return value: 0 for success, or -errno for error. - */ -extern int set_sched_policy(int tid, SchedPolicy policy); - -/* Return the policy associated with the cgroup of thread tid via policy pointer. - * On platforms which support gettid(), zero tid means current thread. - * Return value: 0 for success, or -1 for error and set errno. - */ -extern int get_sched_policy(int tid, SchedPolicy *policy); - -/* Return a displayable string corresponding to policy. - * Return value: non-NULL NUL-terminated name of unspecified length; - * the caller is responsible for displaying the useful part of the string. - */ -extern const char *get_sched_policy_name(SchedPolicy policy); - -#ifdef __cplusplus -} -#endif +#include #endif /* __CUTILS_SCHED_POLICY_H */ diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp index 788419038..72ae55921 100644 --- a/libcutils/tests/Android.bp +++ b/libcutils/tests/Android.bp @@ -59,6 +59,7 @@ test_libraries = [ "libcutils", "liblog", "libbase", + "libprocessgroup", ] cc_test { diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index 05397292c..21d453ef6 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -1,13 +1,42 @@ +cc_library_headers { + name: "libprocessgroup_headers", + vendor_available: true, + recovery_available: true, + host_supported: true, + export_include_dirs: ["include"], + target: { + linux_bionic: { + enabled: true, + }, + windows: { + enabled: true, + }, + }, +} + cc_library { - srcs: ["processgroup.cpp"], + srcs: [ + "processgroup.cpp", + "sched_policy.cpp", + ], name: "libprocessgroup", host_supported: true, recovery_available: true, vendor_available: true, + vndk: { + enabled: true, + support_system_process: true, + }, shared_libs: ["libbase"], // for cutils/android_filesystem_config.h - header_libs: [ "libcutils_headers" ], + header_libs: [ + "libcutils_headers", + "libprocessgroup_headers", + ], export_include_dirs: ["include"], + export_header_lib_headers: [ + "libprocessgroup_headers", + ], cflags: [ "-Wall", "-Werror", diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h new file mode 100644 index 000000000..79a32fdeb --- /dev/null +++ b/libprocessgroup/include/processgroup/sched_policy.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* + * Check if Linux kernel enables CPUSETS feature. + * + * Return value: 1 if Linux kernel CONFIG_CPUSETS=y; 0 otherwise. + */ +extern bool cpusets_enabled(); + +/* + * Check if Linux kernel enables SCHEDTUNE feature (only available in Android + * common kernel or Linaro LSK, not in mainline Linux as of v4.9) + * + * Return value: 1 if Linux kernel CONFIG_CGROUP_SCHEDTUNE=y; 0 otherwise. + */ +extern bool schedboost_enabled(); + +/* Keep in sync with THREAD_GROUP_* in frameworks/base/core/java/android/os/Process.java */ +typedef enum { + SP_DEFAULT = -1, + SP_BACKGROUND = 0, + SP_FOREGROUND = 1, + SP_SYSTEM = 2, // can't be used with set_sched_policy() + SP_AUDIO_APP = 3, + SP_AUDIO_SYS = 4, + SP_TOP_APP = 5, + SP_RT_APP = 6, + SP_RESTRICTED = 7, + SP_CNT, + SP_MAX = SP_CNT - 1, + SP_SYSTEM_DEFAULT = SP_FOREGROUND, +} SchedPolicy; + +extern int set_cpuset_policy(int tid, SchedPolicy policy); + +/* Assign thread tid to the cgroup associated with the specified policy. + * If the thread is a thread group leader, that is it's gettid() == getpid(), + * then the other threads in the same thread group are _not_ affected. + * On platforms which support gettid(), zero tid means current thread. + * Return value: 0 for success, or -errno for error. + */ +extern int set_sched_policy(int tid, SchedPolicy policy); + +/* Return the policy associated with the cgroup of thread tid via policy pointer. + * On platforms which support gettid(), zero tid means current thread. + * Return value: 0 for success, or -1 for error and set errno. + */ +extern int get_sched_policy(int tid, SchedPolicy *policy); + +/* Return a displayable string corresponding to policy. + * Return value: non-NULL NUL-terminated name of unspecified length; + * the caller is responsible for displaying the useful part of the string. + */ +extern const char *get_sched_policy_name(SchedPolicy policy); + +#ifdef __cplusplus +} +#endif diff --git a/libcutils/sched_policy.cpp b/libprocessgroup/sched_policy.cpp similarity index 99% rename from libcutils/sched_policy.cpp rename to libprocessgroup/sched_policy.cpp index 3fa548f78..f95d7e48f 100644 --- a/libcutils/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -14,7 +14,7 @@ ** limitations under the License. */ -#include +#include #define LOG_TAG "SchedPolicy" From 634e8844199b90826d1faaf19c99301cd47bc4e3 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 21 Dec 2018 12:30:16 -0800 Subject: [PATCH 069/221] Add dependencies on libprocessgroup for sched_policy users After moving sched_policy functions into libprocessgroup its users require additional dependency and inclusion of sched_policy_ctrl.h header. Exempt-From-Owner-Approval: janitorial Bug: 111307099 Test: builds, boots Change-Id: Icc052080e1bce46ce06f7264446950cab0490a95 Signed-off-by: Suren Baghdasaryan --- healthd/Android.mk | 1 + libprocessgroup/Android.bp | 5 ++++- libutils/Android.bp | 3 +++ libutils/Threads.cpp | 2 +- lmkd/Android.bp | 1 + logcat/Android.bp | 2 +- logcat/logcat.cpp | 2 +- logd/Android.bp | 1 + logd/main.cpp | 2 +- 9 files changed, 14 insertions(+), 5 deletions(-) diff --git a/healthd/Android.mk b/healthd/Android.mk index 80bf84ae8..2127b9603 100644 --- a/healthd/Android.mk +++ b/healthd/Android.mk @@ -109,6 +109,7 @@ CHARGER_STATIC_LIBRARIES := \ libbase \ libutils \ libcutils \ + libprocessgroup \ liblog \ libm \ libc \ diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index 21d453ef6..d04a79a66 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -27,7 +27,10 @@ cc_library { enabled: true, support_system_process: true, }, - shared_libs: ["libbase"], + shared_libs: [ + "libbase", + "liblog", + ], // for cutils/android_filesystem_config.h header_libs: [ "libcutils_headers", diff --git a/libutils/Android.bp b/libutils/Android.bp index 3e8417eb9..fb7ca3254 100644 --- a/libutils/Android.bp +++ b/libutils/Android.bp @@ -22,11 +22,13 @@ cc_library_headers { "liblog_headers", "libsystem_headers", "libcutils_headers", + "libprocessgroup_headers", ], export_header_lib_headers: [ "liblog_headers", "libsystem_headers", "libcutils_headers", + "libprocessgroup_headers", ], export_include_dirs: ["include"], @@ -82,6 +84,7 @@ cc_defaults { shared_libs: [ "libcutils", + "libprocessgroup", "libdl", "libvndksupport", ], diff --git a/libutils/Threads.cpp b/libutils/Threads.cpp index 64bc4025d..31ca1383e 100644 --- a/libutils/Threads.cpp +++ b/libutils/Threads.cpp @@ -36,7 +36,7 @@ #include -#include +#include #if defined(__ANDROID__) # define __android_unused diff --git a/lmkd/Android.bp b/lmkd/Android.bp index 903d0e243..f9ed57cce 100644 --- a/lmkd/Android.bp +++ b/lmkd/Android.bp @@ -5,6 +5,7 @@ cc_binary { shared_libs: [ "libcutils", "liblog", + "libprocessgroup", ], static_libs: [ "libstatslogc", diff --git a/logcat/Android.bp b/logcat/Android.bp index 0543aba73..5030b1563 100644 --- a/logcat/Android.bp +++ b/logcat/Android.bp @@ -24,8 +24,8 @@ cc_defaults { ], shared_libs: [ "libbase", - "libcutils", "libpcrecpp", + "libprocessgroup", ], static_libs: ["liblog"], logtags: ["event.logtags"], diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp index 87bc6ae84..15e07feef 100644 --- a/logcat/logcat.cpp +++ b/logcat/logcat.cpp @@ -49,11 +49,11 @@ #include #include #include -#include #include #include #include #include +#include #include #include diff --git a/logd/Android.bp b/logd/Android.bp index 3abfc2171..bdbdf12e4 100644 --- a/logd/Android.bp +++ b/logd/Android.bp @@ -73,6 +73,7 @@ cc_binary { "libcutils", "libbase", "libpackagelistparser", + "libprocessgroup", "libcap", ], diff --git a/logd/main.cpp b/logd/main.cpp index 8c38d9aa3..fd3cdf877 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -38,12 +38,12 @@ #include #include #include -#include #include #include #include #include #include +#include #include #include "CommandListener.h" From a49d024987ccab7ede74c3954ddecdedb824f9f5 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 18 Jan 2019 12:28:32 +0900 Subject: [PATCH 070/221] Revert "Don't create separate mount namespaces for pre-apexd processes" This reverts commit 5ab1300481bdc6587139e3ab2bf96b675a8c4a01. Reason: Breaks some 3p apps. Bug: 122920047 Test: run the app, login. Change-Id: Iec3347d7f35fbb6f32fd1192135a0cf87dc123a7 (cherry picked from commit 80aec3f0f016933159c5a9a29214a444ca60fafa) --- init/service.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/init/service.cpp b/init/service.cpp index f3eafe410..c25628e15 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -990,18 +990,7 @@ Result Service::Start() { LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error(); } - // b/122559956: mount namespace is not cloned for the devices that don't support - // the update of bionic libraries via APEX. In that case, because the bionic - // libraries in the runtime APEX and the bootstrap bionic libraries are - // identical, it doesn't matter which libs are used. This is also to avoid the - // bug in sdcardfs which is triggered when we have multiple mount namespaces - // across vold and the others. BIONIC_UPDATABLE shall be true only for the - // devices where kernel has the fix for the sdcardfs bug (see the commit message - // for the fix). - static bool bionic_updatable = - android::base::GetBoolProperty("ro.apex.bionic_updatable", false); - - if (bionic_updatable && pre_apexd_) { + if (pre_apexd_) { // pre-apexd process gets a private copy of the mount namespace. // However, this does not mean that mount/unmount events are not // shared across pre-apexd processes and post-apexd processes. @@ -1028,8 +1017,7 @@ Result Service::Start() { } } - // b/122559956: same as above - if (bionic_updatable && pre_apexd_ && ServiceList::GetInstance().IsRuntimeAvailable()) { + if (pre_apexd_ && ServiceList::GetInstance().IsRuntimeAvailable()) { if (auto result = SetUpPreApexdMounts(); !result) { LOG(FATAL) << "Pre-apexd service '" << name_ << "' could not setup the mount points: " << result.error(); From cf1f0c117b549104b3372dfdb55eaec3424db726 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 18 Jan 2019 12:29:12 +0900 Subject: [PATCH 071/221] Revert "Bionic libs and the dynamic linker are bind mounted" This reverts commit 2599088ff67c10c66a70d3741c41529d3e11c7f5. Reason: Breaks some 3p apps. Bug: 122920047 Test: run the app, login. Change-Id: Idea332b1f91e9d2ac6ebd3879da7820c8ba2284f (cherry picked from commit 8b73dfc0a44e069e57592a50800b7ea10270ce83) --- init/builtins.cpp | 82 ----------------------------------------------- init/service.cpp | 76 ------------------------------------------- init/service.h | 25 --------------- rootdir/init.rc | 21 +++--------- 4 files changed, 5 insertions(+), 199 deletions(-) diff --git a/init/builtins.cpp b/init/builtins.cpp index 43a520fb9..8c1265a1c 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -1093,86 +1093,6 @@ static Result do_parse_apex_configs(const BuiltinArguments& args) { } } -static Result bind_mount_file(const char* source, const char* mount_point, - bool remount_private) { - if (remount_private && mount(nullptr, mount_point, nullptr, MS_PRIVATE, nullptr) == -1) { - return ErrnoError() << "Could not change " << mount_point << " to a private mount point"; - } - if (mount(source, mount_point, nullptr, MS_BIND, nullptr) == -1) { - return ErrnoError() << "Could not bind-mount " << source << " to " << mount_point; - } - return Success(); -} - -static Result bind_mount_bionic(const char* linker_source, const char* lib_dir_source, - const char* linker_mount_point, const char* lib_mount_dir, - bool remount_private) { - if (access(linker_source, F_OK) != 0) { - return Success(); - } - if (auto result = bind_mount_file(linker_source, linker_mount_point, remount_private); - !result) { - return result; - } - for (auto libname : kBionicLibFileNames) { - std::string mount_point = lib_mount_dir + libname; - std::string source = lib_dir_source + libname; - if (auto result = bind_mount_file(source.c_str(), mount_point.c_str(), remount_private); - !result) { - return result; - } - } - return Success(); -} - -// The bootstrap bionic libs and the bootstrap linker are bind-mounted to -// the mount points for pre-apexd processes. -static Result do_prepare_bootstrap_bionic(const BuiltinArguments& args) { - static bool prepare_bootstrap_bionic_done = false; - if (prepare_bootstrap_bionic_done) { - return Error() << "prepare_bootstrap_bionic was already executed. Cannot be executed again"; - } - if (auto result = bind_mount_bionic(kBootstrapLinkerPath, kBootstrapBionicLibsDir, - kLinkerMountPoint, kBionicLibsMountPointDir, false); - !result) { - return result; - } - if (auto result = bind_mount_bionic(kBootstrapLinkerPath64, kBootstrapBionicLibsDir64, - kLinkerMountPoint64, kBionicLibsMountPointDir64, false); - !result) { - return result; - } - - LOG(INFO) << "prepare_bootstrap_bionic done"; - prepare_bootstrap_bionic_done = true; - return Success(); -} - -// The bionic libs and the dynamic linker from the runtime APEX are bind-mounted -// to the mount points. As a result, the previous mounts done by -// prepare_bootstrap_bionic become hidden. -static Result do_setup_runtime_bionic(const BuiltinArguments& args) { - static bool setup_runtime_bionic_done = false; - if (setup_runtime_bionic_done) { - return Error() << "setup_runtime_bionic was already executed. Cannot be executed again"; - } - if (auto result = bind_mount_bionic(kRuntimeLinkerPath, kRuntimeBionicLibsDir, - kLinkerMountPoint, kBionicLibsMountPointDir, true); - !result) { - return result; - } - if (auto result = bind_mount_bionic(kRuntimeLinkerPath64, kRuntimeBionicLibsDir64, - kLinkerMountPoint64, kBionicLibsMountPointDir64, true); - !result) { - return result; - } - - ServiceList::GetInstance().MarkRuntimeAvailable(); - LOG(INFO) << "setup_runtime_bionic done"; - setup_runtime_bionic_done = true; - return Success(); -} - // Builtin-function-map start const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { constexpr std::size_t kMax = std::numeric_limits::max(); @@ -1211,7 +1131,6 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"mount_all", {1, kMax, {false, do_mount_all}}}, {"mount", {3, kMax, {false, do_mount}}}, {"parse_apex_configs", {0, 0, {false, do_parse_apex_configs}}}, - {"prepare_bootstrap_bionic",{0, 0, {false, do_prepare_bootstrap_bionic}}}, {"umount", {1, 1, {false, do_umount}}}, {"readahead", {1, 2, {true, do_readahead}}}, {"restart", {1, 1, {false, do_restart}}}, @@ -1220,7 +1139,6 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"rm", {1, 1, {true, do_rm}}}, {"rmdir", {1, 1, {true, do_rmdir}}}, {"setprop", {2, 2, {true, do_setprop}}}, - {"setup_runtime_bionic", {0, 0, {false, do_setup_runtime_bionic}}}, {"setrlimit", {3, 3, {false, do_setrlimit}}}, {"start", {1, 1, {false, do_start}}}, {"stop", {1, 1, {false, do_stop}}}, diff --git a/init/service.cpp b/init/service.cpp index c25628e15..638dc5a07 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -140,43 +140,6 @@ Result Service::SetUpMountNamespace() const { return Success(); } -Result Service::SetUpPreApexdMounts() const { - // If a pre-apexd service is 're' launched after the runtime APEX is - // available, unmount the linker and bionic libs which are currently - // bind mounted to the files in the runtime APEX. This will reveal - // the hidden mount points (targetting the bootstrap ones in the - // system partition) which were setup before the runtime APEX was - // started. Note that these unmounts are done in a separate mount namespace - // for the process. It does not affect other processes including the init. - if (pre_apexd_ && ServiceList::GetInstance().IsRuntimeAvailable()) { - if (access(kLinkerMountPoint, F_OK) == 0) { - if (umount(kLinkerMountPoint) == -1) { - return ErrnoError() << "Could not umount " << kLinkerMountPoint; - } - for (const auto& libname : kBionicLibFileNames) { - std::string mount_point = kBionicLibsMountPointDir + libname; - if (umount(mount_point.c_str()) == -1) { - return ErrnoError() << "Could not umount " << mount_point; - } - } - } - - if (access(kLinkerMountPoint64, F_OK) == 0) { - if (umount(kLinkerMountPoint64) == -1) { - return ErrnoError() << "Could not umount " << kLinkerMountPoint64; - } - for (const auto& libname : kBionicLibFileNames) { - std::string mount_point = kBionicLibsMountPointDir64 + libname; - std::string source = kBootstrapBionicLibsDir64 + libname; - if (umount(mount_point.c_str()) == -1) { - return ErrnoError() << "Could not umount " << mount_point; - } - } - } - } - return Success(); -} - Result Service::SetUpPidNamespace() const { if (prctl(PR_SET_NAME, name_.c_str()) == -1) { return ErrnoError() << "Could not set name"; @@ -966,14 +929,6 @@ Result Service::Start() { scon = *result; } - if (!ServiceList::GetInstance().IsRuntimeAvailable() && !pre_apexd_) { - // If this service is started before the runtime APEX gets available, - // mark it as pre-apexd one. Note that this marking is permanent. So - // for example, if the service is re-launched (e.g., due to crash), - // it is still recognized as pre-apexd... for consistency. - pre_apexd_ = true; - } - LOG(INFO) << "starting service '" << name_ << "'..."; pid_t pid = -1; @@ -990,26 +945,6 @@ Result Service::Start() { LOG(FATAL) << "Service '" << name_ << "' could not enter namespaces: " << result.error(); } - if (pre_apexd_) { - // pre-apexd process gets a private copy of the mount namespace. - // However, this does not mean that mount/unmount events are not - // shared across pre-apexd processes and post-apexd processes. - // *Most* of the events are still shared because the propagation - // type of / is set to 'shared'. (see `mount rootfs rootfs /shared - // rec` in init.rc) - // - // This unsharing is required to not propagate the mount events - // under /system/lib/{libc|libdl|libm}.so and /system/bin/linker(64) - // whose propagation type is set to private. With this, - // bind-mounting the bionic libs and the dynamic linker from the - // runtime APEX to the mount points does not affect pre-apexd - // processes which should use the bootstrap ones. - if (unshare(CLONE_NEWNS) != 0) { - LOG(FATAL) << "Creating a new mount namespace for service" - << " '" << name_ << "' failed: " << strerror(errno); - } - } - if (namespace_flags_ & CLONE_NEWNS) { if (auto result = SetUpMountNamespace(); !result) { LOG(FATAL) << "Service '" << name_ @@ -1017,13 +952,6 @@ Result Service::Start() { } } - if (pre_apexd_ && ServiceList::GetInstance().IsRuntimeAvailable()) { - if (auto result = SetUpPreApexdMounts(); !result) { - LOG(FATAL) << "Pre-apexd service '" << name_ - << "' could not setup the mount points: " << result.error(); - } - } - if (namespace_flags_ & CLONE_NEWPID) { // This will fork again to run an init process inside the PID // namespace. @@ -1396,10 +1324,6 @@ void ServiceList::MarkServicesUpdate() { delayed_service_names_.clear(); } -void ServiceList::MarkRuntimeAvailable() { - runtime_available_ = true; -} - void ServiceList::DelayService(const Service& service) { if (services_update_finished_) { LOG(ERROR) << "Cannot delay the start of service '" << service.name() diff --git a/init/service.h b/init/service.h index 676111fa1..56e75b0bf 100644 --- a/init/service.h +++ b/init/service.h @@ -62,24 +62,6 @@ namespace android { namespace init { -static constexpr const char* kLinkerMountPoint = "/system/bin/linker"; -static constexpr const char* kBootstrapLinkerPath = "/system/bin/linker"; -static constexpr const char* kRuntimeLinkerPath = "/apex/com.android.runtime/bin/linker"; - -static constexpr const char* kBionicLibsMountPointDir = "/system/lib/"; -static constexpr const char* kBootstrapBionicLibsDir = "/system/lib/"; -static constexpr const char* kRuntimeBionicLibsDir = "/apex/com.android.runtime/lib/bionic/"; - -static constexpr const char* kLinkerMountPoint64 = "/system/bin/linker64"; -static constexpr const char* kBootstrapLinkerPath64 = "/system/bin/linker64"; -static constexpr const char* kRuntimeLinkerPath64 = "/apex/com.android.runtime/bin/linker64"; - -static constexpr const char* kBionicLibsMountPointDir64 = "/system/lib64/"; -static constexpr const char* kBootstrapBionicLibsDir64 = "/system/lib64/"; -static constexpr const char* kRuntimeBionicLibsDir64 = "/apex/com.android.runtime/lib64/bionic/"; - -static const std::vector kBionicLibFileNames = {"libc.so", "libm.so", "libdl.so"}; - class Service { public: Service(const std::string& name, Subcontext* subcontext_for_restart_commands, @@ -142,7 +124,6 @@ class Service { std::optional timeout_period() const { return timeout_period_; } const std::vector& args() const { return args_; } bool is_updatable() const { return updatable_; } - bool is_pre_apexd() const { return pre_apexd_; } private: using OptionParser = Result (Service::*)(std::vector&& args); @@ -151,7 +132,6 @@ class Service { Result SetUpMountNamespace() const; Result SetUpPidNamespace() const; Result EnterNamespaces() const; - Result SetUpPreApexdMounts() const; void NotifyStateChange(const std::string& new_state) const; void StopOrReset(int how); void ZapStdio() const; @@ -262,8 +242,6 @@ class Service { std::vector args_; std::vector> reap_callbacks_; - - bool pre_apexd_ = false; }; class ServiceList { @@ -306,16 +284,13 @@ class ServiceList { const std::vector services_in_shutdown_order() const; void MarkServicesUpdate(); - void MarkRuntimeAvailable(); bool IsServicesUpdated() const { return services_update_finished_; } - bool IsRuntimeAvailable() const { return runtime_available_; } void DelayService(const Service& service); private: std::vector> services_; bool services_update_finished_ = false; - bool runtime_available_ = false; std::vector delayed_service_names_; }; diff --git a/rootdir/init.rc b/rootdir/init.rc index 9b2096412..d1a0ffd37 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -12,12 +12,6 @@ import /init.usb.configfs.rc import /init.${ro.zygote}.rc on early-init - # Mount shared so changes propagate into child namespaces - # Do this before other processes are started from init. Otherwise, - # processes launched while the propagation type of / is 'private' - # won't get mount events from others. - mount rootfs rootfs / shared rec - # Set init and its forked children's oom_adj. write /proc/1/oom_score_adj -1000 @@ -46,8 +40,6 @@ on early-init # cgroup for system_server and surfaceflinger mkdir /dev/memcg/system 0550 system system - prepare_bootstrap_bionic - start ueventd on init @@ -352,6 +344,8 @@ on post-fs # Once everything is setup, no need to modify /. # The bind+remount combination allows this to work in containers. mount rootfs rootfs / remount bind ro nodev + # Mount shared so changes propagate into child namespaces + mount rootfs rootfs / shared rec # Mount default storage into root namespace mount none /mnt/runtime/default /storage bind rec mount none none /storage slave rec @@ -587,14 +581,6 @@ on post-fs-data # Check any timezone data in /data is newer than the copy in the runtime module, delete if not. exec - system system -- /system/bin/tzdatacheck /apex/com.android.runtime/etc/tz /data/misc/zoneinfo - # Wait for apexd to finish activating APEXes before starting more processes. - # This certainly reduces the parallelism but is required to make as many processes - # as possible to use the bionic libs from the runtime APEX. This takes less than 50ms - # so the impact on the booting time is not significant. - wait_for_prop apexd.status ready - setup_runtime_bionic - parse_apex_configs - # If there is no post-fs-data action in the init..rc file, you # must uncomment this line, otherwise encrypted filesystems # won't work. @@ -816,3 +802,6 @@ on property:ro.debuggable=1 service flash_recovery /system/bin/install-recovery.sh class main oneshot + +on property:apexd.status=ready + parse_apex_configs From 10748dc840a55a8b03d6b80b79d17040e732aad6 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Fri, 18 Jan 2019 12:29:23 +0900 Subject: [PATCH 072/221] Revert "Identify post-apexd crashing processes" This reverts commit c661b660fe1eaa82e13ca898390517a94df256c8. Reason: Breaks some 3p apps. Bug: 122920047 Test: run the app, login. Change-Id: Ie56ea5516887b885579764929e82e4fe684a7dcf (cherry picked from commit 60b89aee4c00020124732a82095663d4b5a9aefb) --- init/service.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/init/service.cpp b/init/service.cpp index 638dc5a07..272809f7c 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -369,7 +369,7 @@ void Service::Reap(const siginfo_t& siginfo) { // If we crash > 4 times in 4 minutes, reboot into bootloader or set crashing property boot_clock::time_point now = boot_clock::now(); - if (((flags_ & SVC_CRITICAL) || !pre_apexd_) && !(flags_ & SVC_RESTART)) { + if (((flags_ & SVC_CRITICAL) || classnames_.count("updatable")) && !(flags_ & SVC_RESTART)) { if (now < time_crashed_ + 4min) { if (++crash_count_ > 4) { if (flags_ & SVC_CRITICAL) { From ca11579b6cc87b1b7fc1745c14add937f76dcdf4 Mon Sep 17 00:00:00 2001 From: Chris Wailes Date: Tue, 27 Nov 2018 11:25:25 -0800 Subject: [PATCH 073/221] Added a new socket to Zygote init scripts. This change adds new socket declarations to the init scripts for the Zygote processes. This socket is used for communication between the System Server and the Blastula pool. Bug: 68253328 Change-Id: I5dbb87770b1a3100c6c122bb39ca854006bb0b0d Topic: zygote-prefork Test: build image; flash device; launch apps --- rootdir/init.zygote32.rc | 1 + rootdir/init.zygote32_64.rc | 2 ++ rootdir/init.zygote64.rc | 1 + rootdir/init.zygote64_32.rc | 2 ++ 4 files changed, 6 insertions(+) diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc index 2e9568776..e8c5d8e1b 100644 --- a/rootdir/init.zygote32.rc +++ b/rootdir/init.zygote32.rc @@ -4,6 +4,7 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys user root group root readproc reserved_disk socket zygote stream 660 root system + socket blastula_pool stream 660 root system updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc index 1cfc3d6cc..9c7e80707 100644 --- a/rootdir/init.zygote32_64.rc +++ b/rootdir/init.zygote32_64.rc @@ -4,6 +4,7 @@ service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-s user root group root readproc reserved_disk socket zygote stream 660 root system + socket blastula_pool stream 660 root system updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on @@ -20,6 +21,7 @@ service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote user root group root readproc reserved_disk socket zygote_secondary stream 660 root system + socket blastula_pool_secondary stream 660 root system updatable onrestart restart zygote writepid /dev/cpuset/foreground/tasks diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc index 8ab012dc7..9908c9948 100644 --- a/rootdir/init.zygote64.rc +++ b/rootdir/init.zygote64.rc @@ -4,6 +4,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s user root group root readproc reserved_disk socket zygote stream 660 root system + socket blastula_pool stream 660 root system updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc index 5abf149cd..0b5edff7d 100644 --- a/rootdir/init.zygote64_32.rc +++ b/rootdir/init.zygote64_32.rc @@ -4,6 +4,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s user root group root readproc reserved_disk socket zygote stream 660 root system + socket blastula_pool stream 660 root system updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on @@ -20,6 +21,7 @@ service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote user root group root readproc reserved_disk socket zygote_secondary stream 660 root system + socket blastula_pool_secondary stream 660 root system updatable onrestart restart zygote writepid /dev/cpuset/foreground/tasks From e5bfa7ff24164aa031ccc6c73de03331b209c781 Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Tue, 22 Jan 2019 10:03:27 -0800 Subject: [PATCH 074/221] libcore: add definitions from graphics.commons@1.2 File was auto-generated by runnnig update-base-files.sh Test: header addition, built image. Fixes: 122943743 Change-Id: Ic94ae8f6c42d50ae154659b8922fcebf82437eed --- libsystem/include/system/graphics-base-v1.2.h | 28 +++++++++++++++++++ libsystem/include/system/graphics-base.h | 1 + 2 files changed, 29 insertions(+) create mode 100644 libsystem/include/system/graphics-base-v1.2.h diff --git a/libsystem/include/system/graphics-base-v1.2.h b/libsystem/include/system/graphics-base-v1.2.h new file mode 100644 index 000000000..85b74c693 --- /dev/null +++ b/libsystem/include/system/graphics-base-v1.2.h @@ -0,0 +1,28 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. +// Source: android.hardware.graphics.common@1.2 +// Location: hardware/interfaces/graphics/common/1.2/ + +#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ +#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + HAL_HDR_HDR10_PLUS = 4, +} android_hdr_v1_2_t; + +typedef enum { + HAL_DATASPACE_DISPLAY_BT2020 = 142999552 /* ((STANDARD_BT2020 | TRANSFER_SRGB) | RANGE_FULL) */, +} android_dataspace_v1_2_t; + +typedef enum { + HAL_PIXEL_FORMAT_HSV_888 = 55 /* 0x37 */, +} android_pixel_format_v1_2_t; + +#ifdef __cplusplus +} +#endif + +#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ diff --git a/libsystem/include/system/graphics-base.h b/libsystem/include/system/graphics-base.h index ea920071c..92ee077a6 100644 --- a/libsystem/include/system/graphics-base.h +++ b/libsystem/include/system/graphics-base.h @@ -3,5 +3,6 @@ #include "graphics-base-v1.0.h" #include "graphics-base-v1.1.h" +#include "graphics-base-v1.2.h" #endif // SYSTEM_CORE_GRAPHICS_BASE_H_ From 3857dead177782ea5976590122eb3e02ed75acf7 Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Fri, 28 Dec 2018 20:35:37 -0800 Subject: [PATCH 075/221] Notify framework on adb disconnect Bug: 111656592 Test: atest AdbDebuggingManagerTest Change-Id: I84f0b076799b0628663fde1a14609bc71c5a9ed3 --- adb/daemon/auth.cpp | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp index 180df8f21..dc80a63d7 100644 --- a/adb/daemon/auth.cpp +++ b/adb/daemon/auth.cpp @@ -18,6 +18,7 @@ #include "adb.h" #include "adb_auth.h" +#include "adb_io.h" #include "fdevent.h" #include "sysdeps.h" #include "transport.h" @@ -39,9 +40,9 @@ static fdevent* listener_fde = nullptr; static fdevent* framework_fde = nullptr; static int framework_fd = -1; -static void usb_disconnected(void* unused, atransport* t); -static struct adisconnect usb_disconnect = { usb_disconnected, nullptr}; -static atransport* usb_transport; +static void adb_disconnected(void* unused, atransport* t); +static struct adisconnect adb_disconnect = {adb_disconnected, nullptr}; +static atransport* adb_transport; static bool needs_retry = false; bool auth_required = true; @@ -98,10 +99,17 @@ static bool adbd_auth_generate_token(void* token, size_t token_size) { return okay; } -static void usb_disconnected(void* unused, atransport* t) { - LOG(INFO) << "USB disconnect"; - usb_transport = nullptr; +static void adb_disconnected(void* unused, atransport* t) { + LOG(INFO) << "ADB disconnect"; + adb_transport = nullptr; needs_retry = false; + if (framework_fd >= 0) { + const char msg[] = "DC"; + LOG(DEBUG) << "Sending '" << msg << "'"; + if (!WriteFdExactly(framework_fd, msg, sizeof(msg))) { + PLOG(ERROR) << "Failed to send disconnected message"; + } + } } static void framework_disconnected() { @@ -119,17 +127,17 @@ static void adbd_auth_event(int fd, unsigned events, void*) { if (ret <= 0) { framework_disconnected(); } else if (ret == 2 && response[0] == 'O' && response[1] == 'K') { - if (usb_transport) { - adbd_auth_verified(usb_transport); + if (adb_transport) { + adbd_auth_verified(adb_transport); } } } } void adbd_auth_confirm_key(const char* key, size_t len, atransport* t) { - if (!usb_transport) { - usb_transport = t; - t->AddDisconnect(&usb_disconnect); + if (!adb_transport) { + adb_transport = t; + t->AddDisconnect(&adb_disconnect); } if (framework_fd < 0) { @@ -151,7 +159,7 @@ void adbd_auth_confirm_key(const char* key, size_t len, atransport* t) { } LOG(DEBUG) << "Sending '" << msg << "'"; - if (unix_write(framework_fd, msg, msg_len) == -1) { + if (!WriteFdExactly(framework_fd, msg, msg_len)) { PLOG(ERROR) << "Failed to write PK"; return; } @@ -175,7 +183,7 @@ static void adbd_auth_listener(int fd, unsigned events, void* data) { if (needs_retry) { needs_retry = false; - send_auth_request(usb_transport); + send_auth_request(adb_transport); } } From 97f8353776d0e4f2598d1a882924e7fcce08ac46 Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Fri, 25 Jan 2019 17:06:14 +0000 Subject: [PATCH 076/221] Revert "libcore: add definitions from graphics.commons@1.2" This reverts commit e5bfa7ff24164aa031ccc6c73de03331b209c781. Reason for revert: broke build Change-Id: I61cec3bb6c392bbaf73f0dc31d73df79683d77a0 --- libsystem/include/system/graphics-base-v1.2.h | 28 ------------------- libsystem/include/system/graphics-base.h | 1 - 2 files changed, 29 deletions(-) delete mode 100644 libsystem/include/system/graphics-base-v1.2.h diff --git a/libsystem/include/system/graphics-base-v1.2.h b/libsystem/include/system/graphics-base-v1.2.h deleted file mode 100644 index 85b74c693..000000000 --- a/libsystem/include/system/graphics-base-v1.2.h +++ /dev/null @@ -1,28 +0,0 @@ -// This file is autogenerated by hidl-gen. Do not edit manually. -// Source: android.hardware.graphics.common@1.2 -// Location: hardware/interfaces/graphics/common/1.2/ - -#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ -#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -typedef enum { - HAL_HDR_HDR10_PLUS = 4, -} android_hdr_v1_2_t; - -typedef enum { - HAL_DATASPACE_DISPLAY_BT2020 = 142999552 /* ((STANDARD_BT2020 | TRANSFER_SRGB) | RANGE_FULL) */, -} android_dataspace_v1_2_t; - -typedef enum { - HAL_PIXEL_FORMAT_HSV_888 = 55 /* 0x37 */, -} android_pixel_format_v1_2_t; - -#ifdef __cplusplus -} -#endif - -#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ diff --git a/libsystem/include/system/graphics-base.h b/libsystem/include/system/graphics-base.h index 92ee077a6..ea920071c 100644 --- a/libsystem/include/system/graphics-base.h +++ b/libsystem/include/system/graphics-base.h @@ -3,6 +3,5 @@ #include "graphics-base-v1.0.h" #include "graphics-base-v1.1.h" -#include "graphics-base-v1.2.h" #endif // SYSTEM_CORE_GRAPHICS_BASE_H_ From 23a8310e7a17b462dcc1aa93b754668477855692 Mon Sep 17 00:00:00 2001 From: Kevin DuBois Date: Fri, 25 Jan 2019 10:58:23 -0800 Subject: [PATCH 077/221] libcore: add definitions from graphics.commons@1.2 File was auto-generated by runnnig update-base-files.sh Test: header addition, built image. Fixes: 122943743 Roll-forward of build-breaking topic commit. No changes were needed in this patch. see bug 123404649 for breakage details. This reverts commit 97f8353776d0e4f2598d1a882924e7fcce08ac46. Change-Id: I07abe1d49a5b55f7e0bf5e032e48fb309b2a23bd --- libsystem/include/system/graphics-base-v1.2.h | 28 +++++++++++++++++++ libsystem/include/system/graphics-base.h | 1 + 2 files changed, 29 insertions(+) create mode 100644 libsystem/include/system/graphics-base-v1.2.h diff --git a/libsystem/include/system/graphics-base-v1.2.h b/libsystem/include/system/graphics-base-v1.2.h new file mode 100644 index 000000000..85b74c693 --- /dev/null +++ b/libsystem/include/system/graphics-base-v1.2.h @@ -0,0 +1,28 @@ +// This file is autogenerated by hidl-gen. Do not edit manually. +// Source: android.hardware.graphics.common@1.2 +// Location: hardware/interfaces/graphics/common/1.2/ + +#ifndef HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ +#define HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum { + HAL_HDR_HDR10_PLUS = 4, +} android_hdr_v1_2_t; + +typedef enum { + HAL_DATASPACE_DISPLAY_BT2020 = 142999552 /* ((STANDARD_BT2020 | TRANSFER_SRGB) | RANGE_FULL) */, +} android_dataspace_v1_2_t; + +typedef enum { + HAL_PIXEL_FORMAT_HSV_888 = 55 /* 0x37 */, +} android_pixel_format_v1_2_t; + +#ifdef __cplusplus +} +#endif + +#endif // HIDL_GENERATED_ANDROID_HARDWARE_GRAPHICS_COMMON_V1_2_EXPORTED_CONSTANTS_H_ diff --git a/libsystem/include/system/graphics-base.h b/libsystem/include/system/graphics-base.h index ea920071c..92ee077a6 100644 --- a/libsystem/include/system/graphics-base.h +++ b/libsystem/include/system/graphics-base.h @@ -3,5 +3,6 @@ #include "graphics-base-v1.0.h" #include "graphics-base-v1.1.h" +#include "graphics-base-v1.2.h" #endif // SYSTEM_CORE_GRAPHICS_BASE_H_ From 43c59ca7e295f188d53335d79360978a3dd8263f Mon Sep 17 00:00:00 2001 From: Emilian Peev Date: Sun, 27 Jan 2019 20:08:27 -0800 Subject: [PATCH 078/221] Add graphics-base-v1.2 autogen headers Graphics headers generated by: hidl-gen -Lexport-header -o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base-v1.2.h android.hardware.graphics.common@1.2 Bug: 109735087 Test: Android builds successfully Change-Id: Ie847fdd808ed0daaea917d705a8dc51c6633142a --- libsystem/include/system/graphics-base-v1.2.h | 1 + 1 file changed, 1 insertion(+) diff --git a/libsystem/include/system/graphics-base-v1.2.h b/libsystem/include/system/graphics-base-v1.2.h index 85b74c693..5b857d959 100644 --- a/libsystem/include/system/graphics-base-v1.2.h +++ b/libsystem/include/system/graphics-base-v1.2.h @@ -15,6 +15,7 @@ typedef enum { typedef enum { HAL_DATASPACE_DISPLAY_BT2020 = 142999552 /* ((STANDARD_BT2020 | TRANSFER_SRGB) | RANGE_FULL) */, + HAL_DATASPACE_DYNAMIC_DEPTH = 4098 /* 0x1002 */, } android_dataspace_v1_2_t; typedef enum { From e944c86092469892c621f37dbaa4ed20ac731261 Mon Sep 17 00:00:00 2001 From: Shuzhen Wang Date: Wed, 2 Jan 2019 11:06:22 -0800 Subject: [PATCH 079/221] libsystem: Add JPEG_APP_SEGMENTS and HEIF dataspace hidl-gen -Lexport-header -o $ANDROID_BUILD_TOP/system/core/include/system/graphics-base-v1.2.h android.hardware.graphics.common@1.2 Test: testHeic CTS test Bug: 79465976 Change-Id: Ic2785f082b95ab4088685d6b17d846a4f93160b2 --- libsystem/include/system/graphics-base-v1.2.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libsystem/include/system/graphics-base-v1.2.h b/libsystem/include/system/graphics-base-v1.2.h index 5b857d959..2194f5ea8 100644 --- a/libsystem/include/system/graphics-base-v1.2.h +++ b/libsystem/include/system/graphics-base-v1.2.h @@ -16,6 +16,8 @@ typedef enum { typedef enum { HAL_DATASPACE_DISPLAY_BT2020 = 142999552 /* ((STANDARD_BT2020 | TRANSFER_SRGB) | RANGE_FULL) */, HAL_DATASPACE_DYNAMIC_DEPTH = 4098 /* 0x1002 */, + HAL_DATASPACE_JPEG_APP_SEGMENTS = 4099 /* 0x1003 */, + HAL_DATASPACE_HEIF = 4100 /* 0x1004 */, } android_dataspace_v1_2_t; typedef enum { From b1db592226c35d3f9da7ed35e6437b9aaff30e14 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Wed, 17 Oct 2018 16:42:47 -0700 Subject: [PATCH 080/221] rootdir: Add cgroups and task profiles description files Add cgroups.json and task_profiles.json file to be places under /etc/ on the device to describe cgroups to be mounted and task profiles that processes can request. This adds additional layer of abstraction between what a process wants to achieve and how system implements that request. Bug: 111307099 test: builds, boots Change-Id: If92f011230ef5d24750e184bad776f30ba226f86 Signed-off-by: Suren Baghdasaryan --- rootdir/Android.mk | 22 ++ rootdir/cgroups.json | 43 ++++ rootdir/task_profiles.json | 445 +++++++++++++++++++++++++++++++++++++ 3 files changed, 510 insertions(+) create mode 100644 rootdir/cgroups.json create mode 100644 rootdir/task_profiles.json diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 5a6f41b5f..cbbc7109c 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -46,6 +46,28 @@ LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OU include $(BUILD_PREBUILT) +####################################### +# cgroups.json +include $(CLEAR_VARS) + +LOCAL_MODULE := cgroups.json +LOCAL_SRC_FILES := $(LOCAL_MODULE) +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) + +include $(BUILD_PREBUILT) + +####################################### +# task_profiles.json +include $(CLEAR_VARS) + +LOCAL_MODULE := task_profiles.json +LOCAL_SRC_FILES := $(LOCAL_MODULE) +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) + +include $(BUILD_PREBUILT) + ####################################### # asan.options ifneq ($(filter address,$(SANITIZE_TARGET)),) diff --git a/rootdir/cgroups.json b/rootdir/cgroups.json new file mode 100644 index 000000000..6eb88c957 --- /dev/null +++ b/rootdir/cgroups.json @@ -0,0 +1,43 @@ +{ + "Cgroups": [ + { + "Controller": "cpu", + "Path": "/dev/cpuctl", + "Mode": 0755, + "UID": "system", + "GID": "system" + }, + { + "Controller": "cpuacct", + "Path": "/acct", + "Mode": 0555 + }, + { + "Controller": "cpuset", + "Path": "/dev/cpuset", + "Mode": 0755, + "UID": "system", + "GID": "system" + }, + { + "Controller": "memory", + "Path": "/dev/memcg", + "Mode": 0700, + "UID": "root", + "GID": "system" + }, + { + "Controller": "schedtune", + "Path": "/dev/stune", + "Mode": 0755, + "UID": "system", + "GID": "system" + } + ], + "Cgroups2": { + "Path": "/dev/cg2_bpf", + "Mode": 0600, + "UID": "root", + "GID": "root" + } +} diff --git a/rootdir/task_profiles.json b/rootdir/task_profiles.json new file mode 100644 index 000000000..5a090c5b6 --- /dev/null +++ b/rootdir/task_profiles.json @@ -0,0 +1,445 @@ +{ + "Attributes": [ + { + "Name": "LowCapacityCPUs", + "Controller": "cpuset", + "File": "background/cpus" + }, + { + "Name": "HighCapacityCPUs", + "Controller": "cpuset", + "File": "foreground/cpus" + }, + { + "Name": "MaxCapacityCPUs", + "Controller": "cpuset", + "File": "top-app/cpus" + }, + + { + "Name": "MemLimit", + "Controller": "memory", + "File": "memory.limit_in_bytes" + }, + { + "Name": "MemSoftLimit", + "Controller": "memory", + "File": "memory.soft_limit_in_bytes" + }, + { + "Name": "MemSwappiness", + "Controller": "memory", + "File": "memory.swappiness" + }, + { + "Name": "STuneBoost", + "Controller": "schedtune", + "File": "schedtune.boost" + }, + { + "Name": "STunePreferIdle", + "Controller": "schedtune", + "File": "schedtune.prefer_idle" + }, + { + "Name": "UClampMin", + "Controller": "cpu", + "File": "cpu.util.min" + }, + { + "Name": "UClampMax", + "Controller": "cpu", + "File": "cpu.util.max" + } + ], + + "Profiles": [ + { + "Name": "HighEnergySaving", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "schedtune", + "Path": "background" + } + } + ] + }, + { + "Name": "NormalPerformance", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "schedtune", + "Path": "" + } + } + ] + }, + { + "Name": "HighPerformance", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "schedtune", + "Path": "foreground" + } + } + ] + }, + { + "Name": "MaxPerformance", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "schedtune", + "Path": "top-app" + } + } + ] + }, + { + "Name": "RealtimePerformance", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "schedtune", + "Path": "rt" + } + } + ] + }, + + { + "Name": "CpuPolicySpread", + "Actions" : [ + { + "Name" : "SetAttribute", + "Params" : + { + "Name" : "STunePreferIdle", + "Value" : "1" + } + } + ] + }, + { + "Name": "CpuPolicyPack", + "Actions" : [ + { + "Name" : "SetAttribute", + "Params" : + { + "Name" : "STunePreferIdle", + "Value" : "0" + } + } + ] + }, + + { + "Name": "VrKernelCapacity", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "" + } + } + ] + }, + { + "Name": "VrServiceCapacityLow", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "system/background" + } + } + ] + }, + { + "Name": "VrServiceCapacityNormal", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "system" + } + } + ] + }, + { + "Name": "VrServiceCapacityHigh", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "system/performance" + } + } + ] + }, + { + "Name": "VrProcessCapacityLow", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "application/background" + } + } + ] + }, + { + "Name": "VrProcessCapacityNormal", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "application" + } + } + ] + }, + { + "Name": "VrProcessCapacityHigh", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "application/performance" + } + } + ] + }, + + { + "Name": "ProcessCapacityLow", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "background" + } + } + ] + }, + { + "Name": "ProcessCapacityNormal", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "" + } + } + ] + }, + { + "Name": "ProcessCapacityHigh", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "foreground" + } + } + ] + }, + { + "Name": "ProcessCapacityMax", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "top-app" + } + } + ] + }, + + { + "Name": "ServiceCapacityLow", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "system-background" + } + } + ] + }, + { + "Name": "ServiceCapacityRestricted", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "restricted" + } + } + ] + }, + + { + "Name": "CameraServiceCapacity", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "cpuset", + "Path": "camera-daemon" + } + } + ] + }, + + { + "Name": "TimerSlackHigh", + "Actions" : [ + { + "Name" : "SetTimerSlack", + "Params" : + { + "Slack": "40000000" + } + } + ] + }, + { + "Name": "TimerSlackNormal", + "Actions" : [ + { + "Name" : "SetTimerSlack", + "Params" : + { + "Slack": "50000" + } + } + ] + }, + + { + "Name": "PerfBoost", + "Actions" : [ + { + "Name" : "SetClamps", + "Params" : + { + "Boost" : "50%", + "Clamp" : "0" + } + } + ] + }, + { + "Name": "PerfClamp", + "Actions" : [ + { + "Name" : "SetClamps", + "Params" : + { + "Boost" : "0", + "Clamp" : "30%" + } + } + ] + }, + + { + "Name": "LowMemoryUsage", + "Actions" : [ + { + "Name" : "SetAttribute", + "Params" : + { + "Name" : "MemSoftLimit", + "Value" : "16MB" + } + }, + { + "Name" : "SetAttribute", + "Params" : + { + "Name" : "MemSwappiness", + "Value" : "150" + + } + } + ] + }, + { + "Name": "HighMemoryUsage", + "Actions" : [ + { + "Name" : "SetAttribute", + "Params" : + { + "Name" : "MemSoftLimit", + "Value" : "512MB" + } + }, + { + "Name" : "SetAttribute", + "Params" : + { + "Name" : "MemSwappiness", + "Value" : "100" + } + } + ] + }, + { + "Name": "SystemMemoryProcess", + "Actions" : [ + { + "Name" : "JoinCgroup", + "Params" : + { + "Controller": "memory", + "Path": "system" + } + } + ] + } + ] +} From 192aee782d96b5776e76b9c6d8a329d47f7a4789 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 21 Dec 2018 11:41:50 -0800 Subject: [PATCH 081/221] libprocessgroup: Add support for task profiles Abstract usage of cgroups into task profiles that allows for changes in cgroup hierarchy and version without affecting framework codebase. Rework current processgroup and sched_policy API function implementations to use task profiles instead of hardcoded paths and attributes. Mount cgroups using information from cgroups.json rather than from init.rc Bug: 111307099 Test: builds, boots Change-Id: If5532d6dc570add825cebd5b5148e00c7d688e32 Signed-off-by: Suren Baghdasaryan --- healthd/Android.mk | 1 + init/Android.bp | 2 +- init/init.cpp | 14 + libcutils/tests/Android.bp | 1 + libprocessgroup/Android.bp | 4 +- libprocessgroup/cgroup_map.cpp | 405 ++++++++++++++ libprocessgroup/cgroup_map.h | 96 ++++ .../include/processgroup/processgroup.h | 20 +- .../include/processgroup/sched_policy.h | 6 +- libprocessgroup/processgroup.cpp | 202 +++++-- libprocessgroup/sched_policy.cpp | 522 +++++------------- libprocessgroup/task_profiles.cpp | 373 +++++++++++++ libprocessgroup/task_profiles.h | 140 +++++ rootdir/init.rc | 16 +- 14 files changed, 1333 insertions(+), 469 deletions(-) create mode 100644 libprocessgroup/cgroup_map.cpp create mode 100644 libprocessgroup/cgroup_map.h create mode 100644 libprocessgroup/task_profiles.cpp create mode 100644 libprocessgroup/task_profiles.h diff --git a/healthd/Android.mk b/healthd/Android.mk index 2127b9603..823ed0699 100644 --- a/healthd/Android.mk +++ b/healthd/Android.mk @@ -109,6 +109,7 @@ CHARGER_STATIC_LIBRARIES := \ libbase \ libutils \ libcutils \ + libjsoncpp \ libprocessgroup \ liblog \ libm \ diff --git a/init/Android.bp b/init/Android.bp index 67688f225..639d8d1b9 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -60,7 +60,6 @@ cc_defaults { }, static_libs: [ "libseccomp_policy", - "libprocessgroup", "libavb", "libprotobuf-cpp-lite", "libpropertyinfoserializer", @@ -82,6 +81,7 @@ cc_defaults { "liblog", "liblogwrap", "liblp", + "libprocessgroup", "libselinux", "libutils", ], diff --git a/init/init.cpp b/init/init.cpp index 4f4a15f1d..5a3cc155a 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #ifndef RECOVERY @@ -347,6 +348,17 @@ static Result console_init_action(const BuiltinArguments& args) { return Success(); } +static Result SetupCgroupsAction(const BuiltinArguments&) { + // Have to create using make_dir function + // for appropriate sepolicy to be set for it + make_dir(CGROUPS_RC_DIR, 0711); + if (!CgroupSetupCgroups()) { + return ErrnoError() << "Failed to setup cgroups"; + } + + return Success(); +} + static void import_kernel_nv(const std::string& key, const std::string& value, bool for_emulator) { if (key.empty()) return; @@ -682,6 +694,8 @@ int SecondStageMain(int argc, char** argv) { // Nexus 9 boot time, so it's disabled by default. if (false) DumpState(); + am.QueueBuiltinAction(SetupCgroupsAction, "SetupCgroups"); + am.QueueEventTrigger("early-init"); // Queue an action that waits for coldboot done so we know ueventd has set up all of /dev... diff --git a/libcutils/tests/Android.bp b/libcutils/tests/Android.bp index 72ae55921..fb9bbdd92 100644 --- a/libcutils/tests/Android.bp +++ b/libcutils/tests/Android.bp @@ -59,6 +59,7 @@ test_libraries = [ "libcutils", "liblog", "libbase", + "libjsoncpp", "libprocessgroup", ] diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index d04a79a66..d97f09fad 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -16,8 +16,10 @@ cc_library_headers { cc_library { srcs: [ + "cgroup_map.cpp", "processgroup.cpp", "sched_policy.cpp", + "task_profiles.cpp", ], name: "libprocessgroup", host_supported: true, @@ -29,7 +31,7 @@ cc_library { }, shared_libs: [ "libbase", - "liblog", + "libjsoncpp", ], // for cutils/android_filesystem_config.h header_libs: [ diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp new file mode 100644 index 000000000..1b5f217c7 --- /dev/null +++ b/libprocessgroup/cgroup_map.cpp @@ -0,0 +1,405 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "libprocessgroup" + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using android::base::GetBoolProperty; +using android::base::StringPrintf; +using android::base::unique_fd; + +static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; + +static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs"; +static constexpr const char* CGROUP_TASKS_FILE = "/tasks"; +static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.tasks"; + +static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid, + const std::string& gid) { + if (mode == 0) { + mode = 0755; + } + + if (mkdir(path.c_str(), mode) != 0) { + /* chmod in case the directory already exists */ + if (errno == EEXIST) { + if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) { + // /acct is a special case when the directory already exists + // TODO: check if file mode is already what we want instead of using EROFS + if (errno != EROFS) { + PLOG(ERROR) << "fchmodat() failed for " << path; + return false; + } + } + } else { + PLOG(ERROR) << "mkdir() failed for " << path; + return false; + } + } + + passwd* uid_pwd = nullptr; + passwd* gid_pwd = nullptr; + + if (!uid.empty()) { + uid_pwd = getpwnam(uid.c_str()); + if (!uid_pwd) { + PLOG(ERROR) << "Unable to decode UID for '" << uid << "'"; + return false; + } + + if (!gid.empty()) { + gid_pwd = getpwnam(gid.c_str()); + if (!gid_pwd) { + PLOG(ERROR) << "Unable to decode GID for '" << gid << "'"; + return false; + } + } + } + + if (uid_pwd && lchown(path.c_str(), uid_pwd->pw_uid, gid_pwd ? gid_pwd->pw_uid : -1) < 0) { + PLOG(ERROR) << "lchown() failed for " << path; + return false; + } + + /* chown may have cleared S_ISUID and S_ISGID, chmod again */ + if (mode & (S_ISUID | S_ISGID)) { + if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) { + PLOG(ERROR) << "fchmodat() failed for " << path; + return false; + } + } + + return true; +} + +static bool ReadDescriptors(std::map* descriptors) { + std::vector result; + std::string json_doc; + + if (!android::base::ReadFileToString(CGROUPS_DESC_FILE, &json_doc)) { + LOG(ERROR) << "Failed to read task profiles from " << CGROUPS_DESC_FILE; + return false; + } + + Json::Reader reader; + Json::Value root; + if (!reader.parse(json_doc, root)) { + LOG(ERROR) << "Failed to parse cgroups description: " << reader.getFormattedErrorMessages(); + return false; + } + + Json::Value cgroups = root["Cgroups"]; + for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { + std::string name = cgroups[i]["Controller"].asString(); + descriptors->emplace(std::make_pair( + name, + CgroupDescriptor(1, name, cgroups[i]["Path"].asString(), cgroups[i]["Mode"].asInt(), + cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString()))); + } + + Json::Value cgroups2 = root["Cgroups2"]; + descriptors->emplace(std::make_pair( + CGROUPV2_CONTROLLER_NAME, + CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(), + cgroups2["Mode"].asInt(), cgroups2["UID"].asString(), + cgroups2["GID"].asString()))); + + return true; +} + +static bool SetupCgroup(const CgroupDescriptor& descriptor) { + const CgroupController* controller = descriptor.controller(); + + // mkdir [mode] [owner] [group] + if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { + PLOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup"; + return false; + } + + int result; + if (controller->version() == 2) { + result = mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID, + nullptr); + } else { + // Unfortunately historically cpuset controller was mounted using a mount command + // different from all other controllers. This results in controller attributes not + // to be prepended with controller name. For example this way instead of + // /dev/cpuset/cpuset.cpus the attribute becomes /dev/cpuset/cpus which is what + // the system currently expects. + if (!strcmp(controller->name(), "cpuset")) { + // mount cpuset none /dev/cpuset nodev noexec nosuid + result = mount("none", controller->path(), controller->name(), + MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr); + } else { + // mount cgroup none nodev noexec nosuid + result = mount("none", controller->path(), "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID, + controller->name()); + } + } + + if (result < 0) { + PLOG(ERROR) << "Failed to mount " << controller->name() << " cgroup"; + return false; + } + + return true; +} + +static bool WriteRcFile(const std::map& descriptors) { + std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CgroupMap::CGROUPS_RC_FILE); + unique_fd fd(TEMP_FAILURE_RETRY(open(cgroup_rc_path.c_str(), + O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, + S_IRUSR | S_IRGRP | S_IROTH))); + if (fd < 0) { + PLOG(ERROR) << "open() failed for " << cgroup_rc_path; + return false; + } + + CgroupFile fl; + fl.version_ = CgroupFile::FILE_CURR_VERSION; + fl.controller_count_ = descriptors.size(); + int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl))); + if (ret < 0) { + PLOG(ERROR) << "write() failed for " << cgroup_rc_path; + return false; + } + + for (const auto& [name, descriptor] : descriptors) { + ret = TEMP_FAILURE_RETRY(write(fd, descriptor.controller(), sizeof(CgroupController))); + if (ret < 0) { + PLOG(ERROR) << "write() failed for " << cgroup_rc_path; + return false; + } + } + + return true; +} + +CgroupController::CgroupController(uint32_t version, const std::string& name, + const std::string& path) { + version_ = version; + strncpy(name_, name.c_str(), sizeof(name_) - 1); + name_[sizeof(name_) - 1] = '\0'; + strncpy(path_, path.c_str(), sizeof(path_) - 1); + path_[sizeof(path_) - 1] = '\0'; +} + +std::string CgroupController::GetTasksFilePath(const std::string& path) const { + std::string tasks_path = path_; + + if (!path.empty()) { + tasks_path += "/" + path; + } + return (version_ == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2; +} + +std::string CgroupController::GetProcsFilePath(const std::string& path, uid_t uid, + pid_t pid) const { + std::string proc_path(path_); + proc_path.append("/").append(path); + proc_path = regex_replace(proc_path, std::regex(""), std::to_string(uid)); + proc_path = regex_replace(proc_path, std::regex(""), std::to_string(pid)); + + return proc_path.append(CGROUP_PROCS_FILE); +} + +bool CgroupController::GetTaskGroup(int tid, std::string* group) const { + std::string file_name = StringPrintf("/proc/%d/cgroup", tid); + std::string content; + if (!android::base::ReadFileToString(file_name, &content)) { + LOG(ERROR) << "Failed to read " << file_name; + return false; + } + + // if group is null and tid exists return early because + // user is not interested in cgroup membership + if (group == nullptr) { + return true; + } + + std::string cg_tag = StringPrintf(":%s:", name_); + size_t start_pos = content.find(cg_tag); + if (start_pos == std::string::npos) { + return false; + } + + start_pos += cg_tag.length() + 1; // skip '/' + size_t end_pos = content.find('\n', start_pos); + if (end_pos == std::string::npos) { + *group = content.substr(start_pos, std::string::npos); + } else { + *group = content.substr(start_pos, end_pos - start_pos); + } + + return true; +} + +CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, + const std::string& path, mode_t mode, const std::string& uid, + const std::string& gid) + : controller_(version, name, path), mode_(mode), uid_(uid), gid_(gid) {} + +CgroupMap::CgroupMap() : cg_file_data_(nullptr), cg_file_size_(0) { + if (!LoadRcFile()) { + PLOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed"; + } +} + +CgroupMap::~CgroupMap() { + if (cg_file_data_) { + munmap(cg_file_data_, cg_file_size_); + cg_file_data_ = nullptr; + cg_file_size_ = 0; + } +} + +CgroupMap& CgroupMap::GetInstance() { + static CgroupMap instance; + return instance; +} + +bool CgroupMap::LoadRcFile() { + struct stat sb; + + if (cg_file_data_) { + // Data already initialized + return true; + } + + std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CGROUPS_RC_FILE); + unique_fd fd(TEMP_FAILURE_RETRY(open(cgroup_rc_path.c_str(), O_RDONLY | O_CLOEXEC))); + if (fd < 0) { + PLOG(ERROR) << "open() failed for " << cgroup_rc_path; + return false; + } + + if (fstat(fd, &sb) < 0) { + PLOG(ERROR) << "fstat() failed for " << cgroup_rc_path; + return false; + } + + cg_file_size_ = sb.st_size; + if (cg_file_size_ < sizeof(CgroupFile)) { + PLOG(ERROR) << "Invalid file format " << cgroup_rc_path; + return false; + } + + cg_file_data_ = (CgroupFile*)mmap(nullptr, cg_file_size_, PROT_READ, MAP_SHARED, fd, 0); + if (cg_file_data_ == MAP_FAILED) { + PLOG(ERROR) << "Failed to mmap " << cgroup_rc_path; + return false; + } + + if (cg_file_data_->version_ != CgroupFile::FILE_CURR_VERSION) { + PLOG(ERROR) << cgroup_rc_path << " file version mismatch"; + return false; + } + + return true; +} + +void CgroupMap::Print() { + LOG(INFO) << "File version = " << cg_file_data_->version_; + LOG(INFO) << "File controller count = " << cg_file_data_->controller_count_; + + LOG(INFO) << "Mounted cgroups:"; + CgroupController* controller = (CgroupController*)(cg_file_data_ + 1); + for (int i = 0; i < cg_file_data_->controller_count_; i++, controller++) { + LOG(INFO) << "\t" << controller->name() << " ver " << controller->version() << " path " + << controller->path(); + } +} + +bool CgroupMap::SetupCgroups() { + std::map descriptors; + + // load cgroups.json file + if (!ReadDescriptors(&descriptors)) { + PLOG(ERROR) << "Failed to load cgroup description file"; + return false; + } + + // setup cgroups + for (const auto& [name, descriptor] : descriptors) { + if (!SetupCgroup(descriptor)) { + // issue a warning and proceed with the next cgroup + // TODO: mark the descriptor as invalid and skip it in WriteRcFile() + LOG(WARNING) << "Failed to setup " << name << " cgroup"; + } + } + + // mkdir 0711 system system + if (!Mkdir(CGROUPS_RC_DIR, 0711, "system", "system")) { + PLOG(ERROR) << "Failed to create directory for file"; + return false; + } + + // Generate file which can be directly mmapped into + // process memory. This optimizes performance, memory usage + // and limits infrormation shared with unprivileged processes + // to the minimum subset of information from cgroups.json + if (!WriteRcFile(descriptors)) { + LOG(ERROR) << "Failed to write " << CGROUPS_RC_FILE << " file"; + return false; + } + + std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CGROUPS_RC_FILE); + // chmod 0644 + if (fchmodat(AT_FDCWD, cgroup_rc_path.c_str(), 0644, AT_SYMLINK_NOFOLLOW) < 0) { + LOG(ERROR) << "fchmodat() failed"; + return false; + } + + return true; +} + +const CgroupController* CgroupMap::FindController(const std::string& name) const { + if (!cg_file_data_) { + return nullptr; + } + + // skip the file header to get to the first controller + CgroupController* controller = (CgroupController*)(cg_file_data_ + 1); + for (int i = 0; i < cg_file_data_->controller_count_; i++, controller++) { + if (name == controller->name()) { + return controller; + } + } + + return nullptr; +} diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h new file mode 100644 index 000000000..ba2caf742 --- /dev/null +++ b/libprocessgroup/cgroup_map.h @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +#include +#include +#include + +// Minimal controller description to be mmapped into process address space +class CgroupController { + public: + CgroupController() {} + CgroupController(uint32_t version, const std::string& name, const std::string& path); + + uint32_t version() const { return version_; } + const char* name() const { return name_; } + const char* path() const { return path_; } + + std::string GetTasksFilePath(const std::string& path) const; + std::string GetProcsFilePath(const std::string& path, uid_t uid, pid_t pid) const; + bool GetTaskGroup(int tid, std::string* group) const; + + private: + static constexpr size_t CGROUP_NAME_BUF_SZ = 16; + static constexpr size_t CGROUP_PATH_BUF_SZ = 32; + + uint32_t version_; + char name_[CGROUP_NAME_BUF_SZ]; + char path_[CGROUP_PATH_BUF_SZ]; +}; + +// Complete controller description for mounting cgroups +class CgroupDescriptor { + public: + CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, + mode_t mode, const std::string& uid, const std::string& gid); + + const CgroupController* controller() const { return &controller_; } + mode_t mode() const { return mode_; } + std::string uid() const { return uid_; } + std::string gid() const { return gid_; } + + private: + CgroupController controller_; + mode_t mode_; + std::string uid_; + std::string gid_; +}; + +struct CgroupFile { + static constexpr uint32_t FILE_VERSION_1 = 1; + static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1; + + uint32_t version_; + uint32_t controller_count_; + CgroupController controllers_[]; +}; + +class CgroupMap { + public: + static constexpr const char* CGROUPS_RC_FILE = "cgroup.rc"; + + // Selinux policy ensures only init process can successfully use this function + static bool SetupCgroups(); + + static CgroupMap& GetInstance(); + + const CgroupController* FindController(const std::string& name) const; + + private: + struct CgroupFile* cg_file_data_; + size_t cg_file_size_; + + CgroupMap(); + ~CgroupMap(); + + bool LoadRcFile(); + void Print(); +}; diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 2412f3c99..6f973b832 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -14,14 +14,28 @@ * limitations under the License. */ -#ifndef _PROCESSGROUP_H_ -#define _PROCESSGROUP_H_ +#pragma once #include #include +#include +#include __BEGIN_DECLS +static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2"; +static constexpr const char* CGROUPS_RC_DIR = "/dev/cgroup_info"; + +bool CgroupSetupCgroups(); +bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path); +bool CgroupGetAttributePath(const std::string& attr_name, std::string* path); +bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path); + +bool UsePerAppMemcg(); + +bool SetTaskProfiles(int tid, const std::vector& profiles); +bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles); + // Return 0 and removes the cgroup if there are no longer any processes in it. // Returns -1 in the case of an error occurring or if there are processes still running // even after retrying for up to 200ms. @@ -42,5 +56,3 @@ bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes); void removeAllProcessGroups(void); __END_DECLS - -#endif diff --git a/libprocessgroup/include/processgroup/sched_policy.h b/libprocessgroup/include/processgroup/sched_policy.h index 79a32fdeb..3c498da91 100644 --- a/libprocessgroup/include/processgroup/sched_policy.h +++ b/libprocessgroup/include/processgroup/sched_policy.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2018 The Android Open Source Project + * Copyright (C) 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -67,13 +67,13 @@ extern int set_sched_policy(int tid, SchedPolicy policy); * On platforms which support gettid(), zero tid means current thread. * Return value: 0 for success, or -1 for error and set errno. */ -extern int get_sched_policy(int tid, SchedPolicy *policy); +extern int get_sched_policy(int tid, SchedPolicy* policy); /* Return a displayable string corresponding to policy. * Return value: non-NULL NUL-terminated name of unspecified length; * the caller is responsible for displaying the useful part of the string. */ -extern const char *get_sched_policy_name(SchedPolicy policy); +extern const char* get_sched_policy_name(SchedPolicy policy); #ifdef __cplusplus } diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 8d2ac3d57..e9dec1261 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -25,12 +25,12 @@ #include #include #include -#include #include #include #include #include +#include #include #include #include @@ -43,8 +43,8 @@ #include #include #include - #include +#include using android::base::GetBoolProperty; using android::base::StartsWith; @@ -53,16 +53,103 @@ using android::base::WriteStringToFile; using namespace std::chrono_literals; -static const char kCpuacctCgroup[] = "/acct"; -static const char kMemoryCgroup[] = "/dev/memcg/apps"; - #define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs" +bool CgroupSetupCgroups() { + return CgroupMap::SetupCgroups(); +} + +bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path) { + const CgroupController* controller = CgroupMap::GetInstance().FindController(cgroup_name); + + if (controller == nullptr) { + return false; + } + + if (path) { + *path = controller->path(); + } + + return true; +} + +bool CgroupGetAttributePath(const std::string& attr_name, std::string* path) { + const TaskProfiles& tp = TaskProfiles::GetInstance(); + const ProfileAttribute* attr = tp.GetAttribute(attr_name); + + if (attr == nullptr) { + return false; + } + + if (path) { + *path = StringPrintf("%s/%s", attr->controller()->path(), attr->file_name().c_str()); + } + + return true; +} + +bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path) { + const TaskProfiles& tp = TaskProfiles::GetInstance(); + const ProfileAttribute* attr = tp.GetAttribute(attr_name); + + if (attr == nullptr) { + return false; + } + + if (!attr->GetPathForTask(tid, path)) { + PLOG(ERROR) << "Failed to find cgroup for tid " << tid; + return false; + } + + return true; +} + +bool UsePerAppMemcg() { + bool low_ram_device = GetBoolProperty("ro.config.low_ram", false); + return GetBoolProperty("ro.config.per_app_memcg", low_ram_device); +} + static bool isMemoryCgroupSupported() { - static bool memcg_supported = !access("/dev/memcg/memory.limit_in_bytes", F_OK); + std::string cgroup_name; + static bool memcg_supported = (CgroupMap::GetInstance().FindController("memory") != nullptr); + return memcg_supported; } +bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles) { + const TaskProfiles& tp = TaskProfiles::GetInstance(); + + for (const auto& name : profiles) { + const TaskProfile* profile = tp.GetProfile(name); + if (profile != nullptr) { + if (!profile->ExecuteForProcess(uid, pid)) { + PLOG(WARNING) << "Failed to apply " << name << " process profile"; + } + } else { + PLOG(WARNING) << "Failed to find " << name << "process profile"; + } + } + + return true; +} + +bool SetTaskProfiles(int tid, const std::vector& profiles) { + const TaskProfiles& tp = TaskProfiles::GetInstance(); + + for (const auto& name : profiles) { + const TaskProfile* profile = tp.GetProfile(name); + if (profile != nullptr) { + if (!profile->ExecuteForTask(tid)) { + PLOG(WARNING) << "Failed to apply " << name << " task profile"; + } + } else { + PLOG(WARNING) << "Failed to find " << name << "task profile"; + } + } + + return true; +} + static std::string ConvertUidToPath(const char* cgroup, uid_t uid) { return StringPrintf("%s/uid_%d", cgroup, uid); } @@ -103,11 +190,21 @@ static void RemoveUidProcessGroups(const std::string& uid_path) { } } -void removeAllProcessGroups() -{ +void removeAllProcessGroups() { LOG(VERBOSE) << "removeAllProcessGroups()"; - for (const char* cgroup_root_path : {kCpuacctCgroup, kMemoryCgroup}) { - std::unique_ptr root(opendir(cgroup_root_path), closedir); + + std::vector cgroups; + std::string path; + + if (CgroupGetControllerPath("cpuacct", &path)) { + cgroups.push_back(path); + } + if (CgroupGetControllerPath("memory", &path)) { + cgroups.push_back(path); + } + + for (std::string cgroup_root_path : cgroups) { + std::unique_ptr root(opendir(cgroup_root_path.c_str()), closedir); if (root == NULL) { PLOG(ERROR) << "Failed to open " << cgroup_root_path; } else { @@ -121,7 +218,7 @@ void removeAllProcessGroups() continue; } - auto path = StringPrintf("%s/%s", cgroup_root_path, dir->d_name); + auto path = StringPrintf("%s/%s", cgroup_root_path.c_str(), dir->d_name); RemoveUidProcessGroups(path); LOG(VERBOSE) << "Removing " << path; if (rmdir(path.c_str()) == -1) PLOG(WARNING) << "Failed to remove " << path; @@ -130,6 +227,21 @@ void removeAllProcessGroups() } } +static bool MkdirAndChown(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { + if (mkdir(path.c_str(), mode) == -1 && errno != EEXIST) { + return false; + } + + if (chown(path.c_str(), uid, gid) == -1) { + int saved_errno = errno; + rmdir(path.c_str()); + errno = saved_errno; + return false; + } + + return true; +} + // Returns number of processes killed on success // Returns 0 if there are no processes in the process cgroup left to kill // Returns -1 on error @@ -200,10 +312,16 @@ static int DoKillProcessGroupOnce(const char* cgroup, uid_t uid, int initialPid, } static int KillProcessGroup(uid_t uid, int initialPid, int signal, int retries) { + std::string cpuacct_path; + std::string memory_path; + + CgroupGetControllerPath("cpuacct", &cpuacct_path); + CgroupGetControllerPath("memory", &memory_path); + const char* cgroup = - (!access(ConvertUidPidToPath(kCpuacctCgroup, uid, initialPid).c_str(), F_OK)) - ? kCpuacctCgroup - : kMemoryCgroup; + (!access(ConvertUidPidToPath(cpuacct_path.c_str(), uid, initialPid).c_str(), F_OK)) + ? cpuacct_path.c_str() + : memory_path.c_str(); std::chrono::steady_clock::time_point start = std::chrono::steady_clock::now(); @@ -258,44 +376,22 @@ int killProcessGroupOnce(uid_t uid, int initialPid, int signal) { return KillProcessGroup(uid, initialPid, signal, 0 /*retries*/); } -static bool MkdirAndChown(const std::string& path, mode_t mode, uid_t uid, gid_t gid) { - if (mkdir(path.c_str(), mode) == -1 && errno != EEXIST) { - return false; - } - - if (chown(path.c_str(), uid, gid) == -1) { - int saved_errno = errno; - rmdir(path.c_str()); - errno = saved_errno; - return false; - } - - return true; -} - -static bool isPerAppMemcgEnabled() { - static bool per_app_memcg = - GetBoolProperty("ro.config.per_app_memcg", GetBoolProperty("ro.config.low_ram", false)); - return per_app_memcg; -} - -int createProcessGroup(uid_t uid, int initialPid, bool memControl) -{ - const char* cgroup; - if (isMemoryCgroupSupported() && (memControl || isPerAppMemcgEnabled())) { - cgroup = kMemoryCgroup; +int createProcessGroup(uid_t uid, int initialPid, bool memControl) { + std::string cgroup; + if (isMemoryCgroupSupported() && (memControl || UsePerAppMemcg())) { + CgroupGetControllerPath("memory", &cgroup); } else { - cgroup = kCpuacctCgroup; + CgroupGetControllerPath("cpuacct", &cgroup); } - auto uid_path = ConvertUidToPath(cgroup, uid); + auto uid_path = ConvertUidToPath(cgroup.c_str(), uid); if (!MkdirAndChown(uid_path, 0750, AID_SYSTEM, AID_SYSTEM)) { PLOG(ERROR) << "Failed to make and chown " << uid_path; return -errno; } - auto uid_pid_path = ConvertUidPidToPath(cgroup, uid, initialPid); + auto uid_pid_path = ConvertUidPidToPath(cgroup.c_str(), uid, initialPid); if (!MkdirAndChown(uid_pid_path, 0750, AID_SYSTEM, AID_SYSTEM)) { PLOG(ERROR) << "Failed to make and chown " << uid_pid_path; @@ -313,13 +409,17 @@ int createProcessGroup(uid_t uid, int initialPid, bool memControl) return ret; } -static bool SetProcessGroupValue(uid_t uid, int pid, const std::string& file_name, int64_t value) { +static bool SetProcessGroupValue(int tid, const std::string& attr_name, int64_t value) { if (!isMemoryCgroupSupported()) { PLOG(ERROR) << "Memcg is not mounted."; return false; } - auto path = ConvertUidPidToPath(kMemoryCgroup, uid, pid) + file_name; + std::string path; + if (!CgroupGetAttributePathForTask(attr_name, tid, &path)) { + PLOG(ERROR) << "Failed to find attribute '" << attr_name << "'"; + return false; + } if (!WriteStringToFile(std::to_string(value), path)) { PLOG(ERROR) << "Failed to write '" << value << "' to " << path; @@ -328,14 +428,14 @@ static bool SetProcessGroupValue(uid_t uid, int pid, const std::string& file_nam return true; } -bool setProcessGroupSwappiness(uid_t uid, int pid, int swappiness) { - return SetProcessGroupValue(uid, pid, "/memory.swappiness", swappiness); +bool setProcessGroupSwappiness(uid_t, int pid, int swappiness) { + return SetProcessGroupValue(pid, "MemSwappiness", swappiness); } -bool setProcessGroupSoftLimit(uid_t uid, int pid, int64_t soft_limit_in_bytes) { - return SetProcessGroupValue(uid, pid, "/memory.soft_limit_in_bytes", soft_limit_in_bytes); +bool setProcessGroupSoftLimit(uid_t, int pid, int64_t soft_limit_in_bytes) { + return SetProcessGroupValue(pid, "MemSoftLimit", soft_limit_in_bytes); } -bool setProcessGroupLimit(uid_t uid, int pid, int64_t limit_in_bytes) { - return SetProcessGroupValue(uid, pid, "/memory.limit_in_bytes", limit_in_bytes); +bool setProcessGroupLimit(uid_t, int pid, int64_t limit_in_bytes) { + return SetProcessGroupValue(pid, "MemLimit", limit_in_bytes); } diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp index f95d7e48f..4c8aa6dd7 100644 --- a/libprocessgroup/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -1,372 +1,81 @@ /* -** Copyright 2007, 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. -*/ + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ #include #define LOG_TAG "SchedPolicy" #include -#include -#include -#include -#include #include -#include -#include +#include +#include +#include +#include + +using android::base::GetThreadId; /* Re-map SP_DEFAULT to the system default policy, and leave other values unchanged. * Call this any place a SchedPolicy is used as an input parameter. * Returns the possibly re-mapped policy. */ -static inline SchedPolicy _policy(SchedPolicy p) -{ - return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p; +static inline SchedPolicy _policy(SchedPolicy p) { + return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p; } -#if defined(__ANDROID__) - -#include -#include -#include - -#define POLICY_DEBUG 0 - -// timer slack value in nS enforced when the thread moves to background -#define TIMER_SLACK_BG 40000000 -#define TIMER_SLACK_FG 50000 - -static pthread_once_t the_once = PTHREAD_ONCE_INIT; - -static int __sys_supports_timerslack = -1; - -// File descriptors open to /dev/cpuset/../tasks, setup by initialize, or -1 on error -static int system_bg_cpuset_fd = -1; -static int bg_cpuset_fd = -1; -static int fg_cpuset_fd = -1; -static int ta_cpuset_fd = -1; // special cpuset for top app -static int rs_cpuset_fd = -1; // special cpuset for screen off restrictions - -// File descriptors open to /dev/stune/../tasks, setup by initialize, or -1 on error -static int bg_schedboost_fd = -1; -static int fg_schedboost_fd = -1; -static int ta_schedboost_fd = -1; -static int rt_schedboost_fd = -1; - -/* Add tid to the scheduling group defined by the policy */ -static int add_tid_to_cgroup(int tid, int fd) -{ - if (fd < 0) { - SLOGE("add_tid_to_cgroup failed; fd=%d\n", fd); - errno = EINVAL; - return -1; - } - - // specialized itoa -- works for tid > 0 - char text[22]; - char *end = text + sizeof(text) - 1; - char *ptr = end; - *ptr = '\0'; - while (tid > 0) { - *--ptr = '0' + (tid % 10); - tid = tid / 10; - } - - if (write(fd, ptr, end - ptr) < 0) { - /* - * If the thread is in the process of exiting, - * don't flag an error - */ - if (errno == ESRCH) - return 0; - SLOGW("add_tid_to_cgroup failed to write '%s' (%s); fd=%d\n", - ptr, strerror(errno), fd); - errno = EINVAL; - return -1; - } - - return 0; -} - -/* - If CONFIG_CPUSETS for Linux kernel is set, "tasks" can be found under - /dev/cpuset mounted in init.rc; otherwise, that file does not exist - even though the directory, /dev/cpuset, is still created (by init.rc). - - A couple of other candidates (under cpuset mount directory): - notify_on_release - release_agent - - Yet another way to decide if cpuset is enabled is to parse - /proc/self/status and search for lines begin with "Mems_allowed". - - If CONFIG_PROC_PID_CPUSET is set, the existence "/proc/self/cpuset" can - be used to decide if CONFIG_CPUSETS is set, so we don't have a dependency - on where init.rc mounts cpuset. That's why we'd better require this - configuration be set if CONFIG_CPUSETS is set. - - In older releases, this was controlled by build-time configuration. - */ -bool cpusets_enabled() { - static bool enabled = (access("/dev/cpuset/tasks", F_OK) == 0); - - return enabled; -} - -/* - Similar to CONFIG_CPUSETS above, but with a different configuration - CONFIG_CGROUP_SCHEDTUNE that's in Android common Linux kernel and Linaro - Stable Kernel (LSK), but not in mainline Linux as of v4.9. - - In older releases, this was controlled by build-time configuration. - */ -bool schedboost_enabled() { - static bool enabled = (access("/dev/stune/tasks", F_OK) == 0); - - return enabled; -} - -static void __initialize() { - const char* filename; - - if (cpusets_enabled()) { - if (!access("/dev/cpuset/tasks", W_OK)) { - - filename = "/dev/cpuset/foreground/tasks"; - fg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC); - filename = "/dev/cpuset/background/tasks"; - bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC); - filename = "/dev/cpuset/system-background/tasks"; - system_bg_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC); - filename = "/dev/cpuset/top-app/tasks"; - ta_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC); - filename = "/dev/cpuset/restricted/tasks"; - rs_cpuset_fd = open(filename, O_WRONLY | O_CLOEXEC); - - if (schedboost_enabled()) { - filename = "/dev/stune/top-app/tasks"; - ta_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC); - filename = "/dev/stune/foreground/tasks"; - fg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC); - filename = "/dev/stune/background/tasks"; - bg_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC); - filename = "/dev/stune/rt/tasks"; - rt_schedboost_fd = open(filename, O_WRONLY | O_CLOEXEC); - } - } - } - - char buf[64]; - snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", getpid()); - __sys_supports_timerslack = !access(buf, W_OK); -} - -/* - * Returns the path under the requested cgroup subsystem (if it exists) - * - * The data from /proc//cgroup looks (something) like: - * 2:cpu:/bg_non_interactive - * 1:cpuacct:/ - * - * We return the part after the "/", which will be an empty string for - * the default cgroup. If the string is longer than "bufLen", the string - * will be truncated. - */ -static int getCGroupSubsys(int tid, const char* subsys, char* buf, size_t bufLen) -{ -#if defined(__ANDROID__) - char pathBuf[32]; - char lineBuf[256]; - FILE *fp; - - snprintf(pathBuf, sizeof(pathBuf), "/proc/%d/cgroup", tid); - if (!(fp = fopen(pathBuf, "re"))) { - return -1; - } - - while(fgets(lineBuf, sizeof(lineBuf) -1, fp)) { - char *next = lineBuf; - char *found_subsys; - char *grp; - size_t len; - - /* Junk the first field */ - if (!strsep(&next, ":")) { - goto out_bad_data; - } - - if (!(found_subsys = strsep(&next, ":"))) { - goto out_bad_data; - } - - if (strcmp(found_subsys, subsys)) { - /* Not the subsys we're looking for */ - continue; - } - - if (!(grp = strsep(&next, ":"))) { - goto out_bad_data; - } - grp++; /* Drop the leading '/' */ - len = strlen(grp); - grp[len-1] = '\0'; /* Drop the trailing '\n' */ - - if (bufLen <= len) { - len = bufLen - 1; - } - strncpy(buf, grp, len); - buf[len] = '\0'; - fclose(fp); - return 0; - } - - SLOGE("Failed to find subsys %s", subsys); - fclose(fp); - return -1; - out_bad_data: - SLOGE("Bad cgroup data {%s}", lineBuf); - fclose(fp); - return -1; -#else - errno = ENOSYS; - return -1; -#endif -} - -int get_sched_policy(int tid, SchedPolicy *policy) -{ +int set_cpuset_policy(int tid, SchedPolicy policy) { if (tid == 0) { - tid = gettid(); - } - pthread_once(&the_once, __initialize); - - char grpBuf[32]; - - grpBuf[0] = '\0'; - if (schedboost_enabled()) { - if (getCGroupSubsys(tid, "schedtune", grpBuf, sizeof(grpBuf)) < 0) return -1; - } - if ((grpBuf[0] == '\0') && cpusets_enabled()) { - if (getCGroupSubsys(tid, "cpuset", grpBuf, sizeof(grpBuf)) < 0) return -1; - } - if (grpBuf[0] == '\0') { - *policy = SP_FOREGROUND; - } else if (!strcmp(grpBuf, "foreground")) { - *policy = SP_FOREGROUND; - } else if (!strcmp(grpBuf, "system-background")) { - *policy = SP_SYSTEM; - } else if (!strcmp(grpBuf, "background")) { - *policy = SP_BACKGROUND; - } else if (!strcmp(grpBuf, "top-app")) { - *policy = SP_TOP_APP; - } else { - errno = ERANGE; - return -1; - } - return 0; -} - -int set_cpuset_policy(int tid, SchedPolicy policy) -{ - // in the absence of cpusets, use the old sched policy - if (!cpusets_enabled()) { - return set_sched_policy(tid, policy); - } - - if (tid == 0) { - tid = gettid(); + tid = GetThreadId(); } policy = _policy(policy); - pthread_once(&the_once, __initialize); - int fd = -1; - int boost_fd = -1; switch (policy) { - case SP_BACKGROUND: - fd = bg_cpuset_fd; - boost_fd = bg_schedboost_fd; - break; - case SP_FOREGROUND: - case SP_AUDIO_APP: - case SP_AUDIO_SYS: - fd = fg_cpuset_fd; - boost_fd = fg_schedboost_fd; - break; - case SP_TOP_APP : - fd = ta_cpuset_fd; - boost_fd = ta_schedboost_fd; - break; - case SP_SYSTEM: - fd = system_bg_cpuset_fd; - break; - case SP_RESTRICTED: - fd = rs_cpuset_fd; - break; - default: - boost_fd = fd = -1; - break; - } - - if (add_tid_to_cgroup(tid, fd) != 0) { - if (errno != ESRCH && errno != ENOENT) - return -errno; - } - - if (schedboost_enabled()) { - if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) { - if (errno != ESRCH && errno != ENOENT) - return -errno; - } + case SP_BACKGROUND: + return SetTaskProfiles(tid, + {"HighEnergySaving", "ProcessCapacityLow", "TimerSlackHigh"}) + ? 0 + : -1; + case SP_FOREGROUND: + case SP_AUDIO_APP: + case SP_AUDIO_SYS: + return SetTaskProfiles(tid, + {"HighPerformance", "ProcessCapacityHigh", "TimerSlackNormal"}) + ? 0 + : -1; + case SP_TOP_APP: + return SetTaskProfiles(tid, + {"MaxPerformance", "ProcessCapacityMax", "TimerSlackNormal"}) + ? 0 + : -1; + case SP_SYSTEM: + return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}) ? 0 : -1; + case SP_RESTRICTED: + return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}) ? 0 : -1; + default: + break; } return 0; } -static void set_timerslack_ns(int tid, unsigned long slack) { - // v4.6+ kernels support the /proc//timerslack_ns interface. - // TODO: once we've backported this, log if the open(2) fails. - if (__sys_supports_timerslack) { - char buf[64]; - snprintf(buf, sizeof(buf), "/proc/%d/timerslack_ns", tid); - int fd = open(buf, O_WRONLY | O_CLOEXEC); - if (fd != -1) { - int len = snprintf(buf, sizeof(buf), "%lu", slack); - if (write(fd, buf, len) != len) { - SLOGE("set_timerslack_ns write failed: %s\n", strerror(errno)); - } - close(fd); - return; - } - } - - // TODO: Remove when /proc//timerslack_ns interface is backported. - if ((tid == 0) || (tid == gettid())) { - if (prctl(PR_SET_TIMERSLACK, slack) == -1) { - SLOGE("set_timerslack_ns prctl failed: %s\n", strerror(errno)); - } - } -} - -int set_sched_policy(int tid, SchedPolicy policy) -{ +int set_sched_policy(int tid, SchedPolicy policy) { if (tid == 0) { - tid = gettid(); + tid = GetThreadId(); } policy = _policy(policy); - pthread_once(&the_once, __initialize); #if POLICY_DEBUG char statfile[64]; @@ -376,91 +85,116 @@ int set_sched_policy(int tid, SchedPolicy policy) snprintf(statfile, sizeof(statfile), "/proc/%d/stat", tid); memset(thread_name, 0, sizeof(thread_name)); - int fd = open(statfile, O_RDONLY | O_CLOEXEC); + unique_fd fd(TEMP_FAILURE_RETRY(open(statfile, O_RDONLY | O_CLOEXEC))); if (fd >= 0) { int rc = read(fd, statline, 1023); - close(fd); statline[rc] = 0; - char *p = statline; - char *q; + char* p = statline; + char* q; - for (p = statline; *p != '('; p++); + for (p = statline; *p != '('; p++) + ; p++; - for (q = p; *q != ')'; q++); + for (q = p; *q != ')'; q++) + ; - strncpy(thread_name, p, (q-p)); + strncpy(thread_name, p, (q - p)); } switch (policy) { - case SP_BACKGROUND: - SLOGD("vvv tid %d (%s)", tid, thread_name); - break; - case SP_FOREGROUND: - case SP_AUDIO_APP: - case SP_AUDIO_SYS: - case SP_TOP_APP: - SLOGD("^^^ tid %d (%s)", tid, thread_name); - break; - case SP_SYSTEM: - SLOGD("/// tid %d (%s)", tid, thread_name); - break; - case SP_RT_APP: - SLOGD("RT tid %d (%s)", tid, thread_name); - break; - default: - SLOGD("??? tid %d (%s)", tid, thread_name); - break; - } -#endif - - if (schedboost_enabled()) { - int boost_fd = -1; - switch (policy) { case SP_BACKGROUND: - boost_fd = bg_schedboost_fd; + SLOGD("vvv tid %d (%s)", tid, thread_name); break; case SP_FOREGROUND: case SP_AUDIO_APP: case SP_AUDIO_SYS: - boost_fd = fg_schedboost_fd; - break; case SP_TOP_APP: - boost_fd = ta_schedboost_fd; + SLOGD("^^^ tid %d (%s)", tid, thread_name); + break; + case SP_SYSTEM: + SLOGD("/// tid %d (%s)", tid, thread_name); break; case SP_RT_APP: - boost_fd = rt_schedboost_fd; - break; - default: - boost_fd = -1; + SLOGD("RT tid %d (%s)", tid, thread_name); break; - } - - if (boost_fd > 0 && add_tid_to_cgroup(tid, boost_fd) != 0) { - if (errno != ESRCH && errno != ENOENT) - return -errno; - } + default: + SLOGD("??? tid %d (%s)", tid, thread_name); + break; + } +#endif + switch (policy) { + case SP_BACKGROUND: + return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}) ? 0 : -1; + case SP_FOREGROUND: + case SP_AUDIO_APP: + case SP_AUDIO_SYS: + return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}) ? 0 : -1; + case SP_TOP_APP: + return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}) ? 0 : -1; + case SP_RT_APP: + return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}) ? 0 : -1; + default: + return SetTaskProfiles(tid, {"TimerSlackNormal"}) ? 0 : -1; } - set_timerslack_ns(tid, policy == SP_BACKGROUND ? TIMER_SLACK_BG : TIMER_SLACK_FG); - return 0; } -#else +bool cpusets_enabled() { + static bool enabled = (CgroupMap::GetInstance().FindController("cpuset") != nullptr); + return enabled; +} -/* Stubs for non-Android targets. */ +bool schedboost_enabled() { + static bool enabled = (CgroupMap::GetInstance().FindController("schedtune") != nullptr); + return enabled; +} -int set_sched_policy(int /*tid*/, SchedPolicy /*policy*/) { +static int getCGroupSubsys(int tid, const char* subsys, std::string& subgroup) { + const CgroupController* controller = CgroupMap::GetInstance().FindController(subsys); + + if (!controller) return -1; + + if (!controller->GetTaskGroup(tid, &subgroup)) { + PLOG(ERROR) << "Failed to find cgroup for tid " << tid; + return -1; + } return 0; } -int get_sched_policy(int /*tid*/, SchedPolicy* policy) { - *policy = SP_SYSTEM_DEFAULT; +int get_sched_policy(int tid, SchedPolicy* policy) { + if (tid == 0) { + tid = GetThreadId(); + } + + std::string group; + if (schedboost_enabled()) { + if (getCGroupSubsys(tid, "schedtune", group) < 0) return -1; + } + if (group.empty() && cpusets_enabled()) { + if (getCGroupSubsys(tid, "cpuset", group) < 0) return -1; + } + + // TODO: replace hardcoded directories + if (group.empty()) { + *policy = SP_FOREGROUND; + } else if (group == "foreground") { + *policy = SP_FOREGROUND; + } else if (group == "system-background") { + *policy = SP_SYSTEM; + } else if (group == "background") { + *policy = SP_BACKGROUND; + } else if (group == "top-app") { + *policy = SP_TOP_APP; + } else if (group == "restricted") { + *policy = SP_RESTRICTED; + } else { + errno = ERANGE; + return -1; + } return 0; } -#endif - const char* get_sched_policy_name(SchedPolicy policy) { policy = _policy(policy); static const char* const kSchedPolicyNames[] = { diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp new file mode 100644 index 000000000..eb50f8539 --- /dev/null +++ b/libprocessgroup/task_profiles.cpp @@ -0,0 +1,373 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "libprocessgroup" + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include +#include + +using android::base::GetThreadId; +using android::base::StringPrintf; +using android::base::unique_fd; +using android::base::WriteStringToFile; + +#define TASK_PROFILE_DB_FILE "/etc/task_profiles.json" + +bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { + std::string subgroup; + if (!controller_->GetTaskGroup(tid, &subgroup)) { + return false; + } + + if (path == nullptr) { + return true; + } + + if (subgroup.empty()) { + *path = StringPrintf("%s/%s", controller_->path(), file_name_.c_str()); + } else { + *path = StringPrintf("%s/%s/%s", controller_->path(), subgroup.c_str(), file_name_.c_str()); + } + return true; +} + +bool SetClampsAction::ExecuteForProcess(uid_t, pid_t) const { + // TODO: add support when kernel supports util_clamp + LOG(WARNING) << "SetClampsAction::ExecuteForProcess is not supported"; + return false; +} + +bool SetClampsAction::ExecuteForTask(int) const { + // TODO: add support when kernel supports util_clamp + LOG(WARNING) << "SetClampsAction::ExecuteForTask is not supported"; + return false; +} + +bool SetTimerSlackAction::IsTimerSlackSupported(int tid) { + auto file = StringPrintf("/proc/%d/timerslack_ns", tid); + + return (access(file.c_str(), W_OK) == 0); +} + +bool SetTimerSlackAction::ExecuteForTask(int tid) const { + static bool sys_supports_timerslack = IsTimerSlackSupported(tid); + + // v4.6+ kernels support the /proc//timerslack_ns interface. + // TODO: once we've backported this, log if the open(2) fails. + if (sys_supports_timerslack) { + auto file = StringPrintf("/proc/%d/timerslack_ns", tid); + if (!WriteStringToFile(std::to_string(slack_), file)) { + PLOG(ERROR) << "set_timerslack_ns write failed"; + } + } + + // TODO: Remove when /proc//timerslack_ns interface is backported. + if (tid == 0 || tid == GetThreadId()) { + if (prctl(PR_SET_TIMERSLACK, slack_) == -1) { + PLOG(ERROR) << "set_timerslack_ns prctl failed"; + } + } + + return true; +} + +bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const { + return ExecuteForTask(pid); +} + +bool SetAttributeAction::ExecuteForTask(int tid) const { + std::string path; + + if (!attribute_->GetPathForTask(tid, &path)) { + PLOG(ERROR) << "Failed to find cgroup for tid " << tid; + return false; + } + + if (!WriteStringToFile(value_, path)) { + PLOG(ERROR) << "Failed to write '" << value_ << "' to " << path; + return false; + } + + return true; +} + +bool SetCgroupAction::IsAppDependentPath(const std::string& path) { + return path.find("", 0) != std::string::npos || path.find("", 0) != std::string::npos; +} + +SetCgroupAction::SetCgroupAction(const CgroupController* c, const std::string& p) + : controller_(c), path_(p) { + // cache file descriptor only if path is app independent + if (IsAppDependentPath(path_)) { + // file descriptor is not cached + fd_.reset(-2); + return; + } + + std::string tasks_path = c->GetTasksFilePath(p.c_str()); + + if (access(tasks_path.c_str(), W_OK) != 0) { + // file is not accessible + fd_.reset(-1); + return; + } + + unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC))); + if (fd < 0) { + PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'"; + fd_.reset(-1); + return; + } + + fd_ = std::move(fd); +} + +bool SetCgroupAction::AddTidToCgroup(int tid, int fd) { + if (tid <= 0) { + return true; + } + + std::string value = std::to_string(tid); + + if (TEMP_FAILURE_RETRY(write(fd, value.c_str(), value.length())) < 0) { + // If the thread is in the process of exiting, don't flag an error + if (errno != ESRCH) { + PLOG(ERROR) << "JoinGroup failed to write '" << value << "'; fd=" << fd; + return false; + } + } + + return true; +} + +bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { + if (fd_ >= 0) { + // fd is cached, reuse it + if (!AddTidToCgroup(pid, fd_)) { + PLOG(ERROR) << "Failed to add task into cgroup"; + return false; + } + return true; + } + + if (fd_ == -1) { + // no permissions to access the file, ignore + return true; + } + + // this is app-dependent path, file descriptor is not cached + std::string procs_path = controller_->GetProcsFilePath(path_.c_str(), uid, pid); + unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC))); + if (tmp_fd < 0) { + PLOG(WARNING) << "Failed to open " << procs_path << ": " << strerror(errno); + return false; + } + if (!AddTidToCgroup(pid, tmp_fd)) { + PLOG(ERROR) << "Failed to add task into cgroup"; + return false; + } + + return true; +} + +bool SetCgroupAction::ExecuteForTask(int tid) const { + if (fd_ >= 0) { + // fd is cached, reuse it + if (!AddTidToCgroup(tid, fd_)) { + PLOG(ERROR) << "Failed to add task into cgroup"; + return false; + } + return true; + } + + if (fd_ == -1) { + // no permissions to access the file, ignore + return true; + } + + // application-dependent path can't be used with tid + PLOG(ERROR) << "Application profile can't be applied to a thread"; + return false; +} + +bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const { + for (const auto& element : elements_) { + if (!element->ExecuteForProcess(uid, pid)) { + return false; + } + } + return true; +} + +bool TaskProfile::ExecuteForTask(int tid) const { + if (tid == 0) { + tid = GetThreadId(); + } + for (const auto& element : elements_) { + if (!element->ExecuteForTask(tid)) { + return false; + } + } + return true; +} + +TaskProfiles& TaskProfiles::GetInstance() { + static TaskProfiles instance; + return instance; +} + +TaskProfiles::TaskProfiles() { + if (!Load(CgroupMap::GetInstance())) { + LOG(ERROR) << "TaskProfiles::Load for [" << getpid() << "] failed"; + } +} + +bool TaskProfiles::Load(const CgroupMap& cg_map) { + std::string json_doc; + + if (!android::base::ReadFileToString(TASK_PROFILE_DB_FILE, &json_doc)) { + LOG(ERROR) << "Failed to read task profiles from " << TASK_PROFILE_DB_FILE; + return false; + } + + Json::Reader reader; + Json::Value root; + if (!reader.parse(json_doc, root)) { + LOG(ERROR) << "Failed to parse task profiles: " << reader.getFormattedErrorMessages(); + return false; + } + + Json::Value attr = root["Attributes"]; + for (Json::Value::ArrayIndex i = 0; i < attr.size(); ++i) { + std::string name = attr[i]["Name"].asString(); + std::string ctrlName = attr[i]["Controller"].asString(); + std::string file_name = attr[i]["File"].asString(); + + if (attributes_.find(name) == attributes_.end()) { + const CgroupController* controller = cg_map.FindController(ctrlName.c_str()); + if (controller) { + attributes_[name] = std::make_unique(controller, file_name); + } else { + LOG(WARNING) << "Controller " << ctrlName << " is not found"; + } + } else { + LOG(WARNING) << "Attribute " << name << " is already defined"; + } + } + + std::map params; + + Json::Value profilesVal = root["Profiles"]; + for (Json::Value::ArrayIndex i = 0; i < profilesVal.size(); ++i) { + Json::Value profileVal = profilesVal[i]; + + std::string profileName = profileVal["Name"].asString(); + Json::Value actions = profileVal["Actions"]; + auto profile = std::make_unique(); + + for (Json::Value::ArrayIndex actIdx = 0; actIdx < actions.size(); ++actIdx) { + Json::Value actionVal = actions[actIdx]; + std::string actionName = actionVal["Name"].asString(); + Json::Value paramsVal = actionVal["Params"]; + if (actionName == "JoinCgroup") { + std::string ctrlName = paramsVal["Controller"].asString(); + std::string path = paramsVal["Path"].asString(); + + const CgroupController* controller = cg_map.FindController(ctrlName.c_str()); + if (controller) { + profile->Add(std::make_unique(controller, path)); + } else { + LOG(WARNING) << "JoinCgroup: controller " << ctrlName << " is not found"; + } + } else if (actionName == "SetTimerSlack") { + std::string slackValue = paramsVal["Slack"].asString(); + char* end; + unsigned long slack; + + slack = strtoul(slackValue.c_str(), &end, 10); + if (end > slackValue.c_str()) { + profile->Add(std::make_unique(slack)); + } else { + LOG(WARNING) << "SetTimerSlack: invalid parameter: " << slackValue; + } + } else if (actionName == "SetAttribute") { + std::string attrName = paramsVal["Name"].asString(); + std::string attrValue = paramsVal["Value"].asString(); + + auto iter = attributes_.find(attrName); + if (iter != attributes_.end()) { + profile->Add( + std::make_unique(iter->second.get(), attrValue)); + } else { + LOG(WARNING) << "SetAttribute: unknown attribute: " << attrName; + } + } else if (actionName == "SetClamps") { + std::string boostValue = paramsVal["Boost"].asString(); + std::string clampValue = paramsVal["Clamp"].asString(); + char* end; + unsigned long boost; + + boost = strtoul(boostValue.c_str(), &end, 10); + if (end > boostValue.c_str()) { + unsigned long clamp = strtoul(clampValue.c_str(), &end, 10); + if (end > clampValue.c_str()) { + profile->Add(std::make_unique(boost, clamp)); + } else { + LOG(WARNING) << "SetClamps: invalid parameter " << clampValue; + } + } else { + LOG(WARNING) << "SetClamps: invalid parameter: " << boostValue; + } + } else { + LOG(WARNING) << "Unknown profile action: " << actionName; + } + } + profiles_[profileName] = std::move(profile); + } + + return true; +} + +const TaskProfile* TaskProfiles::GetProfile(const std::string& name) const { + auto iter = profiles_.find(name); + + if (iter != profiles_.end()) { + return iter->second.get(); + } + return nullptr; +} + +const ProfileAttribute* TaskProfiles::GetAttribute(const std::string& name) const { + auto iter = attributes_.find(name); + + if (iter != attributes_.end()) { + return iter->second.get(); + } + return nullptr; +} diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h new file mode 100644 index 000000000..684762aa1 --- /dev/null +++ b/libprocessgroup/task_profiles.h @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include +#include + +class ProfileAttribute { + public: + ProfileAttribute(const CgroupController* controller, const std::string& file_name) + : controller_(controller), file_name_(file_name) {} + + const CgroupController* controller() const { return controller_; } + const std::string& file_name() const { return file_name_; } + + bool GetPathForTask(int tid, std::string* path) const; + + private: + const CgroupController* controller_; + std::string file_name_; +}; + +// Abstract profile element +class ProfileAction { + public: + virtual ~ProfileAction() {} + + // Default implementations will fail + virtual bool ExecuteForProcess(uid_t, pid_t) const { return -1; }; + virtual bool ExecuteForTask(int) const { return -1; }; +}; + +// Profile actions +class SetClampsAction : public ProfileAction { + public: + SetClampsAction(int boost, int clamp) noexcept : boost_(boost), clamp_(clamp) {} + + virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const; + virtual bool ExecuteForTask(int tid) const; + + protected: + int boost_; + int clamp_; +}; + +class SetTimerSlackAction : public ProfileAction { + public: + SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {} + + virtual bool ExecuteForTask(int tid) const; + + private: + unsigned long slack_; + + static bool IsTimerSlackSupported(int tid); +}; + +// Set attribute profile element +class SetAttributeAction : public ProfileAction { + public: + SetAttributeAction(const ProfileAttribute* attribute, const std::string& value) + : attribute_(attribute), value_(value) {} + + virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const; + virtual bool ExecuteForTask(int tid) const; + + private: + const ProfileAttribute* attribute_; + std::string value_; +}; + +// Set cgroup profile element +class SetCgroupAction : public ProfileAction { + public: + SetCgroupAction(const CgroupController* c, const std::string& p); + + virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const; + virtual bool ExecuteForTask(int tid) const; + + const CgroupController* controller() const { return controller_; } + std::string path() const { return path_; } + + private: + const CgroupController* controller_; + std::string path_; + android::base::unique_fd fd_; + + static bool IsAppDependentPath(const std::string& path); + static bool AddTidToCgroup(int tid, int fd); +}; + +class TaskProfile { + public: + TaskProfile() {} + + void Add(std::unique_ptr e) { elements_.push_back(std::move(e)); } + + bool ExecuteForProcess(uid_t uid, pid_t pid) const; + bool ExecuteForTask(int tid) const; + + private: + std::vector> elements_; +}; + +class TaskProfiles { + public: + // Should be used by all users + static TaskProfiles& GetInstance(); + + const TaskProfile* GetProfile(const std::string& name) const; + const ProfileAttribute* GetAttribute(const std::string& name) const; + + private: + std::map> profiles_; + std::map> attributes_; + + TaskProfiles(); + + bool Load(const CgroupMap& cg_map); +}; diff --git a/rootdir/init.rc b/rootdir/init.rc index 86c937707..79873c0ff 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -11,6 +11,7 @@ import /vendor/etc/init/hw/init.${ro.hardware}.rc import /init.usb.configfs.rc import /init.${ro.zygote}.rc +# Cgroups are mounted right before early-init using list from /etc/cgroups.json on early-init # Mount shared so changes propagate into child namespaces # Do this before other processes are started from init. Otherwise, @@ -30,14 +31,8 @@ on early-init # Set the security context of /postinstall if present. restorecon /postinstall - # Mount cgroup mount point for cpu accounting - mount cgroup none /acct nodev noexec nosuid cpuacct - chmod 0555 /acct mkdir /acct/uid - # root memory control cgroup, used by lmkd - mkdir /dev/memcg 0700 root system - mount cgroup none /dev/memcg nodev noexec nosuid memory # memory.pressure_level used by lmkd chown root system /dev/memcg/memory.pressure_level chmod 0040 /dev/memcg/memory.pressure_level @@ -69,8 +64,6 @@ on init symlink /system/vendor /vendor # Create energy-aware scheduler tuning nodes - mkdir /dev/stune - mount cgroup none /dev/stune nodev noexec nosuid schedtune mkdir /dev/stune/foreground mkdir /dev/stune/background mkdir /dev/stune/top-app @@ -164,8 +157,6 @@ on init chmod 0400 /proc/net/fib_trie # Create cgroup mount points for process groups - mkdir /dev/cpuctl - mount cgroup none /dev/cpuctl nodev noexec nosuid cpu chown system system /dev/cpuctl chown system system /dev/cpuctl/tasks chmod 0666 /dev/cpuctl/tasks @@ -173,9 +164,6 @@ on init write /dev/cpuctl/cpu.rt_runtime_us 950000 # sets up initial cpusets for ActivityManager - mkdir /dev/cpuset - mount cpuset none /dev/cpuset nodev noexec nosuid - # this ensures that the cpusets are present and usable, but the device's # init.rc must actually set the correct cpus mkdir /dev/cpuset/foreground @@ -237,8 +225,6 @@ on init # This is needed by any process that uses socket tagging. chmod 0644 /dev/xt_qtaguid - mkdir /dev/cg2_bpf - mount cgroup2 cg2_bpf /dev/cg2_bpf nodev noexec nosuid chown root root /dev/cg2_bpf chmod 0600 /dev/cg2_bpf mount bpf bpf /sys/fs/bpf nodev noexec nosuid From 1c1f2491cca9aae21d6ddd70a729cd6c40fa8da7 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Fri, 21 Dec 2018 12:36:20 -0800 Subject: [PATCH 082/221] init: Replace cgroup hardcoded path with detected one Remove hardcoded cpuset path usage and replace it with a request to get the path using new API. Bug: 111307099 Test: builds, boots Change-Id: I211d093c24a682e2d1992c08e4c1d980379711a4 Signed-off-by: Suren Baghdasaryan --- init/service.cpp | 44 +++++++++++++++++++++++++------------------- 1 file changed, 25 insertions(+), 19 deletions(-) diff --git a/init/service.cpp b/init/service.cpp index a6eb7f7ab..84cb2d88d 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -991,27 +991,33 @@ Result Service::Start() { std::for_each(descriptors_.begin(), descriptors_.end(), std::bind(&DescriptorInfo::CreateAndPublish, std::placeholders::_1, scon)); - // See if there were "writepid" instructions to write to files under /dev/cpuset/. - auto cpuset_predicate = [](const std::string& path) { - return StartsWith(path, "/dev/cpuset/"); - }; - auto iter = std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate); - if (iter == writepid_files_.end()) { - // There were no "writepid" instructions for cpusets, check if the system default - // cpuset is specified to be used for the process. - std::string default_cpuset = GetProperty("ro.cpuset.default", ""); - if (!default_cpuset.empty()) { - // Make sure the cpuset name starts and ends with '/'. - // A single '/' means the 'root' cpuset. - if (default_cpuset.front() != '/') { - default_cpuset.insert(0, 1, '/'); + // See if there were "writepid" instructions to write to files under cpuset path. + std::string cpuset_path; + if (CgroupGetControllerPath("cpuset", &cpuset_path)) { + auto cpuset_predicate = [&cpuset_path](const std::string& path) { + return StartsWith(path, cpuset_path + "/"); + }; + auto iter = + std::find_if(writepid_files_.begin(), writepid_files_.end(), cpuset_predicate); + if (iter == writepid_files_.end()) { + // There were no "writepid" instructions for cpusets, check if the system default + // cpuset is specified to be used for the process. + std::string default_cpuset = GetProperty("ro.cpuset.default", ""); + if (!default_cpuset.empty()) { + // Make sure the cpuset name starts and ends with '/'. + // A single '/' means the 'root' cpuset. + if (default_cpuset.front() != '/') { + default_cpuset.insert(0, 1, '/'); + } + if (default_cpuset.back() != '/') { + default_cpuset.push_back('/'); + } + writepid_files_.push_back( + StringPrintf("%s%stasks", cpuset_path.c_str(), default_cpuset.c_str())); } - if (default_cpuset.back() != '/') { - default_cpuset.push_back('/'); - } - writepid_files_.push_back( - StringPrintf("/dev/cpuset%stasks", default_cpuset.c_str())); } + } else { + LOG(ERROR) << "cpuset cgroup controller is not mounted!"; } std::string pid_str = std::to_string(getpid()); for (const auto& file : writepid_files_) { From d54706cf671c89d989ed202e5fc4a5564dfe4d12 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Sat, 2 Feb 2019 14:19:41 -0800 Subject: [PATCH 083/221] Fix non-Android build targets Non-Android build targets are missing sys/prctl.h header and functionality should be disabled for them like it was done previously inside sched_policy.cpp. Also make the set_sched_policy/get_sched_policy functionality backward compatible by creating stubs for non-Android targets. Bug: 111307099 Test: built sdk_gphone_x86-sdk_addon_mac target using forrest Change-Id: I1c195267e287a84a21c588bd61d7c452bff6cfbe Signed-off-by: Suren Baghdasaryan --- libprocessgroup/sched_policy.cpp | 17 +++++++++++++++++ libprocessgroup/task_profiles.cpp | 11 ++++++++++- libprocessgroup/task_profiles.h | 14 ++++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp index 4c8aa6dd7..337b032f2 100644 --- a/libprocessgroup/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -36,6 +36,8 @@ static inline SchedPolicy _policy(SchedPolicy p) { return p == SP_DEFAULT ? SP_SYSTEM_DEFAULT : p; } +#if defined(__ANDROID__) + int set_cpuset_policy(int tid, SchedPolicy policy) { if (tid == 0) { tid = GetThreadId(); @@ -195,6 +197,21 @@ int get_sched_policy(int tid, SchedPolicy* policy) { return 0; } +#else + +/* Stubs for non-Android targets. */ + +int set_sched_policy(int, SchedPolicy) { + return 0; +} + +int get_sched_policy(int, SchedPolicy* policy) { + *policy = SP_SYSTEM_DEFAULT; + return 0; +} + +#endif + const char* get_sched_policy_name(SchedPolicy policy) { policy = _policy(policy); static const char* const kSchedPolicyNames[] = { diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index eb50f8539..ec6cbbc45 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -18,7 +18,6 @@ #define LOG_TAG "libprocessgroup" #include -#include #include #include @@ -32,6 +31,11 @@ #include #include +// To avoid issues in sdk_mac build +#if defined(__ANDROID__) +#include +#endif + using android::base::GetThreadId; using android::base::StringPrintf; using android::base::unique_fd; @@ -69,6 +73,9 @@ bool SetClampsAction::ExecuteForTask(int) const { return false; } +// To avoid issues in sdk_mac build +#if defined(__ANDROID__) + bool SetTimerSlackAction::IsTimerSlackSupported(int tid) { auto file = StringPrintf("/proc/%d/timerslack_ns", tid); @@ -97,6 +104,8 @@ bool SetTimerSlackAction::ExecuteForTask(int tid) const { return true; } +#endif + bool SetAttributeAction::ExecuteForProcess(uid_t, pid_t pid) const { return ExecuteForTask(pid); } diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index 684762aa1..886ead141 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -63,6 +63,9 @@ class SetClampsAction : public ProfileAction { int clamp_; }; +// To avoid issues in sdk_mac build +#if defined(__ANDROID__) + class SetTimerSlackAction : public ProfileAction { public: SetTimerSlackAction(unsigned long slack) noexcept : slack_(slack) {} @@ -75,6 +78,17 @@ class SetTimerSlackAction : public ProfileAction { static bool IsTimerSlackSupported(int tid); }; +#else + +class SetTimerSlackAction : public ProfileAction { + public: + SetTimerSlackAction(unsigned long) noexcept {} + + virtual bool ExecuteForTask(int) const { return true; } +}; + +#endif + // Set attribute profile element class SetAttributeAction : public ProfileAction { public: From a76780d627a43003492b1fd0acdf046ffad63b56 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Sat, 2 Feb 2019 23:12:01 -0800 Subject: [PATCH 084/221] Disable SetupCgroup for non-Android targets Non-android targets should not mount cgroups described in cgroup map file. When used on non-Android targets SetupCgroup will fail. When SetupCgroup is called via SetupCgroups a warning will be generated for each cgroup that fails to mount. Bug: 111307099 Change-Id: I213a5f9b02f312ba1dd7dc91c89b67334fb939b9 Signed-off-by: Suren Baghdasaryan --- libprocessgroup/cgroup_map.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index 1b5f217c7..12cfb7e62 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -142,6 +142,9 @@ static bool ReadDescriptors(std::map* descriptors return true; } +// To avoid issues in sdk_mac build +#if defined(__ANDROID__) + static bool SetupCgroup(const CgroupDescriptor& descriptor) { const CgroupController* controller = descriptor.controller(); @@ -180,6 +183,15 @@ static bool SetupCgroup(const CgroupDescriptor& descriptor) { return true; } +#else + +// Stubs for non-Android targets. +static bool SetupCgroup(const CgroupDescriptor&) { + return false; +} + +#endif + static bool WriteRcFile(const std::map& descriptors) { std::string cgroup_rc_path = StringPrintf("%s/%s", CGROUPS_RC_DIR, CgroupMap::CGROUPS_RC_FILE); unique_fd fd(TEMP_FAILURE_RETRY(open(cgroup_rc_path.c_str(), From c58cfe7ffeba38e31e2eb59a24b4e7138e73ecd1 Mon Sep 17 00:00:00 2001 From: Martin Stjernholm Date: Tue, 29 Jan 2019 18:19:17 +0000 Subject: [PATCH 085/221] Add compat symlinks into the Runtime APEX for the ART binaries. This is a precaution in case there are dependencies on the binaries in the old location. b/124106384 tracks eliminating them (if any). Test: Flash and check symlinks are there with adb shell ls -l system/bin Test: adb shell system/bin/ Bug: 113373927 Bug: 124106384 Change-Id: Ib4102fe55117611f68184102e68a10ea47de0065 (cherry picked from commit 7f77dbfe64100e31e16e69a5bb5912d50a7c4962) --- rootdir/Android.mk | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/rootdir/Android.mk b/rootdir/Android.mk index cbbc7109c..123fdd787 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -42,6 +42,23 @@ LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu +# TODO(b/124106384): Clean up compat symlinks for ART binaries. +ART_BINARIES= \ + dalvikvm32 \ + dalvikvm64 \ + dex2oat \ + dexdiag \ + dexdump \ + dexlist \ + dexoptanalyzer \ + oatdump \ + profman \ + +$(foreach b,$(ART_BINARIES), \ + $(eval LOCAL_POST_INSTALL_CMD += \ + ; ln -sf /apex/com.android.runtime/bin/$(b) $(TARGET_OUT)/bin/$(b)) \ +) + # End of runtime APEX compatibilty. include $(BUILD_PREBUILT) From ac1eeb7f78f4a86f5e639d4b44adc6ac758adaf0 Mon Sep 17 00:00:00 2001 From: Gavin Corkery Date: Fri, 15 Feb 2019 15:38:46 +0000 Subject: [PATCH 086/221] Rename data/staging to data/pkg_staging. Test: Build and flash, atest apex_e2e_tests Fixes: 122999313 Change-Id: I878ee41f804956ee7533d64e844ce98e5a8afacc --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 3494a5bec..64177bd62 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -538,7 +538,7 @@ on post-fs-data mkdir /data/apex/active 0750 root system mkdir /data/apex/backup 0700 root system mkdir /data/apex/sessions 0700 root system - mkdir /data/staging 0750 system system + mkdir /data/pkg_staging 0750 system system # NFC: create data/nfc for nv storage mkdir /data/nfc 0770 nfc nfc From 491e340c2e7089fc540010330c7e8b12434b7a17 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Tue, 19 Feb 2019 21:32:07 +0000 Subject: [PATCH 087/221] Expose libandroidicu to llndk namespace Bug: 124772622 Test: Treehugger Change-Id: If936eb377c7f0994a9225b8099a672addb2f9ed6 (cherry picked from commit ff67ef3c7d03f2b40daa86a17d6ba33168492880) --- rootdir/etc/ld.config.txt | 3 ++- rootdir/etc/ld.config.vndk_lite.txt | 2 ++ 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt index 44b7035bf..cdfcfe118 100644 --- a/rootdir/etc/ld.config.txt +++ b/rootdir/etc/ld.config.txt @@ -485,7 +485,8 @@ namespace.system.link.runtime.shared_libs = libdexfile_external.so namespace.system.link.runtime.shared_libs += libnativebridge.so namespace.system.link.runtime.shared_libs += libnativehelper.so namespace.system.link.runtime.shared_libs += libnativeloader.so - +# Workaround for b/124772622 +namespace.system.link.runtime.shared_libs += libandroidicu.so ############################################################################### # Namespace config for native tests that need access to both system and vendor diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt index 92f287c25..59fd568f1 100644 --- a/rootdir/etc/ld.config.vndk_lite.txt +++ b/rootdir/etc/ld.config.vndk_lite.txt @@ -344,6 +344,8 @@ namespace.default.link.runtime.shared_libs = libdexfile_external.so namespace.default.link.runtime.shared_libs += libnativebridge.so namespace.default.link.runtime.shared_libs += libnativehelper.so namespace.default.link.runtime.shared_libs += libnativeloader.so +# Workaround for b/124772622 +namespace.default.link.runtime.shared_libs += libandroidicu.so ############################################################################### # "runtime" APEX namespace From 4a25816c22c2f87f675d7be86726e973e36b6fff Mon Sep 17 00:00:00 2001 From: Chris Wailes Date: Fri, 22 Feb 2019 11:35:08 -0800 Subject: [PATCH 088/221] Renamed blastula to unspecialized app process (usap) Bug: 123017829 Test: make & boot & launch apps Change-Id: Id780245f2d86e57cc4964abb2fd10ead9b64da1f --- rootdir/init.zygote32.rc | 2 +- rootdir/init.zygote32_64.rc | 4 ++-- rootdir/init.zygote64.rc | 2 +- rootdir/init.zygote64_32.rc | 4 ++-- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc index e8c5d8e1b..38c5d18bd 100644 --- a/rootdir/init.zygote32.rc +++ b/rootdir/init.zygote32.rc @@ -4,7 +4,7 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys user root group root readproc reserved_disk socket zygote stream 660 root system - socket blastula_pool stream 660 root system + socket usap_pool_primary stream 660 root system updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc index 9c7e80707..58bb45225 100644 --- a/rootdir/init.zygote32_64.rc +++ b/rootdir/init.zygote32_64.rc @@ -4,7 +4,7 @@ service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-s user root group root readproc reserved_disk socket zygote stream 660 root system - socket blastula_pool stream 660 root system + socket usap_pool_primary stream 660 root system updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on @@ -21,7 +21,7 @@ service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote user root group root readproc reserved_disk socket zygote_secondary stream 660 root system - socket blastula_pool_secondary stream 660 root system + socket usap_pool_secondary stream 660 root system updatable onrestart restart zygote writepid /dev/cpuset/foreground/tasks diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc index 9908c9948..f7dc5f640 100644 --- a/rootdir/init.zygote64.rc +++ b/rootdir/init.zygote64.rc @@ -4,7 +4,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s user root group root readproc reserved_disk socket zygote stream 660 root system - socket blastula_pool stream 660 root system + socket usap_pool_primary stream 660 root system updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc index 0b5edff7d..5829a9d8e 100644 --- a/rootdir/init.zygote64_32.rc +++ b/rootdir/init.zygote64_32.rc @@ -4,7 +4,7 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s user root group root readproc reserved_disk socket zygote stream 660 root system - socket blastula_pool stream 660 root system + socket usap_pool_primary stream 660 root system updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on @@ -21,7 +21,7 @@ service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote user root group root readproc reserved_disk socket zygote_secondary stream 660 root system - socket blastula_pool_secondary stream 660 root system + socket usap_pool_secondary stream 660 root system updatable onrestart restart zygote writepid /dev/cpuset/foreground/tasks From e7cfa67a0573a3680ce63dfc48121bf6396be45d Mon Sep 17 00:00:00 2001 From: Rajeev Kumar Date: Fri, 5 Oct 2018 12:34:59 -0700 Subject: [PATCH 089/221] Read memory stats from /proc/pid/stat file. (cherry pick from commit 0301683e49ab255769b15469487feaab3466167a) Bug: 117333340 Test: Manual testing using alloc-stress tool Merged-In: Ie555933aafa6a6b7aa1dbf5518ebe804376e0afd Change-Id: I8ab08606dba7de2f65711204453067dbfbdcbdd8 --- lmkd/lmkd.c | 75 ++++++++++++++++++++++++++++++++++++++----------- lmkd/statslog.h | 3 ++ 2 files changed, 62 insertions(+), 16 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 26f4df6bf..d6632a2f8 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -984,7 +984,7 @@ static void ctrl_connect_handler(int data __unused, uint32_t events __unused) { } #ifdef LMKD_LOG_STATS -static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { +static void memory_stat_parse_line(char* line, struct memory_stat* mem_st) { char key[LINE_MAX + 1]; int64_t value; @@ -1006,25 +1006,61 @@ static void memory_stat_parse_line(char *line, struct memory_stat *mem_st) { mem_st->swap_in_bytes = value; } -static int memory_stat_parse(struct memory_stat *mem_st, int pid, uid_t uid) { - FILE *fp; - char buf[PATH_MAX]; +static int memory_stat_from_cgroup(struct memory_stat* mem_st, int pid, uid_t uid) { + FILE *fp; + char buf[PATH_MAX]; - snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid); + snprintf(buf, sizeof(buf), MEMCG_PROCESS_MEMORY_STAT_PATH, uid, pid); - fp = fopen(buf, "r"); + fp = fopen(buf, "r"); - if (fp == NULL) { - ALOGE("%s open failed: %s", buf, strerror(errno)); - return -1; - } + if (fp == NULL) { + ALOGE("%s open failed: %s", buf, strerror(errno)); + return -1; + } - while (fgets(buf, PAGE_SIZE, fp) != NULL ) { - memory_stat_parse_line(buf, mem_st); - } - fclose(fp); + while (fgets(buf, PAGE_SIZE, fp) != NULL) { + memory_stat_parse_line(buf, mem_st); + } + fclose(fp); - return 0; + return 0; +} + +static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) { + char path[PATH_MAX]; + char buffer[PROC_STAT_BUFFER_SIZE]; + int fd, ret; + + snprintf(path, sizeof(path), PROC_STAT_FILE_PATH, pid); + if ((fd = open(path, O_RDONLY | O_CLOEXEC)) < 0) { + ALOGE("%s open failed: %s", path, strerror(errno)); + return -1; + } + + ret = read(fd, buffer, sizeof(buffer)); + if (ret < 0) { + ALOGE("%s read failed: %s", path, strerror(errno)); + close(fd); + return -1; + } + close(fd); + + // field 10 is pgfault + // field 12 is pgmajfault + // field 24 is rss_in_pages + int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0; + if (sscanf(buffer, + "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d " + "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d " + "%*d %*d %" SCNd64 "", + &pgfault, &pgmajfault, &rss_in_pages) != 3) { + return -1; + } + mem_st->pgfault = pgfault; + mem_st->pgmajfault = pgmajfault; + mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE); + return 0; } #endif @@ -1316,7 +1352,11 @@ static int kill_one_process(struct proc* procp) { #ifdef LMKD_LOG_STATS if (enable_stats_log) { - memory_stat_parse_result = memory_stat_parse(&mem_st, pid, uid); + if (per_app_memcg) { + memory_stat_parse_result = memory_stat_from_cgroup(&mem_st, pid, uid); + } else { + memory_stat_parse_result = memory_stat_from_procfs(&mem_st, pid); + } } #endif @@ -1344,6 +1384,9 @@ static int kill_one_process(struct proc* procp) { stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes, mem_st.cache_in_bytes, mem_st.swap_in_bytes); + } else if (enable_stats_log) { + stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, + -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1); } #endif result = tasksize; diff --git a/lmkd/statslog.h b/lmkd/statslog.h index edebb195b..84584805d 100644 --- a/lmkd/statslog.h +++ b/lmkd/statslog.h @@ -67,6 +67,9 @@ struct memory_stat { }; #define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat" +#define PROC_STAT_FILE_PATH "/proc/%d/stat" +#define PROC_STAT_BUFFER_SIZE 1024 +#define BYTES_IN_KILOBYTE 1024 /** * Logs the change in LMKD state which is used as start/stop boundaries for logging From e7a9fabd647c472ae5b6f0b694d880a8aa51a9ea Mon Sep 17 00:00:00 2001 From: Jim Blackler Date: Wed, 21 Nov 2018 16:22:36 +0000 Subject: [PATCH 090/221] Add start time to LmkKillOccurred This is to measure an application's behavior with respect to being LMKed (the longer an app lives before being LMKed, the better). Bug: 119854389 Test: Manual Change-Id: I4ef6433391c8758626334731d2b5de038e4468ae Merged-In: I4ef6433391c8758626334731d2b5de038e4468ae (cherry picked from I4ef6433391c8758626334731d2b5de038e4468ae) --- lmkd/lmkd.c | 12 +++++++----- lmkd/statslog.c | 6 +++++- lmkd/statslog.h | 3 ++- 3 files changed, 14 insertions(+), 7 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index d6632a2f8..98b3aa1c4 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -1048,18 +1048,20 @@ static int memory_stat_from_procfs(struct memory_stat* mem_st, int pid) { // field 10 is pgfault // field 12 is pgmajfault + // field 22 is starttime // field 24 is rss_in_pages - int64_t pgfault = 0, pgmajfault = 0, rss_in_pages = 0; + int64_t pgfault = 0, pgmajfault = 0, starttime = 0, rss_in_pages = 0; if (sscanf(buffer, "%*u %*s %*s %*d %*d %*d %*d %*d %*d %" SCNd64 " %*d " "%" SCNd64 " %*d %*u %*u %*d %*d %*d %*d %*d %*d " - "%*d %*d %" SCNd64 "", - &pgfault, &pgmajfault, &rss_in_pages) != 3) { + "%" SCNd64 " %*d %" SCNd64 "", + &pgfault, &pgmajfault, &starttime, &rss_in_pages) != 4) { return -1; } mem_st->pgfault = pgfault; mem_st->pgmajfault = pgmajfault; mem_st->rss_in_bytes = (rss_in_pages * PAGE_SIZE); + mem_st->process_start_time_ns = starttime * (NS_PER_SEC / sysconf(_SC_CLK_TCK)); return 0; } #endif @@ -1383,10 +1385,10 @@ static int kill_one_process(struct proc* procp) { if (memory_stat_parse_result == 0) { stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, mem_st.pgfault, mem_st.pgmajfault, mem_st.rss_in_bytes, - mem_st.cache_in_bytes, mem_st.swap_in_bytes); + mem_st.cache_in_bytes, mem_st.swap_in_bytes, mem_st.process_start_time_ns); } else if (enable_stats_log) { stats_write_lmk_kill_occurred(log_ctx, LMK_KILL_OCCURRED, uid, taskname, procp->oomadj, - -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1); + -1, -1, tasksize * BYTES_IN_KILOBYTE, -1, -1, -1); } #endif result = tasksize; diff --git a/lmkd/statslog.c b/lmkd/statslog.c index 66d11647b..689e8aebe 100644 --- a/lmkd/statslog.c +++ b/lmkd/statslog.c @@ -65,7 +65,7 @@ int stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid, char const* process_name, int32_t oom_score, int64_t pgfault, int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes, - int64_t swap_in_bytes) { + int64_t swap_in_bytes, int64_t process_start_time_ns) { assert(ctx != NULL); int ret = -EINVAL; if (!ctx) { @@ -113,5 +113,9 @@ stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid return ret; } + if ((ret = android_log_write_int64(ctx, process_start_time_ns)) < 0) { + return ret; + } + return write_to_logger(ctx, LOG_ID_STATS); } diff --git a/lmkd/statslog.h b/lmkd/statslog.h index 84584805d..f3abe1103 100644 --- a/lmkd/statslog.h +++ b/lmkd/statslog.h @@ -64,6 +64,7 @@ struct memory_stat { int64_t rss_in_bytes; int64_t cache_in_bytes; int64_t swap_in_bytes; + int64_t process_start_time_ns; }; #define MEMCG_PROCESS_MEMORY_STAT_PATH "/dev/memcg/apps/uid_%u/pid_%u/memory.stat" @@ -87,7 +88,7 @@ int stats_write_lmk_kill_occurred(android_log_context ctx, int32_t code, int32_t uid, char const* process_name, int32_t oom_score, int64_t pgfault, int64_t pgmajfault, int64_t rss_in_bytes, int64_t cache_in_bytes, - int64_t swap_in_bytes); + int64_t swap_in_bytes, int64_t process_start_time_ns); __END_DECLS From 538e0b98c4277ed788e0b2e9b642d21c5c027aca Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 6 Mar 2019 14:20:50 +0100 Subject: [PATCH 091/221] Update comments on native_handle_create. To indicate limits. Test: builds Change-Id: Id5129a7f6a8f413911544dedeb02bb4e7a2f6e10 --- libcutils/include/cutils/native_handle.h | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/libcutils/include/cutils/native_handle.h b/libcutils/include/cutils/native_handle.h index f6cae360f..4f0745605 100644 --- a/libcutils/include/cutils/native_handle.h +++ b/libcutils/include/cutils/native_handle.h @@ -69,10 +69,11 @@ native_handle_t* native_handle_init(char* storage, int numFds, int numInts); /* * native_handle_create - * + * * creates a native_handle_t and initializes it. must be destroyed with - * native_handle_delete(). - * + * native_handle_delete(). Note that numFds must be <= NATIVE_HANDLE_MAX_FDS, + * numInts must be <= NATIVE_HANDLE_MAX_INTS, and both must be >= 0. + * */ native_handle_t* native_handle_create(int numFds, int numInts); From cd8b96cb7c6b9d47a30a0198a807e4ae4494be6d Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Wed, 20 Feb 2019 18:04:39 +0900 Subject: [PATCH 092/221] Add product apk support from libnativeloader Currently libnativeloader appends vendor lib path if apk is from vendor partition. Similar to this, as part of mainline core, we should add product lib path if apk if from product partition. Bug: 124705551 Test: m -j && tested from crosshatch with product apps (such as Wallpaper) Change-Id: I8690167ca8098015c8ae4bbb4f028404c5e94dc0 --- .../include/nativeloader/native_loader.h | 11 +- libnativeloader/native_loader.cpp | 112 ++++++++++++------ libnativeloader/native_loader_lazy.cpp | 4 +- 3 files changed, 84 insertions(+), 43 deletions(-) diff --git a/libnativeloader/include/nativeloader/native_loader.h b/libnativeloader/include/nativeloader/native_loader.h index 260f65520..51fb875f6 100644 --- a/libnativeloader/include/nativeloader/native_loader.h +++ b/libnativeloader/include/nativeloader/native_loader.h @@ -36,14 +36,9 @@ extern "C" { __attribute__((visibility("default"))) void InitializeNativeLoader(); -__attribute__((visibility("default"))) -jstring CreateClassLoaderNamespace(JNIEnv* env, - int32_t target_sdk_version, - jobject class_loader, - bool is_shared, - bool is_for_vendor, - jstring library_path, - jstring permitted_path); +__attribute__((visibility("default"))) jstring CreateClassLoaderNamespace( + JNIEnv* env, int32_t target_sdk_version, jobject class_loader, bool is_shared, jstring dex_path, + jstring library_path, jstring permitted_path); __attribute__((visibility("default"))) void* OpenNativeLibrary( JNIEnv* env, int32_t target_sdk_version, const char* path, jobject class_loader, diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index 043f0380f..1c2581f08 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -140,10 +141,24 @@ static constexpr const char* kApexPath = "/apex/"; #if defined(__LP64__) static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib64"; +static constexpr const char* kVendorLibPath = "/vendor/lib64"; +static constexpr const char* kProductLibPath = "/product/lib64:/system/product/lib64"; #else static constexpr const char* kRuntimeApexLibPath = "/apex/com.android.runtime/lib"; +static constexpr const char* kVendorLibPath = "/vendor/lib"; +static constexpr const char* kProductLibPath = "/product/lib:/system/product/lib"; #endif +static const std::regex kVendorDexPathRegex("(^|:)/vendor/"); +static const std::regex kProductDexPathRegex("(^|:)(/system)?/product/"); + +// Define origin of APK if it is from vendor partition or product partition +typedef enum { + APK_ORIGIN_DEFAULT = 0, + APK_ORIGIN_VENDOR = 1, + APK_ORIGIN_PRODUCT = 2, +} ApkOrigin; + static bool is_debuggable() { bool debuggable = false; #ifdef __BIONIC__ @@ -179,7 +194,7 @@ class LibraryNamespaces { LibraryNamespaces() : initialized_(false) { } NativeLoaderNamespace* Create(JNIEnv* env, uint32_t target_sdk_version, jobject class_loader, - bool is_shared, bool is_for_vendor, jstring java_library_path, + bool is_shared, jstring dex_path, jstring java_library_path, jstring java_permitted_path, std::string* error_msg) { std::string library_path; // empty string by default. @@ -188,6 +203,8 @@ class LibraryNamespaces { library_path = library_path_utf_chars.c_str(); } + ApkOrigin apk_origin = GetApkOriginFromDexPath(env, dex_path); + // (http://b/27588281) This is a workaround for apps using custom // classloaders and calling System.load() with an absolute path which // is outside of the classloader library search path. @@ -234,31 +251,50 @@ class LibraryNamespaces { std::string system_exposed_libraries = system_public_libraries_; const char* namespace_name = kClassloaderNamespaceName; android_namespace_t* vndk_ns = nullptr; - if (is_for_vendor && !is_shared) { - LOG_FATAL_IF(is_native_bridge, "Unbundled vendor apk must not use translated architecture"); + if ((apk_origin == APK_ORIGIN_VENDOR || + (apk_origin == APK_ORIGIN_PRODUCT && target_sdk_version > 29)) && + !is_shared) { + LOG_FATAL_IF(is_native_bridge, + "Unbundled vendor / product apk must not use translated architecture"); - // For vendor apks, give access to the vendor lib even though + // For vendor / product apks, give access to the vendor / product lib even though // they are treated as unbundled; the libs and apks are still bundled - // together in the vendor partition. -#if defined(__LP64__) - std::string vendor_lib_path = "/vendor/lib64"; -#else - std::string vendor_lib_path = "/vendor/lib"; -#endif - library_path = library_path + ":" + vendor_lib_path.c_str(); - permitted_path = permitted_path + ":" + vendor_lib_path.c_str(); + // together in the vendor / product partition. + const char* origin_partition; + const char* origin_lib_path; + + switch (apk_origin) { + case APK_ORIGIN_VENDOR: + origin_partition = "vendor"; + origin_lib_path = kVendorLibPath; + break; + case APK_ORIGIN_PRODUCT: + origin_partition = "product"; + origin_lib_path = kProductLibPath; + break; + default: + origin_partition = "unknown"; + origin_lib_path = ""; + } + + LOG_FATAL_IF(is_native_bridge, "Unbundled %s apk must not use translated architecture", + origin_partition); + + library_path = library_path + ":" + origin_lib_path; + permitted_path = permitted_path + ":" + origin_lib_path; // Also give access to LLNDK libraries since they are available to vendors system_exposed_libraries = system_exposed_libraries + ":" + system_llndk_libraries_.c_str(); // Give access to VNDK-SP libraries from the 'vndk' namespace. vndk_ns = android_get_exported_namespace(kVndkNamespaceName); - LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr, - "Cannot find \"%s\" namespace for vendor apks", kVndkNamespaceName); + LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr, "Cannot find \"%s\" namespace for %s apks", + kVndkNamespaceName, origin_partition); // Different name is useful for debugging namespace_name = kVendorClassloaderNamespaceName; - ALOGD("classloader namespace configured for unbundled vendor apk. library_path=%s", library_path.c_str()); + ALOGD("classloader namespace configured for unbundled %s apk. library_path=%s", + origin_partition, library_path.c_str()); } else { // oem and product public libraries are NOT available to vendor apks, otherwise it // would be system->vendor violation. @@ -660,6 +696,28 @@ class LibraryNamespaces { return nullptr; } + ApkOrigin GetApkOriginFromDexPath(JNIEnv* env, jstring dex_path) { + ApkOrigin apk_origin = APK_ORIGIN_DEFAULT; + + if (dex_path != nullptr) { + ScopedUtfChars dex_path_utf_chars(env, dex_path); + + if (std::regex_search(dex_path_utf_chars.c_str(), kVendorDexPathRegex)) { + apk_origin = APK_ORIGIN_VENDOR; + } + + if (std::regex_search(dex_path_utf_chars.c_str(), kProductDexPathRegex)) { + LOG_ALWAYS_FATAL_IF(apk_origin == APK_ORIGIN_VENDOR, + "Dex path contains both vendor and product partition : %s", + dex_path_utf_chars.c_str()); + + apk_origin = APK_ORIGIN_PRODUCT; + } + } + + return apk_origin; + } + bool initialized_; std::list> namespaces_; std::string system_public_libraries_; @@ -690,31 +748,20 @@ void ResetNativeLoader() { #endif } -jstring CreateClassLoaderNamespace(JNIEnv* env, - int32_t target_sdk_version, - jobject class_loader, - bool is_shared, - bool is_for_vendor, - jstring library_path, +jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader, + bool is_shared, jstring dex_path, jstring library_path, jstring permitted_path) { #if defined(__ANDROID__) std::lock_guard guard(g_namespaces_mutex); std::string error_msg; - bool success = g_namespaces->Create(env, - target_sdk_version, - class_loader, - is_shared, - is_for_vendor, - library_path, - permitted_path, - &error_msg) != nullptr; + bool success = g_namespaces->Create(env, target_sdk_version, class_loader, is_shared, dex_path, + library_path, permitted_path, &error_msg) != nullptr; if (!success) { return env->NewStringUTF(error_msg.c_str()); } #else - UNUSED(env, target_sdk_version, class_loader, is_shared, is_for_vendor, - library_path, permitted_path); + UNUSED(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path); #endif return nullptr; } @@ -779,8 +826,7 @@ void* OpenNativeLibrary(JNIEnv* env, int32_t target_sdk_version, const char* pat // In this case we create an isolated not-shared namespace for it. std::string create_error_msg; if ((ns = g_namespaces->Create(env, target_sdk_version, class_loader, false /* is_shared */, - false /* is_for_vendor */, library_path, nullptr, - &create_error_msg)) == nullptr) { + nullptr, library_path, nullptr, &create_error_msg)) == nullptr) { *error_msg = strdup(create_error_msg.c_str()); return nullptr; } diff --git a/libnativeloader/native_loader_lazy.cpp b/libnativeloader/native_loader_lazy.cpp index 11ecc431a..2eb120379 100644 --- a/libnativeloader/native_loader_lazy.cpp +++ b/libnativeloader/native_loader_lazy.cpp @@ -50,10 +50,10 @@ void InitializeNativeLoader() { } jstring CreateClassLoaderNamespace(JNIEnv* env, int32_t target_sdk_version, jobject class_loader, - bool is_shared, bool is_for_vendor, jstring library_path, + bool is_shared, jstring dex_path, jstring library_path, jstring permitted_path) { static auto f = GET_FUNC_PTR(CreateClassLoaderNamespace); - return f(env, target_sdk_version, class_loader, is_shared, is_for_vendor, library_path, + return f(env, target_sdk_version, class_loader, is_shared, dex_path, library_path, permitted_path); } From 3bddd540dd1260285b174dbcf891634ba7939d08 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Tue, 5 Mar 2019 21:54:53 +0900 Subject: [PATCH 093/221] Don't defer zygote Removing 'updatable' from zygote as zygote is started after apexd. All APEXes are guaranteed to be activated at the moment. Sequence of actions: 1) /data mounted. post-fs-data is triggered. 2) apexd starts. APEXes are activated. Init does not execute more commands until the activation finishes. 3) all post-fs-data sections from other *.rc are executed. 4) zygote-start is triggered. Bug: 123404717 Bug: 126555629 Bug: 125549215 Test: device boots Test: no following message on the logcat log Could not restart 'zygote': Cannot start an updatable service 'zygote' before configs from APEXes are all loaded. Queued for execution. Change-Id: Ib4d0716ed5225b6ade3adaa247ff6140a9b2b9d5 --- rootdir/init.zygote32.rc | 1 - rootdir/init.zygote32_64.rc | 2 -- rootdir/init.zygote64.rc | 1 - rootdir/init.zygote64_32.rc | 2 -- 4 files changed, 6 deletions(-) diff --git a/rootdir/init.zygote32.rc b/rootdir/init.zygote32.rc index 38c5d18bd..bf3fb4217 100644 --- a/rootdir/init.zygote32.rc +++ b/rootdir/init.zygote32.rc @@ -5,7 +5,6 @@ service zygote /system/bin/app_process -Xzygote /system/bin --zygote --start-sys group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system - updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver diff --git a/rootdir/init.zygote32_64.rc b/rootdir/init.zygote32_64.rc index 58bb45225..1bab588c4 100644 --- a/rootdir/init.zygote32_64.rc +++ b/rootdir/init.zygote32_64.rc @@ -5,7 +5,6 @@ service zygote /system/bin/app_process32 -Xzygote /system/bin --zygote --start-s group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system - updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver @@ -22,6 +21,5 @@ service zygote_secondary /system/bin/app_process64 -Xzygote /system/bin --zygote group root readproc reserved_disk socket zygote_secondary stream 660 root system socket usap_pool_secondary stream 660 root system - updatable onrestart restart zygote writepid /dev/cpuset/foreground/tasks diff --git a/rootdir/init.zygote64.rc b/rootdir/init.zygote64.rc index f7dc5f640..6fa210a7b 100644 --- a/rootdir/init.zygote64.rc +++ b/rootdir/init.zygote64.rc @@ -5,7 +5,6 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system - updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver diff --git a/rootdir/init.zygote64_32.rc b/rootdir/init.zygote64_32.rc index 5829a9d8e..48461ecd3 100644 --- a/rootdir/init.zygote64_32.rc +++ b/rootdir/init.zygote64_32.rc @@ -5,7 +5,6 @@ service zygote /system/bin/app_process64 -Xzygote /system/bin --zygote --start-s group root readproc reserved_disk socket zygote stream 660 root system socket usap_pool_primary stream 660 root system - updatable onrestart write /sys/android_power/request_state wake onrestart write /sys/power/state on onrestart restart audioserver @@ -22,6 +21,5 @@ service zygote_secondary /system/bin/app_process32 -Xzygote /system/bin --zygote group root readproc reserved_disk socket zygote_secondary stream 660 root system socket usap_pool_secondary stream 660 root system - updatable onrestart restart zygote writepid /dev/cpuset/foreground/tasks From ad0b2473dcddee9564334a7fc9a5182142e1b5c9 Mon Sep 17 00:00:00 2001 From: Gavin Corkery Date: Wed, 27 Feb 2019 12:04:47 +0000 Subject: [PATCH 094/221] Rename data/pkg_staging to data/app-staging. Test: atest apex_e2e_tests Bug: 126330086 Change-Id: Ic5729d60046e8825a2a94e3c3483ea8232a69ed2 --- rootdir/init.rc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 909017027..d6a67e516 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -423,7 +423,7 @@ on post-fs-data mkdir /data/apex/active 0750 root system mkdir /data/apex/backup 0700 root system mkdir /data/apex/sessions 0700 root system - mkdir /data/pkg_staging 0750 system system + mkdir /data/app-staging 0750 system system start apexd # Avoid predictable entropy pool. Carry over entropy from previous boot. From 0ed52b789d917402e494f9dcf9ec46cebd87d8f8 Mon Sep 17 00:00:00 2001 From: Neil Fuller Date: Wed, 13 Mar 2019 14:30:20 +0000 Subject: [PATCH 095/221] Move the logic for creating APEX-related symlinks The existing location of logic for creating symlinks to files that have moved into APEX does not get executed for -user builds, only -userdebug and -eng. The new location is equally arbitrary but appears to be invoked for -user, -userdebug and -eng targets. Tested with: make cleaninstall && lunch taimen-[user|userdebug|eng] && make droid Inspected: ls -l out/target/product/taimen/system/usr/icu Bug: 128249030 Bug: 122985829 Bug: 124106384 Test: see above Change-Id: I92a52d0b5ef97e8cb4f780691f8594e40f2fa6b3 --- rootdir/Android.mk | 77 +++++++++++++++++++++++----------------------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/rootdir/Android.mk b/rootdir/Android.mk index d2125d8cb..e0b291d2a 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -24,44 +24,6 @@ LOCAL_SRC_FILES := $(LOCAL_MODULE) LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_ETC)/init -# Start of runtime APEX compatibility. -# -# Meta-comment: -# The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD -# entries need to be associated with something that goes into /system. -# init-debug.rc qualifies but it could be anything else in /system until soong -# supports creation of symlinks. http://b/123333111 -# -# Keeping the appearance of files/dirs having old locations for apps that have -# come to rely on them. - -# http://b/121248172 - create a link from /system/usr/icu to -# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file. -# A symlink can't overwrite a directory and the /system/usr/icu directory once -# existed so the required structure must be created whatever we find. -LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu -LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu - -# TODO(b/124106384): Clean up compat symlinks for ART binaries. -ART_BINARIES= \ - dalvikvm \ - dalvikvm32 \ - dalvikvm64 \ - dex2oat \ - dexdiag \ - dexdump \ - dexlist \ - dexoptanalyzer \ - oatdump \ - profman \ - -$(foreach b,$(ART_BINARIES), \ - $(eval LOCAL_POST_INSTALL_CMD += \ - ; ln -sf /apex/com.android.runtime/bin/$(b) $(TARGET_OUT)/bin/$(b)) \ -) - -# End of runtime APEX compatibilty. - include $(BUILD_PREBUILT) ####################################### @@ -242,6 +204,45 @@ LOCAL_MODULE := ld.config.txt LOCAL_MODULE_CLASS := ETC LOCAL_MODULE_PATH := $(TARGET_OUT_ETC) +# Start of runtime APEX compatibility. +# +# Meta-comment: +# The placing of this section is somewhat arbitrary. The LOCAL_POST_INSTALL_CMD +# entries need to be associated with something that goes into /system. +# ld.config.txt qualifies but it could be anything else in /system until soong +# supports creation of symlinks. http://b/123333111 +# +# Keeping the appearance of files/dirs having old locations for apps that have +# come to rely on them. + +# http://b/121248172 - create a link from /system/usr/icu to +# /apex/com.android.runtime/etc/icu so that apps can find the ICU .dat file. +# A symlink can't overwrite a directory and the /system/usr/icu directory once +# existed so the required structure must be created whatever we find. +LOCAL_POST_INSTALL_CMD = mkdir -p $(TARGET_OUT)/usr && rm -rf $(TARGET_OUT)/usr/icu +LOCAL_POST_INSTALL_CMD += ; ln -sf /apex/com.android.runtime/etc/icu $(TARGET_OUT)/usr/icu + +# TODO(b/124106384): Clean up compat symlinks for ART binaries. +ART_BINARIES= \ + dalvikvm \ + dalvikvm32 \ + dalvikvm64 \ + dex2oat \ + dexdiag \ + dexdump \ + dexlist \ + dexoptanalyzer \ + oatdump \ + profman \ + +LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_OUT)/bin +$(foreach b,$(ART_BINARIES), \ + $(eval LOCAL_POST_INSTALL_CMD += \ + ; ln -sf /apex/com.android.runtime/bin/$(b) $(TARGET_OUT)/bin/$(b)) \ +) + +# End of runtime APEX compatibilty. + ifeq ($(_enforce_vndk_at_runtime),true) # for VNDK enforced devices From b1303bdb97d8c29c37ce7f2a3da04bd12032f254 Mon Sep 17 00:00:00 2001 From: Hans Boehm Date: Wed, 13 Mar 2019 03:24:12 +0000 Subject: [PATCH 096/221] Revert "Fix wp and sp comparison bugs" This reverts commit 029b12ebde0b5a13b4b1252dc20b2ecc8194d5b7. Reason for revert: There appear to be problems with null comparisons. Reported failure in HwcBufferCacheTest. Change-Id: I19745bb281dabe8b05c2df3fe95e7be7a49dcd51 (cherry picked from commit a2a2ad805775ea88f25388677aa37e0492a492c4) --- libutils/RefBase_test.cpp | 123 ------------------------- libutils/include/utils/RefBase.h | 94 ++++++------------- libutils/include/utils/StrongPointer.h | 64 ++++--------- 3 files changed, 47 insertions(+), 234 deletions(-) diff --git a/libutils/RefBase_test.cpp b/libutils/RefBase_test.cpp index b594ca56d..2e0cf6e46 100644 --- a/libutils/RefBase_test.cpp +++ b/libutils/RefBase_test.cpp @@ -45,44 +45,6 @@ private: bool* mDeleted; }; -// A version of Foo that ensures that all objects are allocated at the same -// address. No more than one can be allocated at a time. Thread-hostile. -class FooFixedAlloc : public RefBase { -public: - static void* operator new(size_t size) { - if (mAllocCount != 0) { - abort(); - } - mAllocCount = 1; - if (theMemory == nullptr) { - theMemory = malloc(size); - } - return theMemory; - } - - static void operator delete(void *p) { - if (mAllocCount != 1 || p != theMemory) { - abort(); - } - mAllocCount = 0; - } - - FooFixedAlloc(bool* deleted_check) : mDeleted(deleted_check) { - *mDeleted = false; - } - - ~FooFixedAlloc() { - *mDeleted = true; - } -private: - bool* mDeleted; - static int mAllocCount; - static void* theMemory; -}; - -int FooFixedAlloc::mAllocCount(0); -void* FooFixedAlloc::theMemory(nullptr); - TEST(RefBase, StrongMoves) { bool isDeleted; Foo* foo = new Foo(&isDeleted); @@ -128,91 +90,6 @@ TEST(RefBase, WeakCopies) { ASSERT_FALSE(isDeleted) << "Deletion on wp destruction should no longer occur"; } -TEST(RefBase, Comparisons) { - bool isDeleted, isDeleted2; - Foo* foo = new Foo(&isDeleted); - Foo* foo2 = new Foo(&isDeleted2); - sp sp1(foo); - sp sp2(foo2); - wp wp1(sp1); - wp wp2(sp1); - wp wp3(sp2); - ASSERT_TRUE(wp1 == wp2); - ASSERT_TRUE(wp1 == sp1); - ASSERT_TRUE(wp3 == sp2); - ASSERT_TRUE(wp1 != sp2); - ASSERT_TRUE(wp1 <= wp2); - ASSERT_TRUE(wp1 >= wp2); - ASSERT_FALSE(wp1 != wp2); - ASSERT_FALSE(wp1 > wp2); - ASSERT_FALSE(wp1 < wp2); - ASSERT_FALSE(sp1 == sp2); - ASSERT_TRUE(sp1 != sp2); - bool sp1_smaller = sp1 < sp2; - wpwp_smaller = sp1_smaller ? wp1 : wp3; - wpwp_larger = sp1_smaller ? wp3 : wp1; - ASSERT_TRUE(wp_smaller < wp_larger); - ASSERT_TRUE(wp_smaller != wp_larger); - ASSERT_TRUE(wp_smaller <= wp_larger); - ASSERT_FALSE(wp_smaller == wp_larger); - ASSERT_FALSE(wp_smaller > wp_larger); - ASSERT_FALSE(wp_smaller >= wp_larger); - sp2 = nullptr; - ASSERT_TRUE(isDeleted2); - ASSERT_FALSE(isDeleted); - ASSERT_FALSE(wp3 == sp2); - // Comparison results on weak pointers should not be affected. - ASSERT_TRUE(wp_smaller < wp_larger); - ASSERT_TRUE(wp_smaller != wp_larger); - ASSERT_TRUE(wp_smaller <= wp_larger); - ASSERT_FALSE(wp_smaller == wp_larger); - ASSERT_FALSE(wp_smaller > wp_larger); - ASSERT_FALSE(wp_smaller >= wp_larger); - wp2 = nullptr; - ASSERT_FALSE(wp1 == wp2); - ASSERT_TRUE(wp1 != wp2); - wp1.clear(); - ASSERT_TRUE(wp1 == wp2); - ASSERT_FALSE(wp1 != wp2); - wp3.clear(); - ASSERT_TRUE(wp1 == wp3); - ASSERT_FALSE(wp1 != wp3); - ASSERT_FALSE(isDeleted); - sp1.clear(); - ASSERT_TRUE(isDeleted); - ASSERT_TRUE(sp1 == sp2); -} - -// Check whether comparison against dead wp works, even if the object referenced -// by the new wp happens to be at the same address. -TEST(RefBase, ReplacedComparison) { - bool isDeleted, isDeleted2; - FooFixedAlloc* foo = new FooFixedAlloc(&isDeleted); - sp sp1(foo); - wp wp1(sp1); - ASSERT_TRUE(wp1 == sp1); - sp1.clear(); // Deallocates the object. - ASSERT_TRUE(isDeleted); - FooFixedAlloc* foo2 = new FooFixedAlloc(&isDeleted2); - ASSERT_FALSE(isDeleted2); - ASSERT_EQ(foo, foo2); // Not technically a legal comparison, but ... - sp sp2(foo2); - wp wp2(sp2); - ASSERT_TRUE(sp2 == wp2); - ASSERT_FALSE(sp2 != wp2); - ASSERT_TRUE(sp2 != wp1); - ASSERT_FALSE(sp2 == wp1); - ASSERT_FALSE(sp2 == sp1); // sp1 is null. - ASSERT_FALSE(wp1 == wp2); // wp1 refers to old object. - ASSERT_TRUE(wp1 != wp2); - ASSERT_TRUE(wp1 > wp2 || wp1 < wp2); - ASSERT_TRUE(wp1 >= wp2 || wp1 <= wp2); - ASSERT_FALSE(wp1 >= wp2 && wp1 <= wp2); - ASSERT_FALSE(wp1 == nullptr); - wp1 = sp2; - ASSERT_TRUE(wp1 == wp2); - ASSERT_FALSE(wp1 != wp2); -} // Set up a situation in which we race with visit2AndRremove() to delete // 2 strong references. Bar destructor checks that there are no early diff --git a/libutils/include/utils/RefBase.h b/libutils/include/utils/RefBase.h index 730d63153..1780cf22f 100644 --- a/libutils/include/utils/RefBase.h +++ b/libutils/include/utils/RefBase.h @@ -171,8 +171,6 @@ #define ANDROID_REF_BASE_H #include -#include -#include // for common_type. #include #include @@ -194,26 +192,19 @@ TextOutput& printWeakPointer(TextOutput& to, const void* val); // --------------------------------------------------------------------------- #define COMPARE_WEAK(_op_) \ +inline bool operator _op_ (const sp& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +inline bool operator _op_ (const T* o) const { \ + return m_ptr _op_ o; \ +} \ +template \ +inline bool operator _op_ (const sp& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ template \ inline bool operator _op_ (const U* o) const { \ return m_ptr _op_ o; \ -} \ -/* Needed to handle type inference for nullptr: */ \ -inline bool operator _op_ (const T* o) const { \ - return m_ptr _op_ o; \ -} - -template class comparator, typename T, typename U> -static inline bool _wp_compare_(T* a, U* b) { - return comparator::type>()(a, b); -} - -// Use std::less and friends to avoid undefined behavior when ordering pointers -// to different objects. -#define COMPARE_WEAK_FUNCTIONAL(_op_, _compare_) \ -template \ -inline bool operator _op_ (const U* o) const { \ - return _wp_compare_<_compare_>(m_ptr, o); \ } // --------------------------------------------------------------------------- @@ -404,51 +395,39 @@ public: COMPARE_WEAK(==) COMPARE_WEAK(!=) - COMPARE_WEAK_FUNCTIONAL(>, std::greater) - COMPARE_WEAK_FUNCTIONAL(<, std::less) - COMPARE_WEAK_FUNCTIONAL(<=, std::less_equal) - COMPARE_WEAK_FUNCTIONAL(>=, std::greater_equal) + COMPARE_WEAK(>) + COMPARE_WEAK(<) + COMPARE_WEAK(<=) + COMPARE_WEAK(>=) + inline bool operator == (const wp& o) const { + return (m_ptr == o.m_ptr) && (m_refs == o.m_refs); + } template inline bool operator == (const wp& o) const { - return m_refs == o.m_refs; // Implies m_ptr == o.mptr; see invariants below. + return m_ptr == o.m_ptr; } - template - inline bool operator == (const sp& o) const { - // Just comparing m_ptr fields is often dangerous, since wp<> may refer to an older - // object at the same address. - if (o == nullptr) { - return m_ptr == nullptr; - } else { - return m_refs == o->getWeakRefs(); // Implies m_ptr == o.mptr. - } + inline bool operator > (const wp& o) const { + return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr); } - - template - inline bool operator != (const sp& o) const { - return !(*this == o); - } - template inline bool operator > (const wp& o) const { - if (m_ptr == o.m_ptr) { - return _wp_compare_(m_refs, o.m_refs); - } else { - return _wp_compare_(m_ptr, o.m_ptr); - } + return (m_ptr == o.m_ptr) ? (m_refs > o.m_refs) : (m_ptr > o.m_ptr); } + inline bool operator < (const wp& o) const { + return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr); + } template inline bool operator < (const wp& o) const { - if (m_ptr == o.m_ptr) { - return _wp_compare_(m_refs, o.m_refs); - } else { - return _wp_compare_(m_ptr, o.m_ptr); - } + return (m_ptr == o.m_ptr) ? (m_refs < o.m_refs) : (m_ptr < o.m_ptr); } + inline bool operator != (const wp& o) const { return m_refs != o.m_refs; } template inline bool operator != (const wp& o) const { return !operator == (o); } + inline bool operator <= (const wp& o) const { return !operator > (o); } template inline bool operator <= (const wp& o) const { return !operator > (o); } + inline bool operator >= (const wp& o) const { return !operator < (o); } template inline bool operator >= (const wp& o) const { return !operator < (o); } private: @@ -467,22 +446,6 @@ TextOutput& operator<<(TextOutput& to, const wp& val); // --------------------------------------------------------------------------- // No user serviceable parts below here. -// Implementation invariants: -// Either -// 1) m_ptr and m_refs are both null, or -// 2) m_refs == m_ptr->mRefs, or -// 3) *m_ptr is no longer live, and m_refs points to the weakref_type object that corresponded -// to m_ptr while it was live. *m_refs remains live while a wp<> refers to it. -// -// The m_refs field in a RefBase object is allocated on construction, unique to that RefBase -// object, and never changes. Thus if two wp's have identical m_refs fields, they are either both -// null or point to the same object. If two wp's have identical m_ptr fields, they either both -// point to the same live object and thus have the same m_ref fields, or at least one of the -// objects is no longer live. -// -// Note that the above comparison operations go out of their way to provide an ordering consistent -// with ordinary pointer comparison; otherwise they could ignore m_ptr, and just compare m_refs. - template wp::wp(T* other) : m_ptr(other) @@ -632,7 +595,6 @@ void wp::clear() { if (m_ptr) { m_refs->decWeak(this); - m_refs = 0; m_ptr = 0; } } diff --git a/libutils/include/utils/StrongPointer.h b/libutils/include/utils/StrongPointer.h index 9cd7c75fd..15711296d 100644 --- a/libutils/include/utils/StrongPointer.h +++ b/libutils/include/utils/StrongPointer.h @@ -17,9 +17,6 @@ #ifndef ANDROID_STRONG_POINTER_H #define ANDROID_STRONG_POINTER_H -#include -#include // for common_type. - // --------------------------------------------------------------------------- namespace android { @@ -27,12 +24,13 @@ template class wp; // --------------------------------------------------------------------------- -// TODO: Maybe remove sp<> ? wp<> comparison? These are dangerous: If the wp<> -// was created before the sp<>, and they point to different objects, they may -// compare equal even if they are entirely unrelated. E.g. CameraService -// currently performa such comparisons. - -#define COMPARE_STRONG(_op_) \ +#define COMPARE(_op_) \ +inline bool operator _op_ (const sp& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +inline bool operator _op_ (const T* o) const { \ + return m_ptr _op_ o; \ +} \ template \ inline bool operator _op_ (const sp& o) const { \ return m_ptr _op_ o.m_ptr; \ @@ -41,27 +39,14 @@ template \ inline bool operator _op_ (const U* o) const { \ return m_ptr _op_ o; \ } \ -/* Needed to handle type inference for nullptr: */ \ -inline bool operator _op_ (const T* o) const { \ - return m_ptr _op_ o; \ +inline bool operator _op_ (const wp& o) const { \ + return m_ptr _op_ o.m_ptr; \ +} \ +template \ +inline bool operator _op_ (const wp& o) const { \ + return m_ptr _op_ o.m_ptr; \ } -template class comparator, typename T, typename U> -static inline bool _sp_compare_(T* a, U* b) { - return comparator::type>()(a, b); -} - -// Use std::less and friends to avoid undefined behavior when ordering pointers -// to different objects. -#define COMPARE_STRONG_FUNCTIONAL(_op_, _compare_) \ -template \ -inline bool operator _op_ (const sp& o) const { \ - return _sp_compare_<_compare_>(m_ptr, o.m_ptr); \ -} \ -template \ -inline bool operator _op_ (const U* o) const { \ - return _sp_compare_<_compare_>(m_ptr, o); \ -} // --------------------------------------------------------------------------- template @@ -104,23 +89,12 @@ public: // Operators - COMPARE_STRONG(==) - COMPARE_STRONG(!=) - COMPARE_STRONG_FUNCTIONAL(>, std::greater) - COMPARE_STRONG_FUNCTIONAL(<, std::less) - COMPARE_STRONG_FUNCTIONAL(<=, std::less_equal) - COMPARE_STRONG_FUNCTIONAL(>=, std::greater_equal) - - // Punt these to the wp<> implementation. - template - inline bool operator == (const wp& o) const { - return o == *this; - } - - template - inline bool operator != (const wp& o) const { - return o != *this; - } + COMPARE(==) + COMPARE(!=) + COMPARE(>) + COMPARE(<) + COMPARE(<=) + COMPARE(>=) private: template friend class sp; From e8d2835d8ddb980eb8fd52e36bc8507f802fccba Mon Sep 17 00:00:00 2001 From: Janis Danisevskis Date: Thu, 14 Mar 2019 13:48:30 -0700 Subject: [PATCH 097/221] gatekeeperd: fixed potential nullptr deref gatekeeperd verifyChallenge may use several pointer parameters unchecked. Also fixed broken length parameter check. Bug: 127909982 Test: Not yet Change-Id: I708bdc8afcb30f252385e51c4aa4bcefe1ef1045 --- gatekeeperd/gatekeeperd.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/gatekeeperd/gatekeeperd.cpp b/gatekeeperd/gatekeeperd.cpp index 8700c3446..54518193d 100644 --- a/gatekeeperd/gatekeeperd.cpp +++ b/gatekeeperd/gatekeeperd.cpp @@ -273,7 +273,8 @@ public: } // can't verify if we're missing either param - if ((enrolled_password_handle_length | provided_password_length) == 0) + if (enrolled_password_handle == nullptr || provided_password == nullptr || + enrolled_password_handle_length == 0 || provided_password_length == 0) return -EINVAL; int ret; @@ -322,7 +323,7 @@ public: if (ret == 0) { // success! re-enroll with HAL - *request_reenroll = true; + if (request_reenroll != nullptr) *request_reenroll = true; } } } else { From e3d0383d38fbac339a6a2ef02403836e41a11cd3 Mon Sep 17 00:00:00 2001 From: dimitry Date: Tue, 19 Mar 2019 12:29:49 +0100 Subject: [PATCH 098/221] Add dependency on libdl_android platform private symbols have been moved to libdl_android.so since they are not intended to be accessible from apps. Test: make Change-Id: I883a6d2ca588a258dd43efa766fad4e07428594e --- libnativeloader/Android.bp | 7 +++++++ libvndksupport/Android.bp | 5 ++++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/libnativeloader/Android.bp b/libnativeloader/Android.bp index b9f0dbff5..66cb49ffb 100644 --- a/libnativeloader/Android.bp +++ b/libnativeloader/Android.bp @@ -24,6 +24,13 @@ cc_library { "libnativebridge", "libbase", ], + target: { + android: { + shared_libs: [ + "libdl_android", + ], + }, + }, required: [ "llndk.libraries.txt", "vndksp.libraries.txt", diff --git a/libvndksupport/Android.bp b/libvndksupport/Android.bp index bfa25088f..546c15c24 100644 --- a/libvndksupport/Android.bp +++ b/libvndksupport/Android.bp @@ -9,7 +9,10 @@ cc_library { ], local_include_dirs: ["include/vndksupport"], export_include_dirs: ["include"], - shared_libs: ["liblog"], + shared_libs: [ + "libdl_android", + "liblog", + ], version_script: "libvndksupport.map.txt", stubs: { symbol_file: "libvndksupport.map.txt", From 508e615b8e55c6f0fae6b538c7fa2a92390b4b84 Mon Sep 17 00:00:00 2001 From: Jone Chou Date: Wed, 20 Mar 2019 19:38:05 +0800 Subject: [PATCH 099/221] bootstat: add 4 reboot reasons to known set - reboot,rtc - reboot,dm-verity_device_corrupted - reboot,dm-verity_enforcing - reboot,keys_clear Test: none Bug: 128929506 Bug: 128929604 Change-Id: I5438c236abb67b74c7b9d717930c0ea69f70540d Signed-off-by: Jone Chou --- bootstat/bootstat.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp index ea49798c9..1ce0ec4c2 100644 --- a/bootstat/bootstat.cpp +++ b/bootstat/bootstat.cpp @@ -295,6 +295,10 @@ const std::map kBootReasonMap = { {"kernel_panic,_sde_encoder_phys_cmd_handle_ppdone_timeout", 168}, {"recovery,quiescent", 169}, {"reboot,quiescent", 170}, + {"reboot,rtc", 171}, + {"reboot,dm-verity_device_corrupted", 172}, + {"reboot,dm-verity_enforcing", 173}, + {"reboot,keys_clear", 174}, }; // Converts a string value representing the reason the system booted to an From 4c2f079dad503315b599d85c3600a23fac8e19e4 Mon Sep 17 00:00:00 2001 From: Tej Singh Date: Tue, 19 Mar 2019 22:03:34 -0700 Subject: [PATCH 100/221] stats_event_list changes for statsd mainline api stats_event_list changes for creating a generic api for statsd mainline logging. Test: builds Test: existing logs continue to flow Change-Id: I4163edc80ffcca61db7ab2a1e14ae8c14aab2347 --- libstats/include/stats_event_list.h | 3 +++ libstats/stats_event_list.c | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h index b5bc5af50..037db13a2 100644 --- a/libstats/include/stats_event_list.h +++ b/libstats/include/stats_event_list.h @@ -18,6 +18,7 @@ #define ANDROID_STATS_LOG_STATS_EVENT_LIST_H #include +#include #ifdef __cplusplus extern "C" { @@ -27,6 +28,8 @@ int write_to_logger(android_log_context context, log_id_t id); void note_log_drop(int error); void stats_log_close(); int android_log_write_char_array(android_log_context ctx, const char* value, size_t len); +extern int (*write_to_statsd)(struct iovec* vec, size_t nr); + #ifdef __cplusplus } #endif diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c index 5b9036108..404b2b68f 100644 --- a/libstats/stats_event_list.c +++ b/libstats/stats_event_list.c @@ -41,7 +41,7 @@ typedef struct { extern struct android_log_transport_write statsdLoggerWrite; static int __write_to_statsd_init(struct iovec* vec, size_t nr); -static int (*write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init; +int (*write_to_statsd)(struct iovec* vec, size_t nr) = __write_to_statsd_init; // Similar to create_android_logger(), but instead of allocation a new buffer, // this function resets the buffer for resuse. From ddbb6ed7e7e56cc2829356b4b7a0b7d9141ae423 Mon Sep 17 00:00:00 2001 From: Kiyoung Kim Date: Thu, 21 Mar 2019 16:56:05 +0900 Subject: [PATCH 101/221] Do not fail when there is no vndk namespace Some of the legacy devices may not have vndk namespace. To make this work, libnativeloader should not fail when it fails to search for vndk namespace. Bug: 129011845 Test: m -j Change-Id: Id9147d4aeee9ba2b301b6893dea5884dce9c14fa --- libnativeloader/native_loader.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index 1c2581f08..5cc0857f6 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -288,8 +288,9 @@ class LibraryNamespaces { // Give access to VNDK-SP libraries from the 'vndk' namespace. vndk_ns = android_get_exported_namespace(kVndkNamespaceName); - LOG_ALWAYS_FATAL_IF(vndk_ns == nullptr, "Cannot find \"%s\" namespace for %s apks", - kVndkNamespaceName, origin_partition); + if (vndk_ns == nullptr) { + ALOGW("Cannot find \"%s\" namespace for %s apks", kVndkNamespaceName, origin_partition); + } // Different name is useful for debugging namespace_name = kVendorClassloaderNamespaceName; From 6606d8df32f24e17732850ec6ac5d25e4cbc3e9f Mon Sep 17 00:00:00 2001 From: Siarhei Vishniakou Date: Mon, 25 Mar 2019 17:43:11 -0700 Subject: [PATCH 102/221] Logtags for com.android.server.policy The definitions for event log tags are currently in system/core. Instead of keeping them there, reserve a range for these event tags and move them into com.android.server.policy. Currently it is only used by PhoneWindowManager. Bug: 128933363 Test: build only Change-Id: Ida903499e9af8650299e3965787b4ac966b66915 --- logcat/event.logtags | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/logcat/event.logtags b/logcat/event.logtags index da8d2d4d2..3a1d36f82 100644 --- a/logcat/event.logtags +++ b/logcat/event.logtags @@ -116,8 +116,8 @@ # audio # 61000 - 61199 reserved for audioserver -# 0 for screen off, 1 for screen on, 2 for key-guard done -70000 screen_toggled (screen_state|1|5) +# com.android.server.policy +# 70000 - 70199 reserved for PhoneWindowManager and other policies # aggregation service 70200 aggregation (aggregation time|2|3) From cf776d9b833952991294b2b898ea4a69b4c2731b Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Tue, 26 Mar 2019 13:51:53 -0700 Subject: [PATCH 103/221] Report last atom tag of the failed stats log. Test: manually tested with statsd Change-Id: I4de61a2eea393e8518cb76147598778293440a81 --- libstats/include/stats_event_list.h | 2 +- libstats/stats_event_list.c | 4 ++-- libstats/statsd_writer.c | 23 +++++++++++++++++++---- libstats/statsd_writer.h | 2 +- 4 files changed, 23 insertions(+), 8 deletions(-) diff --git a/libstats/include/stats_event_list.h b/libstats/include/stats_event_list.h index 037db13a2..845a19776 100644 --- a/libstats/include/stats_event_list.h +++ b/libstats/include/stats_event_list.h @@ -25,7 +25,7 @@ extern "C" { #endif void reset_log_context(android_log_context ctx); int write_to_logger(android_log_context context, log_id_t id); -void note_log_drop(int error); +void note_log_drop(int error, int atom_tag); void stats_log_close(); int android_log_write_char_array(android_log_context ctx, const char* value, size_t len); extern int (*write_to_statsd)(struct iovec* vec, size_t nr); diff --git a/libstats/stats_event_list.c b/libstats/stats_event_list.c index 404b2b68f..ae12cbeaa 100644 --- a/libstats/stats_event_list.c +++ b/libstats/stats_event_list.c @@ -120,8 +120,8 @@ int write_to_logger(android_log_context ctx, log_id_t id) { return retValue; } -void note_log_drop(int error) { - statsdLoggerWrite.noteDrop(error); +void note_log_drop(int error, int tag) { + statsdLoggerWrite.noteDrop(error, tag); } void stats_log_close() { diff --git a/libstats/statsd_writer.c b/libstats/statsd_writer.c index f5be95c19..b778f92b8 100644 --- a/libstats/statsd_writer.c +++ b/libstats/statsd_writer.c @@ -47,9 +47,18 @@ #endif #endif +#ifndef htole64 +#if __BYTE_ORDER == __LITTLE_ENDIAN +#define htole64(x) (x) +#else +#define htole64(x) __bswap_64(x) +#endif +#endif + static pthread_mutex_t log_init_lock = PTHREAD_MUTEX_INITIALIZER; static atomic_int dropped = 0; static atomic_int log_error = 0; +static atomic_int atom_tag = 0; void statsd_writer_init_lock() { /* @@ -152,9 +161,10 @@ static int statsdAvailable() { return 1; } -static void statsdNoteDrop(int error) { +static void statsdNoteDrop(int error, int tag) { atomic_fetch_add_explicit(&dropped, 1, memory_order_relaxed); atomic_exchange_explicit(&log_error, error, memory_order_relaxed); + atomic_exchange_explicit(&atom_tag, tag, memory_order_relaxed); } static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { @@ -203,12 +213,17 @@ static int statsdWrite(struct timespec* ts, struct iovec* vec, size_t nr) { if (sock >= 0) { int32_t snapshot = atomic_exchange_explicit(&dropped, 0, memory_order_relaxed); if (snapshot) { - android_log_event_int_t buffer; + android_log_event_long_t buffer; header.id = LOG_ID_STATS; // store the last log error in the tag field. This tag field is not used by statsd. buffer.header.tag = htole32(atomic_load(&log_error)); - buffer.payload.type = EVENT_TYPE_INT; - buffer.payload.data = htole32(snapshot); + buffer.payload.type = EVENT_TYPE_LONG; + // format: + // |atom_tag|dropped_count| + int64_t composed_long = atomic_load(&atom_tag); + // Send 2 int32's via an int64. + composed_long = ((composed_long << 32) | ((int64_t)snapshot)); + buffer.payload.data = htole64(composed_long); newVec[headerLength].iov_base = &buffer; newVec[headerLength].iov_len = sizeof(buffer); diff --git a/libstats/statsd_writer.h b/libstats/statsd_writer.h index 4fc3f8bc2..fe2d37cbc 100644 --- a/libstats/statsd_writer.h +++ b/libstats/statsd_writer.h @@ -39,7 +39,7 @@ struct android_log_transport_write { /* write log to transport, returns number of bytes propagated, or -errno */ int (*write)(struct timespec* ts, struct iovec* vec, size_t nr); /* note one log drop */ - void (*noteDrop)(int error); + void (*noteDrop)(int error, int tag); }; #endif // ANDROID_STATS_LOG_STATS_WRITER_H From 0a75f928d109e2ad892b30bab38bf23f452a8ace Mon Sep 17 00:00:00 2001 From: Yao Chen Date: Tue, 2 Apr 2019 13:51:46 -0700 Subject: [PATCH 104/221] Increase the SO_SNDBUF for statsd socket. In addition to the dgram queue size, the sender buffer size also matters. Set it to a higher value (default is 224KB). Test: manual Change-Id: Ib610c1fa1eaf3c5e36f51854a2b0720f387dc1b8 --- libstats/statsd_writer.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/libstats/statsd_writer.c b/libstats/statsd_writer.c index b778f92b8..b1c05eac9 100644 --- a/libstats/statsd_writer.c +++ b/libstats/statsd_writer.c @@ -109,6 +109,11 @@ static int statsdOpen() { if (sock < 0) { ret = -errno; } else { + int sndbuf = 1 * 1024 * 1024; // set max send buffer size 1MB + socklen_t bufLen = sizeof(sndbuf); + // SO_RCVBUF does not have an effect on unix domain socket, but SO_SNDBUF does. + // Proceed to connect even setsockopt fails. + setsockopt(sock, SOL_SOCKET, SO_SNDBUF, &sndbuf, bufLen); struct sockaddr_un un; memset(&un, 0, sizeof(struct sockaddr_un)); un.sun_family = AF_UNIX; From f4212744edd3edf9ba55668c3e4755f1e3a3e897 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 22 Mar 2019 15:24:46 -0700 Subject: [PATCH 105/221] libprocessgroup: Add libcgrouprc_format This module defines the wire format of the mmap()ed cgroup.rc file. Test: builds Bug: 123664216 Change-Id: Iaf6199f759a6264590b13ca7ba6d7f576c3ed56a --- libprocessgroup/cgrouprc_format/Android.bp | 32 ++++++++++++ .../cgrouprc_format/cgroup_controller.cpp | 49 +++++++++++++++++++ .../processgroup/format/cgroup_controller.h | 47 ++++++++++++++++++ .../include/processgroup/format/cgroup_file.h | 36 ++++++++++++++ 4 files changed, 164 insertions(+) create mode 100644 libprocessgroup/cgrouprc_format/Android.bp create mode 100644 libprocessgroup/cgrouprc_format/cgroup_controller.cpp create mode 100644 libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h create mode 100644 libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h diff --git a/libprocessgroup/cgrouprc_format/Android.bp b/libprocessgroup/cgrouprc_format/Android.bp new file mode 100644 index 000000000..dfbeed73e --- /dev/null +++ b/libprocessgroup/cgrouprc_format/Android.bp @@ -0,0 +1,32 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_static { + name: "libcgrouprc_format", + host_supported: true, + recovery_available: true, + srcs: [ + "cgroup_controller.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "libbase", + ], +} diff --git a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp new file mode 100644 index 000000000..877eed872 --- /dev/null +++ b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +namespace android { +namespace cgrouprc { +namespace format { + +CgroupController::CgroupController(uint32_t version, const std::string& name, + const std::string& path) { + // strlcpy isn't available on host. Although there is an implementation + // in licutils, libcutils itself depends on libcgrouprc_format, causing + // a circular dependency. + version_ = version; + strncpy(name_, name.c_str(), sizeof(name_) - 1); + name_[sizeof(name_) - 1] = '\0'; + strncpy(path_, path.c_str(), sizeof(path_) - 1); + path_[sizeof(path_) - 1] = '\0'; +} + +uint32_t CgroupController::version() const { + return version_; +} + +const char* CgroupController::name() const { + return name_; +} + +const char* CgroupController::path() const { + return path_; +} + +} // namespace format +} // namespace cgrouprc +} // namespace android diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h new file mode 100644 index 000000000..64c7532d9 --- /dev/null +++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include +#include + +namespace android { +namespace cgrouprc { +namespace format { + +// Minimal controller description to be mmapped into process address space +struct CgroupController { + public: + CgroupController() {} + CgroupController(uint32_t version, const std::string& name, const std::string& path); + + uint32_t version() const; + const char* name() const; + const char* path() const; + + private: + static constexpr size_t CGROUP_NAME_BUF_SZ = 16; + static constexpr size_t CGROUP_PATH_BUF_SZ = 32; + + uint32_t version_; + char name_[CGROUP_NAME_BUF_SZ]; + char path_[CGROUP_PATH_BUF_SZ]; +}; + +} // namespace format +} // namespace cgrouprc +} // namespace android diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h new file mode 100644 index 000000000..f1678a114 --- /dev/null +++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_file.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +namespace android { +namespace cgrouprc { +namespace format { + +struct CgroupFile { + uint32_t version_; + uint32_t controller_count_; + CgroupController controllers_[]; + + static constexpr uint32_t FILE_VERSION_1 = 1; + static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1; +}; + +} // namespace format +} // namespace cgrouprc +} // namespace android From d8956470952c92890f16d9b45ea59113b0322eb1 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Mon, 4 Mar 2019 18:20:02 -0800 Subject: [PATCH 106/221] libprocessgroup: Add libcgrouprc This module is an LL-NDK library that can be loaded by modules that link to libprocessgroup (which is in VNDK). This module defines APIs that reads cgroups.rc file programatically. Internally, it uses libcgrouprc_format to do so. Test: builds Bug: 123664216 Change-Id: I9c13c0528461758154e23cbab3a94ade7fb351ee --- libprocessgroup/cgrouprc/Android.bp | 52 +++++++++ .../cgrouprc/cgroup_controller.cpp | 38 +++++++ libprocessgroup/cgrouprc/cgroup_file.cpp | 106 ++++++++++++++++++ libprocessgroup/cgrouprc/cgrouprc_internal.h | 24 ++++ .../cgrouprc/include/android/cgrouprc.h | 84 ++++++++++++++ libprocessgroup/cgrouprc/libcgrouprc.map.txt | 11 ++ 6 files changed, 315 insertions(+) create mode 100644 libprocessgroup/cgrouprc/Android.bp create mode 100644 libprocessgroup/cgrouprc/cgroup_controller.cpp create mode 100644 libprocessgroup/cgrouprc/cgroup_file.cpp create mode 100644 libprocessgroup/cgrouprc/cgrouprc_internal.h create mode 100644 libprocessgroup/cgrouprc/include/android/cgrouprc.h create mode 100644 libprocessgroup/cgrouprc/libcgrouprc.map.txt diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp new file mode 100644 index 000000000..f5ff7eb9d --- /dev/null +++ b/libprocessgroup/cgrouprc/Android.bp @@ -0,0 +1,52 @@ +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +cc_library_shared { + name: "libcgrouprc", + host_supported: true, + recovery_available: true, + srcs: [ + "cgroup_controller.cpp", + "cgroup_file.cpp", + ], + cflags: [ + "-Wall", + "-Werror", + ], + export_include_dirs: [ + "include", + ], + header_libs: [ + "libprocessgroup_headers", + ], + shared_libs: [ + "libbase", + ], + static_libs: [ + "libcgrouprc_format", + ], + stubs: { + symbol_file: "libcgrouprc.map.txt", + versions: ["29"], + }, + version_script: "libcgrouprc.map.txt", +} + +llndk_library { + name: "libcgrouprc", + symbol_file: "libcgrouprc.map.txt", + export_include_dirs: [ + "include", + ], +} diff --git a/libprocessgroup/cgrouprc/cgroup_controller.cpp b/libprocessgroup/cgrouprc/cgroup_controller.cpp new file mode 100644 index 000000000..d064d312e --- /dev/null +++ b/libprocessgroup/cgrouprc/cgroup_controller.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include "cgrouprc_internal.h" + +// All ACgroupController_* functions implicitly convert the pointer back +// to the original CgroupController pointer before invoking the member functions. + +uint32_t ACgroupController_getVersion(const ACgroupController* controller) { + CHECK(controller != nullptr); + return controller->version(); +} + +const char* ACgroupController_getName(const ACgroupController* controller) { + CHECK(controller != nullptr); + return controller->name(); +} + +const char* ACgroupController_getPath(const ACgroupController* controller) { + CHECK(controller != nullptr); + return controller->path(); +} diff --git a/libprocessgroup/cgrouprc/cgroup_file.cpp b/libprocessgroup/cgrouprc/cgroup_file.cpp new file mode 100644 index 000000000..e26d84114 --- /dev/null +++ b/libprocessgroup/cgrouprc/cgroup_file.cpp @@ -0,0 +1,106 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include + +#include + +#include +#include +#include +#include +#include + +#include "cgrouprc_internal.h" + +using android::base::StringPrintf; +using android::base::unique_fd; + +using android::cgrouprc::format::CgroupController; +using android::cgrouprc::format::CgroupFile; + +static CgroupFile* LoadRcFile() { + struct stat sb; + + unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_RDONLY | O_CLOEXEC))); + if (fd < 0) { + PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; + return nullptr; + } + + if (fstat(fd, &sb) < 0) { + PLOG(ERROR) << "fstat() failed for " << CGROUPS_RC_PATH; + return nullptr; + } + + size_t file_size = sb.st_size; + if (file_size < sizeof(CgroupFile)) { + LOG(ERROR) << "Invalid file format " << CGROUPS_RC_PATH; + return nullptr; + } + + CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0); + if (file_data == MAP_FAILED) { + PLOG(ERROR) << "Failed to mmap " << CGROUPS_RC_PATH; + return nullptr; + } + + if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) { + LOG(ERROR) << CGROUPS_RC_PATH << " file version mismatch"; + munmap(file_data, file_size); + return nullptr; + } + + auto expected = sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController); + if (file_size != expected) { + LOG(ERROR) << CGROUPS_RC_PATH << " file has invalid size, expected " << expected + << ", actual " << file_size; + munmap(file_data, file_size); + return nullptr; + } + + return file_data; +} + +static CgroupFile* GetInstance() { + // Deliberately leak this object (not munmap) to avoid a race between destruction on + // process exit and concurrent access from another thread. + static auto* file = LoadRcFile(); + return file; +} + +uint32_t ACgroupFile_getVersion() { + auto file = GetInstance(); + if (file == nullptr) return 0; + return file->version_; +} + +uint32_t ACgroupFile_getControllerCount() { + auto file = GetInstance(); + if (file == nullptr) return 0; + return file->controller_count_; +} + +const ACgroupController* ACgroupFile_getController(uint32_t index) { + auto file = GetInstance(); + if (file == nullptr) return nullptr; + CHECK(index < file->controller_count_); + // Although the object is not actually an ACgroupController object, all ACgroupController_* + // functions implicitly convert ACgroupController* back to CgroupController* before invoking + // member functions. + return static_cast(&file->controllers_[index]); +} diff --git a/libprocessgroup/cgrouprc/cgrouprc_internal.h b/libprocessgroup/cgrouprc/cgrouprc_internal.h new file mode 100644 index 000000000..cd02f0304 --- /dev/null +++ b/libprocessgroup/cgrouprc/cgrouprc_internal.h @@ -0,0 +1,24 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +#include +#include + +struct ACgroupController : android::cgrouprc::format::CgroupController {}; diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h new file mode 100644 index 000000000..4edd239e2 --- /dev/null +++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h @@ -0,0 +1,84 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +#include + +__BEGIN_DECLS + +// For host builds, __INTRODUCED_IN is not defined. +#ifndef __INTRODUCED_IN +#define __INTRODUCED_IN(x) +#endif + +struct ACgroupController; +typedef struct ACgroupController ACgroupController; + +#if __ANDROID_API__ >= __ANDROID_API_Q__ + +// ACgroupFile + +/** + * Returns file version. See android::cgrouprc::format::CgroupFile for a list of valid versions + * for the file. + * If ACgroupFile_init() isn't called, initialization will be done first. + * If initialization failed, return 0. + */ +__attribute__((warn_unused_result)) uint32_t ACgroupFile_getVersion() __INTRODUCED_IN(29); + +/** + * Returns the number of controllers. + * If ACgroupFile_init() isn't called, initialization will be done first. + * If initialization failed, return 0. + */ +__attribute__((warn_unused_result)) uint32_t ACgroupFile_getControllerCount() __INTRODUCED_IN(29); + +/** + * Returns the controller at the given index. + * Returnss nullptr if the given index exceeds getControllerCount(). + * If ACgroupFile_init() isn't called, initialization will be done first. + * If initialization failed, return 0. + */ +__attribute__((warn_unused_result)) const ACgroupController* ACgroupFile_getController( + uint32_t index) __INTRODUCED_IN(29); + +// ACgroupController + +/** + * Returns the version of the given controller. + * If the given controller is null, return 0. + */ +__attribute__((warn_unused_result)) uint32_t ACgroupController_getVersion(const ACgroupController*) + __INTRODUCED_IN(29); + +/** + * Returns the name of the given controller. + * If the given controller is null, return nullptr. + */ +__attribute__((warn_unused_result)) const char* ACgroupController_getName(const ACgroupController*) + __INTRODUCED_IN(29); + +/** + * Returns the path of the given controller. + * If the given controller is null, return nullptr. + */ +__attribute__((warn_unused_result)) const char* ACgroupController_getPath(const ACgroupController*) + __INTRODUCED_IN(29); + +__END_DECLS + +#endif diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.map.txt new file mode 100644 index 000000000..91df3929d --- /dev/null +++ b/libprocessgroup/cgrouprc/libcgrouprc.map.txt @@ -0,0 +1,11 @@ +LIBCGROUPRC { # introduced=29 + global: + ACgroupFile_getVersion; + ACgroupFile_getControllerCount; + ACgroupFile_getController; + ACgroupController_getVersion; + ACgroupController_getName; + ACgroupController_getPath; + local: + *; +}; From bd623a4ce047416aaf8946af09dae635fd210c41 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 5 Mar 2019 15:47:16 -0800 Subject: [PATCH 107/221] libprocessgroup: Move CgroupSetupCgroups() to libprocessgroup_setup Only init uses SetupCgroups. This functionality is moved from libprocessgroup to its own library, and only init links to it. Also, merge CgroupSetupCgroups() with CgroupMap::SetupCgroups() because the former is just an alias of the latter, and CgroupMap does not belong to libcgrouprc_setup. Test: boots Bug: 123664216 Change-Id: I941dc0c415e2b22ae663d43e30dc7a464687325e --- init/Android.bp | 1 + init/init.cpp | 1 + libprocessgroup/cgroup_map.cpp | 271 --------------- libprocessgroup/cgroup_map.h | 18 - .../include/processgroup/processgroup.h | 1 - libprocessgroup/processgroup.cpp | 4 - libprocessgroup/setup/Android.bp | 41 +++ libprocessgroup/setup/cgroup_descriptor.h | 38 ++ libprocessgroup/setup/cgroup_map_write.cpp | 324 ++++++++++++++++++ .../setup/include/processgroup/setup.h | 19 + 10 files changed, 424 insertions(+), 294 deletions(-) create mode 100644 libprocessgroup/setup/Android.bp create mode 100644 libprocessgroup/setup/cgroup_descriptor.h create mode 100644 libprocessgroup/setup/cgroup_map_write.cpp create mode 100644 libprocessgroup/setup/include/processgroup/setup.h diff --git a/init/Android.bp b/init/Android.bp index 8292aa0e2..e834e99e0 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -82,6 +82,7 @@ cc_defaults { "liblogwrap", "liblp", "libprocessgroup", + "libprocessgroup_setup", "libselinux", "libutils", ], diff --git a/init/init.cpp b/init/init.cpp index cdec41cd8..1792f288e 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #ifndef RECOVERY diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index 1e66fa4ee..3b852ae9b 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -44,222 +44,10 @@ using android::base::GetBoolProperty; using android::base::StringPrintf; using android::base::unique_fd; -static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; -static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; - static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs"; static constexpr const char* CGROUP_TASKS_FILE = "/tasks"; static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.tasks"; -static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid, - const std::string& gid) { - if (mode == 0) { - mode = 0755; - } - - if (mkdir(path.c_str(), mode) != 0) { - /* chmod in case the directory already exists */ - if (errno == EEXIST) { - if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) { - // /acct is a special case when the directory already exists - // TODO: check if file mode is already what we want instead of using EROFS - if (errno != EROFS) { - PLOG(ERROR) << "fchmodat() failed for " << path; - return false; - } - } - } else { - PLOG(ERROR) << "mkdir() failed for " << path; - return false; - } - } - - if (uid.empty()) { - return true; - } - - passwd* uid_pwd = getpwnam(uid.c_str()); - if (!uid_pwd) { - PLOG(ERROR) << "Unable to decode UID for '" << uid << "'"; - return false; - } - - uid_t pw_uid = uid_pwd->pw_uid; - gid_t gr_gid = -1; - if (!gid.empty()) { - group* gid_pwd = getgrnam(gid.c_str()); - if (!gid_pwd) { - PLOG(ERROR) << "Unable to decode GID for '" << gid << "'"; - return false; - } - gr_gid = gid_pwd->gr_gid; - } - - if (lchown(path.c_str(), pw_uid, gr_gid) < 0) { - PLOG(ERROR) << "lchown() failed for " << path; - return false; - } - - /* chown may have cleared S_ISUID and S_ISGID, chmod again */ - if (mode & (S_ISUID | S_ISGID)) { - if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) { - PLOG(ERROR) << "fchmodat() failed for " << path; - return false; - } - } - - return true; -} - -static bool ReadDescriptorsFromFile(const std::string& file_name, - std::map* descriptors) { - std::vector result; - std::string json_doc; - - if (!android::base::ReadFileToString(file_name, &json_doc)) { - PLOG(ERROR) << "Failed to read task profiles from " << file_name; - return false; - } - - Json::Reader reader; - Json::Value root; - if (!reader.parse(json_doc, root)) { - LOG(ERROR) << "Failed to parse cgroups description: " << reader.getFormattedErrorMessages(); - return false; - } - - if (root.isMember("Cgroups")) { - const Json::Value& cgroups = root["Cgroups"]; - for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { - std::string name = cgroups[i]["Controller"].asString(); - auto iter = descriptors->find(name); - if (iter == descriptors->end()) { - descriptors->emplace(name, CgroupDescriptor(1, name, cgroups[i]["Path"].asString(), - std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8), - cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString())); - } else { - iter->second = CgroupDescriptor(1, name, cgroups[i]["Path"].asString(), - std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8), - cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString()); - } - } - } - - if (root.isMember("Cgroups2")) { - const Json::Value& cgroups2 = root["Cgroups2"]; - auto iter = descriptors->find(CGROUPV2_CONTROLLER_NAME); - if (iter == descriptors->end()) { - descriptors->emplace(CGROUPV2_CONTROLLER_NAME, CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(), - std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8), - cgroups2["UID"].asString(), cgroups2["GID"].asString())); - } else { - iter->second = CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(), - std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8), - cgroups2["UID"].asString(), cgroups2["GID"].asString()); - } - } - - return true; -} - -static bool ReadDescriptors(std::map* descriptors) { - // load system cgroup descriptors - if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) { - return false; - } - - // load vendor cgroup descriptors if the file exists - if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) && - !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) { - return false; - } - - return true; -} - -// To avoid issues in sdk_mac build -#if defined(__ANDROID__) - -static bool SetupCgroup(const CgroupDescriptor& descriptor) { - const CgroupController* controller = descriptor.controller(); - - // mkdir [mode] [owner] [group] - if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { - LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup"; - return false; - } - - int result; - if (controller->version() == 2) { - result = mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID, - nullptr); - } else { - // Unfortunately historically cpuset controller was mounted using a mount command - // different from all other controllers. This results in controller attributes not - // to be prepended with controller name. For example this way instead of - // /dev/cpuset/cpuset.cpus the attribute becomes /dev/cpuset/cpus which is what - // the system currently expects. - if (!strcmp(controller->name(), "cpuset")) { - // mount cpuset none /dev/cpuset nodev noexec nosuid - result = mount("none", controller->path(), controller->name(), - MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr); - } else { - // mount cgroup none nodev noexec nosuid - result = mount("none", controller->path(), "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID, - controller->name()); - } - } - - if (result < 0) { - PLOG(ERROR) << "Failed to mount " << controller->name() << " cgroup"; - return false; - } - - return true; -} - -#else - -// Stubs for non-Android targets. -static bool SetupCgroup(const CgroupDescriptor&) { - return false; -} - -#endif - -// WARNING: This function should be called only from SetupCgroups and only once. -// It intentionally leaks an FD, so additional invocation will result in additional leak. -static bool WriteRcFile(const std::map& descriptors) { - // WARNING: We are intentionally leaking the FD to keep the file open forever. - // Let init keep the FD open to prevent file mappings from becoming invalid in - // case the file gets deleted somehow. - int fd = TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, - S_IRUSR | S_IRGRP | S_IROTH)); - if (fd < 0) { - PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; - return false; - } - - CgroupFile fl; - fl.version_ = CgroupFile::FILE_CURR_VERSION; - fl.controller_count_ = descriptors.size(); - int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl))); - if (ret < 0) { - PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; - return false; - } - - for (const auto& [name, descriptor] : descriptors) { - ret = TEMP_FAILURE_RETRY(write(fd, descriptor.controller(), sizeof(CgroupController))); - if (ret < 0) { - PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; - return false; - } - } - - return true; -} - CgroupController::CgroupController(uint32_t version, const std::string& name, const std::string& path) { version_ = version; @@ -319,11 +107,6 @@ bool CgroupController::GetTaskGroup(int tid, std::string* group) const { return true; } -CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, - const std::string& path, mode_t mode, const std::string& uid, - const std::string& gid) - : controller_(version, name, path), mode_(mode), uid_(uid), gid_(gid) {} - CgroupMap::CgroupMap() : cg_file_data_(nullptr), cg_file_size_(0) { if (!LoadRcFile()) { LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed"; @@ -411,60 +194,6 @@ void CgroupMap::Print() const { } } -bool CgroupMap::SetupCgroups() { - std::map descriptors; - - if (getpid() != 1) { - LOG(ERROR) << "Cgroup setup can be done only by init process"; - return false; - } - - // Make sure we do this only one time. No need for std::call_once because - // init is a single-threaded process - if (access(CGROUPS_RC_PATH, F_OK) == 0) { - LOG(WARNING) << "Attempt to call SetupCgroups more than once"; - return true; - } - - // load cgroups.json file - if (!ReadDescriptors(&descriptors)) { - LOG(ERROR) << "Failed to load cgroup description file"; - return false; - } - - // setup cgroups - for (const auto& [name, descriptor] : descriptors) { - if (!SetupCgroup(descriptor)) { - // issue a warning and proceed with the next cgroup - // TODO: mark the descriptor as invalid and skip it in WriteRcFile() - LOG(WARNING) << "Failed to setup " << name << " cgroup"; - } - } - - // mkdir 0711 system system - if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) { - LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file"; - return false; - } - - // Generate file which can be directly mmapped into - // process memory. This optimizes performance, memory usage - // and limits infrormation shared with unprivileged processes - // to the minimum subset of information from cgroups.json - if (!WriteRcFile(descriptors)) { - LOG(ERROR) << "Failed to write " << CGROUPS_RC_PATH << " file"; - return false; - } - - // chmod 0644 - if (fchmodat(AT_FDCWD, CGROUPS_RC_PATH, 0644, AT_SYMLINK_NOFOLLOW) < 0) { - PLOG(ERROR) << "fchmodat() failed"; - return false; - } - - return true; -} - const CgroupController* CgroupMap::FindController(const std::string& name) const { if (!cg_file_data_) { LOG(ERROR) << "CgroupMap::FindController called for [" << getpid() diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index 304ae155e..044510ba2 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -46,24 +46,6 @@ class CgroupController { char path_[CGROUP_PATH_BUF_SZ]; }; -// Complete controller description for mounting cgroups -class CgroupDescriptor { - public: - CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, - mode_t mode, const std::string& uid, const std::string& gid); - - const CgroupController* controller() const { return &controller_; } - mode_t mode() const { return mode_; } - std::string uid() const { return uid_; } - std::string gid() const { return gid_; } - - private: - CgroupController controller_; - mode_t mode_; - std::string uid_; - std::string gid_; -}; - struct CgroupFile { static constexpr uint32_t FILE_VERSION_1 = 1; static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1; diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 46b86762a..86e60356b 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -26,7 +26,6 @@ __BEGIN_DECLS static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2"; static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; -bool CgroupSetupCgroups(); bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path); bool CgroupGetAttributePath(const std::string& attr_name, std::string* path); bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path); diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 8884650ee..3f6b2d707 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -55,10 +55,6 @@ using namespace std::chrono_literals; #define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs" -bool CgroupSetupCgroups() { - return CgroupMap::SetupCgroups(); -} - bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path) { const CgroupController* controller = CgroupMap::GetInstance().FindController(cgroup_name); diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp new file mode 100644 index 000000000..a403a23f1 --- /dev/null +++ b/libprocessgroup/setup/Android.bp @@ -0,0 +1,41 @@ +// +// Copyright (C) 2019 The Android Open Source Project +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +// + +cc_library_shared { + name: "libprocessgroup_setup", + recovery_available: true, + srcs: [ + "cgroup_map_write.cpp", + ], + export_include_dirs: [ + "include", + ], + shared_libs: [ + "libbase", + "libprocessgroup", + "libjsoncpp", + ], + header_libs: [ + "libprocessgroup_headers", + ], + export_header_lib_headers: [ + "libprocessgroup_headers", + ], + cflags: [ + "-Wall", + "-Werror", + ], +} diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h new file mode 100644 index 000000000..185c5f9fe --- /dev/null +++ b/libprocessgroup/setup/cgroup_descriptor.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +// TODO(b/123664216): Use libcgrouprc_format +#include "../cgroup_map.h" + +// Complete controller description for mounting cgroups +class CgroupDescriptor { + public: + CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, + mode_t mode, const std::string& uid, const std::string& gid); + + const CgroupController* controller() const { return &controller_; } + mode_t mode() const { return mode_; } + std::string uid() const { return uid_; } + std::string gid() const { return gid_; } + + private: + CgroupController controller_; + mode_t mode_ = 0; + std::string uid_; + std::string gid_; +}; diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp new file mode 100644 index 000000000..8ecc0a4ac --- /dev/null +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -0,0 +1,324 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +//#define LOG_NDEBUG 0 +#define LOG_TAG "libprocessgroup" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cgroup_descriptor.h" + +using android::base::GetBoolProperty; +using android::base::StringPrintf; +using android::base::unique_fd; + +static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; +static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; + +static bool Mkdir(const std::string& path, mode_t mode, const std::string& uid, + const std::string& gid) { + if (mode == 0) { + mode = 0755; + } + + if (mkdir(path.c_str(), mode) != 0) { + /* chmod in case the directory already exists */ + if (errno == EEXIST) { + if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) { + // /acct is a special case when the directory already exists + // TODO: check if file mode is already what we want instead of using EROFS + if (errno != EROFS) { + PLOG(ERROR) << "fchmodat() failed for " << path; + return false; + } + } + } else { + PLOG(ERROR) << "mkdir() failed for " << path; + return false; + } + } + + if (uid.empty()) { + return true; + } + + passwd* uid_pwd = getpwnam(uid.c_str()); + if (!uid_pwd) { + PLOG(ERROR) << "Unable to decode UID for '" << uid << "'"; + return false; + } + + uid_t pw_uid = uid_pwd->pw_uid; + gid_t gr_gid = -1; + if (!gid.empty()) { + group* gid_pwd = getgrnam(gid.c_str()); + if (!gid_pwd) { + PLOG(ERROR) << "Unable to decode GID for '" << gid << "'"; + return false; + } + gr_gid = gid_pwd->gr_gid; + } + + if (lchown(path.c_str(), pw_uid, gr_gid) < 0) { + PLOG(ERROR) << "lchown() failed for " << path; + return false; + } + + /* chown may have cleared S_ISUID and S_ISGID, chmod again */ + if (mode & (S_ISUID | S_ISGID)) { + if (fchmodat(AT_FDCWD, path.c_str(), mode, AT_SYMLINK_NOFOLLOW) != 0) { + PLOG(ERROR) << "fchmodat() failed for " << path; + return false; + } + } + + return true; +} + +static bool ReadDescriptorsFromFile(const std::string& file_name, + std::map* descriptors) { + std::vector result; + std::string json_doc; + + if (!android::base::ReadFileToString(file_name, &json_doc)) { + PLOG(ERROR) << "Failed to read task profiles from " << file_name; + return false; + } + + Json::Reader reader; + Json::Value root; + if (!reader.parse(json_doc, root)) { + LOG(ERROR) << "Failed to parse cgroups description: " << reader.getFormattedErrorMessages(); + return false; + } + + if (root.isMember("Cgroups")) { + const Json::Value& cgroups = root["Cgroups"]; + for (Json::Value::ArrayIndex i = 0; i < cgroups.size(); ++i) { + std::string name = cgroups[i]["Controller"].asString(); + auto iter = descriptors->find(name); + if (iter == descriptors->end()) { + descriptors->emplace( + name, CgroupDescriptor( + 1, name, cgroups[i]["Path"].asString(), + std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8), + cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString())); + } else { + iter->second = CgroupDescriptor( + 1, name, cgroups[i]["Path"].asString(), + std::strtoul(cgroups[i]["Mode"].asString().c_str(), 0, 8), + cgroups[i]["UID"].asString(), cgroups[i]["GID"].asString()); + } + } + } + + if (root.isMember("Cgroups2")) { + const Json::Value& cgroups2 = root["Cgroups2"]; + auto iter = descriptors->find(CGROUPV2_CONTROLLER_NAME); + if (iter == descriptors->end()) { + descriptors->emplace( + CGROUPV2_CONTROLLER_NAME, + CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(), + std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8), + cgroups2["UID"].asString(), cgroups2["GID"].asString())); + } else { + iter->second = + CgroupDescriptor(2, CGROUPV2_CONTROLLER_NAME, cgroups2["Path"].asString(), + std::strtoul(cgroups2["Mode"].asString().c_str(), 0, 8), + cgroups2["UID"].asString(), cgroups2["GID"].asString()); + } + } + + return true; +} + +static bool ReadDescriptors(std::map* descriptors) { + // load system cgroup descriptors + if (!ReadDescriptorsFromFile(CGROUPS_DESC_FILE, descriptors)) { + return false; + } + + // load vendor cgroup descriptors if the file exists + if (!access(CGROUPS_DESC_VENDOR_FILE, F_OK) && + !ReadDescriptorsFromFile(CGROUPS_DESC_VENDOR_FILE, descriptors)) { + return false; + } + + return true; +} + +// To avoid issues in sdk_mac build +#if defined(__ANDROID__) + +static bool SetupCgroup(const CgroupDescriptor& descriptor) { + const CgroupController* controller = descriptor.controller(); + + // mkdir [mode] [owner] [group] + if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { + LOG(ERROR) << "Failed to create directory for " << controller->name() << " cgroup"; + return false; + } + + int result; + if (controller->version() == 2) { + result = mount("none", controller->path(), "cgroup2", MS_NODEV | MS_NOEXEC | MS_NOSUID, + nullptr); + } else { + // Unfortunately historically cpuset controller was mounted using a mount command + // different from all other controllers. This results in controller attributes not + // to be prepended with controller name. For example this way instead of + // /dev/cpuset/cpuset.cpus the attribute becomes /dev/cpuset/cpus which is what + // the system currently expects. + if (!strcmp(controller->name(), "cpuset")) { + // mount cpuset none /dev/cpuset nodev noexec nosuid + result = mount("none", controller->path(), controller->name(), + MS_NODEV | MS_NOEXEC | MS_NOSUID, nullptr); + } else { + // mount cgroup none nodev noexec nosuid + result = mount("none", controller->path(), "cgroup", MS_NODEV | MS_NOEXEC | MS_NOSUID, + controller->name()); + } + } + + if (result < 0) { + PLOG(ERROR) << "Failed to mount " << controller->name() << " cgroup"; + return false; + } + + return true; +} + +#else + +// Stubs for non-Android targets. +static bool SetupCgroup(const CgroupDescriptor&) { + return false; +} + +#endif + +// WARNING: This function should be called only from SetupCgroups and only once. +// It intentionally leaks an FD, so additional invocation will result in additional leak. +static bool WriteRcFile(const std::map& descriptors) { + // WARNING: We are intentionally leaking the FD to keep the file open forever. + // Let init keep the FD open to prevent file mappings from becoming invalid in + // case the file gets deleted somehow. + int fd = TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, + S_IRUSR | S_IRGRP | S_IROTH)); + if (fd < 0) { + PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; + return false; + } + + CgroupFile fl; + fl.version_ = CgroupFile::FILE_CURR_VERSION; + fl.controller_count_ = descriptors.size(); + int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl))); + if (ret < 0) { + PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; + return false; + } + + for (const auto& [name, descriptor] : descriptors) { + ret = TEMP_FAILURE_RETRY(write(fd, descriptor.controller(), sizeof(CgroupController))); + if (ret < 0) { + PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; + return false; + } + } + + return true; +} + +CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, + const std::string& path, mode_t mode, const std::string& uid, + const std::string& gid) + : controller_(version, name, path), mode_(mode), uid_(uid), gid_(gid) {} + +bool CgroupSetupCgroups() { + std::map descriptors; + + if (getpid() != 1) { + LOG(ERROR) << "Cgroup setup can be done only by init process"; + return false; + } + + // Make sure we do this only one time. No need for std::call_once because + // init is a single-threaded process + if (access(CGROUPS_RC_PATH, F_OK) == 0) { + LOG(WARNING) << "Attempt to call SetupCgroups more than once"; + return true; + } + + // load cgroups.json file + if (!ReadDescriptors(&descriptors)) { + LOG(ERROR) << "Failed to load cgroup description file"; + return false; + } + + // setup cgroups + for (const auto& [name, descriptor] : descriptors) { + if (!SetupCgroup(descriptor)) { + // issue a warning and proceed with the next cgroup + // TODO: mark the descriptor as invalid and skip it in WriteRcFile() + LOG(WARNING) << "Failed to setup " << name << " cgroup"; + } + } + + // mkdir 0711 system system + if (!Mkdir(android::base::Dirname(CGROUPS_RC_PATH), 0711, "system", "system")) { + LOG(ERROR) << "Failed to create directory for " << CGROUPS_RC_PATH << " file"; + return false; + } + + // Generate file which can be directly mmapped into + // process memory. This optimizes performance, memory usage + // and limits infrormation shared with unprivileged processes + // to the minimum subset of information from cgroups.json + if (!WriteRcFile(descriptors)) { + LOG(ERROR) << "Failed to write " << CGROUPS_RC_PATH << " file"; + return false; + } + + // chmod 0644 + if (fchmodat(AT_FDCWD, CGROUPS_RC_PATH, 0644, AT_SYMLINK_NOFOLLOW) < 0) { + PLOG(ERROR) << "fchmodat() failed"; + return false; + } + + return true; +} diff --git a/libprocessgroup/setup/include/processgroup/setup.h b/libprocessgroup/setup/include/processgroup/setup.h new file mode 100644 index 000000000..b488217d0 --- /dev/null +++ b/libprocessgroup/setup/include/processgroup/setup.h @@ -0,0 +1,19 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +bool CgroupSetupCgroups(); From 1a0996a308ef4c5dbf1ee2b7d388f044c06f62cd Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 22 Mar 2019 17:21:58 -0700 Subject: [PATCH 108/221] libprocessgroup_setup: use libcgrouprc_format Use CgroupController definition from libcgrouprc_format, not libprocessgroup, because the wire format will be removed from libprocessgroup later. Bug: 123664216 Test: builds Change-Id: If5e2301a1b65c3f6a51a1661cfeeed4e299f634e --- init/Android.bp | 1 + libprocessgroup/setup/Android.bp | 5 ++++- libprocessgroup/setup/cgroup_descriptor.h | 13 +++++++++---- libprocessgroup/setup/cgroup_map_write.cpp | 18 ++++++++++++++---- 4 files changed, 28 insertions(+), 9 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index e834e99e0..69ee34f13 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -61,6 +61,7 @@ cc_defaults { static_libs: [ "libseccomp_policy", "libavb", + "libcgrouprc_format", "libprotobuf-cpp-lite", "libpropertyinfoserializer", "libpropertyinfoparser", diff --git a/libprocessgroup/setup/Android.bp b/libprocessgroup/setup/Android.bp index a403a23f1..f6fc066f2 100644 --- a/libprocessgroup/setup/Android.bp +++ b/libprocessgroup/setup/Android.bp @@ -25,9 +25,12 @@ cc_library_shared { ], shared_libs: [ "libbase", - "libprocessgroup", + "libcgrouprc", "libjsoncpp", ], + static_libs: [ + "libcgrouprc_format", + ], header_libs: [ "libprocessgroup_headers", ], diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h index 185c5f9fe..597060e35 100644 --- a/libprocessgroup/setup/cgroup_descriptor.h +++ b/libprocessgroup/setup/cgroup_descriptor.h @@ -16,8 +16,10 @@ #pragma once -// TODO(b/123664216): Use libcgrouprc_format -#include "../cgroup_map.h" +#include + +namespace android { +namespace cgrouprc { // Complete controller description for mounting cgroups class CgroupDescriptor { @@ -25,14 +27,17 @@ class CgroupDescriptor { CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, mode_t mode, const std::string& uid, const std::string& gid); - const CgroupController* controller() const { return &controller_; } + const format::CgroupController* controller() const { return &controller_; } mode_t mode() const { return mode_; } std::string uid() const { return uid_; } std::string gid() const { return gid_; } private: - CgroupController controller_; + format::CgroupController controller_; mode_t mode_ = 0; std::string uid_; std::string gid_; }; + +} // namespace cgrouprc +} // namespace android diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index 8ecc0a4ac..6aabd56bd 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -46,6 +47,9 @@ using android::base::GetBoolProperty; using android::base::StringPrintf; using android::base::unique_fd; +namespace android { +namespace cgrouprc { + static constexpr const char* CGROUPS_DESC_FILE = "/etc/cgroups.json"; static constexpr const char* CGROUPS_DESC_VENDOR_FILE = "/vendor/etc/cgroups.json"; @@ -185,7 +189,7 @@ static bool ReadDescriptors(std::map* descriptors #if defined(__ANDROID__) static bool SetupCgroup(const CgroupDescriptor& descriptor) { - const CgroupController* controller = descriptor.controller(); + const format::CgroupController* controller = descriptor.controller(); // mkdir [mode] [owner] [group] if (!Mkdir(controller->path(), descriptor.mode(), descriptor.uid(), descriptor.gid())) { @@ -244,8 +248,8 @@ static bool WriteRcFile(const std::map& descripto return false; } - CgroupFile fl; - fl.version_ = CgroupFile::FILE_CURR_VERSION; + format::CgroupFile fl; + fl.version_ = format::CgroupFile::FILE_CURR_VERSION; fl.controller_count_ = descriptors.size(); int ret = TEMP_FAILURE_RETRY(write(fd, &fl, sizeof(fl))); if (ret < 0) { @@ -254,7 +258,8 @@ static bool WriteRcFile(const std::map& descripto } for (const auto& [name, descriptor] : descriptors) { - ret = TEMP_FAILURE_RETRY(write(fd, descriptor.controller(), sizeof(CgroupController))); + ret = TEMP_FAILURE_RETRY( + write(fd, descriptor.controller(), sizeof(format::CgroupController))); if (ret < 0) { PLOG(ERROR) << "write() failed for " << CGROUPS_RC_PATH; return false; @@ -269,7 +274,12 @@ CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, const std::string& gid) : controller_(version, name, path), mode_(mode), uid_(uid), gid_(gid) {} +} // namespace cgrouprc +} // namespace android + bool CgroupSetupCgroups() { + using namespace android::cgrouprc; + std::map descriptors; if (getpid() != 1) { From fad638c82d0d6b5b3dab36e47eb6b0b684f70fd5 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 22 Mar 2019 17:01:08 -0700 Subject: [PATCH 109/221] libprocessgroup: use libcgrouprc to read cgroup.rc Use the LL-NDK library to read cgroup.rc. As a side-effect, the CgroupController class is changed to a wrapper of ACgroupController* from the library. The class itself essentially becomes the pointer, and can be trivially copied. Modify all client code for this change. Test: builds and boots Bug: 123664216 Change-Id: I635d9885db62e82f37421f6d20f59c84a6f4cbb2 --- libcutils/Android.bp | 6 +- libprocessgroup/Android.bp | 1 + libprocessgroup/cgroup_map.cpp | 135 ++++++++++------------------ libprocessgroup/cgroup_map.h | 44 ++++----- libprocessgroup/cgrouprc/Android.bp | 7 +- libprocessgroup/processgroup.cpp | 8 +- libprocessgroup/sched_policy.cpp | 10 +-- libprocessgroup/task_profiles.cpp | 25 +++--- libprocessgroup/task_profiles.h | 12 +-- 9 files changed, 104 insertions(+), 144 deletions(-) diff --git a/libcutils/Android.bp b/libcutils/Android.bp index a27ecef9e..619bc567a 100644 --- a/libcutils/Android.bp +++ b/libcutils/Android.bp @@ -235,6 +235,7 @@ test_libraries = [ "libbase", "libjsoncpp", "libprocessgroup", + "libcgrouprc", ] cc_test { @@ -249,7 +250,10 @@ cc_test { name: "libcutils_test_static", test_suites: ["device-tests"], defaults: ["libcutils_test_default"], - static_libs: ["libc"] + test_libraries, + static_libs: [ + "libc", + "libcgrouprc_format", + ] + test_libraries, stl: "libc++_static", target: { diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index 07cbce987..78a02e5d4 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -31,6 +31,7 @@ cc_library { }, shared_libs: [ "libbase", + "libcgrouprc", "libjsoncpp", ], // for cutils/android_filesystem_config.h diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index 3b852ae9b..6cd6b6e50 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -48,28 +48,38 @@ static constexpr const char* CGROUP_PROCS_FILE = "/cgroup.procs"; static constexpr const char* CGROUP_TASKS_FILE = "/tasks"; static constexpr const char* CGROUP_TASKS_FILE_V2 = "/cgroup.tasks"; -CgroupController::CgroupController(uint32_t version, const std::string& name, - const std::string& path) { - version_ = version; - strncpy(name_, name.c_str(), sizeof(name_) - 1); - name_[sizeof(name_) - 1] = '\0'; - strncpy(path_, path.c_str(), sizeof(path_) - 1); - path_[sizeof(path_) - 1] = '\0'; +uint32_t CgroupController::version() const { + CHECK(HasValue()); + return ACgroupController_getVersion(controller_); } -std::string CgroupController::GetTasksFilePath(const std::string& path) const { - std::string tasks_path = path_; +const char* CgroupController::name() const { + CHECK(HasValue()); + return ACgroupController_getName(controller_); +} - if (!path.empty()) { - tasks_path += "/" + path; +const char* CgroupController::path() const { + CHECK(HasValue()); + return ACgroupController_getPath(controller_); +} + +bool CgroupController::HasValue() const { + return controller_ != nullptr; +} + +std::string CgroupController::GetTasksFilePath(const std::string& rel_path) const { + std::string tasks_path = path(); + + if (!rel_path.empty()) { + tasks_path += "/" + rel_path; } - return (version_ == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2; + return (version() == 1) ? tasks_path + CGROUP_TASKS_FILE : tasks_path + CGROUP_TASKS_FILE_V2; } -std::string CgroupController::GetProcsFilePath(const std::string& path, uid_t uid, +std::string CgroupController::GetProcsFilePath(const std::string& rel_path, uid_t uid, pid_t pid) const { - std::string proc_path(path_); - proc_path.append("/").append(path); + std::string proc_path(path()); + proc_path.append("/").append(rel_path); proc_path = regex_replace(proc_path, std::regex(""), std::to_string(uid)); proc_path = regex_replace(proc_path, std::regex(""), std::to_string(pid)); @@ -90,7 +100,7 @@ bool CgroupController::GetTaskGroup(int tid, std::string* group) const { return true; } - std::string cg_tag = StringPrintf(":%s:", name_); + std::string cg_tag = StringPrintf(":%s:", name()); size_t start_pos = content.find(cg_tag); if (start_pos == std::string::npos) { return false; @@ -107,20 +117,12 @@ bool CgroupController::GetTaskGroup(int tid, std::string* group) const { return true; } -CgroupMap::CgroupMap() : cg_file_data_(nullptr), cg_file_size_(0) { +CgroupMap::CgroupMap() { if (!LoadRcFile()) { LOG(ERROR) << "CgroupMap::LoadRcFile called for [" << getpid() << "] failed"; } } -CgroupMap::~CgroupMap() { - if (cg_file_data_) { - munmap(cg_file_data_, cg_file_size_); - cg_file_data_ = nullptr; - cg_file_size_ = 0; - } -} - CgroupMap& CgroupMap::GetInstance() { // Deliberately leak this object to avoid a race between destruction on // process exit and concurrent access from another thread. @@ -129,85 +131,46 @@ CgroupMap& CgroupMap::GetInstance() { } bool CgroupMap::LoadRcFile() { - struct stat sb; - - if (cg_file_data_) { - // Data already initialized - return true; + if (!loaded_) { + loaded_ = (ACgroupFile_getVersion() != 0); } - - unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_RDONLY | O_CLOEXEC))); - if (fd < 0) { - PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; - return false; - } - - if (fstat(fd, &sb) < 0) { - PLOG(ERROR) << "fstat() failed for " << CGROUPS_RC_PATH; - return false; - } - - size_t file_size = sb.st_size; - if (file_size < sizeof(CgroupFile)) { - LOG(ERROR) << "Invalid file format " << CGROUPS_RC_PATH; - return false; - } - - CgroupFile* file_data = (CgroupFile*)mmap(nullptr, file_size, PROT_READ, MAP_SHARED, fd, 0); - if (file_data == MAP_FAILED) { - PLOG(ERROR) << "Failed to mmap " << CGROUPS_RC_PATH; - return false; - } - - if (file_data->version_ != CgroupFile::FILE_CURR_VERSION) { - LOG(ERROR) << CGROUPS_RC_PATH << " file version mismatch"; - munmap(file_data, file_size); - return false; - } - - if (file_size != sizeof(CgroupFile) + file_data->controller_count_ * sizeof(CgroupController)) { - LOG(ERROR) << CGROUPS_RC_PATH << " file has invalid size"; - munmap(file_data, file_size); - return false; - } - - cg_file_data_ = file_data; - cg_file_size_ = file_size; - - return true; + return loaded_; } void CgroupMap::Print() const { - if (!cg_file_data_) { + if (!loaded_) { LOG(ERROR) << "CgroupMap::Print called for [" << getpid() << "] failed, RC file was not initialized properly"; return; } - LOG(INFO) << "File version = " << cg_file_data_->version_; - LOG(INFO) << "File controller count = " << cg_file_data_->controller_count_; + LOG(INFO) << "File version = " << ACgroupFile_getVersion(); + LOG(INFO) << "File controller count = " << ACgroupFile_getControllerCount(); LOG(INFO) << "Mounted cgroups:"; - CgroupController* controller = (CgroupController*)(cg_file_data_ + 1); - for (int i = 0; i < cg_file_data_->controller_count_; i++, controller++) { - LOG(INFO) << "\t" << controller->name() << " ver " << controller->version() << " path " - << controller->path(); + + auto controller_count = ACgroupFile_getControllerCount(); + for (uint32_t i = 0; i < controller_count; ++i) { + const ACgroupController* controller = ACgroupFile_getController(i); + LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver " + << ACgroupController_getVersion(controller) << " path " + << ACgroupController_getPath(controller); } } -const CgroupController* CgroupMap::FindController(const std::string& name) const { - if (!cg_file_data_) { +CgroupController CgroupMap::FindController(const std::string& name) const { + if (!loaded_) { LOG(ERROR) << "CgroupMap::FindController called for [" << getpid() << "] failed, RC file was not initialized properly"; - return nullptr; + return CgroupController(nullptr); } - // skip the file header to get to the first controller - CgroupController* controller = (CgroupController*)(cg_file_data_ + 1); - for (int i = 0; i < cg_file_data_->controller_count_; i++, controller++) { - if (name == controller->name()) { - return controller; + auto controller_count = ACgroupFile_getControllerCount(); + for (uint32_t i = 0; i < controller_count; ++i) { + const ACgroupController* controller = ACgroupFile_getController(i); + if (name == ACgroupController_getName(controller)) { + return CgroupController(controller); } } - return nullptr; + return CgroupController(nullptr); } diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index 044510ba2..d765e600c 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -20,39 +20,30 @@ #include #include +#include #include #include +#include -// Minimal controller description to be mmapped into process address space +#include + +// Convenient wrapper of an ACgroupController pointer. class CgroupController { public: - CgroupController() {} - CgroupController(uint32_t version, const std::string& name, const std::string& path); + // Does not own controller + explicit CgroupController(const ACgroupController* controller) : controller_(controller) {} - uint32_t version() const { return version_; } - const char* name() const { return name_; } - const char* path() const { return path_; } + uint32_t version() const; + const char* name() const; + const char* path() const; + + bool HasValue() const; std::string GetTasksFilePath(const std::string& path) const; std::string GetProcsFilePath(const std::string& path, uid_t uid, pid_t pid) const; bool GetTaskGroup(int tid, std::string* group) const; - private: - static constexpr size_t CGROUP_NAME_BUF_SZ = 16; - static constexpr size_t CGROUP_PATH_BUF_SZ = 32; - - uint32_t version_; - char name_[CGROUP_NAME_BUF_SZ]; - char path_[CGROUP_PATH_BUF_SZ]; -}; - -struct CgroupFile { - static constexpr uint32_t FILE_VERSION_1 = 1; - static constexpr uint32_t FILE_CURR_VERSION = FILE_VERSION_1; - - uint32_t version_; - uint32_t controller_count_; - CgroupController controllers_[]; + const ACgroupController* controller_ = nullptr; }; class CgroupMap { @@ -61,16 +52,11 @@ class CgroupMap { static bool SetupCgroups(); static CgroupMap& GetInstance(); - - const CgroupController* FindController(const std::string& name) const; + CgroupController FindController(const std::string& name) const; private: - struct CgroupFile* cg_file_data_; - size_t cg_file_size_; - + bool loaded_ = false; CgroupMap(); - ~CgroupMap(); - bool LoadRcFile(); void Print() const; }; diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index f5ff7eb9d..774738dd1 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -12,10 +12,15 @@ // See the License for the specific language governing permissions and // limitations under the License. -cc_library_shared { +cc_library { name: "libcgrouprc", host_supported: true, recovery_available: true, + // Do not ever mark this as vendor_available; otherwise, vendor modules + // that links to the static library will behave unexpectedly. All on-device + // modules should use libprocessgroup which links to the LL-NDK library + // defined below. The static library is built for tests. + vendor_available: false, srcs: [ "cgroup_controller.cpp", "cgroup_file.cpp", diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 3f6b2d707..abe63dd70 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -56,14 +56,14 @@ using namespace std::chrono_literals; #define PROCESSGROUP_CGROUP_PROCS_FILE "/cgroup.procs" bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path) { - const CgroupController* controller = CgroupMap::GetInstance().FindController(cgroup_name); + auto controller = CgroupMap::GetInstance().FindController(cgroup_name); - if (controller == nullptr) { + if (!controller.HasValue()) { return false; } if (path) { - *path = controller->path(); + *path = controller.path(); } return true; @@ -107,7 +107,7 @@ bool UsePerAppMemcg() { static bool isMemoryCgroupSupported() { std::string cgroup_name; - static bool memcg_supported = (CgroupMap::GetInstance().FindController("memory") != nullptr); + static bool memcg_supported = CgroupMap::GetInstance().FindController("memory").HasValue(); return memcg_supported; } diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp index 1eefadab9..c7d0cca4c 100644 --- a/libprocessgroup/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -152,21 +152,21 @@ int set_sched_policy(int tid, SchedPolicy policy) { } bool cpusets_enabled() { - static bool enabled = (CgroupMap::GetInstance().FindController("cpuset") != nullptr); + static bool enabled = (CgroupMap::GetInstance().FindController("cpuset").HasValue()); return enabled; } bool schedboost_enabled() { - static bool enabled = (CgroupMap::GetInstance().FindController("schedtune") != nullptr); + static bool enabled = (CgroupMap::GetInstance().FindController("schedtune").HasValue()); return enabled; } static int getCGroupSubsys(int tid, const char* subsys, std::string& subgroup) { - const CgroupController* controller = CgroupMap::GetInstance().FindController(subsys); + auto controller = CgroupMap::GetInstance().FindController(subsys); - if (!controller) return -1; + if (!controller.HasValue()) return -1; - if (!controller->GetTaskGroup(tid, &subgroup)) { + if (!controller.GetTaskGroup(tid, &subgroup)) { LOG(ERROR) << "Failed to find cgroup for tid " << tid; return -1; } diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 9362c0387..4b45c8765 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -46,7 +46,7 @@ using android::base::WriteStringToFile; bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { std::string subgroup; - if (!controller_->GetTaskGroup(tid, &subgroup)) { + if (!controller()->GetTaskGroup(tid, &subgroup)) { return false; } @@ -55,9 +55,10 @@ bool ProfileAttribute::GetPathForTask(int tid, std::string* path) const { } if (subgroup.empty()) { - *path = StringPrintf("%s/%s", controller_->path(), file_name_.c_str()); + *path = StringPrintf("%s/%s", controller()->path(), file_name_.c_str()); } else { - *path = StringPrintf("%s/%s/%s", controller_->path(), subgroup.c_str(), file_name_.c_str()); + *path = StringPrintf("%s/%s/%s", controller()->path(), subgroup.c_str(), + file_name_.c_str()); } return true; } @@ -135,7 +136,7 @@ bool SetCgroupAction::IsAppDependentPath(const std::string& path) { return path.find("", 0) != std::string::npos || path.find("", 0) != std::string::npos; } -SetCgroupAction::SetCgroupAction(const CgroupController* c, const std::string& p) +SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p) : controller_(c), path_(p) { #ifdef CACHE_FILE_DESCRIPTORS // cache file descriptor only if path is app independent @@ -145,7 +146,7 @@ SetCgroupAction::SetCgroupAction(const CgroupController* c, const std::string& p return; } - std::string tasks_path = c->GetTasksFilePath(p.c_str()); + std::string tasks_path = c.GetTasksFilePath(p); if (access(tasks_path.c_str(), W_OK) != 0) { // file is not accessible @@ -199,7 +200,7 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { } // this is app-dependent path, file descriptor is not cached - std::string procs_path = controller_->GetProcsFilePath(path_, uid, pid); + std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid); unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC))); if (tmp_fd < 0) { PLOG(WARNING) << "Failed to open " << procs_path; @@ -212,7 +213,7 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { return true; #else - std::string procs_path = controller_->GetProcsFilePath(path_, uid, pid); + std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid); unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC))); if (tmp_fd < 0) { // no permissions to access the file, ignore @@ -247,7 +248,7 @@ bool SetCgroupAction::ExecuteForTask(int tid) const { LOG(ERROR) << "Application profile can't be applied to a thread"; return false; #else - std::string tasks_path = controller_->GetTasksFilePath(path_); + std::string tasks_path = controller()->GetTasksFilePath(path_); unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC))); if (tmp_fd < 0) { // no permissions to access the file, ignore @@ -326,8 +327,8 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { std::string file_attr = attr[i]["File"].asString(); if (attributes_.find(name) == attributes_.end()) { - const CgroupController* controller = cg_map.FindController(controller_name); - if (controller) { + auto controller = cg_map.FindController(controller_name); + if (controller.HasValue()) { attributes_[name] = std::make_unique(controller, file_attr); } else { LOG(WARNING) << "Controller " << controller_name << " is not found"; @@ -355,8 +356,8 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { std::string controller_name = params_val["Controller"].asString(); std::string path = params_val["Path"].asString(); - const CgroupController* controller = cg_map.FindController(controller_name); - if (controller) { + auto controller = cg_map.FindController(controller_name); + if (controller.HasValue()) { profile->Add(std::make_unique(controller, path)); } else { LOG(WARNING) << "JoinCgroup: controller " << controller_name << " is not found"; diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index 9ee81c1ef..37cc305d5 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -27,16 +27,16 @@ class ProfileAttribute { public: - ProfileAttribute(const CgroupController* controller, const std::string& file_name) + ProfileAttribute(const CgroupController& controller, const std::string& file_name) : controller_(controller), file_name_(file_name) {} - const CgroupController* controller() const { return controller_; } + const CgroupController* controller() const { return &controller_; } const std::string& file_name() const { return file_name_; } bool GetPathForTask(int tid, std::string* path) const; private: - const CgroupController* controller_; + CgroupController controller_; std::string file_name_; }; @@ -106,16 +106,16 @@ class SetAttributeAction : public ProfileAction { // Set cgroup profile element class SetCgroupAction : public ProfileAction { public: - SetCgroupAction(const CgroupController* c, const std::string& p); + SetCgroupAction(const CgroupController& c, const std::string& p); virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const; virtual bool ExecuteForTask(int tid) const; - const CgroupController* controller() const { return controller_; } + const CgroupController* controller() const { return &controller_; } std::string path() const { return path_; } private: - const CgroupController* controller_; + CgroupController controller_; std::string path_; #ifdef CACHE_FILE_DESCRIPTORS android::base::unique_fd fd_; From 169a3e6095c531dcf75becd9f7f505f16ad15380 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Fri, 29 Mar 2019 13:17:35 -0700 Subject: [PATCH 110/221] Add libcgrouprc to ld.config.*.txt. Test: boots (sanity) Bug: 123664216 Change-Id: I23c3ece44816e4e213f9630b915e19978a259823 --- rootdir/etc/ld.config.legacy.txt | 2 ++ rootdir/etc/ld.config.txt | 1 + rootdir/etc/ld.config.vndk_lite.txt | 2 ++ 3 files changed, 5 insertions(+) diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt index 0fccd312c..7324ba96b 100644 --- a/rootdir/etc/ld.config.legacy.txt +++ b/rootdir/etc/ld.config.legacy.txt @@ -100,6 +100,7 @@ namespace.media.links = default namespace.media.link.default.shared_libs = libandroid.so namespace.media.link.default.shared_libs += libbinder_ndk.so namespace.media.link.default.shared_libs += libc.so +namespace.media.link.default.shared_libs += libcgrouprc.so namespace.media.link.default.shared_libs += libdl.so namespace.media.link.default.shared_libs += liblog.so namespace.media.link.default.shared_libs += libmediametrics.so @@ -143,6 +144,7 @@ namespace.resolv.search.paths = /apex/com.android.resolv/${LIB} namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB} namespace.resolv.links = default namespace.resolv.link.default.shared_libs = libc.so +namespace.resolv.link.default.shared_libs += libcgrouprc.so namespace.resolv.link.default.shared_libs += libm.so namespace.resolv.link.default.shared_libs += libdl.so namespace.resolv.link.default.shared_libs += libbinder_ndk.so diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt index 2b0ef4cb6..ac19000e2 100644 --- a/rootdir/etc/ld.config.txt +++ b/rootdir/etc/ld.config.txt @@ -212,6 +212,7 @@ namespace.resolv.search.paths = /apex/com.android.resolv/${LIB} namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB} namespace.resolv.links = default namespace.resolv.link.default.shared_libs = libc.so +namespace.resolv.link.default.shared_libs += libcgrouprc.so namespace.resolv.link.default.shared_libs += libm.so namespace.resolv.link.default.shared_libs += libdl.so namespace.resolv.link.default.shared_libs += libbinder_ndk.so diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt index c8312df39..177010c2f 100644 --- a/rootdir/etc/ld.config.vndk_lite.txt +++ b/rootdir/etc/ld.config.vndk_lite.txt @@ -154,6 +154,7 @@ namespace.resolv.search.paths = /apex/com.android.resolv/${LIB} namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB} namespace.resolv.links = default namespace.resolv.link.default.shared_libs = libc.so +namespace.resolv.link.default.shared_libs += libcgrouprc.so namespace.resolv.link.default.shared_libs += libm.so namespace.resolv.link.default.shared_libs += libdl.so namespace.resolv.link.default.shared_libs += libbinder_ndk.so @@ -474,6 +475,7 @@ namespace.resolv.search.paths = /apex/com.android.resolv/${LIB} namespace.resolv.asan.search.paths = /apex/com.android.resolv/${LIB} namespace.resolv.links = default namespace.resolv.link.default.shared_libs = libc.so +namespace.resolv.link.default.shared_libs += libcgrouprc.so namespace.resolv.link.default.shared_libs += libm.so namespace.resolv.link.default.shared_libs += libdl.so namespace.resolv.link.default.shared_libs += libbinder_ndk.so From eecba5c11d525a10cd254660f7a98432c2be41e3 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 2 Apr 2019 15:10:40 -0700 Subject: [PATCH 111/221] CgroupSetupCgroups -> CgroupSetup Test: builds Bug: 123664216 Change-Id: I47c46ca9ba5c1fbf3f9f7a1b185dc48b058b1e32 --- init/init.cpp | 2 +- libprocessgroup/setup/cgroup_map_write.cpp | 2 +- libprocessgroup/setup/include/processgroup/setup.h | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index 1792f288e..0f44efda4 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -359,7 +359,7 @@ static Result SetupCgroupsAction(const BuiltinArguments&) { // Have to create using make_dir function // for appropriate sepolicy to be set for it make_dir(android::base::Dirname(CGROUPS_RC_PATH), 0711); - if (!CgroupSetupCgroups()) { + if (!CgroupSetup()) { return ErrnoError() << "Failed to setup cgroups"; } diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index 6aabd56bd..26703eea7 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -277,7 +277,7 @@ CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, } // namespace cgrouprc } // namespace android -bool CgroupSetupCgroups() { +bool CgroupSetup() { using namespace android::cgrouprc; std::map descriptors; diff --git a/libprocessgroup/setup/include/processgroup/setup.h b/libprocessgroup/setup/include/processgroup/setup.h index b488217d0..6ea19793e 100644 --- a/libprocessgroup/setup/include/processgroup/setup.h +++ b/libprocessgroup/setup/include/processgroup/setup.h @@ -16,4 +16,4 @@ #pragma once -bool CgroupSetupCgroups(); +bool CgroupSetup(); From a46de76024ad3799739b9a6715e5b03bb8cdeac0 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 3 Apr 2019 14:14:30 -0700 Subject: [PATCH 112/221] Fix off by one reading build id. Update unit tests and add new build id displaying in offline unwinds. Bug: 129873279 Test: All unit tests pass. Test: Verify that debuggerd displays build id properly. Change-Id: I97f4a204842447a20c812f535a458155b937d5e1 Merged-In: I97f4a204842447a20c812f535a458155b937d5e1 (cherry picked from commit 1760b45709df4d925c3a131db0b443b585837703) --- libunwindstack/ElfInterface.cpp | 2 +- libunwindstack/tests/ElfInterfaceTest.cpp | 47 +++++++++++++--------- libunwindstack/tests/UnwindOfflineTest.cpp | 17 ++++++++ 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index e09a2aef4..32c637f85 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -285,7 +285,7 @@ std::string ElfInterface::ReadBuildID() { if (gnu_build_id_size_ - offset < hdr.n_descsz || hdr.n_descsz == 0) { return ""; } - std::string build_id(hdr.n_descsz - 1, '\0'); + std::string build_id(hdr.n_descsz, '\0'); if (memory_->ReadFully(gnu_build_id_offset_ + offset, &build_id[0], hdr.n_descsz)) { return build_id; } diff --git a/libunwindstack/tests/ElfInterfaceTest.cpp b/libunwindstack/tests/ElfInterfaceTest.cpp index d895863bb..cdc927aba 100644 --- a/libunwindstack/tests/ElfInterfaceTest.cpp +++ b/libunwindstack/tests/ElfInterfaceTest.cpp @@ -1192,14 +1192,16 @@ void ElfInterfaceTest::BuildID() { char note_section[128]; Nhdr note_header = {}; note_header.n_namesz = 4; // "GNU" - note_header.n_descsz = 8; // "BUILDID" + note_header.n_descsz = 7; // "BUILDID" note_header.n_type = NT_GNU_BUILD_ID; memcpy(¬e_section, ¬e_header, sizeof(note_header)); size_t note_offset = sizeof(note_header); + // The note information contains the GNU and trailing '\0'. memcpy(¬e_section[note_offset], "GNU", sizeof("GNU")); note_offset += sizeof("GNU"); - memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID")); - note_offset += sizeof("BUILDID"); + // This part of the note does not contain any trailing '\0'. + memcpy(¬e_section[note_offset], "BUILDID", 7); + note_offset += 8; Shdr shdr = {}; shdr.sh_type = SHT_NOTE; @@ -1244,24 +1246,27 @@ void ElfInterfaceTest::BuildIDTwoNotes() { char note_section[128]; Nhdr note_header = {}; note_header.n_namesz = 8; // "WRONG" aligned to 4 - note_header.n_descsz = 8; // "BUILDID" + note_header.n_descsz = 7; // "BUILDID" note_header.n_type = NT_GNU_BUILD_ID; memcpy(¬e_section, ¬e_header, sizeof(note_header)); size_t note_offset = sizeof(note_header); memcpy(¬e_section[note_offset], "WRONG", sizeof("WRONG")); note_offset += 8; - memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID")); - note_offset += sizeof("BUILDID"); + // This part of the note does not contain any trailing '\0'. + memcpy(¬e_section[note_offset], "BUILDID", 7); + note_offset += 8; note_header.n_namesz = 4; // "GNU" - note_header.n_descsz = 8; // "BUILDID" + note_header.n_descsz = 7; // "BUILDID" note_header.n_type = NT_GNU_BUILD_ID; memcpy(¬e_section[note_offset], ¬e_header, sizeof(note_header)); note_offset += sizeof(note_header); + // The note information contains the GNU and trailing '\0'. memcpy(¬e_section[note_offset], "GNU", sizeof("GNU")); note_offset += sizeof("GNU"); - memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID")); - note_offset += sizeof("BUILDID"); + // This part of the note does not contain any trailing '\0'. + memcpy(¬e_section[note_offset], "BUILDID", 7); + note_offset += 8; Shdr shdr = {}; shdr.sh_type = SHT_NOTE; @@ -1306,14 +1311,16 @@ void ElfInterfaceTest::BuildIDSectionTooSmallForName () { char note_section[128]; Nhdr note_header = {}; note_header.n_namesz = 4; // "GNU" - note_header.n_descsz = 8; // "BUILDID" + note_header.n_descsz = 7; // "BUILDID" note_header.n_type = NT_GNU_BUILD_ID; memcpy(¬e_section, ¬e_header, sizeof(note_header)); size_t note_offset = sizeof(note_header); + // The note information contains the GNU and trailing '\0'. memcpy(¬e_section[note_offset], "GNU", sizeof("GNU")); note_offset += sizeof("GNU"); - memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID")); - note_offset += sizeof("BUILDID"); + // This part of the note does not contain any trailing '\0'. + memcpy(¬e_section[note_offset], "BUILDID", 7); + note_offset += 8; Shdr shdr = {}; shdr.sh_type = SHT_NOTE; @@ -1358,14 +1365,16 @@ void ElfInterfaceTest::BuildIDSectionTooSmallForDesc () { char note_section[128]; Nhdr note_header = {}; note_header.n_namesz = 4; // "GNU" - note_header.n_descsz = 8; // "BUILDID" + note_header.n_descsz = 7; // "BUILDID" note_header.n_type = NT_GNU_BUILD_ID; memcpy(¬e_section, ¬e_header, sizeof(note_header)); size_t note_offset = sizeof(note_header); + // The note information contains the GNU and trailing '\0'. memcpy(¬e_section[note_offset], "GNU", sizeof("GNU")); note_offset += sizeof("GNU"); - memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID")); - note_offset += sizeof("BUILDID"); + // This part of the note does not contain any trailing '\0'. + memcpy(¬e_section[note_offset], "BUILDID", 7); + note_offset += 8; Shdr shdr = {}; shdr.sh_type = SHT_NOTE; @@ -1410,14 +1419,16 @@ void ElfInterfaceTest::BuildIDSectionTooSmallForHeader () { char note_section[128]; Nhdr note_header = {}; note_header.n_namesz = 4; // "GNU" - note_header.n_descsz = 8; // "BUILDID" + note_header.n_descsz = 7; // "BUILDID" note_header.n_type = NT_GNU_BUILD_ID; memcpy(¬e_section, ¬e_header, sizeof(note_header)); size_t note_offset = sizeof(note_header); + // The note information contains the GNU and trailing '\0'. memcpy(¬e_section[note_offset], "GNU", sizeof("GNU")); note_offset += sizeof("GNU"); - memcpy(¬e_section[note_offset], "BUILDID", sizeof("BUILDID")); - note_offset += sizeof("BUILDID"); + // This part of the note does not contain any trailing '\0'. + memcpy(¬e_section[note_offset], "BUILDID", 7); + note_offset += 8; Shdr shdr = {}; shdr.sh_type = SHT_NOTE; diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 0867561d5..e3c646a74 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -204,6 +204,7 @@ static std::string DumpFrames(Unwinder& unwinder) { TEST_F(UnwindOfflineTest, pc_straddle_arm) { ASSERT_NO_FATAL_FAILURE(Init("straddle_arm/", ARCH_ARM)); + std::unique_ptr regs_copy(regs_->Clone()); Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); unwinder.Unwind(); @@ -223,6 +224,22 @@ TEST_F(UnwindOfflineTest, pc_straddle_arm) { EXPECT_EQ(0xe9c86730U, unwinder.frames()[2].sp); EXPECT_EQ(0xf3367147U, unwinder.frames()[3].pc); EXPECT_EQ(0xe9c86778U, unwinder.frames()[3].sp); + + // Display build ids now. + unwinder.SetRegs(regs_copy.get()); + unwinder.SetDisplayBuildID(true); + unwinder.Unwind(); + + frame_info = DumpFrames(unwinder); + ASSERT_EQ(4U, unwinder.NumFrames()) << "Unwind:\n" << frame_info; + EXPECT_EQ( + " #00 pc 0001a9f8 libc.so (abort+64) (BuildId: 2dd0d4ba881322a0edabeed94808048c)\n" + " #01 pc 00006a1b libbase.so (android::base::DefaultAborter(char const*)+6) (BuildId: " + "ed43842c239cac1a618e600ea91c4cbd)\n" + " #02 pc 00007441 libbase.so (android::base::LogMessage::~LogMessage()+748) (BuildId: " + "ed43842c239cac1a618e600ea91c4cbd)\n" + " #03 pc 00015147 /does/not/exist/libhidlbase.so\n", + frame_info); } TEST_F(UnwindOfflineTest, pc_in_gnu_debugdata_arm) { From 4113cf749e9b6634f2b0b311bcd379ce065e7808 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Wed, 3 Apr 2019 17:57:00 -0700 Subject: [PATCH 113/221] Open image files in binary mode This is required for read() to function correctly in Windows since it behaves differently in text mode and binary mode and may cause unpredictable behavior depending on the contents of the image file. Bug: 129281908 Test: fastboot.exe flashall Change-Id: I64370af44a050bafea60ff1b0b2be18cc531480a Merged-In: I64370af44a050bafea60ff1b0b2be18cc531480a (cherry picked from commit 1a6f6feff425edf6076269c0f971675fa41de56c) --- fastboot/fastboot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 827db9671..f8f7eb36e 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1407,7 +1407,7 @@ bool LocalImageSource::ReadFile(const std::string& name, std::vector* out) int LocalImageSource::OpenFile(const std::string& name) const { auto path = find_item_given_name(name); - return open(path.c_str(), O_RDONLY); + return open(path.c_str(), O_RDONLY | O_BINARY); } static void do_flashall(const std::string& slot_override, bool skip_secondary, bool wipe) { From d588728951add8b934204c03e52c79fdbd30ac34 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Wed, 3 Apr 2019 14:44:10 -0700 Subject: [PATCH 114/221] libcgrouprc: version script: linux only mac builds doesn't support version script. This fixes the build. Test: pass Fixes: 129905103 Change-Id: Ia3d06e4eff05b41982b3dfbb946efa41358b2c76 --- libprocessgroup/cgrouprc/Android.bp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index 774738dd1..6848620f9 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -45,7 +45,11 @@ cc_library { symbol_file: "libcgrouprc.map.txt", versions: ["29"], }, - version_script: "libcgrouprc.map.txt", + target: { + linux: { + version_script: "libcgrouprc.map.txt", + }, + }, } llndk_library { From 0558e5821467f10a88631b204f1d55c381e622f3 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 2 Apr 2019 15:07:48 -0700 Subject: [PATCH 115/221] CgroupSetupCgroups: don't leak fd. - If file is unlinked, the mmapped region is still there. - If file is truncated, a SIGBUS will be seen, and holding the fd doesn't help. Test: boots (sanity) Bug: 123664216 Change-Id: I6683804bc795fab6798891a4471e5fe58fbffe13 Merged-In: I6683804bc795fab6798891a4471e5fe58fbffe13 --- libprocessgroup/setup/cgroup_map_write.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index 26703eea7..da6094879 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -235,14 +235,9 @@ static bool SetupCgroup(const CgroupDescriptor&) { #endif -// WARNING: This function should be called only from SetupCgroups and only once. -// It intentionally leaks an FD, so additional invocation will result in additional leak. static bool WriteRcFile(const std::map& descriptors) { - // WARNING: We are intentionally leaking the FD to keep the file open forever. - // Let init keep the FD open to prevent file mappings from becoming invalid in - // case the file gets deleted somehow. - int fd = TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, - S_IRUSR | S_IRGRP | S_IROTH)); + unique_fd fd(TEMP_FAILURE_RETRY(open(CGROUPS_RC_PATH, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, + S_IRUSR | S_IRGRP | S_IROTH))); if (fd < 0) { PLOG(ERROR) << "open() failed for " << CGROUPS_RC_PATH; return false; From b4b2bfc115c172c1ebfcb364bf74c0083c94f8f1 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 2 Apr 2019 16:16:49 -0700 Subject: [PATCH 116/221] Allow to build non-sparse super image. - Rename SparseBuilder to ImageBuilder, WriteSplitSparseFiles to WriteSplitImageFiles, WriteToSparseFile to WriteToImageFile, etc. - Add sparsify argument to ImageBuilder, WriteToImageFile, and WriteSplitImageFiles This allows lpmake to write non-sparse super image directly. Virtual devices needs non-sparse images to work on. Test: lpmake without --sparse Test: liblp_test Bug: 120041578 Change-Id: I76ee09efd02df7caaa8abd37a55ae0bebf9cfa29 Merged-In: I76ee09efd02df7caaa8abd37a55ae0bebf9cfa29 --- fs_mgr/liblp/images.cpp | 50 ++++++++++++++++-------------- fs_mgr/liblp/images.h | 9 +++--- fs_mgr/liblp/include/liblp/liblp.h | 9 +++--- fs_mgr/liblp/io_test.cpp | 2 +- 4 files changed, 37 insertions(+), 33 deletions(-) diff --git a/fs_mgr/liblp/images.cpp b/fs_mgr/liblp/images.cpp index 56b535353..db27022db 100644 --- a/fs_mgr/liblp/images.cpp +++ b/fs_mgr/liblp/images.cpp @@ -98,11 +98,12 @@ bool WriteToImageFile(const char* file, const LpMetadata& input) { return WriteToImageFile(fd, input); } -SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size, - const std::map& images) +ImageBuilder::ImageBuilder(const LpMetadata& metadata, uint32_t block_size, + const std::map& images, bool sparsify) : metadata_(metadata), geometry_(metadata.geometry), block_size_(block_size), + sparsify_(sparsify), images_(images) { uint64_t total_size = GetTotalSuperPartitionSize(metadata); if (block_size % LP_SECTOR_SIZE != 0) { @@ -144,11 +145,11 @@ SparseBuilder::SparseBuilder(const LpMetadata& metadata, uint32_t block_size, } } -bool SparseBuilder::IsValid() const { +bool ImageBuilder::IsValid() const { return device_images_.size() == metadata_.block_devices.size(); } -bool SparseBuilder::Export(const char* file) { +bool ImageBuilder::Export(const char* file) { unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC | O_CLOEXEC, 0644)); if (fd < 0) { PERROR << "open failed: " << file; @@ -158,8 +159,8 @@ bool SparseBuilder::Export(const char* file) { LERROR << "Cannot export to a single image on retrofit builds."; return false; } - // No gzip compression; sparseify; no checksum. - int ret = sparse_file_write(device_images_[0].get(), fd, false, true, false); + // No gzip compression; no checksum. + int ret = sparse_file_write(device_images_[0].get(), fd, false, sparsify_, false); if (ret != 0) { LERROR << "sparse_file_write failed (error code " << ret << ")"; return false; @@ -167,7 +168,7 @@ bool SparseBuilder::Export(const char* file) { return true; } -bool SparseBuilder::ExportFiles(const std::string& output_dir) { +bool ImageBuilder::ExportFiles(const std::string& output_dir) { for (size_t i = 0; i < device_images_.size(); i++) { std::string name = GetBlockDevicePartitionName(metadata_.block_devices[i]); std::string file_name = "super_" + name + ".img"; @@ -179,8 +180,8 @@ bool SparseBuilder::ExportFiles(const std::string& output_dir) { PERROR << "open failed: " << file_path; return false; } - // No gzip compression; sparseify; no checksum. - int ret = sparse_file_write(device_images_[i].get(), fd, false, true, false); + // No gzip compression; no checksum. + int ret = sparse_file_write(device_images_[i].get(), fd, false, sparsify_, false); if (ret != 0) { LERROR << "sparse_file_write failed (error code " << ret << ")"; return false; @@ -189,7 +190,7 @@ bool SparseBuilder::ExportFiles(const std::string& output_dir) { return true; } -bool SparseBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) { +bool ImageBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t sector) { uint32_t block; if (!SectorToBlock(sector, &block)) { return false; @@ -203,7 +204,7 @@ bool SparseBuilder::AddData(sparse_file* file, const std::string& blob, uint64_t return true; } -bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) { +bool ImageBuilder::SectorToBlock(uint64_t sector, uint32_t* block) { // The caller must ensure that the metadata has an alignment that is a // multiple of the block size. liblp will take care of the rest, ensuring // that all partitions are on an aligned boundary. Therefore all writes @@ -218,11 +219,11 @@ bool SparseBuilder::SectorToBlock(uint64_t sector, uint32_t* block) { return true; } -uint64_t SparseBuilder::BlockToSector(uint64_t block) const { +uint64_t ImageBuilder::BlockToSector(uint64_t block) const { return (block * block_size_) / LP_SECTOR_SIZE; } -bool SparseBuilder::Build() { +bool ImageBuilder::Build() { if (sparse_file_add_fill(device_images_[0].get(), 0, LP_PARTITION_RESERVED_BYTES, 0) < 0) { LERROR << "Could not add initial sparse block for reserved zeroes"; return false; @@ -275,8 +276,8 @@ static inline bool HasFillValue(uint32_t* buffer, size_t count) { return true; } -bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition, - const std::string& file) { +bool ImageBuilder::AddPartitionImage(const LpMetadataPartition& partition, + const std::string& file) { // Track which extent we're processing. uint32_t extent_index = partition.first_extent_index; @@ -371,7 +372,7 @@ bool SparseBuilder::AddPartitionImage(const LpMetadataPartition& partition, return true; } -uint64_t SparseBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const { +uint64_t ImageBuilder::ComputePartitionSize(const LpMetadataPartition& partition) const { uint64_t sectors = 0; for (size_t i = 0; i < partition.num_extents; i++) { sectors += metadata_.extents[partition.first_extent_index + i].num_sectors; @@ -386,7 +387,7 @@ uint64_t SparseBuilder::ComputePartitionSize(const LpMetadataPartition& partitio // // Without this, it would be more difficult to find the appropriate extent for // an output block. With this guarantee it is a linear walk. -bool SparseBuilder::CheckExtentOrdering() { +bool ImageBuilder::CheckExtentOrdering() { std::vector last_sectors(metadata_.block_devices.size()); for (const auto& extent : metadata_.extents) { @@ -407,7 +408,7 @@ bool SparseBuilder::CheckExtentOrdering() { return true; } -int SparseBuilder::OpenImageFile(const std::string& file) { +int ImageBuilder::OpenImageFile(const std::string& file) { android::base::unique_fd source_fd = GetControlFileOrOpen(file.c_str(), O_RDONLY | O_CLOEXEC); if (source_fd < 0) { PERROR << "open image file failed: " << file; @@ -437,15 +438,16 @@ int SparseBuilder::OpenImageFile(const std::string& file) { return temp_fds_.back().get(); } -bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size, - const std::map& images) { - SparseBuilder builder(metadata, block_size, images); +bool WriteToImageFile(const char* file, const LpMetadata& metadata, uint32_t block_size, + const std::map& images, bool sparsify) { + ImageBuilder builder(metadata, block_size, images, sparsify); return builder.IsValid() && builder.Build() && builder.Export(file); } -bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata, - uint32_t block_size, const std::map& images) { - SparseBuilder builder(metadata, block_size, images); +bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata, + uint32_t block_size, const std::map& images, + bool sparsify) { + ImageBuilder builder(metadata, block_size, images, sparsify); return builder.IsValid() && builder.Build() && builder.ExportFiles(output_dir); } diff --git a/fs_mgr/liblp/images.h b/fs_mgr/liblp/images.h index 44217a015..75060f9d7 100644 --- a/fs_mgr/liblp/images.h +++ b/fs_mgr/liblp/images.h @@ -32,13 +32,13 @@ std::unique_ptr ReadFromImageFile(int fd); bool WriteToImageFile(const char* file, const LpMetadata& metadata); bool WriteToImageFile(int fd, const LpMetadata& metadata); -// We use an object to build the sparse file since it requires that data +// We use an object to build the image file since it requires that data // pointers be held alive until the sparse file is destroyed. It's easier // to do this when the data pointers are all in one place. -class SparseBuilder { +class ImageBuilder { public: - SparseBuilder(const LpMetadata& metadata, uint32_t block_size, - const std::map& images); + ImageBuilder(const LpMetadata& metadata, uint32_t block_size, + const std::map& images, bool sparsify); bool Build(); bool Export(const char* file); @@ -60,6 +60,7 @@ class SparseBuilder { const LpMetadata& metadata_; const LpMetadataGeometry& geometry_; uint32_t block_size_; + bool sparsify_; std::vector device_images_; std::string all_metadata_; diff --git a/fs_mgr/liblp/include/liblp/liblp.h b/fs_mgr/liblp/include/liblp/liblp.h index 6348f556f..5f782b0ad 100644 --- a/fs_mgr/liblp/include/liblp/liblp.h +++ b/fs_mgr/liblp/include/liblp/liblp.h @@ -72,8 +72,8 @@ std::unique_ptr ReadMetadata(const std::string& super_partition, uin // Read/Write logical partition metadata to an image file, for diagnostics or // flashing. -bool WriteToSparseFile(const char* file, const LpMetadata& metadata, uint32_t block_size, - const std::map& images); +bool WriteToImageFile(const char* file, const LpMetadata& metadata, uint32_t block_size, + const std::map& images, bool sparsify); bool WriteToImageFile(const char* file, const LpMetadata& metadata); std::unique_ptr ReadFromImageFile(const std::string& image_file); std::unique_ptr ReadFromImageBlob(const void* data, size_t bytes); @@ -83,8 +83,9 @@ std::unique_ptr ReadFromImageBlob(const void* data, size_t bytes); // is intended for retrofit devices, and will generate one sparse file per // block device (each named super_.img) and placed in the specified // output folder. -bool WriteSplitSparseFiles(const std::string& output_dir, const LpMetadata& metadata, - uint32_t block_size, const std::map& images); +bool WriteSplitImageFiles(const std::string& output_dir, const LpMetadata& metadata, + uint32_t block_size, const std::map& images, + bool sparsify); // Helper to extract safe C++ strings from partition info. std::string GetPartitionName(const LpMetadataPartition& partition); diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp index 9f3314d34..8fc02cbde 100644 --- a/fs_mgr/liblp/io_test.cpp +++ b/fs_mgr/liblp/io_test.cpp @@ -598,7 +598,7 @@ TEST(liblp, FlashSparseImage) { ASSERT_NE(exported, nullptr); // Build the sparse file. - SparseBuilder sparse(*exported.get(), 512, {}); + ImageBuilder sparse(*exported.get(), 512, {}, true /* sparsify */); ASSERT_TRUE(sparse.IsValid()); ASSERT_TRUE(sparse.Build()); From 943f1c1d4a823ab96c12fb4ad1ab6e5119cb5fbb Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Thu, 4 Apr 2019 09:16:32 -0700 Subject: [PATCH 117/221] cutils: add ashmem_init Add a new ashmem_init function that only dlopens libashmemd_client. This allows the library to be preloaded in the zygote. Test: boots, works Bug: 129543489 Change-Id: Ie106791edf381654f085203c266c9f9c0df35cfc --- libcutils/ashmem-dev.cpp | 15 ++++++++++++++- libcutils/ashmem-host.cpp | 2 ++ libcutils/include/cutils/ashmem.h | 1 + 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp index e35b91ae3..e67b45808 100644 --- a/libcutils/ashmem-dev.cpp +++ b/libcutils/ashmem-dev.cpp @@ -73,6 +73,8 @@ static pthread_mutex_t __ashmem_lock = PTHREAD_MUTEX_INITIALIZER; #ifndef __ANDROID_VNDK__ using openFdType = int (*)(); +static openFdType openFd; + openFdType initOpenAshmemFd() { openFdType openFd = nullptr; void* handle = dlopen("libashmemd_client.so", RTLD_NOW); @@ -221,7 +223,10 @@ static int __ashmem_open_locked() int fd = -1; #ifndef __ANDROID_VNDK__ - static auto openFd = initOpenAshmemFd(); + if (!openFd) { + openFd = initOpenAshmemFd(); + } + if (openFd) { fd = openFd(); } @@ -480,3 +485,11 @@ int ashmem_get_size_region(int fd) return __ashmem_check_failure(fd, TEMP_FAILURE_RETRY(ioctl(fd, ASHMEM_GET_SIZE, NULL))); } + +void ashmem_init() { +#ifndef __ANDROID_VNDK__ + pthread_mutex_lock(&__ashmem_lock); + openFd = initOpenAshmemFd(); + pthread_mutex_unlock(&__ashmem_lock); +#endif //__ANDROID_VNDK__ +} diff --git a/libcutils/ashmem-host.cpp b/libcutils/ashmem-host.cpp index bb990d562..32446d478 100644 --- a/libcutils/ashmem-host.cpp +++ b/libcutils/ashmem-host.cpp @@ -82,3 +82,5 @@ int ashmem_get_size_region(int fd) return buf.st_size; } + +void ashmem_init() {} diff --git a/libcutils/include/cutils/ashmem.h b/libcutils/include/cutils/ashmem.h index d80caa698..abc50681a 100644 --- a/libcutils/include/cutils/ashmem.h +++ b/libcutils/include/cutils/ashmem.h @@ -26,6 +26,7 @@ int ashmem_set_prot_region(int fd, int prot); int ashmem_pin_region(int fd, size_t offset, size_t len); int ashmem_unpin_region(int fd, size_t offset, size_t len); int ashmem_get_size_region(int fd); +void ashmem_init(); #ifdef __cplusplus } From 13d92df720dd8f116cc92d9a880fb08680492705 Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Wed, 3 Apr 2019 17:51:48 +0800 Subject: [PATCH 118/221] Update GSI keys for dynamic system image Bug: 112293933 Test: tree hugger Change-Id: Ia5fd08410fd680b8fd3676cfc4daae1caf1ff425 Merged-In: Ia5fd08410fd680b8fd3676cfc4daae1caf1ff425 (cherry picked from commit b9b9a68f49d465176c9dbd2344bac030ec3e89f0) --- fs_mgr/fs_mgr_fstab.cpp | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index f6f6f50f9..4043fc6a1 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -754,14 +754,15 @@ std::set GetBootDevices() { FstabEntry BuildGsiSystemFstabEntry() { // .logical_partition_name is required to look up AVB Hashtree descriptors. - FstabEntry system = {.blk_device = "system_gsi", - .mount_point = "/system", - .fs_type = "ext4", - .flags = MS_RDONLY, - .fs_options = "barrier=1", - // could add more keys separated by ':'. - .avb_keys = "/avb/gsi.avbpubkey:", - .logical_partition_name = "system"}; + FstabEntry system = { + .blk_device = "system_gsi", + .mount_point = "/system", + .fs_type = "ext4", + .flags = MS_RDONLY, + .fs_options = "barrier=1", + // could add more keys separated by ':'. + .avb_keys = "/avb/q-gsi.avbpubkey:/avb/r-gsi.avbpubkey:/avb/s-gsi.avbpubkey", + .logical_partition_name = "system"}; system.fs_mgr_flags.wait = true; system.fs_mgr_flags.logical = true; system.fs_mgr_flags.first_stage_mount = true; From 1e30c33a1a364d5064e3b916d34f0d480516d790 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Thu, 4 Apr 2019 13:43:29 -0700 Subject: [PATCH 119/221] Test is-logical command for vendor and boot partitions. Vendor must be a logical partition and boot must not be a logical partition. Test: fuzzy_fastboot --gtest_filter=*Logical* Bug: 117220134 Change-Id: Ifc6f2f715ca92cd1fe779e8fce2d6a10a1f140b9 Merged-In: Ifc6f2f715ca92cd1fe779e8fce2d6a10a1f140b9 (cherry picked from commit 61a5bc6cf4cf22186505d87db31a449ed960818e) --- fastboot/fuzzy_fastboot/main.cpp | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp index 7ffc7d57c..a40bc27ef 100644 --- a/fastboot/fuzzy_fastboot/main.cpp +++ b/fastboot/fuzzy_fastboot/main.cpp @@ -201,18 +201,28 @@ TEST_F(LogicalPartitionCompliance, GetVarIsLogical) { ASSERT_TRUE(UserSpaceFastboot()); std::string has_slot; EXPECT_EQ(fb->GetVar("has-slot:system", &has_slot), SUCCESS) << "getvar has-slot:system failed"; - std::string is_logical_cmd; + std::string is_logical_cmd_system = "is-logical:system"; + std::string is_logical_cmd_vendor = "is-logical:vendor"; + std::string is_logical_cmd_boot = "is-logical:boot"; if (has_slot == "yes") { std::string current_slot; - EXPECT_EQ(fb->GetVar("current-slot", ¤t_slot), SUCCESS) + ASSERT_EQ(fb->GetVar("current-slot", ¤t_slot), SUCCESS) << "getvar current-slot failed"; - is_logical_cmd = "is-logical:system_" + current_slot; - } else { - is_logical_cmd = "is-logical:system"; + std::string slot_suffix = "_" + current_slot; + is_logical_cmd_system += slot_suffix; + is_logical_cmd_vendor += slot_suffix; + is_logical_cmd_boot += slot_suffix; } std::string is_logical; - EXPECT_EQ(fb->GetVar(is_logical_cmd, &is_logical), SUCCESS) << "getvar is-logical failed"; - ASSERT_EQ(is_logical, "yes"); + EXPECT_EQ(fb->GetVar(is_logical_cmd_system, &is_logical), SUCCESS) + << "system must be a logical partition"; + EXPECT_EQ(is_logical, "yes"); + EXPECT_EQ(fb->GetVar(is_logical_cmd_vendor, &is_logical), SUCCESS) + << "vendor must be a logical partition"; + EXPECT_EQ(is_logical, "yes"); + EXPECT_EQ(fb->GetVar(is_logical_cmd_boot, &is_logical), SUCCESS) + << "boot must not be logical partition"; + EXPECT_EQ(is_logical, "no"); } TEST_F(LogicalPartitionCompliance, FastbootRebootTest) { From c9a9d279efbaa55f2ba51576bfd9ad587c5fef17 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Mon, 8 Apr 2019 13:29:07 -0700 Subject: [PATCH 120/221] charger: Allow to rw /sys/power/[state,wakeup_count] charger needs to suspend the device when the power goes away when it doesn't have root. These two files are marked with group system, user system, mode 0600 in 'on boot', but it is not executed in charger. Hence, move these actions to 'on init'. Test: no failure in libsuspend in charger Bug: 129138950 Change-Id: I787b935b4ff6177601329aeedccdac361b119ca3 --- rootdir/init.rc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 75035d09c..b274cf30e 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -280,6 +280,11 @@ on init write /dev/cpu_variant:${ro.bionic.2nd_arch} ${ro.bionic.2nd_cpu_variant} chmod 0444 /dev/cpu_variant:${ro.bionic.2nd_arch} + # Allow system processes to read / write power state. + chown system system /sys/power/state + chown system system /sys/power/wakeup_count + chmod 0660 /sys/power/state + # Start logd before any other services run to ensure we capture all of their logs. start logd @@ -671,11 +676,8 @@ on boot chown radio system /sys/android_power/acquire_partial_wake_lock chown radio system /sys/android_power/release_wake_lock chown system system /sys/power/autosleep - chown system system /sys/power/state - chown system system /sys/power/wakeup_count chown radio wakelock /sys/power/wake_lock chown radio wakelock /sys/power/wake_unlock - chmod 0660 /sys/power/state chmod 0660 /sys/power/wake_lock chmod 0660 /sys/power/wake_unlock From 98877cbabef1c496fd0e272c7e659c84f85e6b69 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Mon, 8 Apr 2019 17:18:24 -0700 Subject: [PATCH 121/221] Remove include of backtrace/Backtrace.h. Somehow the code was still including this include from libbacktrace. I think the libbacktrace include directory was coming from some transitive includes. I verified that nothing in debuggerd is using the libbacktace.so shared library. Bug: 120606663 Test: Builds, unit tests pass. Change-Id: I85c2837c5a539ccefc5a7140949988058d21697a Merged-In: I85c2837c5a539ccefc5a7140949988058d21697a (cherry picked from commit 3336c7bce087d33cc9ab0b02139b39551539f8a6) --- debuggerd/libdebuggerd/include/libdebuggerd/utility.h | 10 +++++++++- debuggerd/libdebuggerd/test/tombstone_test.cpp | 1 + debuggerd/libdebuggerd/tombstone.cpp | 1 + debuggerd/libdebuggerd/utility.cpp | 1 - 4 files changed, 11 insertions(+), 2 deletions(-) diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h index 7c5304e84..238c00c5d 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h @@ -18,6 +18,7 @@ #ifndef _DEBUGGERD_UTILITY_H #define _DEBUGGERD_UTILITY_H +#include #include #include #include @@ -25,7 +26,6 @@ #include #include -#include struct log_t { // Tombstone file descriptor. @@ -61,6 +61,14 @@ enum logtype { OPEN_FILES }; +#if defined(__LP64__) +#define PRIPTR "016" PRIx64 +typedef uint64_t word_t; +#else +#define PRIPTR "08" PRIx64 +typedef uint32_t word_t; +#endif + // Log information onto the tombstone. void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4))); diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp index eed5bd30f..3196ce84b 100644 --- a/debuggerd/libdebuggerd/test/tombstone_test.cpp +++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp @@ -15,6 +15,7 @@ */ #include +#include #include #include diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index 4bdb9c86a..4c1d63317 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -27,6 +27,7 @@ #include #include #include +#include #include #include #include diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index d0c5234d3..7aebea8fe 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -35,7 +35,6 @@ #include #include #include -#include #include #include #include From 50f524515c12f5c411ef6ad30c9b45d829be2c3a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 20 Mar 2019 18:10:25 -0700 Subject: [PATCH 122/221] Add fiemap_writer_test to VTS. Note: fiemap_writer_test's default argument now defaults to /data/local/unencrypted or /data (whichever exists), since there is no way to pass arguments via AndroidTest.xml. Bug: 129000341 Test: vts-tradefed run commandAndExit vts-kernel --primary-abi-only --module VtsFiemapWriterTest Change-Id: I8cc2e39e170b26b53cf0a829b308171890ae82fd --- fs_mgr/libfiemap_writer/Android.mk | 22 ++++++++++++++ fs_mgr/libfiemap_writer/AndroidTest.xml | 29 +++++++++++++++++++ .../libfiemap_writer/fiemap_writer_test.cpp | 13 ++++++--- 3 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 fs_mgr/libfiemap_writer/Android.mk create mode 100644 fs_mgr/libfiemap_writer/AndroidTest.xml diff --git a/fs_mgr/libfiemap_writer/Android.mk b/fs_mgr/libfiemap_writer/Android.mk new file mode 100644 index 000000000..3c07b8ea6 --- /dev/null +++ b/fs_mgr/libfiemap_writer/Android.mk @@ -0,0 +1,22 @@ +# +# Copyright (C) 2019 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := VtsFiemapWriterTest +-include test/vts/tools/build/Android.host_config.mk diff --git a/fs_mgr/libfiemap_writer/AndroidTest.xml b/fs_mgr/libfiemap_writer/AndroidTest.xml new file mode 100644 index 000000000..08cff0e24 --- /dev/null +++ b/fs_mgr/libfiemap_writer/AndroidTest.xml @@ -0,0 +1,29 @@ + + + + diff --git a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp index ca5168968..dda7dfda4 100644 --- a/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp +++ b/fs_mgr/libfiemap_writer/fiemap_writer_test.cpp @@ -498,17 +498,22 @@ using namespace android::fiemap_writer; int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); - if (argc <= 1) { - cerr << "Usage: [file_size]\n"; + if (argc > 1 && argv[1] == "-h"s) { + cerr << "Usage: [test_dir] [file_size]\n"; cerr << "\n"; cerr << "Note: test_dir must be a writable, unencrypted directory.\n"; exit(EXIT_FAILURE); } ::android::base::InitLogging(argv, ::android::base::StderrLogger); - std::string tempdir = argv[1] + "/XXXXXX"s; + std::string root_dir = "/data/local/unencrypted"; + if (access(root_dir.c_str(), F_OK)) { + root_dir = "/data"; + } + + std::string tempdir = root_dir + "/XXXXXX"s; if (!mkdtemp(tempdir.data())) { - cerr << "unable to create tempdir on " << argv[1] << "\n"; + cerr << "unable to create tempdir on " << root_dir << "\n"; exit(EXIT_FAILURE); } if (!android::base::Realpath(tempdir, &gTestDir)) { From ac3ca99b77c4944333649dda4670d509f9facc05 Mon Sep 17 00:00:00 2001 From: Nick Kralevich Date: Tue, 9 Apr 2019 10:59:39 -0700 Subject: [PATCH 123/221] introduce auditctl and use it to configure SELinux throttling In an effort to ensure that our development community does not introduce new code without corresponding SELinux changes, Android closely monitors the number of SELinux denials which occur during boot. This monitoring occurs both in treehugger, as well as various dashboards. If SELinux denials are dropped during early boot, this could result in non-determinism for the various SELinux treehugger tests. Introduce /system/bin/auditctl. This tool, model after https://linux.die.net/man/8/auditctl , allows for configuring the throttling rate for the kernel auditing system. Remove any throttling from early boot. This will hopefully reduce treehugger flakiness by making denial generation more predictible during early boot. Reapply the throttling at boot complete, to avoid denial of service attacks against the auditing subsystem. Delete pre-existing unittests for logd / SELinux integration. It's intended that all throttling decisions be made in the kernel, and shouldn't be a concern of logd. Bug: 118815957 Test: Perform an operation which generates lots of SELinux denials, and count how many occur before and after the time period. (cherry picked from commit be5e44679146d333c20e28bf99c52d168f422626) Change-Id: I283cd56151d199cd66f0d217b49115460c4a01e5 --- logd/Android.bp | 18 +++++ logd/auditctl.cpp | 74 +++++++++++++++++ logd/libaudit.c | 11 ++- logd/libaudit.h | 13 ++- logd/logd.rc | 11 +++ logd/tests/logd_test.cpp | 143 --------------------------------- shell_and_utilities/Android.bp | 1 + 7 files changed, 124 insertions(+), 147 deletions(-) create mode 100644 logd/auditctl.cpp diff --git a/logd/Android.bp b/logd/Android.bp index 360f2fe53..9b8625821 100644 --- a/logd/Android.bp +++ b/logd/Android.bp @@ -80,6 +80,24 @@ cc_binary { cflags: ["-Werror"], } +cc_binary { + name: "auditctl", + + srcs: ["auditctl.cpp"], + + static_libs: [ + "liblogd", + ], + + shared_libs: ["libbase"], + + cflags: [ + "-Wall", + "-Wextra", + "-Werror", + "-Wconversion" + ], +} prebuilt_etc { name: "logtagd.rc", diff --git a/logd/auditctl.cpp b/logd/auditctl.cpp new file mode 100644 index 000000000..98bb02dbe --- /dev/null +++ b/logd/auditctl.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include +#include "libaudit.h" + +static void usage(const char* cmdline) { + fprintf(stderr, "Usage: %s [-r rate]\n", cmdline); +} + +static void do_update_rate(uint32_t rate) { + int fd = audit_open(); + if (fd == -1) { + error(EXIT_FAILURE, errno, "Unable to open audit socket"); + } + int result = audit_rate_limit(fd, rate); + close(fd); + if (result < 0) { + fprintf(stderr, "Can't update audit rate limit: %d\n", result); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char* argv[]) { + uint32_t rate = 0; + bool update_rate = false; + int opt; + + while ((opt = getopt(argc, argv, "r:")) != -1) { + switch (opt) { + case 'r': + if (!android::base::ParseUint(optarg, &rate)) { + error(EXIT_FAILURE, errno, "Invalid Rate"); + } + update_rate = true; + break; + default: /* '?' */ + usage(argv[0]); + exit(EXIT_FAILURE); + } + } + + // In the future, we may add other options to auditctl + // so this if statement will expand. + // if (!update_rate && !update_backlog && !update_whatever) ... + if (!update_rate) { + fprintf(stderr, "Nothing to do\n"); + usage(argv[0]); + exit(EXIT_FAILURE); + } + + if (update_rate) { + do_update_rate(rate); + } + + return 0; +} diff --git a/logd/libaudit.c b/logd/libaudit.c index 9d9a85742..f452c71ab 100644 --- a/logd/libaudit.c +++ b/logd/libaudit.c @@ -160,8 +160,7 @@ int audit_setup(int fd, pid_t pid) { * and the the mask set to AUDIT_STATUS_PID */ status.pid = pid; - status.mask = AUDIT_STATUS_PID | AUDIT_STATUS_RATE_LIMIT; - status.rate_limit = AUDIT_RATE_LIMIT; /* audit entries per second */ + status.mask = AUDIT_STATUS_PID; /* Let the kernel know this pid will be registering for audit events */ rc = audit_send(fd, AUDIT_SET, &status, sizeof(status)); @@ -188,6 +187,14 @@ int audit_open() { return socket(PF_NETLINK, SOCK_RAW | SOCK_CLOEXEC, NETLINK_AUDIT); } +int audit_rate_limit(int fd, uint32_t limit) { + struct audit_status status; + memset(&status, 0, sizeof(status)); + status.mask = AUDIT_STATUS_RATE_LIMIT; + status.rate_limit = limit; /* audit entries per second */ + return audit_send(fd, AUDIT_SET, &status, sizeof(status)); +} + int audit_get_reply(int fd, struct audit_message* rep, reply_t block, int peek) { ssize_t len; int flags; diff --git a/logd/libaudit.h b/logd/libaudit.h index 2a93ea361..b4a92a8a3 100644 --- a/logd/libaudit.h +++ b/logd/libaudit.h @@ -89,8 +89,17 @@ extern int audit_get_reply(int fd, struct audit_message* rep, reply_t block, */ extern int audit_setup(int fd, pid_t pid); -/* Max audit messages per second */ -#define AUDIT_RATE_LIMIT 5 +/** + * Throttle kernel messages at the provided rate + * @param fd + * The fd returned by a call to audit_open() + * @param rate + * The rate, in messages per second, above which the kernel + * should drop audit messages. + * @return + * This function returns 0 on success, -errno on error. + */ +extern int audit_rate_limit(int fd, uint32_t limit); __END_DECLS diff --git a/logd/logd.rc b/logd/logd.rc index c740ecfce..438419ad6 100644 --- a/logd/logd.rc +++ b/logd/logd.rc @@ -16,8 +16,19 @@ service logd-reinit /system/bin/logd --reinit group logd writepid /dev/cpuset/system-background/tasks +# Limit SELinux denial generation to 5/second +service logd-auditctl /system/bin/auditctl -r 5 + oneshot + disabled + user logd + group logd + capabilities AUDIT_CONTROL + on fs write /dev/event-log-tags "# content owned by logd " chown logd logd /dev/event-log-tags chmod 0644 /dev/event-log-tags + +on property:sys.boot_completed=1 + start logd-auditctl diff --git a/logd/tests/logd_test.cpp b/logd/tests/logd_test.cpp index 7d7a22f92..447b06731 100644 --- a/logd/tests/logd_test.cpp +++ b/logd/tests/logd_test.cpp @@ -39,7 +39,6 @@ #endif #include "../LogReader.h" // pickup LOGD_SNDTIMEO -#include "../libaudit.h" // pickup AUDIT_RATE_LIMIT_* #ifdef __ANDROID__ static void send_to_control(char* buf, size_t len) { @@ -1065,145 +1064,3 @@ TEST(logd, multiple_test_3) { TEST(logd, multiple_test_10) { __android_log_btwrite_multiple__helper(10); } - -#ifdef __ANDROID__ -// returns violating pid -static pid_t sepolicy_rate(unsigned rate, unsigned num) { - pid_t pid = fork(); - - if (pid) { - siginfo_t info = {}; - if (TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))) return -1; - if (info.si_status) return -1; - return pid; - } - - // We may have DAC, but let's not have MAC - if ((setcon("u:object_r:shell:s0") < 0) && (setcon("u:r:shell:s0") < 0)) { - int save_errno = errno; - security_context_t context; - getcon(&context); - if (strcmp(context, "u:r:shell:s0")) { - fprintf(stderr, "setcon(\"u:r:shell:s0\") failed @\"%s\" %s\n", - context, strerror(save_errno)); - freecon(context); - _exit(-1); - // NOTREACHED - return -1; - } - } - - // The key here is we are root, but we are in u:r:shell:s0, - // and the directory does not provide us DAC access - // (eg: 0700 system system) so we trigger the pair dac_override - // and dac_read_search on every try to get past the message - // de-duper. We will also rotate the file name in the directory - // as another measure. - static const char file[] = "/data/drm/cannot_access_directory_%u"; - static const unsigned avc_requests_per_access = 2; - - rate /= avc_requests_per_access; - useconds_t usec; - if (rate == 0) { - rate = 1; - usec = 2000000; - } else { - usec = (1000000 + (rate / 2)) / rate; - } - num = (num + (avc_requests_per_access / 2)) / avc_requests_per_access; - - if (usec < 2) usec = 2; - - while (num > 0) { - if (access(android::base::StringPrintf(file, num).c_str(), F_OK) == 0) { - _exit(-1); - // NOTREACHED - return -1; - } - usleep(usec); - --num; - } - _exit(0); - // NOTREACHED - return -1; -} - -static constexpr int background_period = 10; - -static int count_avc(pid_t pid) { - int count = 0; - - // pid=-1 skip as pid is in error - if (pid == (pid_t)-1) return count; - - // pid=0 means we want to report the background count of avc: activities - struct logger_list* logger_list = - pid ? android_logger_list_alloc( - ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, 0, pid) - : android_logger_list_alloc_time( - ANDROID_LOG_RDONLY | ANDROID_LOG_NONBLOCK, - log_time(android_log_clockid()) - - log_time(background_period, 0), - 0); - if (!logger_list) return count; - struct logger* logger = android_logger_open(logger_list, LOG_ID_EVENTS); - if (!logger) { - android_logger_list_close(logger_list); - return count; - } - for (;;) { - log_msg log_msg; - - if (android_logger_list_read(logger_list, &log_msg) <= 0) break; - - if ((log_msg.entry.pid != pid) || (log_msg.entry.len < (4 + 1 + 8)) || - (log_msg.id() != LOG_ID_EVENTS)) - continue; - - char* eventData = log_msg.msg(); - if (!eventData) continue; - - uint32_t tag = get4LE(eventData); - if (tag != AUDITD_LOG_TAG) continue; - - if (eventData[4] != EVENT_TYPE_STRING) continue; - - // int len = get4LE(eventData + 4 + 1); - log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0'; - const char* cp = strstr(eventData + 4 + 1 + 4, "): avc: denied"); - if (!cp) continue; - - ++count; - } - - android_logger_list_close(logger_list); - - return count; -} -#endif - -TEST(logd, sepolicy_rate_limiter) { -#ifdef __ANDROID__ - int background_selinux_activity_too_high = count_avc(0); - if (background_selinux_activity_too_high > 2) { - GTEST_LOG_(ERROR) << "Too much background selinux activity " - << background_selinux_activity_too_high * 60 / - background_period - << "/minute on the device, this test\n" - << "can not measure the functionality of the " - << "sepolicy rate limiter. Expect test to\n" - << "fail as this device is in a bad state, " - << "but is not strictly a unit test failure."; - } - - static const int rate = AUDIT_RATE_LIMIT; - static const int duration = 2; - // Two seconds of sustained denials. Depending on the overlap in the time - // window that the kernel is considering vs what this test is considering, - // allow some additional denials to prevent a flaky test. - EXPECT_LE(count_avc(sepolicy_rate(rate, rate * duration)), - rate * duration + rate); -#else - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif -} diff --git a/shell_and_utilities/Android.bp b/shell_and_utilities/Android.bp index f01a8c7ec..3bc3883a5 100644 --- a/shell_and_utilities/Android.bp +++ b/shell_and_utilities/Android.bp @@ -10,6 +10,7 @@ phony { phony { name: "shell_and_utilities_system", required: [ + "auditctl", "awk", "bzip2", "grep", From c4c05e3b25c4e2935f5214850b8ff3103f94dc25 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Tue, 9 Apr 2019 12:31:36 -0700 Subject: [PATCH 124/221] libmeminfo/procrank: Ignore failures when process disappears. procrank currently fails if a process gets killed while it is reading the stats. This behavior is a regression from the previous version of procrank and is often undesired. Change procrank to silently ignore the process if it detects that it had been killed while reading the stats. If the process is still around, then print a warning about it and continue to read stats for other processes in the system. Fixes: 130177765 Test: Tested by deliberately killing specific process in ProcessRecord() constructor Change-Id: I701808c3226bb9b3a350ccf8e67fb29b59b0d4e0 Merged-In: I701808c3226bb9b3a350ccf8e67fb29b59b0d4e0 Signed-off-by: Sandeep Patil --- libmeminfo/tools/procrank.cpp | 32 +++++++++++++++++++------------- 1 file changed, 19 insertions(+), 13 deletions(-) diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp index 21a684c5c..5e89254b9 100644 --- a/libmeminfo/tools/procrank.cpp +++ b/libmeminfo/tools/procrank.cpp @@ -14,11 +14,17 @@ * limitations under the License. */ +#include +#include +#include +#include #include #include #include #include #include +#include +#include #include #include #include @@ -29,14 +35,6 @@ #include #include -#include -#include -#include -#include - -#include -#include - using ::android::meminfo::MemUsage; using ::android::meminfo::ProcMemInfo; @@ -460,8 +458,16 @@ int main(int argc, char* argv[]) { auto mark_swap_usage = [&](pid_t pid) -> bool { ProcessRecord proc(pid, show_wss, pgflags, pgflags_mask); if (!proc.valid()) { - std::cerr << "Failed to create process record for: " << pid << std::endl; - return false; + // Check to see if the process is still around, skip the process if the proc + // directory is inaccessible. It was most likely killed while creating the process + // record + std::string procdir = ::android::base::StringPrintf("/proc/%d", pid); + if (access(procdir.c_str(), F_OK | R_OK)) return true; + + // Warn if we failed to gather process stats even while it is still alive. + // Return success here, so we continue to print stats for other processes. + std::cerr << "warning: failed to create process record for: " << pid << std::endl; + return true; } // Skip processes with no memory mappings @@ -479,9 +485,9 @@ int main(int argc, char* argv[]) { return true; }; - // Get a list of all pids currently running in the system in - // 1st pass through all processes. Mark each swap offset used by the process as we find them - // for calculating proportional swap usage later. + // Get a list of all pids currently running in the system in 1st pass through all processes. + // Mark each swap offset used by the process as we find them for calculating proportional + // swap usage later. if (!read_all_pids(&pids, mark_swap_usage)) { std::cerr << "Failed to read all pids from the system" << std::endl; exit(EXIT_FAILURE); From a7f6cd04700df65c9f1a6865c984b277020560e1 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 3 Apr 2019 12:56:22 -0700 Subject: [PATCH 125/221] adb: defuse CHECK on IOVector::append of an empty block. Bug: http://b/129706741 Test: treehugger Change-Id: I35a35d20d179a155adb4fe83078739fcaf517136 (cherry picked from commit 3443b774155abb2e1d8583b11a8fc87ffa64c1ef) --- adb/types.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/adb/types.h b/adb/types.h index 0090c9878..cd1366dfb 100644 --- a/adb/types.h +++ b/adb/types.h @@ -216,7 +216,10 @@ struct IOVector { // Add a nonempty block to the chain. // The end of the chain must be a complete block (i.e. end_offset_ == 0). void append(std::unique_ptr block) { - CHECK_NE(0ULL, block->size()); + if (block->size() == 0) { + return; + } + CHECK_EQ(0ULL, end_offset_); chain_length_ += block->size(); chain_.emplace_back(std::move(block)); From 7e1d397d1a0fb9397b91a636dc6a71d132e7286d Mon Sep 17 00:00:00 2001 From: Alex Buynytskyy Date: Fri, 5 Apr 2019 20:52:32 -0700 Subject: [PATCH 126/221] Binding err to inout for raw protocol for in-process execute. As raw protocol does not allow for splitting err - it has to be redirected to inout. Before this change it was not done for in-process and all err data was lost. Bug: 130086616 Test: manual + atest adbd_test Change-Id: I6cd11c940673d73e2993a6eb23c46d31bd8bf504 (cherry picked from commit 704c97d6c244093a94e0a39deb0f2265c3bf83dd) --- adb/daemon/shell_service.cpp | 15 +++-- adb/daemon/shell_service_test.cpp | 91 ++++++++++++++++++++++++------- 2 files changed, 82 insertions(+), 24 deletions(-) diff --git a/adb/daemon/shell_service.cpp b/adb/daemon/shell_service.cpp index e9d9c63fc..3c8f3939f 100644 --- a/adb/daemon/shell_service.cpp +++ b/adb/daemon/shell_service.cpp @@ -406,11 +406,16 @@ bool Subprocess::ExecInProcess(Command command, std::string* _Nonnull error) { strerror(errno)); return false; } - // Raw subprocess + shell protocol allows for splitting stderr. - if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) { - *error = android::base::StringPrintf("failed to create socketpair for stderr: %s", - strerror(errno)); - return false; + if (protocol_ == SubprocessProtocol::kShell) { + // Shell protocol allows for splitting stderr. + if (!CreateSocketpair(&stderr_sfd_, &child_stderr_sfd)) { + *error = android::base::StringPrintf("failed to create socketpair for stderr: %s", + strerror(errno)); + return false; + } + } else { + // Raw protocol doesn't support multiple output streams, so combine stdout and stderr. + child_stderr_sfd.reset(dup(child_stdinout_sfd)); } D("execinprocess: stdin/stdout FD = %d, stderr FD = %d", stdinout_sfd_.get(), diff --git a/adb/daemon/shell_service_test.cpp b/adb/daemon/shell_service_test.cpp index 323bceced..dc79d1213 100644 --- a/adb/daemon/shell_service_test.cpp +++ b/adb/daemon/shell_service_test.cpp @@ -35,7 +35,6 @@ class ShellServiceTest : public ::testing::Test { static void SetUpTestCase() { // This is normally done in main.cpp. saved_sigpipe_handler_ = signal(SIGPIPE, SIG_IGN); - } static void TearDownTestCase() { @@ -49,26 +48,32 @@ class ShellServiceTest : public ::testing::Test { SubprocessProtocol protocol); void CleanupTestSubprocess(); - virtual void TearDown() override { - void CleanupTestSubprocess(); - } + void StartTestCommandInProcess(std::string name, Command command, SubprocessProtocol protocol); + + virtual void TearDown() override { CleanupTestSubprocess(); } static sighandler_t saved_sigpipe_handler_; - unique_fd subprocess_fd_; + unique_fd command_fd_; }; sighandler_t ShellServiceTest::saved_sigpipe_handler_ = nullptr; void ShellServiceTest::StartTestSubprocess( const char* command, SubprocessType type, SubprocessProtocol protocol) { - subprocess_fd_ = StartSubprocess(command, nullptr, type, protocol); - ASSERT_TRUE(subprocess_fd_ >= 0); + command_fd_ = StartSubprocess(command, nullptr, type, protocol); + ASSERT_TRUE(command_fd_ >= 0); } void ShellServiceTest::CleanupTestSubprocess() { } +void ShellServiceTest::StartTestCommandInProcess(std::string name, Command command, + SubprocessProtocol protocol) { + command_fd_ = StartCommandInProcess(std::move(name), std::move(command), protocol); + ASSERT_TRUE(command_fd_ >= 0); +} + namespace { // Reads raw data from |fd| until it closes or errors. @@ -93,7 +98,7 @@ int ReadShellProtocol(int fd, std::string* stdout, std::string* stderr) { stdout->clear(); stderr->clear(); - ShellProtocol* protocol = new ShellProtocol(fd); + auto protocol = std::make_unique(fd); while (protocol->Read()) { switch (protocol->id()) { case ShellProtocol::kIdStdout: @@ -111,7 +116,6 @@ int ReadShellProtocol(int fd, std::string* stdout, std::string* stderr) { ADD_FAILURE() << "Unidentified packet ID: " << protocol->id(); } } - delete protocol; return exit_code; } @@ -154,7 +158,7 @@ TEST_F(ShellServiceTest, RawNoProtocolSubprocess) { // [ -t 0 ] == 0 means we have a terminal (PTY). Even when requesting a raw subprocess, without // the shell protocol we should always force a PTY to ensure proper cleanup. - ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"}); + ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"}); } // Tests a PTY subprocess with no protocol. @@ -165,7 +169,7 @@ TEST_F(ShellServiceTest, PtyNoProtocolSubprocess) { SubprocessType::kPty, SubprocessProtocol::kNone)); // [ -t 0 ] == 0 means we have a terminal (PTY). - ExpectLinesEqual(ReadRaw(subprocess_fd_), {"foo", "bar", "0"}); + ExpectLinesEqual(ReadRaw(command_fd_), {"foo", "bar", "0"}); } // Tests a raw subprocess with the shell protocol. @@ -175,7 +179,7 @@ TEST_F(ShellServiceTest, RawShellProtocolSubprocess) { SubprocessType::kRaw, SubprocessProtocol::kShell)); std::string stdout, stderr; - EXPECT_EQ(24, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); + EXPECT_EQ(24, ReadShellProtocol(command_fd_, &stdout, &stderr)); ExpectLinesEqual(stdout, {"foo", "baz"}); ExpectLinesEqual(stderr, {"bar"}); } @@ -189,7 +193,7 @@ TEST_F(ShellServiceTest, PtyShellProtocolSubprocess) { // PTY always combines stdout and stderr but the shell protocol should // still give us an exit code. std::string stdout, stderr; - EXPECT_EQ(50, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); + EXPECT_EQ(50, ReadShellProtocol(command_fd_, &stdout, &stderr)); ExpectLinesEqual(stdout, {"foo", "bar", "baz"}); ExpectLinesEqual(stderr, {}); } @@ -204,7 +208,7 @@ TEST_F(ShellServiceTest, InteractivePtySubprocess) { "echo --${TEST_STR}--", "exit"}; - ShellProtocol* protocol = new ShellProtocol(subprocess_fd_); + ShellProtocol* protocol = new ShellProtocol(command_fd_); for (std::string command : commands) { // Interactive shell requires a newline to complete each command. command.push_back('\n'); @@ -214,7 +218,7 @@ TEST_F(ShellServiceTest, InteractivePtySubprocess) { delete protocol; std::string stdout, stderr; - EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); + EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr)); // An unpredictable command prompt makes parsing exact output difficult but // it should at least contain echoed input and the expected output. for (const char* command : commands) { @@ -230,14 +234,14 @@ TEST_F(ShellServiceTest, CloseClientStdin) { SubprocessType::kRaw, SubprocessProtocol::kShell)); std::string input = "foo\nbar"; - ShellProtocol* protocol = new ShellProtocol(subprocess_fd_); + ShellProtocol* protocol = new ShellProtocol(command_fd_); memcpy(protocol->data(), input.data(), input.length()); ASSERT_TRUE(protocol->Write(ShellProtocol::kIdStdin, input.length())); ASSERT_TRUE(protocol->Write(ShellProtocol::kIdCloseStdin, 0)); delete protocol; std::string stdout, stderr; - EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); + EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr)); ExpectLinesEqual(stdout, {"foo", "barTEST_DONE"}); ExpectLinesEqual(stderr, {}); } @@ -249,7 +253,7 @@ TEST_F(ShellServiceTest, CloseStdinStdoutSubprocess) { SubprocessType::kRaw, SubprocessProtocol::kShell)); std::string stdout, stderr; - EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); + EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr)); ExpectLinesEqual(stdout, {}); ExpectLinesEqual(stderr, {"bar"}); } @@ -261,7 +265,56 @@ TEST_F(ShellServiceTest, CloseStderrSubprocess) { SubprocessType::kRaw, SubprocessProtocol::kShell)); std::string stdout, stderr; - EXPECT_EQ(0, ReadShellProtocol(subprocess_fd_, &stdout, &stderr)); + EXPECT_EQ(0, ReadShellProtocol(command_fd_, &stdout, &stderr)); ExpectLinesEqual(stdout, {"foo"}); ExpectLinesEqual(stderr, {}); } + +// Tests an inprocess command with no protocol. +TEST_F(ShellServiceTest, RawNoProtocolInprocess) { + ASSERT_NO_FATAL_FAILURE( + StartTestCommandInProcess("123", + [](auto args, auto in, auto out, auto err) -> int { + EXPECT_EQ("123", args); + char input[10]; + EXPECT_TRUE(ReadFdExactly(in, input, 2)); + input[2] = 0; + EXPECT_STREQ("in", input); + WriteFdExactly(out, "out\n"); + WriteFdExactly(err, "err\n"); + return 0; + }, + SubprocessProtocol::kNone)); + + WriteFdExactly(command_fd_, "in"); + ExpectLinesEqual(ReadRaw(command_fd_), {"out", "err"}); +} + +// Tests an inprocess command with the shell protocol. +TEST_F(ShellServiceTest, RawShellProtocolInprocess) { + ASSERT_NO_FATAL_FAILURE( + StartTestCommandInProcess("321", + [](auto args, auto in, auto out, auto err) -> int { + EXPECT_EQ("321", args); + char input[10]; + EXPECT_TRUE(ReadFdExactly(in, input, 2)); + input[2] = 0; + EXPECT_STREQ("in", input); + WriteFdExactly(out, "out\n"); + WriteFdExactly(err, "err\n"); + return 0; + }, + SubprocessProtocol::kShell)); + + { + auto write_protocol = std::make_unique(command_fd_); + memcpy(write_protocol->data(), "in", 2); + write_protocol->Write(ShellProtocol::kIdStdin, 2); + } + + std::string stdout, stderr; + // For in-process commands the exit code is always the default (1). + EXPECT_EQ(1, ReadShellProtocol(command_fd_, &stdout, &stderr)); + ExpectLinesEqual(stdout, {"out"}); + ExpectLinesEqual(stderr, {"err"}); +} From 7a4fb7a435459222b718ceb4607fb0577a7ed8a9 Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Sat, 23 Mar 2019 21:59:26 +0800 Subject: [PATCH 127/221] first-stage mount: support using other avb_keys This change allows specifying additional avb keys to verify a fstab entry. It can be used together with the original 'avb' flag. When both 'avb' and 'avb_keys' are present, it will try to use avb_keys to verify this partition and extract the AVB descriptor from the end of it first. When avb_key fails, it falls back to searching the AVB descriptor in the built-in /vbmeta (and its chained partitions) with the matched partition name. An example of a fstab file: system /system ext4 ro,barrier=1 wait,slotselect,avb=vbmeta,logical,first_stage_mount,avb_keys=/avb/gsi.avbpubkey vendor /vendor ext4 ro,barrier=1 wait,slotselect,avb,logical,first_stage_mount The overhead of adding an additional 'avb_keys' should not be significant, as the typical size of a AVB Hashtree descriptor for /system is usually less than 1000 bytes. e.g., on crosshatch, it's about 600 bytes, which takes less than 1 millisecond for the following call to return failure. auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry); We also checked the time spent on init's first stage on crosshatch, with the following CL to set ro.boottime.init.first_stage. The testing result shows no significant difference between them as well. https://android-review.googlesource.com/c/platform/system/core/+/934536 With an additional avb_keys entry for /system [ro.boottime.init.first_stage]: [728] [ro.boottime.init.first_stage]: [720] [ro.boottime.init.first_stage]: [722] Without an additional avb_keys entry for /system [ro.boottime.init.first_stage]: [730] [ro.boottime.init.first_stage]: [728] [ro.boottime.init.first_stage]: [725] Bug: 124491153 Test: boot a device with above fstab settings Change-Id: I0c81f816efb0dd40c93da2df304f2e215df9d105 Merged-In: I0c81f816efb0dd40c93da2df304f2e215df9d105 (cherry picked from commit a0f8b05d913855e3d8e9836f124fc9fdc755d450) --- init/first_stage_mount.cpp | 53 ++++++++++++++++++++++++-------------- 1 file changed, 33 insertions(+), 20 deletions(-) diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index d458924a7..3900f7246 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -80,7 +80,7 @@ class FirstStageMount { bool InitMappedDevice(const std::string& verity_device); bool InitDeviceMapper(); bool CreateLogicalPartitions(); - bool MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry, + bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts, Fstab::iterator* end = nullptr); bool MountPartitions(); @@ -437,21 +437,26 @@ bool FirstStageMount::InitMappedDevice(const std::string& dm_device) { uevent_listener_.RegenerateUeventsForPath(syspath, verity_callback); if (!found) { - LOG(INFO) << "dm-verity device not found in /sys, waiting for its uevent"; + LOG(INFO) << "dm device '" << dm_device << "' not found in /sys, waiting for its uevent"; Timer t; uevent_listener_.Poll(verity_callback, 10s); - LOG(INFO) << "wait for dm-verity device returned after " << t; + LOG(INFO) << "wait for dm device '" << dm_device << "' returned after " << t; } if (!found) { - LOG(ERROR) << "dm-verity device not found after polling timeout"; + LOG(ERROR) << "dm device '" << dm_device << "' not found after polling timeout"; return false; } return true; } -bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_used_fstab_entry, +bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts, Fstab::iterator* end) { + // Sets end to begin + 1, so we can just return on failure below. + if (end) { + *end = begin + 1; + } + if (begin->fs_mgr_flags.logical) { if (!fs_mgr_update_logical_partition(&(*begin))) { return false; @@ -477,7 +482,7 @@ bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_us mounted = (fs_mgr_do_mount_one(*current) == 0); } } - if (erase_used_fstab_entry) { + if (erase_same_mounts) { current = fstab_.erase(begin, current); } if (end) { @@ -494,7 +499,7 @@ bool FirstStageMount::TrySwitchSystemAsRoot() { return entry.mount_point == "/metadata"; }); if (metadata_partition != fstab_.end()) { - if (MountPartition(metadata_partition, true /* erase_used_fstab_entry */)) { + if (MountPartition(metadata_partition, true /* erase_same_mounts */)) { UseGsiIfPresent(); } } @@ -505,7 +510,7 @@ bool FirstStageMount::TrySwitchSystemAsRoot() { if (system_partition == fstab_.end()) return true; - if (MountPartition(system_partition, false)) { + if (MountPartition(system_partition, false /* erase_same_mounts */)) { if (gsi_not_on_userdata_ && fs_mgr_verity_is_check_at_most_once(*system_partition)) { LOG(ERROR) << "check_most_at_once forbidden on external media"; return false; @@ -560,7 +565,7 @@ bool FirstStageMount::MountPartitions() { } Fstab::iterator end; - if (!MountPartition(current, false, &end)) { + if (!MountPartition(current, false /* erase_same_mounts */, &end)) { if (current->fs_mgr_flags.no_fail) { LOG(INFO) << "Failed to mount " << current->mount_point << ", ignoring mount for no_fail partition"; @@ -797,11 +802,9 @@ bool FirstStageMountVBootV2::GetDmVerityDevices() { bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) { AvbHashtreeResult hashtree_result; - if (fstab_entry->fs_mgr_flags.avb) { - if (!InitAvbHandle()) return false; - hashtree_result = - avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */); - } else if (!fstab_entry->avb_keys.empty()) { + // It's possible for a fstab_entry to have both avb_keys and avb flag. + // In this case, try avb_keys first, then fallback to avb flag. + if (!fstab_entry->avb_keys.empty()) { if (!InitAvbHandle()) return false; // Checks if hashtree should be disabled from the top-level /vbmeta. if (avb_handle_->status() == AvbHandleStatus::kHashtreeDisabled || @@ -813,14 +816,24 @@ bool FirstStageMountVBootV2::SetUpDmVerity(FstabEntry* fstab_entry) { auto avb_standalone_handle = AvbHandle::LoadAndVerifyVbmeta(*fstab_entry); if (!avb_standalone_handle) { LOG(ERROR) << "Failed to load offline vbmeta for " << fstab_entry->mount_point; - return false; + // Fallbacks to built-in hashtree if fs_mgr_flags.avb is set. + if (!fstab_entry->fs_mgr_flags.avb) return false; + LOG(INFO) << "Fallback to built-in hashtree for " << fstab_entry->mount_point; + hashtree_result = + avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */); + } else { + // Sets up hashtree via the standalone handle. + if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) { + return false; + } + hashtree_result = avb_standalone_handle->SetUpAvbHashtree( + fstab_entry, false /* wait_for_verity_dev */); } - if (IsStandaloneImageRollback(*avb_handle_, *avb_standalone_handle, *fstab_entry)) { - return false; - } - hashtree_result = avb_standalone_handle->SetUpAvbHashtree( - fstab_entry, false /* wait_for_verity_dev */); } + } else if (fstab_entry->fs_mgr_flags.avb) { + if (!InitAvbHandle()) return false; + hashtree_result = + avb_handle_->SetUpAvbHashtree(fstab_entry, false /* wait_for_verity_dev */); } else { return true; // No need AVB, returns true to mount the partition directly. } From 6732aa1659a6fbff0668687a176e09b5877006df Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Wed, 10 Apr 2019 17:38:06 +0800 Subject: [PATCH 128/221] avb_ops: support reading from a logical partition On some devices (e.g., emulator), init needs to read AVB footer from a logical partition because: 1) Dynamic/logical partition is enabled 2) The partition is AVB chained, i.e., need to locate footer from the end 3) Logical partition is not understandable by bootloader, but there is no bootloader in this case Bug: 125540538 Bug: 128434470 Test: boot and force the fallback path, to check it can get logical path Change-Id: Ie304bce234cbf0f938f386f7ce59235c851e0e2d Merged-In: Ie304bce234cbf0f938f386f7ce59235c851e0e2d (cherry picked from commit 84d4933686b332944978402f4f1595b53b3e886d) --- fs_mgr/libfs_avb/avb_ops.cpp | 58 ++++++++++++++++++++++++++++++++++-- fs_mgr/libfs_avb/avb_ops.h | 3 ++ 2 files changed, 59 insertions(+), 2 deletions(-) diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp index 6a3e2c026..c192bf572 100644 --- a/fs_mgr/libfs_avb/avb_ops.cpp +++ b/fs_mgr/libfs_avb/avb_ops.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include "util.h" @@ -104,6 +105,20 @@ static AvbIOResult dummy_get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED, return AVB_IO_RESULT_OK; } +// Converts a partition name (with ab_suffix) to the corresponding mount point. +// e.g., "system_a" => "/system", +// e.g., "vendor_a" => "/vendor", +static std::string DeriveMountPoint(const std::string& partition_name) { + const std::string ab_suffix = fs_mgr_get_slot_suffix(); + std::string mount_point(partition_name); + auto found = partition_name.rfind(ab_suffix); + if (found != std::string::npos) { + mount_point.erase(found); // converts system_a => system + } + + return "/" + mount_point; +} + FsManagerAvbOps::FsManagerAvbOps() { // We only need to provide the implementation of read_from_partition() // operation since that's all what is being used by the avb_slot_verify(). @@ -122,14 +137,53 @@ FsManagerAvbOps::FsManagerAvbOps() { avb_ops_.user_data = this; } +// Given a partition name (with ab_suffix), e.g., system_a, returns the corresponding +// dm-linear path for it. e.g., /dev/block/dm-0. If not found, returns an empty string. +// This assumes that the prefix of the partition name and the mount point are the same. +// e.g., partition vendor_a is mounted under /vendor, product_a is mounted under /product, etc. +// This might not be true for some special fstab files, e.g., fstab.postinstall. +// But it's good enough for the default fstab. Also note that the logical path is a +// fallback solution when the physical path (/dev/block/by-name/) cannot be found. +std::string FsManagerAvbOps::GetLogicalPath(const std::string& partition_name) { + if (fstab_.empty() && !ReadDefaultFstab(&fstab_)) { + return ""; + } + + const auto mount_point = DeriveMountPoint(partition_name); + if (mount_point.empty()) return ""; + + auto fstab_entry = GetEntryForMountPoint(&fstab_, mount_point); + if (!fstab_entry) return ""; + + std::string device_path; + if (fstab_entry->fs_mgr_flags.logical) { + dm::DeviceMapper& dm = dm::DeviceMapper::Instance(); + if (!dm.GetDmDevicePathByName(fstab_entry->blk_device, &device_path)) { + LERROR << "Failed to resolve logical device path for: " << fstab_entry->blk_device; + return ""; + } + return device_path; + } + + return ""; +} + AvbIOResult FsManagerAvbOps::ReadFromPartition(const char* partition, int64_t offset, size_t num_bytes, void* buffer, size_t* out_num_read) { - const std::string path = "/dev/block/by-name/"s + partition; + std::string path = "/dev/block/by-name/"s + partition; // Ensures the device path (a symlink created by init) is ready to access. if (!WaitForFile(path, 1s)) { - return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + LERROR << "Device path not found: " << path; + // Falls back to logical path if the physical path is not found. + // This mostly only works for emulator (no bootloader). Because in normal + // device, bootloader is unable to read logical partitions. So if libavb in + // the bootloader failed to read a physical partition, it will failed to boot + // the HLOS and we won't reach the code here. + path = GetLogicalPath(partition); + if (path.empty() || !WaitForFile(path, 1s)) return AVB_IO_RESULT_ERROR_NO_SUCH_PARTITION; + LINFO << "Fallback to use logical device path: " << path; } android::base::unique_fd fd(TEMP_FAILURE_RETRY(open(path.c_str(), O_RDONLY | O_CLOEXEC))); diff --git a/fs_mgr/libfs_avb/avb_ops.h b/fs_mgr/libfs_avb/avb_ops.h index a849d94ff..b39812df6 100644 --- a/fs_mgr/libfs_avb/avb_ops.h +++ b/fs_mgr/libfs_avb/avb_ops.h @@ -28,6 +28,7 @@ #include #include +#include #include namespace android { @@ -60,7 +61,9 @@ class FsManagerAvbOps { std::vector* out_vbmeta_images); private: + std::string GetLogicalPath(const std::string& partition_name); AvbOps avb_ops_; + Fstab fstab_; }; } // namespace fs_mgr From e5c4d62ba3fca09fed86ec605542b2be74a59851 Mon Sep 17 00:00:00 2001 From: David Srbecky Date: Fri, 5 Apr 2019 18:23:32 +0000 Subject: [PATCH 129/221] Revert "Check for data races when reading JIT/DEX entries." This reverts commit 85b5fecec920208ec43b42488f08d4c2e5aaeda2. Reason for revert: Breaks ART tests, reverting to investigate. Exempt-From-Owner-Approval: Revert. (cherry picked from commit b9cc4fbb268652744c812415cb2e5d1fbe04879a) Bug: 130406806 Change-Id: I634e37060b97484d627fc544e3b406fd90aaa784 --- debuggerd/crash_dump.cpp | 3 +- debuggerd/handler/debuggerd_fallback.cpp | 7 +- debuggerd/libdebuggerd/tombstone.cpp | 3 +- libbacktrace/UnwindStack.cpp | 11 + libbacktrace/UnwindStackMap.cpp | 7 + libbacktrace/UnwindStackMap.h | 14 + libunwindstack/Android.bp | 3 + libunwindstack/DexFile.cpp | 23 +- libunwindstack/DexFile.h | 7 +- libunwindstack/DexFiles.cpp | 179 ++++++++ libunwindstack/Elf.cpp | 18 - libunwindstack/ElfInterface.cpp | 36 +- libunwindstack/JitDebug.cpp | 428 ++++++------------ libunwindstack/Unwinder.cpp | 57 ++- libunwindstack/include/unwindstack/DexFiles.h | 79 ++++ libunwindstack/include/unwindstack/Elf.h | 2 - .../include/unwindstack/ElfInterface.h | 5 - libunwindstack/include/unwindstack/JitDebug.h | 41 +- libunwindstack/include/unwindstack/Unwinder.h | 34 +- libunwindstack/tests/DexFileTest.cpp | 8 +- libunwindstack/tests/DexFilesTest.cpp | 154 +++---- libunwindstack/tests/JitDebugTest.cpp | 95 ++-- libunwindstack/tests/UnwindOfflineTest.cpp | 8 + libunwindstack/tests/UnwindTest.cpp | 6 +- libunwindstack/tools/unwind.cpp | 3 +- libunwindstack/tools/unwind_for_offline.cpp | 2 +- 26 files changed, 663 insertions(+), 570 deletions(-) create mode 100644 libunwindstack/DexFiles.cpp create mode 100644 libunwindstack/include/unwindstack/DexFiles.h diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 437450c05..82ba0a18e 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -48,6 +48,7 @@ #define ATRACE_TAG ATRACE_TAG_BIONIC #include +#include #include #include #include @@ -566,7 +567,7 @@ int main(int argc, char** argv) { // TODO: Use seccomp to lock ourselves down. unwindstack::UnwinderFromPid unwinder(256, vm_pid); - if (!unwinder.Init()) { + if (!unwinder.Init(unwindstack::Regs::CurrentArch())) { LOG(FATAL) << "Failed to init unwinder object."; } diff --git a/debuggerd/handler/debuggerd_fallback.cpp b/debuggerd/handler/debuggerd_fallback.cpp index 5f7ebc34c..bbec612a8 100644 --- a/debuggerd/handler/debuggerd_fallback.cpp +++ b/debuggerd/handler/debuggerd_fallback.cpp @@ -42,6 +42,7 @@ #include #include #include +#include #include #include #include @@ -80,12 +81,12 @@ static void debuggerd_fallback_trace(int output_fd, ucontext_t* ucontext) { thread.pid = getpid(); thread.tid = gettid(); thread.thread_name = get_thread_name(gettid()); - thread.registers.reset( - unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); + unwindstack::ArchEnum arch = unwindstack::Regs::CurrentArch(); + thread.registers.reset(unwindstack::Regs::CreateFromUcontext(arch, ucontext)); // TODO: Create this once and store it in a global? unwindstack::UnwinderFromPid unwinder(kMaxFrames, getpid()); - if (unwinder.Init()) { + if (unwinder.Init(arch)) { dump_backtrace_thread(output_fd, &unwinder, thread); } else { async_safe_format_log(ANDROID_LOG_ERROR, "libc", "Unable to init unwinder."); diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index 4c1d63317..cc337ed30 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -45,6 +45,7 @@ #include #include #include +#include #include #include #include @@ -650,7 +651,7 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si }; unwindstack::UnwinderFromPid unwinder(kMaxFrames, pid); - if (!unwinder.Init()) { + if (!unwinder.Init(unwindstack::Regs::CurrentArch())) { LOG(FATAL) << "Failed to init unwinder object."; } diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index ff19833a4..f5f9b2ada 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -32,6 +32,9 @@ #include #include +#if !defined(NO_LIBDEXFILE_SUPPORT) +#include +#endif #include #include "BacktraceLog.h" @@ -47,6 +50,14 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, regs, stack_map->process_memory()); unwinder.SetResolveNames(stack_map->ResolveNames()); stack_map->SetArch(regs->Arch()); + if (stack_map->GetJitDebug() != nullptr) { + unwinder.SetJitDebug(stack_map->GetJitDebug(), regs->Arch()); + } +#if !defined(NO_LIBDEXFILE_SUPPORT) + if (stack_map->GetDexFiles() != nullptr) { + unwinder.SetDexFiles(stack_map->GetDexFiles(), regs->Arch()); + } +#endif unwinder.Unwind(skip_names, &stack_map->GetSuffixesToIgnore()); if (error != nullptr) { switch (unwinder.LastErrorCode()) { diff --git a/libbacktrace/UnwindStackMap.cpp b/libbacktrace/UnwindStackMap.cpp index 726fdfa04..4518891c3 100644 --- a/libbacktrace/UnwindStackMap.cpp +++ b/libbacktrace/UnwindStackMap.cpp @@ -43,6 +43,13 @@ bool UnwindStackMap::Build() { // Create the process memory object. process_memory_ = unwindstack::Memory::CreateProcessMemory(pid_); + // Create a JitDebug object for getting jit unwind information. + std::vector search_libs_{"libart.so", "libartd.so"}; + jit_debug_.reset(new unwindstack::JitDebug(process_memory_, search_libs_)); +#if !defined(NO_LIBDEXFILE_SUPPORT) + dex_files_.reset(new unwindstack::DexFiles(process_memory_, search_libs_)); +#endif + if (!stack_maps_->Parse()) { return false; } diff --git a/libbacktrace/UnwindStackMap.h b/libbacktrace/UnwindStackMap.h index 9bb970915..e19b60565 100644 --- a/libbacktrace/UnwindStackMap.h +++ b/libbacktrace/UnwindStackMap.h @@ -27,6 +27,9 @@ #include #include +#if !defined(NO_LIBDEXFILE_SUPPORT) +#include +#endif #include #include #include @@ -50,6 +53,12 @@ class UnwindStackMap : public BacktraceMap { const std::shared_ptr& process_memory() { return process_memory_; } + unwindstack::JitDebug* GetJitDebug() { return jit_debug_.get(); } + +#if !defined(NO_LIBDEXFILE_SUPPORT) + unwindstack::DexFiles* GetDexFiles() { return dex_files_.get(); } +#endif + void SetArch(unwindstack::ArchEnum arch) { arch_ = arch; } protected: @@ -57,6 +66,11 @@ class UnwindStackMap : public BacktraceMap { std::unique_ptr stack_maps_; std::shared_ptr process_memory_; + std::unique_ptr jit_debug_; +#if !defined(NO_LIBDEXFILE_SUPPORT) + std::unique_ptr dex_files_; +#endif + unwindstack::ArchEnum arch_ = unwindstack::ARCH_UNKNOWN; }; diff --git a/libunwindstack/Android.bp b/libunwindstack/Android.bp index ce2510821..b7650a178 100644 --- a/libunwindstack/Android.bp +++ b/libunwindstack/Android.bp @@ -49,6 +49,7 @@ cc_library { srcs: [ "ArmExidx.cpp", "DexFile.cpp", + "DexFiles.cpp", "DwarfCfa.cpp", "DwarfEhFrameWithHdr.cpp", "DwarfMemory.cpp", @@ -91,6 +92,7 @@ cc_library { cflags: ["-DNO_LIBDEXFILE_SUPPORT"], exclude_srcs: [ "DexFile.cpp", + "DexFiles.cpp", ], exclude_shared_libs: [ "libdexfile_support", @@ -100,6 +102,7 @@ cc_library { cflags: ["-DNO_LIBDEXFILE_SUPPORT"], exclude_srcs: [ "DexFile.cpp", + "DexFiles.cpp", ], exclude_shared_libs: [ "libdexfile_support", diff --git a/libunwindstack/DexFile.cpp b/libunwindstack/DexFile.cpp index d8d5a24de..eaf867fd0 100644 --- a/libunwindstack/DexFile.cpp +++ b/libunwindstack/DexFile.cpp @@ -35,31 +35,22 @@ namespace unwindstack { std::unique_ptr DexFile::Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info) { if (!info->name.empty()) { - std::unique_ptr dex_file_from_file = + std::unique_ptr dex_file = DexFileFromFile::Create(dex_file_offset_in_memory - info->start + info->offset, info->name); - if (dex_file_from_file) { - dex_file_from_file->addr_ = dex_file_offset_in_memory; - return dex_file_from_file; + if (dex_file) { + return dex_file; } } - std::unique_ptr dex_file_from_memory = - DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name); - if (dex_file_from_memory) { - dex_file_from_memory->addr_ = dex_file_offset_in_memory; - return dex_file_from_memory; - } - return nullptr; + return DexFileFromMemory::Create(dex_file_offset_in_memory, memory, info->name); } -bool DexFile::GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset) { - uint64_t dex_offset = dex_pc - addr_; +bool DexFile::GetMethodInformation(uint64_t dex_offset, std::string* method_name, + uint64_t* method_offset) { art_api::dex::MethodInfo method_info = GetMethodInfoForOffset(dex_offset, false); if (method_info.offset == 0) { return false; } - if (method_name != nullptr) { - *method_name = method_info.name; - } + *method_name = method_info.name; *method_offset = dex_offset - method_info.offset; return true; } diff --git a/libunwindstack/DexFile.h b/libunwindstack/DexFile.h index 1448a4b56..ca658e688 100644 --- a/libunwindstack/DexFile.h +++ b/libunwindstack/DexFile.h @@ -29,22 +29,17 @@ namespace unwindstack { -class Memory; -struct MapInfo; - class DexFile : protected art_api::dex::DexFile { public: virtual ~DexFile() = default; - bool GetFunctionName(uint64_t dex_pc, std::string* method_name, uint64_t* method_offset); + bool GetMethodInformation(uint64_t dex_offset, std::string* method_name, uint64_t* method_offset); static std::unique_ptr Create(uint64_t dex_file_offset_in_memory, Memory* memory, MapInfo* info); protected: DexFile(art_api::dex::DexFile&& art_dex_file) : art_api::dex::DexFile(std::move(art_dex_file)) {} - - uint64_t addr_ = 0; }; class DexFileFromFile : public DexFile { diff --git a/libunwindstack/DexFiles.cpp b/libunwindstack/DexFiles.cpp new file mode 100644 index 000000000..63a77e50f --- /dev/null +++ b/libunwindstack/DexFiles.cpp @@ -0,0 +1,179 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "DexFile.h" + +namespace unwindstack { + +struct DEXFileEntry32 { + uint32_t next; + uint32_t prev; + uint32_t dex_file; +}; + +struct DEXFileEntry64 { + uint64_t next; + uint64_t prev; + uint64_t dex_file; +}; + +DexFiles::DexFiles(std::shared_ptr& memory) : Global(memory) {} + +DexFiles::DexFiles(std::shared_ptr& memory, std::vector& search_libs) + : Global(memory, search_libs) {} + +DexFiles::~DexFiles() {} + +void DexFiles::ProcessArch() { + switch (arch()) { + case ARCH_ARM: + case ARCH_MIPS: + case ARCH_X86: + read_entry_ptr_func_ = &DexFiles::ReadEntryPtr32; + read_entry_func_ = &DexFiles::ReadEntry32; + break; + + case ARCH_ARM64: + case ARCH_MIPS64: + case ARCH_X86_64: + read_entry_ptr_func_ = &DexFiles::ReadEntryPtr64; + read_entry_func_ = &DexFiles::ReadEntry64; + break; + + case ARCH_UNKNOWN: + abort(); + } +} + +uint64_t DexFiles::ReadEntryPtr32(uint64_t addr) { + uint32_t entry; + const uint32_t field_offset = 12; // offset of first_entry_ in the descriptor struct. + if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) { + return 0; + } + return entry; +} + +uint64_t DexFiles::ReadEntryPtr64(uint64_t addr) { + uint64_t entry; + const uint32_t field_offset = 16; // offset of first_entry_ in the descriptor struct. + if (!memory_->ReadFully(addr + field_offset, &entry, sizeof(entry))) { + return 0; + } + return entry; +} + +bool DexFiles::ReadEntry32() { + DEXFileEntry32 entry; + if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { + entry_addr_ = 0; + return false; + } + + addrs_.push_back(entry.dex_file); + entry_addr_ = entry.next; + return true; +} + +bool DexFiles::ReadEntry64() { + DEXFileEntry64 entry; + if (!memory_->ReadFully(entry_addr_, &entry, sizeof(entry)) || entry.dex_file == 0) { + entry_addr_ = 0; + return false; + } + + addrs_.push_back(entry.dex_file); + entry_addr_ = entry.next; + return true; +} + +bool DexFiles::ReadVariableData(uint64_t ptr_offset) { + entry_addr_ = (this->*read_entry_ptr_func_)(ptr_offset); + return entry_addr_ != 0; +} + +void DexFiles::Init(Maps* maps) { + if (initialized_) { + return; + } + initialized_ = true; + entry_addr_ = 0; + + FindAndReadVariable(maps, "__dex_debug_descriptor"); +} + +DexFile* DexFiles::GetDexFile(uint64_t dex_file_offset, MapInfo* info) { + // Lock while processing the data. + DexFile* dex_file; + auto entry = files_.find(dex_file_offset); + if (entry == files_.end()) { + std::unique_ptr new_dex_file = DexFile::Create(dex_file_offset, memory_.get(), info); + dex_file = new_dex_file.get(); + files_[dex_file_offset] = std::move(new_dex_file); + } else { + dex_file = entry->second.get(); + } + return dex_file; +} + +bool DexFiles::GetAddr(size_t index, uint64_t* addr) { + if (index < addrs_.size()) { + *addr = addrs_[index]; + return true; + } + if (entry_addr_ != 0 && (this->*read_entry_func_)()) { + *addr = addrs_.back(); + return true; + } + return false; +} + +void DexFiles::GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, + std::string* method_name, uint64_t* method_offset) { + std::lock_guard guard(lock_); + if (!initialized_) { + Init(maps); + } + + size_t index = 0; + uint64_t addr; + while (GetAddr(index++, &addr)) { + if (addr < info->start || addr >= info->end) { + continue; + } + + DexFile* dex_file = GetDexFile(addr, info); + if (dex_file != nullptr && + dex_file->GetMethodInformation(dex_pc - addr, method_name, method_offset)) { + break; + } + } +} + +} // namespace unwindstack diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index 5b402ed13..4b93abb43 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp @@ -243,24 +243,6 @@ bool Elf::IsValidPc(uint64_t pc) { return false; } -bool Elf::GetTextRange(uint64_t* addr, uint64_t* size) { - if (!valid_) { - return false; - } - - if (interface_->GetTextRange(addr, size)) { - *addr += load_bias_; - return true; - } - - if (gnu_debugdata_interface_ != nullptr && gnu_debugdata_interface_->GetTextRange(addr, size)) { - *addr += load_bias_; - return true; - } - - return false; -} - ElfInterface* Elf::CreateInterfaceFromMemory(Memory* memory) { if (!IsValidElf(memory)) { return nullptr; diff --git a/libunwindstack/ElfInterface.cpp b/libunwindstack/ElfInterface.cpp index 32c637f85..dee8eb36a 100644 --- a/libunwindstack/ElfInterface.cpp +++ b/libunwindstack/ElfInterface.cpp @@ -69,15 +69,6 @@ bool ElfInterface::IsValidPc(uint64_t pc) { return false; } -bool ElfInterface::GetTextRange(uint64_t* addr, uint64_t* size) { - if (text_size_ != 0) { - *addr = text_addr_; - *size = text_size_; - return true; - } - return false; -} - Memory* ElfInterface::CreateGnuDebugdataMemory() { if (gnu_debugdata_offset_ == 0 || gnu_debugdata_size_ == 0) { return nullptr; @@ -339,26 +330,29 @@ void ElfInterface::ReadSectionHeaders(const EhdrType& ehdr) { } symbols_.push_back(new Symbols(shdr.sh_offset, shdr.sh_size, shdr.sh_entsize, str_shdr.sh_offset, str_shdr.sh_size)); - } else if (shdr.sh_type == SHT_PROGBITS || shdr.sh_type == SHT_NOBITS) { + } else if (shdr.sh_type == SHT_PROGBITS && sec_size != 0) { // Look for the .debug_frame and .gnu_debugdata. if (shdr.sh_name < sec_size) { std::string name; if (memory_->ReadString(sec_offset + shdr.sh_name, &name)) { + uint64_t* offset_ptr = nullptr; + uint64_t* size_ptr = nullptr; if (name == ".debug_frame") { - debug_frame_offset_ = shdr.sh_offset; - debug_frame_size_ = shdr.sh_size; + offset_ptr = &debug_frame_offset_; + size_ptr = &debug_frame_size_; } else if (name == ".gnu_debugdata") { - gnu_debugdata_offset_ = shdr.sh_offset; - gnu_debugdata_size_ = shdr.sh_size; + offset_ptr = &gnu_debugdata_offset_; + size_ptr = &gnu_debugdata_size_; } else if (name == ".eh_frame") { - eh_frame_offset_ = shdr.sh_offset; - eh_frame_size_ = shdr.sh_size; + offset_ptr = &eh_frame_offset_; + size_ptr = &eh_frame_size_; } else if (eh_frame_hdr_offset_ == 0 && name == ".eh_frame_hdr") { - eh_frame_hdr_offset_ = shdr.sh_offset; - eh_frame_hdr_size_ = shdr.sh_size; - } else if (name == ".text") { - text_addr_ = shdr.sh_addr; - text_size_ = shdr.sh_size; + offset_ptr = &eh_frame_hdr_offset_; + size_ptr = &eh_frame_hdr_size_; + } + if (offset_ptr != nullptr) { + *offset_ptr = shdr.sh_offset; + *size_ptr = shdr.sh_size; } } } diff --git a/libunwindstack/JitDebug.cpp b/libunwindstack/JitDebug.cpp index 71665a135..20bc4b902 100644 --- a/libunwindstack/JitDebug.cpp +++ b/libunwindstack/JitDebug.cpp @@ -16,13 +16,8 @@ #include #include -#include -#include -#include -#include #include -#include #include #include @@ -30,334 +25,197 @@ #include #include -#if !defined(NO_LIBDEXFILE_SUPPORT) -#include -#endif - // This implements the JIT Compilation Interface. // See https://sourceware.org/gdb/onlinedocs/gdb/JIT-Interface.html namespace unwindstack { -// 32-bit platforms may differ in alignment of uint64_t. -struct Uint64_P { - uint64_t value; +struct JITCodeEntry32Pack { + uint32_t next; + uint32_t prev; + uint32_t symfile_addr; + uint64_t symfile_size; } __attribute__((packed)); -struct Uint64_A { - uint64_t value; -} __attribute__((aligned(8))); -// Wrapper around other memory object which protects us against data races. -// It will check seqlock after every read, and fail if the seqlock changed. -// This ensues that the read memory has not been partially modified. -struct JitMemory : public Memory { - size_t Read(uint64_t addr, void* dst, size_t size) override; - - Memory* parent_ = nullptr; - uint64_t seqlock_addr_ = 0; - uint32_t expected_seqlock_ = 0; - bool failed_due_to_race_ = false; +struct JITCodeEntry32Pad { + uint32_t next; + uint32_t prev; + uint32_t symfile_addr; + uint32_t pad; + uint64_t symfile_size; }; -template -struct JitCacheEntry { - // PC memory range described by this entry. - uint64_t addr_ = 0; - uint64_t size_ = 0; - std::unique_ptr symfile_; - - bool Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t size); +struct JITCodeEntry64 { + uint64_t next; + uint64_t prev; + uint64_t symfile_addr; + uint64_t symfile_size; }; -template -class JitDebugImpl : public JitDebug, public Global { - public: - static constexpr const char* kDescriptorExtMagic = "Android1"; - static constexpr int kMaxRaceRetries = 16; +struct JITDescriptorHeader { + uint32_t version; + uint32_t action_flag; +}; - struct JITCodeEntry { - PointerT next; - PointerT prev; - PointerT symfile_addr; - Uint64_T symfile_size; - }; +struct JITDescriptor32 { + JITDescriptorHeader header; + uint32_t relevant_entry; + uint32_t first_entry; +}; - struct JITDescriptor { - uint32_t version; - uint32_t action_flag; - PointerT relevant_entry; - PointerT first_entry; - }; +struct JITDescriptor64 { + JITDescriptorHeader header; + uint64_t relevant_entry; + uint64_t first_entry; +}; - // Android-specific extensions. - struct JITDescriptorExt { - JITDescriptor desc; - uint8_t magic[8]; - uint32_t flags; - uint32_t sizeof_descriptor; - uint32_t sizeof_entry; - uint32_t action_seqlock; - uint64_t action_timestamp; - }; +JitDebug::JitDebug(std::shared_ptr& memory) : Global(memory) {} - JitDebugImpl(ArchEnum arch, std::shared_ptr& memory, - std::vector& search_libs) - : Global(memory, search_libs) { - SetArch(arch); +JitDebug::JitDebug(std::shared_ptr& memory, std::vector& search_libs) + : Global(memory, search_libs) {} + +JitDebug::~JitDebug() { + for (auto* elf : elf_list_) { + delete elf; + } +} + +uint64_t JitDebug::ReadDescriptor32(uint64_t addr) { + JITDescriptor32 desc; + if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { + return 0; } - Symfile* Get(Maps* maps, uint64_t pc) override; - virtual bool ReadVariableData(uint64_t offset); - virtual void ProcessArch() {} - bool Update(Maps* maps); - bool Read(Maps* maps, JitMemory* memory); + if (desc.header.version != 1 || desc.first_entry == 0) { + // Either unknown version, or no jit entries. + return 0; + } - bool initialized_ = false; - uint64_t descriptor_addr_ = 0; // Non-zero if we have found (non-empty) descriptor. - uint64_t seqlock_addr_ = 0; // Re-read entries if the value at this address changes. - uint32_t last_seqlock_ = ~0u; // The value of seqlock when we last read the entries. + return desc.first_entry; +} - std::deque> entries_; +uint64_t JitDebug::ReadDescriptor64(uint64_t addr) { + JITDescriptor64 desc; + if (!memory_->ReadFully(addr, &desc, sizeof(desc))) { + return 0; + } - std::mutex lock_; -}; + if (desc.header.version != 1 || desc.first_entry == 0) { + // Either unknown version, or no jit entries. + return 0; + } -template -std::unique_ptr> JitDebug::Create(ArchEnum arch, - std::shared_ptr& memory, - std::vector search_libs) { - typedef JitDebugImpl JitDebugImpl32P; - typedef JitDebugImpl JitDebugImpl32A; - typedef JitDebugImpl JitDebugImpl64A; - switch (arch) { + return desc.first_entry; +} + +uint64_t JitDebug::ReadEntry32Pack(uint64_t* start, uint64_t* size) { + JITCodeEntry32Pack code; + if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { + return 0; + } + + *start = code.symfile_addr; + *size = code.symfile_size; + return code.next; +} + +uint64_t JitDebug::ReadEntry32Pad(uint64_t* start, uint64_t* size) { + JITCodeEntry32Pad code; + if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { + return 0; + } + + *start = code.symfile_addr; + *size = code.symfile_size; + return code.next; +} + +uint64_t JitDebug::ReadEntry64(uint64_t* start, uint64_t* size) { + JITCodeEntry64 code; + if (!memory_->ReadFully(entry_addr_, &code, sizeof(code))) { + return 0; + } + + *start = code.symfile_addr; + *size = code.symfile_size; + return code.next; +} + +void JitDebug::ProcessArch() { + switch (arch()) { case ARCH_X86: - static_assert(sizeof(typename JitDebugImpl32P::JITCodeEntry) == 20, "layout"); - static_assert(sizeof(typename JitDebugImpl32P::JITDescriptor) == 16, "layout"); - static_assert(sizeof(typename JitDebugImpl32P::JITDescriptorExt) == 48, "layout"); - return std::unique_ptr(new JitDebugImpl32P(arch, memory, search_libs)); + read_descriptor_func_ = &JitDebug::ReadDescriptor32; + read_entry_func_ = &JitDebug::ReadEntry32Pack; break; + case ARCH_ARM: case ARCH_MIPS: - static_assert(sizeof(typename JitDebugImpl32A::JITCodeEntry) == 24, "layout"); - static_assert(sizeof(typename JitDebugImpl32A::JITDescriptor) == 16, "layout"); - static_assert(sizeof(typename JitDebugImpl32A::JITDescriptorExt) == 48, "layout"); - return std::unique_ptr(new JitDebugImpl32A(arch, memory, search_libs)); + read_descriptor_func_ = &JitDebug::ReadDescriptor32; + read_entry_func_ = &JitDebug::ReadEntry32Pad; break; + case ARCH_ARM64: case ARCH_X86_64: case ARCH_MIPS64: - static_assert(sizeof(typename JitDebugImpl64A::JITCodeEntry) == 32, "layout"); - static_assert(sizeof(typename JitDebugImpl64A::JITDescriptor) == 24, "layout"); - static_assert(sizeof(typename JitDebugImpl64A::JITDescriptorExt) == 56, "layout"); - return std::unique_ptr(new JitDebugImpl64A(arch, memory, search_libs)); + read_descriptor_func_ = &JitDebug::ReadDescriptor64; + read_entry_func_ = &JitDebug::ReadEntry64; break; - default: + case ARCH_UNKNOWN: abort(); } } -size_t JitMemory::Read(uint64_t addr, void* dst, size_t size) { - if (!parent_->ReadFully(addr, dst, size)) { - return 0; - } - // This is required for memory synchronization if the we are working with local memory. - // For other types of memory (e.g. remote) this is no-op and has no significant effect. - std::atomic_thread_fence(std::memory_order_acquire); - uint32_t seen_seqlock; - if (!parent_->Read32(seqlock_addr_, &seen_seqlock)) { - return 0; - } - if (seen_seqlock != expected_seqlock_) { - failed_due_to_race_ = true; - return 0; - } - return size; +bool JitDebug::ReadVariableData(uint64_t ptr) { + entry_addr_ = (this->*read_descriptor_func_)(ptr); + return entry_addr_ != 0; } -template -bool JitDebugImpl::ReadVariableData(uint64_t addr) { - JITDescriptor desc; - if (!this->memory_->ReadFully(addr, &desc, sizeof(desc))) { - return false; +void JitDebug::Init(Maps* maps) { + if (initialized_) { + return; } - if (desc.version != 1) { - return false; - } - if (desc.first_entry == 0) { - return false; // There could be multiple descriptors. Ignore empty ones. - } - descriptor_addr_ = addr; - JITDescriptorExt desc_ext; - if (this->memory_->ReadFully(addr, &desc_ext, sizeof(desc_ext)) && - memcmp(desc_ext.magic, kDescriptorExtMagic, 8) == 0) { - seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptorExt, action_seqlock); - } else { - // In the absence of Android-specific fields, use the head pointer instead. - seqlock_addr_ = descriptor_addr_ + offsetof(JITDescriptor, first_entry); - } - return true; + // Regardless of what happens below, consider the init finished. + initialized_ = true; + + FindAndReadVariable(maps, "__jit_debug_descriptor"); } -template -static const char* GetDescriptorName(); - -template <> -const char* GetDescriptorName() { - return "__jit_debug_descriptor"; -} - -template -Symfile* JitDebugImpl::Get(Maps* maps, uint64_t pc) { +Elf* JitDebug::GetElf(Maps* maps, uint64_t pc) { + // Use a single lock, this object should be used so infrequently that + // a fine grain lock is unnecessary. std::lock_guard guard(lock_); if (!initialized_) { - FindAndReadVariable(maps, GetDescriptorName()); - initialized_ = true; + Init(maps); } - if (descriptor_addr_ == 0) { - return nullptr; - } - - if (!Update(maps)) { - return nullptr; - } - - Symfile* fallback = nullptr; - for (auto& entry : entries_) { - // Skip entries which are obviously not relevant (if we know the PC range). - if (entry.size_ == 0 || (entry.addr_ <= pc && (pc - entry.addr_) < entry.size_)) { - // Double check the entry contains the PC in case there are overlapping entries. - // This is might happen for native-code due to GC and for DEX due to data sharing. - std::string method_name; - uint64_t method_offset; - if (entry.symfile_->GetFunctionName(pc, &method_name, &method_offset)) { - return entry.symfile_.get(); - } - fallback = entry.symfile_.get(); // Tests don't have any symbols. - } - } - return fallback; // Not found. -} - -// Update JIT entries if needed. It will retry if there are data races. -template -bool JitDebugImpl::Update(Maps* maps) { - // We might need to retry the whole read in the presence of data races. - for (int i = 0; i < kMaxRaceRetries; i++) { - // Read the seqlock (counter which is incremented before and after any modification). - uint32_t seqlock = 0; - if (!this->memory_->Read32(seqlock_addr_, &seqlock)) { - return false; // Failed to read seqlock. - } - - // Check if anything changed since the last time we checked. - if (last_seqlock_ != seqlock) { - // Create memory wrapper to allow us to read the entries safely even in a live process. - JitMemory safe_memory; - safe_memory.parent_ = this->memory_.get(); - safe_memory.seqlock_addr_ = seqlock_addr_; - safe_memory.expected_seqlock_ = seqlock; - std::atomic_thread_fence(std::memory_order_acquire); - - // Add all entries to our cache. - if (!Read(maps, &safe_memory)) { - if (safe_memory.failed_due_to_race_) { - sleep(0); - continue; // Try again (there was a data race). - } else { - return false; // Proper failure (we could not read the data). - } - } - last_seqlock_ = seqlock; - } - return true; - } - return false; // Too many retries. -} - -// Read all JIT entries. It might randomly fail due to data races. -template -bool JitDebugImpl::Read(Maps* maps, JitMemory* memory) { - std::unordered_set seen_entry_addr; - - // Read and verify the descriptor (must be after we have read the initial seqlock). - JITDescriptor desc; - if (!(memory->ReadFully(descriptor_addr_, &desc, sizeof(desc)))) { - return false; - } - - entries_.clear(); - JITCodeEntry entry; - for (uint64_t entry_addr = desc.first_entry; entry_addr != 0; entry_addr = entry.next) { - // Check for infinite loops in the lined list. - if (!seen_entry_addr.emplace(entry_addr).second) { - return true; // TODO: Fail when seening infinite loop. - } - - // Read the entry (while checking for data races). - if (!memory->ReadFully(entry_addr, &entry, sizeof(entry))) { - return false; - } - - // Copy and load the symfile. - entries_.emplace_back(JitCacheEntry()); - if (!entries_.back().Init(maps, memory, entry.symfile_addr, entry.symfile_size.value)) { - return false; + // Search the existing elf object first. + for (Elf* elf : elf_list_) { + if (elf->IsValidPc(pc)) { + return elf; } } - return true; -} + while (entry_addr_ != 0) { + uint64_t start; + uint64_t size; + entry_addr_ = (this->*read_entry_func_)(&start, &size); -// Copy and load ELF file. -template <> -bool JitCacheEntry::Init(Maps*, JitMemory* memory, uint64_t addr, uint64_t size) { - // Make a copy of the in-memory symbol file (while checking for data races). - std::unique_ptr buffer(new MemoryBuffer()); - buffer->Resize(size); - if (!memory->ReadFully(addr, buffer->GetPtr(0), buffer->Size())) { - return false; + Elf* elf = new Elf(new MemoryRange(memory_, start, size, 0)); + elf->Init(); + if (!elf->valid()) { + // The data is not formatted in a way we understand, do not attempt + // to process any other entries. + entry_addr_ = 0; + delete elf; + return nullptr; + } + elf_list_.push_back(elf); + + if (elf->IsValidPc(pc)) { + return elf; + } } - - // Load and validate the ELF file. - symfile_.reset(new Elf(buffer.release())); - symfile_->Init(); - if (!symfile_->valid()) { - return false; - } - - symfile_->GetTextRange(&addr_, &size_); - return true; + return nullptr; } -template std::unique_ptr> JitDebug::Create(ArchEnum, std::shared_ptr&, - std::vector); - -#if !defined(NO_LIBDEXFILE_SUPPORT) - -template <> -const char* GetDescriptorName() { - return "__dex_debug_descriptor"; -} - -// Copy and load DEX file. -template <> -bool JitCacheEntry::Init(Maps* maps, JitMemory* memory, uint64_t addr, uint64_t) { - MapInfo* info = maps->Find(addr); - if (info == nullptr) { - return false; - } - symfile_ = DexFile::Create(addr, memory, info); - if (symfile_ == nullptr) { - return false; - } - return true; -} - -template std::unique_ptr> JitDebug::Create(ArchEnum, - std::shared_ptr&, - std::vector); - -#endif - } // namespace unwindstack diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index 73c5a0475..3f2e1c1b8 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -36,38 +36,11 @@ #include #if !defined(NO_LIBDEXFILE_SUPPORT) -#include +#include #endif namespace unwindstack { -Unwinder::Unwinder(size_t max_frames, Maps* maps, Regs* regs, - std::shared_ptr process_memory) - : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) { - frames_.reserve(max_frames); - if (regs != nullptr) { - ArchEnum arch = regs_->Arch(); - - jit_debug_ = JitDebug::Create(arch, process_memory_); -#if !defined(NO_LIBDEXFILE_SUPPORT) - dex_files_ = JitDebug::Create(arch, process_memory_); -#endif - } -} - -void Unwinder::SetRegs(Regs* regs) { - regs_ = regs; - - if (jit_debug_ == nullptr) { - ArchEnum arch = regs_->Arch(); - - jit_debug_ = JitDebug::Create(arch, process_memory_); -#if !defined(NO_LIBDEXFILE_SUPPORT) - dex_files_ = JitDebug::Create(arch, process_memory_); -#endif - } -} - // Inject extra 'virtual' frame that represents the dex pc data. // The dex pc is a magic register defined in the Mterp interpreter, // and thus it will be restored/observed in the frame after it. @@ -111,7 +84,8 @@ void Unwinder::FillInDexFrame() { return; } - dex_files_->GetFunctionName(maps_, dex_pc, &frame->function_name, &frame->function_offset); + dex_files_->GetMethodInformation(maps_, info, dex_pc, &frame->function_name, + &frame->function_offset); #endif } @@ -211,7 +185,7 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, // using the jit debug information. if (!elf->valid() && jit_debug_ != nullptr) { uint64_t adjusted_jit_pc = regs_->pc() - pc_adjustment; - Elf* jit_elf = jit_debug_->Get(maps_, adjusted_jit_pc); + Elf* jit_elf = jit_debug_->GetElf(maps_, adjusted_jit_pc); if (jit_elf != nullptr) { // The jit debug information requires a non relative adjusted pc. step_pc = adjusted_jit_pc; @@ -356,7 +330,19 @@ std::string Unwinder::FormatFrame(size_t frame_num) { return FormatFrame(frames_[frame_num]); } -bool UnwinderFromPid::Init() { +void Unwinder::SetJitDebug(JitDebug* jit_debug, ArchEnum arch) { + jit_debug->SetArch(arch); + jit_debug_ = jit_debug; +} + +#if !defined(NO_LIBDEXFILE_SUPPORT) +void Unwinder::SetDexFiles(DexFiles* dex_files, ArchEnum arch) { + dex_files->SetArch(arch); + dex_files_ = dex_files; +} +#endif + +bool UnwinderFromPid::Init(ArchEnum arch) { if (pid_ == getpid()) { maps_ptr_.reset(new LocalMaps()); } else { @@ -369,6 +355,15 @@ bool UnwinderFromPid::Init() { process_memory_ = Memory::CreateProcessMemoryCached(pid_); + jit_debug_ptr_.reset(new JitDebug(process_memory_)); + jit_debug_ = jit_debug_ptr_.get(); + SetJitDebug(jit_debug_, arch); +#if !defined(NO_LIBDEXFILE_SUPPORT) + dex_files_ptr_.reset(new DexFiles(process_memory_)); + dex_files_ = dex_files_ptr_.get(); + SetDexFiles(dex_files_, arch); +#endif + return true; } diff --git a/libunwindstack/include/unwindstack/DexFiles.h b/libunwindstack/include/unwindstack/DexFiles.h new file mode 100644 index 000000000..67a9640d6 --- /dev/null +++ b/libunwindstack/include/unwindstack/DexFiles.h @@ -0,0 +1,79 @@ +/* + * Copyright (C) 2018 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. + */ + +#ifndef _LIBUNWINDSTACK_DEX_FILES_H +#define _LIBUNWINDSTACK_DEX_FILES_H + +#include + +#include +#include +#include +#include +#include + +#include +#include + +namespace unwindstack { + +// Forward declarations. +class DexFile; +class Maps; +struct MapInfo; +enum ArchEnum : uint8_t; + +class DexFiles : public Global { + public: + explicit DexFiles(std::shared_ptr& memory); + DexFiles(std::shared_ptr& memory, std::vector& search_libs); + virtual ~DexFiles(); + + DexFile* GetDexFile(uint64_t dex_file_offset, MapInfo* info); + + void GetMethodInformation(Maps* maps, MapInfo* info, uint64_t dex_pc, std::string* method_name, + uint64_t* method_offset); + + private: + void Init(Maps* maps); + + bool GetAddr(size_t index, uint64_t* addr); + + uint64_t ReadEntryPtr32(uint64_t addr); + + uint64_t ReadEntryPtr64(uint64_t addr); + + bool ReadEntry32(); + + bool ReadEntry64(); + + bool ReadVariableData(uint64_t ptr_offset) override; + + void ProcessArch() override; + + std::mutex lock_; + bool initialized_ = false; + std::unordered_map> files_; + + uint64_t entry_addr_ = 0; + uint64_t (DexFiles::*read_entry_ptr_func_)(uint64_t) = nullptr; + bool (DexFiles::*read_entry_func_)() = nullptr; + std::vector addrs_; +}; + +} // namespace unwindstack + +#endif // _LIBUNWINDSTACK_DEX_FILES_H diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h index 25a665d81..ac94f101c 100644 --- a/libunwindstack/include/unwindstack/Elf.h +++ b/libunwindstack/include/unwindstack/Elf.h @@ -78,8 +78,6 @@ class Elf { bool IsValidPc(uint64_t pc); - bool GetTextRange(uint64_t* addr, uint64_t* size); - void GetLastError(ErrorData* data); ErrorCode GetLastErrorCode(); uint64_t GetLastErrorAddress(); diff --git a/libunwindstack/include/unwindstack/ElfInterface.h b/libunwindstack/include/unwindstack/ElfInterface.h index 945c27740..dbd917d67 100644 --- a/libunwindstack/include/unwindstack/ElfInterface.h +++ b/libunwindstack/include/unwindstack/ElfInterface.h @@ -68,8 +68,6 @@ class ElfInterface { virtual bool IsValidPc(uint64_t pc); - bool GetTextRange(uint64_t* addr, uint64_t* size); - Memory* CreateGnuDebugdataMemory(); Memory* memory() { return memory_; } @@ -158,9 +156,6 @@ class ElfInterface { uint64_t gnu_build_id_offset_ = 0; uint64_t gnu_build_id_size_ = 0; - uint64_t text_addr_ = 0; - uint64_t text_size_ = 0; - uint8_t soname_type_ = SONAME_UNKNOWN; std::string soname_; diff --git a/libunwindstack/include/unwindstack/JitDebug.h b/libunwindstack/include/unwindstack/JitDebug.h index 0c3ded984..8b7b4b590 100644 --- a/libunwindstack/include/unwindstack/JitDebug.h +++ b/libunwindstack/include/unwindstack/JitDebug.h @@ -19,7 +19,6 @@ #include -#include #include #include #include @@ -31,24 +30,40 @@ namespace unwindstack { // Forward declarations. +class Elf; class Maps; enum ArchEnum : uint8_t; -template -class JitDebug { +class JitDebug : public Global { public: - static std::unique_ptr Create(ArchEnum arch, std::shared_ptr& memory, - std::vector search_libs = {}); - virtual ~JitDebug() {} + explicit JitDebug(std::shared_ptr& memory); + JitDebug(std::shared_ptr& memory, std::vector& search_libs); + virtual ~JitDebug(); - // Find symbol file for given pc. - virtual Symfile* Get(Maps* maps, uint64_t pc) = 0; + Elf* GetElf(Maps* maps, uint64_t pc); - // Find symbol for given pc. - bool GetFunctionName(Maps* maps, uint64_t pc, std::string* name, uint64_t* offset) { - Symfile* file = Get(maps, pc); - return file != nullptr && file->GetFunctionName(pc, name, offset); - } + private: + void Init(Maps* maps); + + uint64_t (JitDebug::*read_descriptor_func_)(uint64_t) = nullptr; + uint64_t (JitDebug::*read_entry_func_)(uint64_t*, uint64_t*) = nullptr; + + uint64_t ReadDescriptor32(uint64_t); + uint64_t ReadDescriptor64(uint64_t); + + uint64_t ReadEntry32Pack(uint64_t* start, uint64_t* size); + uint64_t ReadEntry32Pad(uint64_t* start, uint64_t* size); + uint64_t ReadEntry64(uint64_t* start, uint64_t* size); + + bool ReadVariableData(uint64_t ptr_offset) override; + + void ProcessArch() override; + + uint64_t entry_addr_ = 0; + bool initialized_ = false; + std::vector elf_list_; + + std::mutex lock_; }; } // namespace unwindstack diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h index a04d7c304..8b01654a9 100644 --- a/libunwindstack/include/unwindstack/Unwinder.h +++ b/libunwindstack/include/unwindstack/Unwinder.h @@ -24,6 +24,7 @@ #include #include +#include #include #include #include @@ -33,7 +34,6 @@ namespace unwindstack { // Forward declarations. -class DexFile; class Elf; enum ArchEnum : uint8_t; @@ -63,14 +63,14 @@ struct FrameData { class Unwinder { public: - Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr process_memory); + Unwinder(size_t max_frames, Maps* maps, Regs* regs, std::shared_ptr process_memory) + : max_frames_(max_frames), maps_(maps), regs_(regs), process_memory_(process_memory) { + frames_.reserve(max_frames); + } Unwinder(size_t max_frames, Maps* maps, std::shared_ptr process_memory) - : Unwinder(max_frames, maps, nullptr, process_memory) {} - - Unwinder(const Unwinder&) = delete; - Unwinder& operator=(const Unwinder&) = delete; - Unwinder(Unwinder&&) = default; - Unwinder& operator=(Unwinder&&) = default; + : max_frames_(max_frames), maps_(maps), process_memory_(process_memory) { + frames_.reserve(max_frames); + } virtual ~Unwinder() = default; @@ -90,7 +90,9 @@ class Unwinder { std::string FormatFrame(size_t frame_num); std::string FormatFrame(const FrameData& frame); - void SetRegs(Regs* regs); + void SetJitDebug(JitDebug* jit_debug, ArchEnum arch); + + void SetRegs(Regs* regs) { regs_ = regs; } Maps* GetMaps() { return maps_; } std::shared_ptr& GetProcessMemory() { return process_memory_; } @@ -105,6 +107,10 @@ class Unwinder { void SetDisplayBuildID(bool display_build_id) { display_build_id_ = display_build_id; } +#if !defined(NO_LIBDEXFILE_SUPPORT) + void SetDexFiles(DexFiles* dex_files, ArchEnum arch); +#endif + ErrorCode LastErrorCode() { return last_error_.code; } uint64_t LastErrorAddress() { return last_error_.address; } @@ -120,9 +126,9 @@ class Unwinder { Regs* regs_; std::vector frames_; std::shared_ptr process_memory_; - std::unique_ptr> jit_debug_; + JitDebug* jit_debug_ = nullptr; #if !defined(NO_LIBDEXFILE_SUPPORT) - std::unique_ptr> dex_files_; + DexFiles* dex_files_ = nullptr; #endif bool resolve_names_ = true; bool embedded_soname_ = true; @@ -135,11 +141,15 @@ class UnwinderFromPid : public Unwinder { UnwinderFromPid(size_t max_frames, pid_t pid) : Unwinder(max_frames), pid_(pid) {} virtual ~UnwinderFromPid() = default; - bool Init(); + bool Init(ArchEnum arch); private: pid_t pid_; std::unique_ptr maps_ptr_; + std::unique_ptr jit_debug_ptr_; +#if !defined(NO_LIBDEXFILE_SUPPORT) + std::unique_ptr dex_files_ptr_; +#endif }; } // namespace unwindstack diff --git a/libunwindstack/tests/DexFileTest.cpp b/libunwindstack/tests/DexFileTest.cpp index df7b31dfd..0149a42c7 100644 --- a/libunwindstack/tests/DexFileTest.cpp +++ b/libunwindstack/tests/DexFileTest.cpp @@ -177,11 +177,11 @@ TEST(DexFileTest, get_method) { std::string method; uint64_t method_offset; - ASSERT_TRUE(dex_file->GetFunctionName(0x4102, &method, &method_offset)); + ASSERT_TRUE(dex_file->GetMethodInformation(0x102, &method, &method_offset)); EXPECT_EQ("Main.", method); EXPECT_EQ(2U, method_offset); - ASSERT_TRUE(dex_file->GetFunctionName(0x4118, &method, &method_offset)); + ASSERT_TRUE(dex_file->GetMethodInformation(0x118, &method, &method_offset)); EXPECT_EQ("Main.main", method); EXPECT_EQ(0U, method_offset); } @@ -195,9 +195,9 @@ TEST(DexFileTest, get_method_empty) { std::string method; uint64_t method_offset; - EXPECT_FALSE(dex_file->GetFunctionName(0x100000, &method, &method_offset)); + EXPECT_FALSE(dex_file->GetMethodInformation(0x100000, &method, &method_offset)); - EXPECT_FALSE(dex_file->GetFunctionName(0x98, &method, &method_offset)); + EXPECT_FALSE(dex_file->GetMethodInformation(0x98, &method, &method_offset)); } } // namespace unwindstack diff --git a/libunwindstack/tests/DexFilesTest.cpp b/libunwindstack/tests/DexFilesTest.cpp index 655dcc8e3..1ea9e5c03 100644 --- a/libunwindstack/tests/DexFilesTest.cpp +++ b/libunwindstack/tests/DexFilesTest.cpp @@ -22,8 +22,8 @@ #include +#include #include -#include #include #include #include @@ -32,10 +32,6 @@ #include "ElfFake.h" #include "MemoryFake.h" -#if !defined(NO_LIBDEXFILE_SUPPORT) -#include -#endif - namespace unwindstack { class DexFilesTest : public ::testing::Test { @@ -52,7 +48,8 @@ class DexFilesTest : public ::testing::Test { } void Init(ArchEnum arch) { - dex_files_ = JitDebug::Create(arch, process_memory_); + dex_files_.reset(new DexFiles(process_memory_)); + dex_files_->SetArch(arch); maps_.reset( new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf\n" @@ -89,11 +86,10 @@ class DexFilesTest : public ::testing::Test { Init(ARCH_ARM); } - void WriteDescriptor32(uint64_t addr, uint32_t entry); - void WriteDescriptor64(uint64_t addr, uint64_t entry); - void WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex); - void WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex); - void WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex); + void WriteDescriptor32(uint64_t addr, uint32_t head); + void WriteDescriptor64(uint64_t addr, uint64_t head); + void WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, uint32_t dex_file); + void WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, uint64_t dex_file); void WriteDex(uint64_t dex_file); static constexpr size_t kMapGlobalNonReadable = 2; @@ -105,70 +101,40 @@ class DexFilesTest : public ::testing::Test { std::shared_ptr process_memory_; MemoryFake* memory_; - std::unique_ptr> dex_files_; + std::unique_ptr dex_files_; std::unique_ptr maps_; }; -void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t entry) { - // Format of the 32 bit JITDescriptor structure: - // uint32_t version - memory_->SetData32(addr, 1); - // uint32_t action_flag - memory_->SetData32(addr + 4, 0); - // uint32_t relevant_entry - memory_->SetData32(addr + 8, 0); - // uint32_t first_entry - memory_->SetData32(addr + 12, entry); +void DexFilesTest::WriteDescriptor32(uint64_t addr, uint32_t head) { + // void* first_entry_ + memory_->SetData32(addr + 12, head); } -void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t entry) { - // Format of the 64 bit JITDescriptor structure: - // uint32_t version - memory_->SetData32(addr, 1); - // uint32_t action_flag - memory_->SetData32(addr + 4, 0); - // uint64_t relevant_entry - memory_->SetData64(addr + 8, 0); - // uint64_t first_entry - memory_->SetData64(addr + 16, entry); +void DexFilesTest::WriteDescriptor64(uint64_t addr, uint64_t head) { + // void* first_entry_ + memory_->SetData64(addr + 16, head); } -void DexFilesTest::WriteEntry32Pack(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) { - // Format of the 32 bit JITCodeEntry structure: +void DexFilesTest::WriteEntry32(uint64_t entry_addr, uint32_t next, uint32_t prev, + uint32_t dex_file) { + // Format of the 32 bit DEXFileEntry structure: // uint32_t next - memory_->SetData32(addr, next); + memory_->SetData32(entry_addr, next); // uint32_t prev - memory_->SetData32(addr + 4, prev); - // uint32_t dex - memory_->SetData32(addr + 8, dex); - // uint64_t symfile_size - memory_->SetData64(addr + 12, sizeof(kDexData) * sizeof(uint32_t)); + memory_->SetData32(entry_addr + 4, prev); + // uint32_t dex_file + memory_->SetData32(entry_addr + 8, dex_file); } -void DexFilesTest::WriteEntry32Pad(uint64_t addr, uint32_t next, uint32_t prev, uint32_t dex) { - // Format of the 32 bit JITCodeEntry structure: - // uint32_t next - memory_->SetData32(addr, next); - // uint32_t prev - memory_->SetData32(addr + 4, prev); - // uint32_t dex - memory_->SetData32(addr + 8, dex); - // uint32_t pad - memory_->SetData32(addr + 12, 0); - // uint64_t symfile_size - memory_->SetData64(addr + 16, sizeof(kDexData) * sizeof(uint32_t)); -} - -void DexFilesTest::WriteEntry64(uint64_t addr, uint64_t next, uint64_t prev, uint64_t dex) { - // Format of the 64 bit JITCodeEntry structure: +void DexFilesTest::WriteEntry64(uint64_t entry_addr, uint64_t next, uint64_t prev, + uint64_t dex_file) { + // Format of the 64 bit DEXFileEntry structure: // uint64_t next - memory_->SetData64(addr, next); + memory_->SetData64(entry_addr, next); // uint64_t prev - memory_->SetData64(addr + 8, prev); - // uint64_t dex - memory_->SetData64(addr + 16, dex); - // uint64_t symfile_size - memory_->SetData64(addr + 24, sizeof(kDexData) * sizeof(uint32_t)); + memory_->SetData64(entry_addr + 8, prev); + // uint64_t dex_file + memory_->SetData64(entry_addr + 16, dex_file); } void DexFilesTest::WriteDex(uint64_t dex_file) { @@ -178,8 +144,9 @@ void DexFilesTest::WriteDex(uint64_t dex_file) { TEST_F(DexFilesTest, get_method_information_invalid) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFileEntries); - dex_files_->GetFunctionName(maps_.get(), 0, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0, &method_name, &method_offset); EXPECT_EQ("nothing", method_name); EXPECT_EQ(0x124U, method_offset); } @@ -187,12 +154,13 @@ TEST_F(DexFilesTest, get_method_information_invalid) { TEST_F(DexFilesTest, get_method_information_32) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFiles); WriteDescriptor32(0xf800, 0x200000); - WriteEntry32Pad(0x200000, 0, 0, 0x300000); + WriteEntry32(0x200000, 0, 0, 0x300000); WriteDex(0x300000); - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(0U, method_offset); } @@ -202,12 +170,13 @@ TEST_F(DexFilesTest, get_method_information_64) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFiles); WriteDescriptor64(0xf800, 0x200000); WriteEntry64(0x200000, 0, 0, 0x301000); WriteDex(0x301000); - dex_files_->GetFunctionName(maps_.get(), 0x301102, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x301102, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(2U, method_offset); } @@ -215,14 +184,14 @@ TEST_F(DexFilesTest, get_method_information_64) { TEST_F(DexFilesTest, get_method_information_not_first_entry_32) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFiles); WriteDescriptor32(0xf800, 0x200000); - WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000); - WriteDex(0x100000); - WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000); + WriteEntry32(0x200000, 0x200100, 0, 0x100000); + WriteEntry32(0x200100, 0, 0x200000, 0x300000); WriteDex(0x300000); - dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(4U, method_offset); } @@ -232,14 +201,14 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_64) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFiles); WriteDescriptor64(0xf800, 0x200000); WriteEntry64(0x200000, 0x200100, 0, 0x100000); - WriteDex(0x100000); WriteEntry64(0x200100, 0, 0x200000, 0x300000); WriteDex(0x300000); - dex_files_->GetFunctionName(maps_.get(), 0x300106, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300106, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(6U, method_offset); } @@ -247,18 +216,19 @@ TEST_F(DexFilesTest, get_method_information_not_first_entry_64) { TEST_F(DexFilesTest, get_method_information_cached) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFiles); WriteDescriptor32(0xf800, 0x200000); - WriteEntry32Pad(0x200000, 0, 0, 0x300000); + WriteEntry32(0x200000, 0, 0, 0x300000); WriteDex(0x300000); - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(0U, method_offset); // Clear all memory and make sure that data is acquired from the cache. memory_->Clear(); - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(0U, method_offset); } @@ -266,24 +236,26 @@ TEST_F(DexFilesTest, get_method_information_cached) { TEST_F(DexFilesTest, get_method_information_search_libs) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFiles); WriteDescriptor32(0xf800, 0x200000); - WriteEntry32Pad(0x200000, 0x200100, 0, 0x100000); - WriteDex(0x100000); - WriteEntry32Pad(0x200100, 0, 0x200000, 0x300000); + WriteEntry32(0x200000, 0x200100, 0, 0x100000); + WriteEntry32(0x200100, 0, 0x200000, 0x300000); WriteDex(0x300000); // Only search a given named list of libs. std::vector libs{"libart.so"}; - dex_files_ = JitDebug::Create(ARCH_ARM, process_memory_, libs); + dex_files_.reset(new DexFiles(process_memory_, libs)); + dex_files_->SetArch(ARCH_ARM); - dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); EXPECT_EQ("nothing", method_name); EXPECT_EQ(0x124U, method_offset); MapInfo* map_info = maps_->Get(kMapGlobal); map_info->name = "/system/lib/libart.so"; - dex_files_ = JitDebug::Create(ARCH_ARM, process_memory_, libs); + dex_files_.reset(new DexFiles(process_memory_, libs)); + dex_files_->SetArch(ARCH_ARM); // Set the rw map to the same name or this will not scan this entry. map_info = maps_->Get(kMapGlobalRw); map_info->name = "/system/lib/libart.so"; @@ -291,7 +263,7 @@ TEST_F(DexFilesTest, get_method_information_search_libs) { // DexFiles object. libs.clear(); - dex_files_->GetFunctionName(maps_.get(), 0x300104, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300104, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(4U, method_offset); } @@ -299,24 +271,26 @@ TEST_F(DexFilesTest, get_method_information_search_libs) { TEST_F(DexFilesTest, get_method_information_global_skip_zero_32) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFiles); // First global variable found, but value is zero. WriteDescriptor32(0xa800, 0); WriteDescriptor32(0xf800, 0x200000); - WriteEntry32Pad(0x200000, 0, 0, 0x300000); + WriteEntry32(0x200000, 0, 0, 0x300000); WriteDex(0x300000); - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(0U, method_offset); // Verify that second is ignored when first is set to non-zero - dex_files_ = JitDebug::Create(ARCH_ARM, process_memory_); + dex_files_.reset(new DexFiles(process_memory_)); + dex_files_->SetArch(ARCH_ARM); method_name = "fail"; method_offset = 0x123; WriteDescriptor32(0xa800, 0x100000); - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("fail", method_name); EXPECT_EQ(0x123U, method_offset); } @@ -326,6 +300,7 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { std::string method_name = "nothing"; uint64_t method_offset = 0x124; + MapInfo* info = maps_->Get(kMapDexFiles); // First global variable found, but value is zero. WriteDescriptor64(0xa800, 0); @@ -334,16 +309,17 @@ TEST_F(DexFilesTest, get_method_information_global_skip_zero_64) { WriteEntry64(0x200000, 0, 0, 0x300000); WriteDex(0x300000); - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("Main.", method_name); EXPECT_EQ(0U, method_offset); // Verify that second is ignored when first is set to non-zero - dex_files_ = JitDebug::Create(ARCH_ARM64, process_memory_); + dex_files_.reset(new DexFiles(process_memory_)); + dex_files_->SetArch(ARCH_ARM64); method_name = "fail"; method_offset = 0x123; WriteDescriptor64(0xa800, 0x100000); - dex_files_->GetFunctionName(maps_.get(), 0x300100, &method_name, &method_offset); + dex_files_->GetMethodInformation(maps_.get(), info, 0x300100, &method_name, &method_offset); EXPECT_EQ("fail", method_name); EXPECT_EQ(0x123U, method_offset); } diff --git a/libunwindstack/tests/JitDebugTest.cpp b/libunwindstack/tests/JitDebugTest.cpp index 438194a9f..b1ca111cb 100644 --- a/libunwindstack/tests/JitDebugTest.cpp +++ b/libunwindstack/tests/JitDebugTest.cpp @@ -46,7 +46,8 @@ class JitDebugTest : public ::testing::Test { } void Init(ArchEnum arch) { - jit_debug_ = JitDebug::Create(arch, process_memory_); + jit_debug_.reset(new JitDebug(process_memory_)); + jit_debug_->SetArch(arch); maps_.reset( new BufferMaps("1000-4000 ---s 00000000 00:00 0 /fake/elf1\n" @@ -61,12 +62,6 @@ class JitDebugTest : public ::testing::Test { "200000-210000 rw-p 0002000 00:00 0 /fake/elf4\n")); ASSERT_TRUE(maps_->Parse()); - // Ensure all memory of the ELF file is initialized, - // otherwise reads within it may fail. - for (uint64_t addr = 0x4000; addr < 0x6000; addr += 8) { - memory_->SetData64(addr, 0); - } - MapInfo* map_info = maps_->Get(3); ASSERT_TRUE(map_info != nullptr); CreateFakeElf(map_info); @@ -99,7 +94,7 @@ class JitDebugTest : public ::testing::Test { ehdr.e_shstrndx = 1; ehdr.e_shoff = sh_offset; ehdr.e_shentsize = sizeof(ShdrType); - ehdr.e_shnum = 4; + ehdr.e_shnum = 3; memory_->SetMemory(offset, &ehdr, sizeof(ehdr)); ShdrType shdr; @@ -115,7 +110,6 @@ class JitDebugTest : public ::testing::Test { shdr.sh_size = 0x100; memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr)); memory_->SetMemory(offset + 0x500, ".debug_frame"); - memory_->SetMemory(offset + 0x550, ".text"); sh_offset += sizeof(shdr); memset(&shdr, 0, sizeof(shdr)); @@ -126,15 +120,6 @@ class JitDebugTest : public ::testing::Test { shdr.sh_size = 0x200; memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr)); - sh_offset += sizeof(shdr); - memset(&shdr, 0, sizeof(shdr)); - shdr.sh_type = SHT_NOBITS; - shdr.sh_name = 0x50; - shdr.sh_addr = pc; - shdr.sh_offset = 0; - shdr.sh_size = size; - memory_->SetMemory(offset + sh_offset, &shdr, sizeof(shdr)); - // Now add a single cie/fde. uint64_t dwarf_offset = offset + 0x600; if (class_type == ELFCLASS32) { @@ -183,7 +168,7 @@ class JitDebugTest : public ::testing::Test { std::shared_ptr process_memory_; MemoryFake* memory_; - std::unique_ptr> jit_debug_; + std::unique_ptr jit_debug_; std::unique_ptr maps_; }; @@ -253,20 +238,20 @@ void JitDebugTest::WriteEntry64(uint64_t addr, uint64_t prev, uint64_t next, uin } TEST_F(JitDebugTest, get_elf_invalid) { - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); } TEST_F(JitDebugTest, get_elf_no_global_variable) { maps_.reset(new BufferMaps("")); - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); } TEST_F(JitDebugTest, get_elf_no_valid_descriptor_in_memory) { CreateElf(0x4000, ELFCLASS32, EM_ARM, 0x1500, 0x200); - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); } @@ -275,7 +260,7 @@ TEST_F(JitDebugTest, get_elf_no_valid_code_entry) { WriteDescriptor32(0xf800, 0x200000); - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); } @@ -284,7 +269,7 @@ TEST_F(JitDebugTest, get_elf_invalid_descriptor_first_entry) { WriteDescriptor32(0xf800, 0); - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); } @@ -295,7 +280,7 @@ TEST_F(JitDebugTest, get_elf_invalid_descriptor_version) { // Set the version to an invalid value. memory_->SetData32(0xf800, 2); - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf == nullptr); } @@ -305,18 +290,12 @@ TEST_F(JitDebugTest, get_elf_32) { WriteDescriptor32(0xf800, 0x200000); WriteEntry32Pad(0x200000, 0, 0, 0x4000, 0x1000); - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf != nullptr); - uint64_t text_addr; - uint64_t text_size; - ASSERT_TRUE(elf->GetTextRange(&text_addr, &text_size)); - ASSERT_EQ(text_addr, 0x1500u); - ASSERT_EQ(text_size, 0x200u); // Clear the memory and verify all of the data is cached. memory_->Clear(); - WriteDescriptor32(0xf800, 0x200000); - Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf2 != nullptr); EXPECT_EQ(elf, elf2); } @@ -330,15 +309,16 @@ TEST_F(JitDebugTest, get_multiple_jit_debug_descriptors_valid) { WriteDescriptor32(0x12800, 0x201000); WriteEntry32Pad(0x201000, 0, 0, 0x5000, 0x1000); - ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr); - ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) == nullptr); + ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr); + ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) == nullptr); // Now clear the descriptor entry for the first one. WriteDescriptor32(0xf800, 0); - jit_debug_ = JitDebug::Create(ARCH_ARM, process_memory_); + jit_debug_.reset(new JitDebug(process_memory_)); + jit_debug_->SetArch(ARCH_ARM); - ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr); - ASSERT_TRUE(jit_debug_->Get(maps_.get(), 0x2000) != nullptr); + ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr); + ASSERT_TRUE(jit_debug_->GetElf(maps_.get(), 0x2000) != nullptr); } TEST_F(JitDebugTest, get_elf_x86) { @@ -349,14 +329,13 @@ TEST_F(JitDebugTest, get_elf_x86) { WriteDescriptor32(0xf800, 0x200000); WriteEntry32Pack(0x200000, 0, 0, 0x4000, 0x1000); - jit_debug_ = JitDebug::Create(ARCH_X86, process_memory_); - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + jit_debug_->SetArch(ARCH_X86); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf != nullptr); // Clear the memory and verify all of the data is cached. memory_->Clear(); - WriteDescriptor32(0xf800, 0x200000); - Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf2 != nullptr); EXPECT_EQ(elf, elf2); } @@ -369,13 +348,12 @@ TEST_F(JitDebugTest, get_elf_64) { WriteDescriptor64(0xf800, 0x200000); WriteEntry64(0x200000, 0, 0, 0x4000, 0x1000); - Elf* elf = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf != nullptr); // Clear the memory and verify all of the data is cached. memory_->Clear(); - WriteDescriptor64(0xf800, 0x200000); - Elf* elf2 = jit_debug_->Get(maps_.get(), 0x1500); + Elf* elf2 = jit_debug_->GetElf(maps_.get(), 0x1500); ASSERT_TRUE(elf2 != nullptr); EXPECT_EQ(elf, elf2); } @@ -388,21 +366,20 @@ TEST_F(JitDebugTest, get_elf_multiple_entries) { WriteEntry32Pad(0x200000, 0, 0x200100, 0x4000, 0x1000); WriteEntry32Pad(0x200100, 0x200100, 0, 0x5000, 0x1000); - Elf* elf_2 = jit_debug_->Get(maps_.get(), 0x2400); + Elf* elf_2 = jit_debug_->GetElf(maps_.get(), 0x2400); ASSERT_TRUE(elf_2 != nullptr); - Elf* elf_1 = jit_debug_->Get(maps_.get(), 0x1600); + Elf* elf_1 = jit_debug_->GetElf(maps_.get(), 0x1600); ASSERT_TRUE(elf_1 != nullptr); // Clear the memory and verify all of the data is cached. memory_->Clear(); - WriteDescriptor32(0xf800, 0x200000); - EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x1500)); - EXPECT_EQ(elf_1, jit_debug_->Get(maps_.get(), 0x16ff)); - EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x2300)); - EXPECT_EQ(elf_2, jit_debug_->Get(maps_.get(), 0x26ff)); - EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x1700)); - EXPECT_EQ(nullptr, jit_debug_->Get(maps_.get(), 0x2700)); + EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x1500)); + EXPECT_EQ(elf_1, jit_debug_->GetElf(maps_.get(), 0x16ff)); + EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x2300)); + EXPECT_EQ(elf_2, jit_debug_->GetElf(maps_.get(), 0x26ff)); + EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x1700)); + EXPECT_EQ(nullptr, jit_debug_->GetElf(maps_.get(), 0x2700)); } TEST_F(JitDebugTest, get_elf_search_libs) { @@ -413,19 +390,21 @@ TEST_F(JitDebugTest, get_elf_search_libs) { // Only search a given named list of libs. std::vector libs{"libart.so"}; - jit_debug_ = JitDebug::Create(ARCH_ARM, process_memory_, libs); - EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) == nullptr); + jit_debug_.reset(new JitDebug(process_memory_, libs)); + jit_debug_->SetArch(ARCH_ARM); + EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) == nullptr); // Change the name of the map that includes the value and verify this works. MapInfo* map_info = maps_->Get(5); map_info->name = "/system/lib/libart.so"; map_info = maps_->Get(6); map_info->name = "/system/lib/libart.so"; - jit_debug_ = JitDebug::Create(ARCH_ARM, process_memory_); + jit_debug_.reset(new JitDebug(process_memory_, libs)); // Make sure that clearing our copy of the libs doesn't affect the // JitDebug object. libs.clear(); - EXPECT_TRUE(jit_debug_->Get(maps_.get(), 0x1500) != nullptr); + jit_debug_->SetArch(ARCH_ARM); + EXPECT_TRUE(jit_debug_->GetElf(maps_.get(), 0x1500) != nullptr); } } // namespace unwindstack diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index e3c646a74..02ba9c8fa 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -307,7 +307,9 @@ TEST_F(UnwindOfflineTest, jit_debug_x86) { } process_memory_.reset(memory); + JitDebug jit_debug(process_memory_); Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); + unwinder.SetJitDebug(&jit_debug, regs_->Arch()); unwinder.Unwind(); std::string frame_info(DumpFrames(unwinder)); @@ -607,7 +609,9 @@ TEST_F(UnwindOfflineTest, jit_debug_arm) { } process_memory_.reset(memory); + JitDebug jit_debug(process_memory_); Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); + unwinder.SetJitDebug(&jit_debug, regs_->Arch()); unwinder.Unwind(); std::string frame_info(DumpFrames(unwinder)); @@ -928,7 +932,9 @@ static void OfflineUnwind(void* data) { LeakType* leak_data = reinterpret_cast(data); std::unique_ptr regs_copy(leak_data->regs->Clone()); + JitDebug jit_debug(leak_data->process_memory); Unwinder unwinder(128, leak_data->maps, regs_copy.get(), leak_data->process_memory); + unwinder.SetJitDebug(&jit_debug, regs_copy->Arch()); unwinder.Unwind(); ASSERT_EQ(76U, unwinder.NumFrames()); } @@ -1049,7 +1055,9 @@ TEST_F(UnwindOfflineTest, art_quick_osr_stub_arm) { } process_memory_.reset(memory); + JitDebug jit_debug(process_memory_); Unwinder unwinder(128, maps_.get(), regs_.get(), process_memory_); + unwinder.SetJitDebug(&jit_debug, regs_->Arch()); unwinder.Unwind(); std::string frame_info(DumpFrames(unwinder)); diff --git a/libunwindstack/tests/UnwindTest.cpp b/libunwindstack/tests/UnwindTest.cpp index 5e7e6bf9f..4e3801511 100644 --- a/libunwindstack/tests/UnwindTest.cpp +++ b/libunwindstack/tests/UnwindTest.cpp @@ -170,7 +170,7 @@ extern "C" void InnerFunction(TestTypeEnum test_type) { unwinder.reset(new Unwinder(512, maps.get(), regs.get(), process_memory)); } else { UnwinderFromPid* unwinder_from_pid = new UnwinderFromPid(512, getpid()); - ASSERT_TRUE(unwinder_from_pid->Init()); + ASSERT_TRUE(unwinder_from_pid->Init(regs->Arch())); unwinder_from_pid->SetRegs(regs.get()); unwinder.reset(unwinder_from_pid); } @@ -283,7 +283,7 @@ TEST_F(UnwindTest, unwind_from_pid_remote) { ASSERT_TRUE(regs.get() != nullptr); UnwinderFromPid unwinder(512, pid); - ASSERT_TRUE(unwinder.Init()); + ASSERT_TRUE(unwinder.Init(regs->Arch())); unwinder.SetRegs(regs.get()); VerifyUnwind(&unwinder, kFunctionOrder); @@ -335,7 +335,7 @@ static void RemoteUnwindFromPid(void* data) { ASSERT_TRUE(regs.get() != nullptr); UnwinderFromPid unwinder(512, *pid); - ASSERT_TRUE(unwinder.Init()); + ASSERT_TRUE(unwinder.Init(regs->Arch())); unwinder.SetRegs(regs.get()); VerifyUnwind(&unwinder, kFunctionOrder); diff --git a/libunwindstack/tools/unwind.cpp b/libunwindstack/tools/unwind.cpp index cad95f8c5..1812e5037 100644 --- a/libunwindstack/tools/unwind.cpp +++ b/libunwindstack/tools/unwind.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include #include @@ -89,7 +90,7 @@ void DoUnwind(pid_t pid) { printf("\n"); unwindstack::UnwinderFromPid unwinder(1024, pid); - if (!unwinder.Init()) { + if (!unwinder.Init(regs->Arch())) { printf("Failed to init unwinder object.\n"); return; } diff --git a/libunwindstack/tools/unwind_for_offline.cpp b/libunwindstack/tools/unwind_for_offline.cpp index 86f3163e3..4f67d679f 100644 --- a/libunwindstack/tools/unwind_for_offline.cpp +++ b/libunwindstack/tools/unwind_for_offline.cpp @@ -248,7 +248,7 @@ int SaveData(pid_t pid) { // Do an unwind so we know how much of the stack to save, and what // elf files are involved. unwindstack::UnwinderFromPid unwinder(1024, pid); - if (!unwinder.Init()) { + if (!unwinder.Init(regs->Arch())) { printf("Unable to init unwinder object.\n"); return 1; } From c18cccc227d7fdccfa5a60e4e8d20951d1f6ed89 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Wed, 10 Apr 2019 16:31:31 -0700 Subject: [PATCH 130/221] Allow fuzzy_fastboot number to run for a specific device serial number Test: ./fuzzy_fastboot --serial=826X003L --gtest_filter=*Logical* Bug: 117181762 Change-Id: I9dec510aa604b7994f25ce26edb87d7f6ec3e875 Merged-In: I9dec510aa604b7994f25ce26edb87d7f6ec3e875 (cherry picked from commit b9051a3e6559b14759015d679c97d0e9e5fad9a4) --- fastboot/fuzzy_fastboot/fixtures.cpp | 15 ++++++++++----- fastboot/fuzzy_fastboot/fixtures.h | 3 ++- fastboot/fuzzy_fastboot/main.cpp | 8 ++++++-- 3 files changed, 18 insertions(+), 8 deletions(-) diff --git a/fastboot/fuzzy_fastboot/fixtures.cpp b/fastboot/fuzzy_fastboot/fixtures.cpp index c23da01a2..bc13a8c4e 100644 --- a/fastboot/fuzzy_fastboot/fixtures.cpp +++ b/fastboot/fuzzy_fastboot/fixtures.cpp @@ -59,7 +59,7 @@ using namespace std::literals::chrono_literals; namespace fastboot { -int FastBootTest::MatchFastboot(usb_ifc_info* info, const char* local_serial) { +int FastBootTest::MatchFastboot(usb_ifc_info* info, const std::string& local_serial) { if (info->ifc_class != 0xff || info->ifc_subclass != 0x42 || info->ifc_protocol != 0x03) { return -1; } @@ -68,8 +68,8 @@ int FastBootTest::MatchFastboot(usb_ifc_info* info, const char* local_serial) { // require matching serial number or device path if requested // at the command line with the -s option. - if (local_serial && (strcmp(local_serial, info->serial_number) != 0 && - strcmp(local_serial, info->device_path) != 0)) + if (!local_serial.empty() && local_serial != info->serial_number && + local_serial != info->device_path) return -1; return 0; } @@ -113,7 +113,9 @@ void FastBootTest::SetUp() { ASSERT_TRUE(UsbStillAvailible()); // The device disconnected } - const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); }; + const auto matcher = [](usb_ifc_info* info) -> int { + return MatchFastboot(info, device_serial); + }; for (int i = 0; i < MAX_USB_TRIES && !transport; i++) { std::unique_ptr usb(usb_open(matcher, USB_TIMEOUT)); if (usb) @@ -172,7 +174,9 @@ void FastBootTest::ReconnectFastbootDevice() { ; printf("WAITING FOR DEVICE\n"); // Need to wait for device - const auto matcher = [](usb_ifc_info* info) -> int { return MatchFastboot(info, nullptr); }; + const auto matcher = [](usb_ifc_info* info) -> int { + return MatchFastboot(info, device_serial); + }; while (!transport) { std::unique_ptr usb(usb_open(matcher, USB_TIMEOUT)); if (usb) { @@ -238,6 +242,7 @@ std::string FastBootTest::device_path = ""; std::string FastBootTest::cb_scratch = ""; std::string FastBootTest::initial_slot = ""; int FastBootTest::serial_port = 0; +std::string FastBootTest::device_serial = ""; template void ModeTest::SetUp() { diff --git a/fastboot/fuzzy_fastboot/fixtures.h b/fastboot/fuzzy_fastboot/fixtures.h index 7c8d54d27..c71c89766 100644 --- a/fastboot/fuzzy_fastboot/fixtures.h +++ b/fastboot/fuzzy_fastboot/fixtures.h @@ -43,9 +43,10 @@ constexpr char USB_PORT_GONE[] = class FastBootTest : public testing::Test { public: static int serial_port; + static std::string device_serial; static constexpr int MAX_USB_TRIES = 10; - static int MatchFastboot(usb_ifc_info* info, const char* local_serial = nullptr); + static int MatchFastboot(usb_ifc_info* info, const std::string& local_serial = ""); bool UsbStillAvailible(); bool UserSpaceFastboot(); void ReconnectFastbootDevice(); diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp index a40bc27ef..ff918a7fc 100644 --- a/fastboot/fuzzy_fastboot/main.cpp +++ b/fastboot/fuzzy_fastboot/main.cpp @@ -162,7 +162,7 @@ const auto not_allowed = [](char c) -> int { // Test that USB even works TEST(USBFunctionality, USBConnect) { const auto matcher = [](usb_ifc_info* info) -> int { - return FastBootTest::MatchFastboot(info, nullptr); + return FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial); }; Transport* transport = nullptr; for (int i = 0; i < FastBootTest::MAX_USB_TRIES && !transport; i++) { @@ -1738,10 +1738,14 @@ int main(int argc, char** argv) { fastboot::GenerateXmlTests(fastboot::config); } + if (args.find("serial") != args.end()) { + fastboot::FastBootTest::device_serial = args.at("serial"); + } + setbuf(stdout, NULL); // no buffering printf("\n"); const auto matcher = [](usb_ifc_info* info) -> int { - return fastboot::FastBootTest::MatchFastboot(info, nullptr); + return fastboot::FastBootTest::MatchFastboot(info, fastboot::FastBootTest::device_serial); }; Transport* transport = nullptr; while (!transport) { From 81f13855895c9c0a890520f2da9985cb0aa75e09 Mon Sep 17 00:00:00 2001 From: Yifan Hong Date: Tue, 9 Apr 2019 10:11:34 -0700 Subject: [PATCH 131/221] init: add umount_all builtin. umount_all is the cleanup step for mount_all. In particular, the mount_all builtin creates a verity device, 'postinstall-verity', for the following line: system /postinstall ... ... slotselect_other,logical,avb_keys=... cppreopt umounts /postinstall but doesn't destroy the postinstall-verity device, causing OTA to fail (because it cannot destroy the system_[other] device). umount_all also destroy the verity device. Note that mount_all does not map system_[other]; it is mapped by first stage init. Hence, umount_all doesn't destroy it either. The OTA client is reponsible for unmapping the device itself. Bug: 129988285 Test: flash, boot, then check `dmctl list devices`, then OTA Change-Id: Id3ab65b3860b6ea6cfec310ab13652009c81f415 --- fs_mgr/fs_mgr.cpp | 40 ++++++++++++++++ fs_mgr/fs_mgr_dm_linear.cpp | 9 +++- fs_mgr/fs_mgr_priv.h | 8 ++++ fs_mgr/fs_mgr_verity.cpp | 10 ++++ fs_mgr/include/fs_mgr.h | 11 +++++ fs_mgr/libfs_avb/fs_avb.cpp | 23 ++++++++++ fs_mgr/libfs_avb/include/fs_avb/fs_avb.h | 5 ++ fs_mgr/libfs_avb/tests/util_test.cpp | 5 +- fs_mgr/libfs_avb/util.cpp | 11 +++-- fs_mgr/libfs_avb/util.h | 4 +- init/builtins.cpp | 58 +++++++++++++++++++----- 11 files changed, 166 insertions(+), 18 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 045bb48ec..5114f5517 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -1268,6 +1268,46 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) { } } +int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab) { + AvbUniquePtr avb_handle(nullptr); + int ret = FsMgrUmountStatus::SUCCESS; + for (auto& current_entry : *fstab) { + if (!IsMountPointMounted(current_entry.mount_point)) { + continue; + } + + if (umount(current_entry.mount_point.c_str()) == -1) { + PERROR << "Failed to umount " << current_entry.mount_point; + ret |= FsMgrUmountStatus::ERROR_UMOUNT; + continue; + } + + if (current_entry.fs_mgr_flags.logical) { + if (!fs_mgr_update_logical_partition(¤t_entry)) { + LERROR << "Could not get logical partition blk_device, skipping!"; + ret |= FsMgrUmountStatus::ERROR_DEVICE_MAPPER; + continue; + } + } + + if (current_entry.fs_mgr_flags.avb || !current_entry.avb_keys.empty()) { + if (!AvbHandle::TearDownAvbHashtree(¤t_entry, true /* wait */)) { + LERROR << "Failed to tear down AVB on mount point: " << current_entry.mount_point; + ret |= FsMgrUmountStatus::ERROR_VERITY; + continue; + } + } else if ((current_entry.fs_mgr_flags.verify)) { + if (!fs_mgr_teardown_verity(¤t_entry, true /* wait */)) { + LERROR << "Failed to tear down verified partition on mount point: " + << current_entry.mount_point; + ret |= FsMgrUmountStatus::ERROR_VERITY; + continue; + } + } + } + return ret; +} + // wrapper to __mount() and expects a fully prepared fstab_rec, // unlike fs_mgr_do_mount which does more things with avb / verity etc. int fs_mgr_do_mount_one(const FstabEntry& entry, const std::string& mount_point) { diff --git a/fs_mgr/fs_mgr_dm_linear.cpp b/fs_mgr/fs_mgr_dm_linear.cpp index 45cbff3a9..ee6ffdb18 100644 --- a/fs_mgr/fs_mgr_dm_linear.cpp +++ b/fs_mgr/fs_mgr_dm_linear.cpp @@ -193,7 +193,7 @@ bool CreateLogicalPartition(const std::string& block_device, uint32_t metadata_s timeout_ms, path); } -bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) { +bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms) { DeviceMapper& dm = DeviceMapper::Instance(); std::string path; if (timeout_ms > std::chrono::milliseconds::zero()) { @@ -206,6 +206,13 @@ bool DestroyLogicalPartition(const std::string& name, const std::chrono::millise LERROR << "Timed out waiting for device path to unlink: " << path; return false; } + return true; +} + +bool DestroyLogicalPartition(const std::string& name, const std::chrono::milliseconds& timeout_ms) { + if (!UnmapDevice(name, timeout_ms)) { + return false; + } LINFO << "Unmapped logical partition " << name; return true; } diff --git a/fs_mgr/fs_mgr_priv.h b/fs_mgr/fs_mgr_priv.h index 11602ea61..70abf5b78 100644 --- a/fs_mgr/fs_mgr_priv.h +++ b/fs_mgr/fs_mgr_priv.h @@ -103,3 +103,11 @@ int load_verity_state(const android::fs_mgr::FstabEntry& entry, int* mode); bool fs_mgr_is_ext4(const std::string& blk_device); bool fs_mgr_is_f2fs(const std::string& blk_device); + +bool fs_mgr_teardown_verity(android::fs_mgr::FstabEntry* fstab, bool wait); + +namespace android { +namespace fs_mgr { +bool UnmapDevice(const std::string& name, const std::chrono::milliseconds& timeout_ms); +} // namespace fs_mgr +} // namespace android diff --git a/fs_mgr/fs_mgr_verity.cpp b/fs_mgr/fs_mgr_verity.cpp index c53e8664f..3f0915780 100644 --- a/fs_mgr/fs_mgr_verity.cpp +++ b/fs_mgr/fs_mgr_verity.cpp @@ -44,6 +44,7 @@ #include "fec/io.h" #include "fs_mgr.h" +#include "fs_mgr_dm_linear.h" #include "fs_mgr_priv.h" // Realistically, this file should be part of the android::fs_mgr namespace; @@ -882,3 +883,12 @@ out: return retval; } + +bool fs_mgr_teardown_verity(FstabEntry* entry, bool wait) { + const std::string mount_point(basename(entry->mount_point.c_str())); + if (!android::fs_mgr::UnmapDevice(mount_point, wait ? 1000ms : 0ms)) { + return false; + } + LINFO << "Unmapped verity device " << mount_point; + return true; +} diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 8abe609a5..88b2f8f4f 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -93,3 +93,14 @@ int fs_mgr_setup_verity(android::fs_mgr::FstabEntry* fstab, bool wait_for_verity // specified, the super partition for the corresponding metadata slot will be // returned. Otherwise, it will use the current slot. std::string fs_mgr_get_super_partition_name(int slot = -1); + +enum FsMgrUmountStatus : int { + SUCCESS = 0, + ERROR_UNKNOWN = 1 << 0, + ERROR_UMOUNT = 1 << 1, + ERROR_VERITY = 1 << 2, + ERROR_DEVICE_MAPPER = 1 << 3, +}; +// fs_mgr_umount_all() is the reverse of fs_mgr_mount_all. In particular, +// it destroys verity devices from device mapper after the device is unmounted. +int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab); diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp index f0767dc47..04776edc5 100644 --- a/fs_mgr/libfs_avb/fs_avb.cpp +++ b/fs_mgr/libfs_avb/fs_avb.cpp @@ -449,6 +449,29 @@ AvbHashtreeResult AvbHandle::SetUpAvbHashtree(FstabEntry* fstab_entry, bool wait return AvbHashtreeResult::kSuccess; } +bool AvbHandle::TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait) { + if (!fstab_entry) { + return false; + } + + const std::string device_name(GetVerityDeviceName(*fstab_entry)); + + // TODO: remove duplicated code with UnmapDevice() + android::dm::DeviceMapper& dm = android::dm::DeviceMapper::Instance(); + std::string path; + if (wait) { + dm.GetDmDevicePathByName(device_name, &path); + } + if (!dm.DeleteDevice(device_name)) { + return false; + } + if (!path.empty() && !WaitForFile(path, 1000ms, FileWaitMode::DoesNotExist)) { + return false; + } + + return true; +} + std::string AvbHandle::GetSecurityPatchLevel(const FstabEntry& fstab_entry) const { if (vbmeta_images_.size() < 1) { return ""; diff --git a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h index 7127fa6ea..521f2d582 100644 --- a/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h +++ b/fs_mgr/libfs_avb/include/fs_avb/fs_avb.h @@ -110,6 +110,11 @@ class AvbHandle { static AvbHashtreeResult SetUpStandaloneAvbHashtree(FstabEntry* fstab_entry, bool wait_for_verity_dev = true); + // Tear down dm devices created by SetUp[Standalone]AvbHashtree + // The 'wait' parameter makes this function wait for the verity device to get destroyed + // before return. + static bool TearDownAvbHashtree(FstabEntry* fstab_entry, bool wait); + static bool IsDeviceUnlocked(); std::string GetSecurityPatchLevel(const FstabEntry& fstab_entry) const; diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp index 9e37d2261..12b5acb8b 100644 --- a/fs_mgr/libfs_avb/tests/util_test.cpp +++ b/fs_mgr/libfs_avb/tests/util_test.cpp @@ -27,6 +27,7 @@ // Target functions to test: using android::fs_mgr::BytesToHex; +using android::fs_mgr::FileWaitMode; using android::fs_mgr::HexToBytes; using android::fs_mgr::NibbleValue; using android::fs_mgr::WaitForFile; @@ -175,7 +176,7 @@ TEST(BasicUtilTest, WaitForFileDeferCreation) { // Waits this path. base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir"); ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */)); - auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms); + auto wait_file = std::async(WaitForFile, wait_path.value(), 500ms, FileWaitMode::Exists); // Sleeps 100ms before creating the wait_path. std::this_thread::sleep_for(100ms); @@ -196,7 +197,7 @@ TEST(BasicUtilTest, WaitForFileDeferCreationFailure) { // Waits this path. base::FilePath wait_path = tmp_dir.Append("libfs_avb-test-exist-dir"); ASSERT_TRUE(base::DeleteFile(wait_path, false /* resursive */)); - auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms); + auto wait_file = std::async(WaitForFile, wait_path.value(), 50ms, FileWaitMode::Exists); // Sleeps 100ms before creating the wait_path. std::this_thread::sleep_for(100ms); diff --git a/fs_mgr/libfs_avb/util.cpp b/fs_mgr/libfs_avb/util.cpp index 9d4f05f57..d214b5bdb 100644 --- a/fs_mgr/libfs_avb/util.cpp +++ b/fs_mgr/libfs_avb/util.cpp @@ -82,12 +82,17 @@ std::string BytesToHex(const uint8_t* bytes, size_t bytes_len) { return hex; } -bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout) { +// TODO: remove duplicate code with fs_mgr_wait_for_file +bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout, + FileWaitMode file_wait_mode) { auto start_time = std::chrono::steady_clock::now(); while (true) { - if (0 == access(filename.c_str(), F_OK) || errno != ENOENT) { - return true; + int rv = access(filename.c_str(), F_OK); + if (file_wait_mode == FileWaitMode::Exists) { + if (!rv || errno != ENOENT) return true; + } else if (file_wait_mode == FileWaitMode::DoesNotExist) { + if (rv && errno == ENOENT) return true; } std::this_thread::sleep_for(50ms); diff --git a/fs_mgr/libfs_avb/util.h b/fs_mgr/libfs_avb/util.h index cb861f466..7763da502 100644 --- a/fs_mgr/libfs_avb/util.h +++ b/fs_mgr/libfs_avb/util.h @@ -52,7 +52,9 @@ bool HexToBytes(uint8_t* bytes, size_t bytes_len, const std::string& hex); std::string BytesToHex(const uint8_t* bytes, size_t bytes_len); -bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout); +enum class FileWaitMode { Exists, DoesNotExist }; +bool WaitForFile(const std::string& filename, const std::chrono::milliseconds relative_timeout, + FileWaitMode wait_mode = FileWaitMode::Exists); bool IsDeviceUnlocked(); diff --git a/init/builtins.cpp b/init/builtins.cpp index 8437e3790..fc75072b6 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -451,13 +451,13 @@ static void import_late(const std::vector& args, size_t start_index if (false) DumpState(); } -/* mount_fstab +/* handle_fstab * - * Call fs_mgr_mount_all() to mount the given fstab + * Read the given fstab file and execute func on it. */ -static Result mount_fstab(const char* fstabfile, int mount_mode) { +static Result handle_fstab(const std::string& fstabfile, std::function func) { /* - * Call fs_mgr_mount_all() to mount all filesystems. We fork(2) and + * Call fs_mgr_[u]mount_all() to [u]mount all filesystems. We fork(2) and * do the call in the child to provide protection to the main init * process if anything goes wrong (crash or memory leak), and wait for * the child to finish in the parent. @@ -478,25 +478,51 @@ static Result mount_fstab(const char* fstabfile, int mount_mode) { return Error() << "child aborted"; } } else if (pid == 0) { - /* child, call fs_mgr_mount_all() */ + /* child, call fs_mgr_[u]mount_all() */ - // So we can always see what fs_mgr_mount_all() does. + // So we can always see what fs_mgr_[u]mount_all() does. // Only needed if someone explicitly changes the default log level in their init.rc. android::base::ScopedLogSeverity info(android::base::INFO); Fstab fstab; ReadFstabFromFile(fstabfile, &fstab); - int child_ret = fs_mgr_mount_all(&fstab, mount_mode); - if (child_ret == -1) { - PLOG(ERROR) << "fs_mgr_mount_all returned an error"; - } + int child_ret = func(&fstab); + _exit(child_ret); } else { return Error() << "fork() failed"; } } +/* mount_fstab + * + * Call fs_mgr_mount_all() to mount the given fstab + */ +static Result mount_fstab(const std::string& fstabfile, int mount_mode) { + return handle_fstab(fstabfile, [mount_mode](Fstab* fstab) { + int ret = fs_mgr_mount_all(fstab, mount_mode); + if (ret == -1) { + PLOG(ERROR) << "fs_mgr_mount_all returned an error"; + } + return ret; + }); +} + +/* umount_fstab + * + * Call fs_mgr_umount_all() to umount the given fstab + */ +static Result umount_fstab(const std::string& fstabfile) { + return handle_fstab(fstabfile, [](Fstab* fstab) { + int ret = fs_mgr_umount_all(fstab); + if (ret != 0) { + PLOG(ERROR) << "fs_mgr_umount_all returned " << ret; + } + return ret; + }); +} + /* Queue event based on fs_mgr return code. * * code: return code of fs_mgr_mount_all @@ -583,7 +609,7 @@ static Result do_mount_all(const BuiltinArguments& args) { bool import_rc = true; bool queue_event = true; int mount_mode = MOUNT_MODE_DEFAULT; - const char* fstabfile = args[1].c_str(); + const auto& fstabfile = args[1]; std::size_t path_arg_end = args.size(); const char* prop_post_fix = "default"; @@ -626,6 +652,15 @@ static Result do_mount_all(const BuiltinArguments& args) { return Success(); } +/* umount_all */ +static Result do_umount_all(const BuiltinArguments& args) { + auto umount_fstab_return_code = umount_fstab(args[1]); + if (!umount_fstab_return_code) { + return Error() << "umount_fstab() failed " << umount_fstab_return_code.error(); + } + return Success(); +} + static Result do_swapon_all(const BuiltinArguments& args) { Fstab fstab; if (!ReadFstabFromFile(args[1], &fstab)) { @@ -1165,6 +1200,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"mount", {3, kMax, {false, do_mount}}}, {"parse_apex_configs", {0, 0, {false, do_parse_apex_configs}}}, {"umount", {1, 1, {false, do_umount}}}, + {"umount_all", {1, 1, {false, do_umount_all}}}, {"readahead", {1, 2, {true, do_readahead}}}, {"restart", {1, 1, {false, do_restart}}}, {"restorecon", {1, kMax, {true, do_restorecon}}}, From 82866421b8b357b18c71e2b560c81c95ab925934 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Thu, 11 Apr 2019 19:45:35 -0700 Subject: [PATCH 132/221] Fix pc/function name for signal handler frame. This refactors the step function slightly to split it up into distinct pieces since the code needs to handle a signal handler versus normal step slightly differently. Add a new error for an invalid elf. Modify libbacktrace code to handle new error code. Bug: 130302288 Test: libbacktrace/libunwindstack unit tests. Change-Id: I3fb9b00c02d2cf2cc5911541bba0346c6f39b8e6 Merged-In: I3fb9b00c02d2cf2cc5911541bba0346c6f39b8e6 (cherry picked from commit d11ed86d65e870c5ea0d4918693376d474dbfe7d) --- libbacktrace/Backtrace.cpp | 2 + libbacktrace/UnwindStack.cpp | 4 ++ libbacktrace/include/backtrace/Backtrace.h | 2 + libunwindstack/Elf.cpp | 21 +++---- libunwindstack/LocalUnwinder.cpp | 26 ++++----- libunwindstack/Unwinder.cpp | 55 ++++++++++++------- libunwindstack/include/unwindstack/Elf.h | 5 +- libunwindstack/include/unwindstack/Error.h | 1 + libunwindstack/include/unwindstack/Unwinder.h | 3 +- libunwindstack/tests/ElfTest.cpp | 13 +++-- libunwindstack/tests/UnwindOfflineTest.cpp | 12 ++-- 11 files changed, 84 insertions(+), 60 deletions(-) diff --git a/libbacktrace/Backtrace.cpp b/libbacktrace/Backtrace.cpp index 6bec63c23..71980d7a5 100644 --- a/libbacktrace/Backtrace.cpp +++ b/libbacktrace/Backtrace.cpp @@ -170,5 +170,7 @@ std::string Backtrace::GetErrorString(BacktraceUnwindError error) { return "Failed to unwind due to invalid unwind information"; case BACKTRACE_UNWIND_ERROR_REPEATED_FRAME: return "Failed to unwind due to same sp/pc repeating"; + case BACKTRACE_UNWIND_ERROR_INVALID_ELF: + return "Failed to unwind due to invalid elf"; } } diff --git a/libbacktrace/UnwindStack.cpp b/libbacktrace/UnwindStack.cpp index f5f9b2ada..36640cdfa 100644 --- a/libbacktrace/UnwindStack.cpp +++ b/libbacktrace/UnwindStack.cpp @@ -89,6 +89,10 @@ bool Backtrace::Unwind(unwindstack::Regs* regs, BacktraceMap* back_map, case unwindstack::ERROR_REPEATED_FRAME: error->error_code = BACKTRACE_UNWIND_ERROR_REPEATED_FRAME; break; + + case unwindstack::ERROR_INVALID_ELF: + error->error_code = BACKTRACE_UNWIND_ERROR_INVALID_ELF; + break; } } diff --git a/libbacktrace/include/backtrace/Backtrace.h b/libbacktrace/include/backtrace/Backtrace.h index 10e790b3d..404e7e8ab 100644 --- a/libbacktrace/include/backtrace/Backtrace.h +++ b/libbacktrace/include/backtrace/Backtrace.h @@ -64,6 +64,8 @@ enum BacktraceUnwindErrorCode : uint32_t { BACKTRACE_UNWIND_ERROR_UNWIND_INFO, // Unwind information stopped due to sp/pc repeating. BACKTRACE_UNWIND_ERROR_REPEATED_FRAME, + // Unwind information stopped due to invalid elf. + BACKTRACE_UNWIND_ERROR_INVALID_ELF, }; struct BacktraceUnwindError { diff --git a/libunwindstack/Elf.cpp b/libunwindstack/Elf.cpp index 4b93abb43..345491356 100644 --- a/libunwindstack/Elf.cpp +++ b/libunwindstack/Elf.cpp @@ -160,7 +160,7 @@ ErrorCode Elf::GetLastErrorCode() { if (valid_) { return interface_->LastErrorCode(); } - return ERROR_NONE; + return ERROR_INVALID_ELF; } uint64_t Elf::GetLastErrorAddress() { @@ -170,22 +170,23 @@ uint64_t Elf::GetLastErrorAddress() { return 0; } +// The relative pc expectd by this function is relative to the start of the elf. +bool Elf::StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory) { + if (!valid_) { + return false; + } + return regs->StepIfSignalHandler(rel_pc, this, process_memory); +} + // The relative pc is always relative to the start of the map from which it comes. -bool Elf::Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory, - bool* finished) { +bool Elf::Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished) { if (!valid_) { return false; } - // The relative pc expectd by StepIfSignalHandler is relative to the start of the elf. - if (regs->StepIfSignalHandler(rel_pc, this, process_memory)) { - *finished = false; - return true; - } - // Lock during the step which can update information in the object. std::lock_guard guard(lock_); - return interface_->Step(adjusted_rel_pc, regs, process_memory, finished); + return interface_->Step(rel_pc, regs, process_memory, finished); } bool Elf::IsValidElf(Memory* memory) { diff --git a/libunwindstack/LocalUnwinder.cpp b/libunwindstack/LocalUnwinder.cpp index 5b2fadf2b..5d8120036 100644 --- a/libunwindstack/LocalUnwinder.cpp +++ b/libunwindstack/LocalUnwinder.cpp @@ -111,6 +111,14 @@ bool LocalUnwinder::Unwind(std::vector* frame_info, size_t max_f pc_adjustment = 0; } step_pc -= pc_adjustment; + + bool finished = false; + if (elf->StepIfSignalHandler(rel_pc, regs.get(), process_memory_.get())) { + step_pc = rel_pc; + } else if (!elf->Step(step_pc, regs.get(), process_memory_.get(), &finished)) { + finished = true; + } + // Skip any locations that are within this library. if (num_frames != 0 || !ShouldSkipLibrary(map_info->name)) { // Add frame information. @@ -124,22 +132,12 @@ bool LocalUnwinder::Unwind(std::vector* frame_info, size_t max_f } num_frames++; } - if (!elf->valid()) { - break; - } - if (frame_info->size() == max_frames) { - break; - } + if (finished || frame_info->size() == max_frames || + (cur_pc == regs->pc() && cur_sp == regs->sp())) { + break; + } adjust_pc = true; - bool finished; - if (!elf->Step(rel_pc, step_pc, regs.get(), process_memory_.get(), &finished) || finished) { - break; - } - // pc and sp are the same, terminate the unwind. - if (cur_pc == regs->pc() && cur_sp == regs->sp()) { - break; - } } return num_frames != 0; } diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index 3f2e1c1b8..f3d2b5e1c 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -89,8 +89,8 @@ void Unwinder::FillInDexFrame() { #endif } -void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc, - uint64_t pc_adjustment) { +FrameData* Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, + uint64_t pc_adjustment) { size_t frame_num = frames_.size(); frames_.resize(frame_num + 1); FrameData* frame = &frames_.at(frame_num); @@ -100,7 +100,8 @@ void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_ frame->pc = regs_->pc() - pc_adjustment; if (map_info == nullptr) { - return; + // Nothing else to update. + return nullptr; } if (resolve_names_) { @@ -118,12 +119,7 @@ void Unwinder::FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_ frame->map_end = map_info->end; frame->map_flags = map_info->flags; frame->map_load_bias = elf->GetLoadBias(); - - if (!resolve_names_ || - !elf->GetFunctionName(func_pc, &frame->function_name, &frame->function_offset)) { - frame->function_name = ""; - frame->function_offset = 0; - } + return frame; } static bool ShouldStop(const std::vector* map_suffixes_to_ignore, @@ -194,6 +190,7 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, } } + FrameData* frame = nullptr; if (map_info == nullptr || initial_map_names_to_skip == nullptr || std::find(initial_map_names_to_skip->begin(), initial_map_names_to_skip->end(), basename(map_info->name.c_str())) == initial_map_names_to_skip->end()) { @@ -210,23 +207,21 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, } } - FillInFrame(map_info, elf, rel_pc, step_pc, pc_adjustment); + frame = FillInFrame(map_info, elf, rel_pc, pc_adjustment); // Once a frame is added, stop skipping frames. initial_map_names_to_skip = nullptr; } adjust_pc = true; - bool stepped; + bool stepped = false; bool in_device_map = false; - if (map_info == nullptr) { - stepped = false; - } else { + bool finished = false; + if (map_info != nullptr) { if (map_info->flags & MAPS_FLAGS_DEVICE_MAP) { // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. - stepped = false; in_device_map = true; } else { MapInfo* sp_info = maps_->Find(regs_->sp()); @@ -234,19 +229,37 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, // Do not stop here, fall through in case we are // in the speculative unwind path and need to remove // some of the speculative frames. - stepped = false; in_device_map = true; } else { - bool finished; - stepped = elf->Step(rel_pc, step_pc, regs_, process_memory_.get(), &finished); - elf->GetLastError(&last_error_); - if (stepped && finished) { - break; + if (elf->StepIfSignalHandler(rel_pc, regs_, process_memory_.get())) { + stepped = true; + if (frame != nullptr) { + // Need to adjust the relative pc because the signal handler + // pc should not be adjusted. + frame->rel_pc = rel_pc; + frame->pc += pc_adjustment; + step_pc = rel_pc; + } + } else if (elf->Step(step_pc, regs_, process_memory_.get(), &finished)) { + stepped = true; } + elf->GetLastError(&last_error_); } } } + if (frame != nullptr) { + if (!resolve_names_ || + !elf->GetFunctionName(step_pc, &frame->function_name, &frame->function_offset)) { + frame->function_name = ""; + frame->function_offset = 0; + } + } + + if (finished) { + break; + } + if (!stepped) { if (return_address_attempt) { // Only remove the speculative frame if there are more than two frames diff --git a/libunwindstack/include/unwindstack/Elf.h b/libunwindstack/include/unwindstack/Elf.h index ac94f101c..56bf318c8 100644 --- a/libunwindstack/include/unwindstack/Elf.h +++ b/libunwindstack/include/unwindstack/Elf.h @@ -67,8 +67,9 @@ class Elf { uint64_t GetRelPc(uint64_t pc, const MapInfo* map_info); - bool Step(uint64_t rel_pc, uint64_t adjusted_rel_pc, Regs* regs, Memory* process_memory, - bool* finished); + bool StepIfSignalHandler(uint64_t rel_pc, Regs* regs, Memory* process_memory); + + bool Step(uint64_t rel_pc, Regs* regs, Memory* process_memory, bool* finished); ElfInterface* CreateInterfaceFromMemory(Memory* memory); diff --git a/libunwindstack/include/unwindstack/Error.h b/libunwindstack/include/unwindstack/Error.h index 6ed0e0fb0..72ec4547f 100644 --- a/libunwindstack/include/unwindstack/Error.h +++ b/libunwindstack/include/unwindstack/Error.h @@ -29,6 +29,7 @@ enum ErrorCode : uint8_t { ERROR_INVALID_MAP, // Unwind in an invalid map. ERROR_MAX_FRAMES_EXCEEDED, // The number of frames exceed the total allowed. ERROR_REPEATED_FRAME, // The last frame has the same pc/sp as the next. + ERROR_INVALID_ELF, // Unwind in an invalid elf. }; struct ErrorData { diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h index 8b01654a9..75be209a3 100644 --- a/libunwindstack/include/unwindstack/Unwinder.h +++ b/libunwindstack/include/unwindstack/Unwinder.h @@ -118,8 +118,7 @@ class Unwinder { Unwinder(size_t max_frames) : max_frames_(max_frames) { frames_.reserve(max_frames); } void FillInDexFrame(); - void FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t func_pc, - uint64_t pc_adjustment); + FrameData* FillInFrame(MapInfo* map_info, Elf* elf, uint64_t rel_pc, uint64_t pc_adjustment); size_t max_frames_; Maps* maps_; diff --git a/libunwindstack/tests/ElfTest.cpp b/libunwindstack/tests/ElfTest.cpp index 23c9cf860..c432d6d4f 100644 --- a/libunwindstack/tests/ElfTest.cpp +++ b/libunwindstack/tests/ElfTest.cpp @@ -132,8 +132,12 @@ TEST_F(ElfTest, elf_invalid) { uint64_t func_offset; ASSERT_FALSE(elf.GetFunctionName(0, &name, &func_offset)); + ASSERT_FALSE(elf.StepIfSignalHandler(0, nullptr, nullptr)); + EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode()); + bool finished; - ASSERT_FALSE(elf.Step(0, 0, nullptr, nullptr, &finished)); + ASSERT_FALSE(elf.Step(0, nullptr, nullptr, &finished)); + EXPECT_EQ(ERROR_INVALID_ELF, elf.GetLastErrorCode()); } TEST_F(ElfTest, elf32_invalid_machine) { @@ -295,9 +299,8 @@ TEST_F(ElfTest, step_in_signal_map) { } elf.FakeSetValid(true); - bool finished; - ASSERT_TRUE(elf.Step(0x3000, 0x1000, ®s, &process_memory, &finished)); - EXPECT_FALSE(finished); + ASSERT_TRUE(elf.StepIfSignalHandler(0x3000, ®s, &process_memory)); + EXPECT_EQ(ERROR_NONE, elf.GetLastErrorCode()); EXPECT_EQ(15U, regs.pc()); EXPECT_EQ(13U, regs.sp()); } @@ -336,7 +339,7 @@ TEST_F(ElfTest, step_in_interface) { EXPECT_CALL(*interface, Step(0x1000, ®s, &process_memory, &finished)) .WillOnce(::testing::Return(true)); - ASSERT_TRUE(elf.Step(0x1004, 0x1000, ®s, &process_memory, &finished)); + ASSERT_TRUE(elf.Step(0x1000, ®s, &process_memory, &finished)); } TEST_F(ElfTest, get_global_invalid_elf) { diff --git a/libunwindstack/tests/UnwindOfflineTest.cpp b/libunwindstack/tests/UnwindOfflineTest.cpp index 02ba9c8fa..6c64c4097 100644 --- a/libunwindstack/tests/UnwindOfflineTest.cpp +++ b/libunwindstack/tests/UnwindOfflineTest.cpp @@ -1215,7 +1215,7 @@ TEST_F(UnwindOfflineTest, offset_arm) { " #02 pc 0032bff3 libunwindstack_test (SignalOuterFunction+2)\n" " #03 pc 0032fed3 libunwindstack_test " "(unwindstack::SignalCallerHandler(int, siginfo*, void*)+26)\n" - " #04 pc 00026528 libc.so\n" + " #04 pc 0002652c libc.so (__restore)\n" " #05 pc 00000000 \n" " #06 pc 0032c2d9 libunwindstack_test (InnerFunction+736)\n" " #07 pc 0032cc4f libunwindstack_test (MiddleFunction+42)\n" @@ -1243,7 +1243,7 @@ TEST_F(UnwindOfflineTest, offset_arm) { EXPECT_EQ(0xf43d2ce8U, unwinder.frames()[2].sp); EXPECT_EQ(0x2e59ed3U, unwinder.frames()[3].pc); EXPECT_EQ(0xf43d2cf0U, unwinder.frames()[3].sp); - EXPECT_EQ(0xf4136528U, unwinder.frames()[4].pc); + EXPECT_EQ(0xf413652cU, unwinder.frames()[4].pc); EXPECT_EQ(0xf43d2d10U, unwinder.frames()[4].sp); EXPECT_EQ(0U, unwinder.frames()[5].pc); EXPECT_EQ(0xffcc0ee0U, unwinder.frames()[5].sp); @@ -1326,7 +1326,7 @@ TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) { " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n" " #01 pc 000000000005426c linker64 " "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n" - " #02 pc 00000000000008bc vdso.so\n" + " #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)\n" " #03 pc 00000000000846f4 libc.so (abort+172)\n" " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n" " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk!libfeature_support_angle.so (offset 0x4000) " @@ -1338,7 +1338,7 @@ TEST_F(UnwindOfflineTest, shared_lib_in_apk_arm64) { EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp); EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp); - EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc); + EXPECT_EQ(0x7e82b018c0ULL, unwinder.frames()[2].pc); EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp); EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc); EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp); @@ -1366,7 +1366,7 @@ TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) { " #00 pc 000000000014ccbc linker64 (__dl_syscall+28)\n" " #01 pc 000000000005426c linker64 " "(__dl__ZL24debuggerd_signal_handleriP7siginfoPv+1128)\n" - " #02 pc 00000000000008bc vdso.so\n" + " #02 pc 00000000000008c0 vdso.so (__kernel_rt_sigreturn)\n" " #03 pc 00000000000846f4 libc.so (abort+172)\n" " #04 pc 0000000000084ad4 libc.so (__assert2+36)\n" " #05 pc 000000000003d5b4 ANGLEPrebuilt.apk (offset 0x21d5000)\n" @@ -1377,7 +1377,7 @@ TEST_F(UnwindOfflineTest, shared_lib_in_apk_memory_only_arm64) { EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[0].sp); EXPECT_EQ(0x7e82b5726cULL, unwinder.frames()[1].pc); EXPECT_EQ(0x7df8ca3bf0ULL, unwinder.frames()[1].sp); - EXPECT_EQ(0x7e82b018bcULL, unwinder.frames()[2].pc); + EXPECT_EQ(0x7e82b018c0ULL, unwinder.frames()[2].pc); EXPECT_EQ(0x7df8ca3da0ULL, unwinder.frames()[2].sp); EXPECT_EQ(0x7e7eecc6f4ULL, unwinder.frames()[3].pc); EXPECT_EQ(0x7dabf3db60ULL, unwinder.frames()[3].sp); From 6569f35ae08b5de4323ae52be47f73e4ecb58ae1 Mon Sep 17 00:00:00 2001 From: Rick Yiu Date: Fri, 29 Mar 2019 20:03:47 +0800 Subject: [PATCH 133/221] Let blkio cgroup follow cpuset cgroup only Some app may have different cgroup settings in cpuset and schedtune for its threads, so let blkio follow cpuset only, which represents the app's current state more accurately. Otherwise, if that thread is doing IO, then its performance will be affected because its blkio group is in lower priority group as schedtune. ex: an app is now in top-app, but some thread of it set schedtune group to background, and blkio follows schedtune because it is called later. Main thread: 6:schedtune:/top-app 5:memory:/ 4:cpuset:/top-app 3:cpuacct:/uid_1000/pid_8766 2:cpu:/ 1:blkio:/ 0::/ Some thread: 6:schedtune:/background 5:memory:/ 4:cpuset:/top-app 3:cpuacct:/uid_1000/pid_8766 2:cpu:/ 1:blkio:/background 0::/ Bug: 124727032 Test: blkio has same settings with cpuset Change-Id: I9a140c7d9d93e1dd43c34c8cf066f4a62e2bf604 Merged-In: I9a140c7d9d93e1dd43c34c8cf066f4a62e2bf604 --- libprocessgroup/sched_policy.cpp | 17 ++++------------- 1 file changed, 4 insertions(+), 13 deletions(-) diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp index c7d0cca4c..ab0f1ca35 100644 --- a/libprocessgroup/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -126,24 +126,15 @@ int set_sched_policy(int tid, SchedPolicy policy) { switch (policy) { case SP_BACKGROUND: - return SetTaskProfiles(tid, {"HighEnergySaving", "LowIoPriority", "TimerSlackHigh"}) - ? 0 - : -1; + return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}) ? 0 : -1; case SP_FOREGROUND: case SP_AUDIO_APP: case SP_AUDIO_SYS: - return SetTaskProfiles(tid, {"HighPerformance", "HighIoPriority", "TimerSlackNormal"}) - ? 0 - : -1; + return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}) ? 0 : -1; case SP_TOP_APP: - return SetTaskProfiles(tid, {"MaxPerformance", "MaxIoPriority", "TimerSlackNormal"}) - ? 0 - : -1; + return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}) ? 0 : -1; case SP_RT_APP: - return SetTaskProfiles(tid, - {"RealtimePerformance", "MaxIoPriority", "TimerSlackNormal"}) - ? 0 - : -1; + return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}) ? 0 : -1; default: return SetTaskProfiles(tid, {"TimerSlackNormal"}) ? 0 : -1; } From a8e4b89768568ea65bdadfd03c71604329be5fee Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Wed, 17 Apr 2019 10:47:33 -0700 Subject: [PATCH 134/221] Remove libandroid.so from media namespace. Test: adb shell dumpsys media.extractor Bug: 130637522 Change-Id: Ia6366834613d1e12498fa90377e79f62a2149776 --- rootdir/etc/ld.config.legacy.txt | 1 - rootdir/etc/ld.config.txt | 2 -- rootdir/etc/ld.config.vndk_lite.txt | 2 -- 3 files changed, 5 deletions(-) diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt index 7324ba96b..bd6327505 100644 --- a/rootdir/etc/ld.config.legacy.txt +++ b/rootdir/etc/ld.config.legacy.txt @@ -97,7 +97,6 @@ namespace.media.asan.search.paths = /apex/com.android.media/${LIB} namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default -namespace.media.link.default.shared_libs = libandroid.so namespace.media.link.default.shared_libs += libbinder_ndk.so namespace.media.link.default.shared_libs += libc.so namespace.media.link.default.shared_libs += libcgrouprc.so diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt index 45e80e17c..91a437363 100644 --- a/rootdir/etc/ld.config.txt +++ b/rootdir/etc/ld.config.txt @@ -177,7 +177,6 @@ namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES% -namespace.media.link.default.shared_libs += libandroid.so namespace.media.link.default.shared_libs += libbinder_ndk.so namespace.media.link.default.shared_libs += libmediametrics.so namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES% @@ -620,7 +619,6 @@ namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES% -namespace.media.link.default.shared_libs += libandroid.so namespace.media.link.default.shared_libs += libbinder_ndk.so namespace.media.link.default.shared_libs += libmediametrics.so namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES% diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt index a762ba8b7..11729eeb0 100644 --- a/rootdir/etc/ld.config.vndk_lite.txt +++ b/rootdir/etc/ld.config.vndk_lite.txt @@ -119,7 +119,6 @@ namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES% -namespace.media.link.default.shared_libs += libandroid.so namespace.media.link.default.shared_libs += libbinder_ndk.so namespace.media.link.default.shared_libs += libmediametrics.so namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES% @@ -443,7 +442,6 @@ namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES% -namespace.media.link.default.shared_libs += libandroid.so namespace.media.link.default.shared_libs += libbinder_ndk.so namespace.media.link.default.shared_libs += libmediametrics.so namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES% From 90611aa3e6918448301e5712703062348a005546 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Tue, 9 Apr 2019 14:12:44 -0700 Subject: [PATCH 135/221] fs_mgr: overlay: wait for logical partition to be created Test: adb-remount-test.sh Bug: 130238923 Change-Id: Iaff01565d6df5c4434e66f742ed0939f61f6005a --- fs_mgr/fs_mgr_overlayfs.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index dea484406..730d3db68 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -715,7 +715,7 @@ bool fs_mgr_overlayfs_create_scratch(const Fstab& fstab, std::string* scratch_de } if (changed || partition_create) { - if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s, + if (!CreateLogicalPartition(super_device, slot_number, partition_name, true, 10s, scratch_device)) return false; @@ -940,7 +940,7 @@ bool fs_mgr_overlayfs_teardown(const char* mount_point, bool* change) { auto slot_number = fs_mgr_overlayfs_slot_number(); auto super_device = fs_mgr_overlayfs_super_device(slot_number); const auto partition_name = android::base::Basename(kScratchMountPoint); - CreateLogicalPartition(super_device, slot_number, partition_name, true, 0s, + CreateLogicalPartition(super_device, slot_number, partition_name, true, 10s, &scratch_device); } mount_scratch = fs_mgr_overlayfs_mount_scratch(scratch_device, From 08ccc735a386bdfb410538c714ec7871fda21537 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Tue, 16 Apr 2019 11:20:04 -0700 Subject: [PATCH 136/221] adbd: reduce the USB buffer sizes to 16k. Some USB controllers only support 16k writes, so drop down to that. Bug: http://b/130622010 Test: treehugger Change-Id: I836d5b2d0d6fcae05f290af11a6a19c6e8d7c1ba (cherry picked from commit 770a6a4d46343dcb5b8ba5c584245c8fc369ac6a) --- adb/daemon/usb.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp index 8c33ca580..3b29ab5fc 100644 --- a/adb/daemon/usb.cpp +++ b/adb/daemon/usb.cpp @@ -57,11 +57,12 @@ using android::base::StringPrintf; // We can't find out whether we have support for AIO on ffs endpoints until we submit a read. static std::optional gFfsAioSupported; +// Not all USB controllers support operations larger than 16k, so don't go above that. static constexpr size_t kUsbReadQueueDepth = 32; -static constexpr size_t kUsbReadSize = 8 * PAGE_SIZE; +static constexpr size_t kUsbReadSize = 4 * PAGE_SIZE; static constexpr size_t kUsbWriteQueueDepth = 32; -static constexpr size_t kUsbWriteSize = 8 * PAGE_SIZE; +static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE; static const char* to_string(enum usb_functionfs_event_type type) { switch (type) { From 6b8caf8eb709cc8eec1691d44ce09db4559e165d Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Tue, 16 Apr 2019 13:17:08 -0700 Subject: [PATCH 137/221] debuggerd: call setsid in our children. There appears to be a kernel bug that causes SIGHUP and SIGCONT to be sent to the parent process group we spawn from if the process group contains stopped jobs (e.g. the parent itself, because of wait_for_gdb). Call setsid in all of our children to prevent this from happening. Bug: http://b/31124563 Test: adb shell 'setprop debug.debuggerd.wait_for_gdb 1; killall -ABRT surfaceflinger' Change-Id: I1a48d70886880a5bfbe2deb80d48deece55faf09 (cherry picked from commit 18cb6812474e00050efab19e242c8a04ed470bec) --- debuggerd/crash_dump.cpp | 6 ++++++ debuggerd/handler/debuggerd_handler.cpp | 11 +++++++++-- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index 82ba0a18e..c608a8c33 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -363,6 +363,12 @@ int main(int argc, char** argv) { DefuseSignalHandlers(); InstallSigPipeHandler(); + // There appears to be a bug in the kernel where our death causes SIGHUP to + // be sent to our process group if we exit while it has stopped jobs (e.g. + // because of wait_for_gdb). Use setsid to create a new process group to + // avoid hitting this. + setsid(); + atrace_begin(ATRACE_TAG, "before reparent"); pid_t target_process = getppid(); diff --git a/debuggerd/handler/debuggerd_handler.cpp b/debuggerd/handler/debuggerd_handler.cpp index bca5e36d5..598ea85e8 100644 --- a/debuggerd/handler/debuggerd_handler.cpp +++ b/debuggerd/handler/debuggerd_handler.cpp @@ -268,8 +268,15 @@ static void create_vm_process() { _exit(errno); } - // Exit immediately on both sides of the fork. - // crash_dump is ptracing us, so it'll get to do whatever it wants in between. + // crash_dump is ptracing both sides of the fork; it'll let the parent exit, + // but keep the orphan stopped to peek at its memory. + + // There appears to be a bug in the kernel where our death causes SIGHUP to + // be sent to our process group if we exit while it has stopped jobs (e.g. + // because of wait_for_gdb). Use setsid to create a new process group to + // avoid hitting this. + setsid(); + _exit(0); } From cad2733f491af1d2757d63b9ff0317ccc572001a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Thu, 18 Apr 2019 14:14:33 -0700 Subject: [PATCH 138/221] Don't assume an A/B device when overriding the super partition name. Bug: 130750333 Test: launch cuttlefish with DAP enabled Change-Id: I1ea309d448866a8914f58be98d860eca36d47062 Merged-In: I1ea309d448866a8914f58be98d860eca36d47062 --- fs_mgr/fs_mgr.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 5114f5517..c1aafdac9 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -1695,11 +1695,12 @@ bool fs_mgr_verity_is_check_at_most_once(const android::fs_mgr::FstabEntry& entr std::string fs_mgr_get_super_partition_name(int slot) { // Devices upgrading to dynamic partitions are allowed to specify a super - // partition name, assumed to be A/B (non-A/B retrofit is not supported). - // For devices launching with dynamic partition support, the partition - // name must be "super". + // partition name. This includes cuttlefish, which is a non-A/B device. std::string super_partition; if (fs_mgr_get_boot_config_from_kernel_cmdline("super_partition", &super_partition)) { + if (fs_mgr_get_slot_suffix().empty()) { + return super_partition; + } std::string suffix; if (slot == 0) { suffix = "_a"; From bb2bc1586d1de2afec9874fdbeb1e204b996aadf Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Thu, 18 Apr 2019 14:56:24 -0700 Subject: [PATCH 139/221] init: set oom_adj early before fork vendor_init right now vendor_init is forked before we set oom_adj for init which leaves a chance vendor_init could be killed in heavy memory pressure. this CL set the oom_adj before forking everything to ensure all native have correct oom_adj settings. Fixes: 130824864 Test: procrank -o (cherry picked from commit 45d8174fe7b6f35883f74ceefdf591b209f1fab2) Change-Id: I68c18f9db24d55239f7f0608592fcc702f04542e --- init/init.cpp | 5 +++++ rootdir/init.rc | 3 --- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/init/init.cpp b/init/init.cpp index 0f44efda4..ac0e67a80 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -630,6 +630,11 @@ int SecondStageMain(int argc, char** argv) { InitKernelLogging(argv, InitAborter); LOG(INFO) << "init second stage started!"; + // Set init and its forked children's oom_adj. + if (auto result = WriteFile("/proc/1/oom_score_adj", "-1000"); !result) { + LOG(ERROR) << "Unable to write -1000 to /proc/1/oom_score_adj: " << result.error(); + } + // Enable seccomp if global boot option was passed (otherwise it is enabled in zygote). GlobalSeccomp(); diff --git a/rootdir/init.rc b/rootdir/init.rc index b274cf30e..17dd1457b 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -13,9 +13,6 @@ import /init.${ro.zygote}.rc # Cgroups are mounted right before early-init using list from /etc/cgroups.json on early-init - # Set init and its forked children's oom_adj. - write /proc/1/oom_score_adj -1000 - # Disable sysrq from keyboard write /proc/sys/kernel/sysrq 0 From b7b0cecce43022a31d99622be0591e9f900fa80c Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Wed, 3 Apr 2019 09:27:12 -0700 Subject: [PATCH 140/221] Add indicator that an elf is memory backed. Modify the unwinder library to indicate that at least one of the stack frames contains an elf file that is unreadable. Modify debuggerd to display a note about the unreadable frame and a possible way to fix it. Bug: 129769339 Test: New unit tests pass. Test: Ran an app that crashes and has an unreadable file and verified the Test: message is displayed. Then setenforce 0 and verify the message is Test: not displayed. Change-Id: Ibc4fe1d117e9b5840290454e90914ddc698d3cc2 Merged-In: Ibc4fe1d117e9b5840290454e90914ddc698d3cc2 (cherry picked from commit 4ae266ccbddbd0a6529248ecd1b324feab261c0d) --- debuggerd/Android.bp | 6 + debuggerd/libdebuggerd/backtrace.cpp | 5 +- .../include/libdebuggerd/utility.h | 3 + debuggerd/libdebuggerd/tombstone.cpp | 9 +- debuggerd/libdebuggerd/utility.cpp | 20 +++ libunwindstack/MapInfo.cpp | 3 + libunwindstack/Unwinder.cpp | 7 + libunwindstack/include/unwindstack/MapInfo.h | 3 + libunwindstack/include/unwindstack/Unwinder.h | 5 + .../tests/MapInfoCreateMemoryTest.cpp | 19 +++ libunwindstack/tests/UnwinderTest.cpp | 131 ++++++++++++++++++ 11 files changed, 199 insertions(+), 12 deletions(-) diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 0cf3378b1..2e226da6c 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -183,6 +183,12 @@ cc_library_static { ], }, }, + + product_variables: { + debuggable: { + cflags: ["-DROOT_POSSIBLE"], + }, + }, } cc_test { diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp index 94fcfb28c..c60697099 100644 --- a/debuggerd/libdebuggerd/backtrace.cpp +++ b/debuggerd/libdebuggerd/backtrace.cpp @@ -74,10 +74,7 @@ void dump_backtrace_thread(int output_fd, unwindstack::Unwinder* unwinder, return; } - unwinder->SetDisplayBuildID(true); - for (size_t i = 0; i < unwinder->NumFrames(); i++) { - _LOG(&log, logtype::BACKTRACE, " %s\n", unwinder->FormatFrame(i).c_str()); - } + log_backtrace(&log, unwinder, " "); } void dump_backtrace(android::base::unique_fd output_fd, unwindstack::Unwinder* unwinder, diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h index 238c00c5d..f189c451b 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h @@ -73,9 +73,12 @@ typedef uint32_t word_t; void _LOG(log_t* log, logtype ltype, const char* fmt, ...) __attribute__((format(printf, 3, 4))); namespace unwindstack { +class Unwinder; class Memory; } +void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix); + void dump_memory(log_t* log, unwindstack::Memory* backtrace, uint64_t addr, const std::string&); void read_with_default(const char* path, char* buf, size_t len, const char* default_value); diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index cc337ed30..d1726cdee 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -371,13 +371,6 @@ static void dump_all_maps(log_t* log, unwindstack::Unwinder* unwinder, uint64_t } } -void dump_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) { - unwinder->SetDisplayBuildID(true); - for (size_t i = 0; i < unwinder->NumFrames(); i++) { - _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str()); - } -} - static void print_register_row(log_t* log, const std::vector>& registers) { std::string output; @@ -470,7 +463,7 @@ static bool dump_thread(log_t* log, unwindstack::Unwinder* unwinder, const Threa _LOG(log, logtype::THREAD, "Failed to unwind"); } else { _LOG(log, logtype::BACKTRACE, "\nbacktrace:\n"); - dump_backtrace(log, unwinder, " "); + log_backtrace(log, unwinder, " "); _LOG(log, logtype::STACK, "\nstack:\n"); dump_stack(log, unwinder->frames(), unwinder->GetMaps(), unwinder->GetProcessMemory().get()); diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index 7aebea8fe..9b2779a9e 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -38,6 +38,7 @@ #include #include #include +#include using android::base::unique_fd; @@ -422,3 +423,22 @@ const char* get_sigcode(const siginfo_t* si) { // Then give up... return "?"; } + +void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* prefix) { + if (unwinder->elf_from_memory_not_file()) { + _LOG(log, logtype::BACKTRACE, + "%sNOTE: Function names and BuildId information is missing for some frames due\n", prefix); + _LOG(log, logtype::BACKTRACE, + "%sNOTE: to unreadable libraries. For unwinds of apps, only shared libraries\n", prefix); + _LOG(log, logtype::BACKTRACE, "%sNOTE: found under the lib/ directory are readable.\n", prefix); +#if defined(ROOT_POSSIBLE) + _LOG(log, logtype::BACKTRACE, + "%sNOTE: On this device, run setenforce 0 to make the libraries readable.\n", prefix); +#endif + } + + unwinder->SetDisplayBuildID(true); + for (size_t i = 0; i < unwinder->NumFrames(); i++) { + _LOG(log, logtype::BACKTRACE, "%s%s\n", prefix, unwinder->FormatFrame(i).c_str()); + } +} diff --git a/libunwindstack/MapInfo.cpp b/libunwindstack/MapInfo.cpp index 28373b27f..03658b445 100644 --- a/libunwindstack/MapInfo.cpp +++ b/libunwindstack/MapInfo.cpp @@ -161,6 +161,7 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr& process_memory) { // option is used. std::unique_ptr memory(new MemoryRange(process_memory, start, end - start, 0)); if (Elf::IsValidElf(memory.get())) { + memory_backed_elf = true; return memory.release(); } @@ -184,6 +185,7 @@ Memory* MapInfo::CreateMemory(const std::shared_ptr& process_memory) { new MemoryRange(process_memory, prev_map->start, prev_map->end - prev_map->start, 0)); ranges->Insert(new MemoryRange(process_memory, start, end - start, elf_offset)); + memory_backed_elf = true; return ranges; } @@ -237,6 +239,7 @@ Elf* MapInfo::GetElf(const std::shared_ptr& process_memory, ArchEnum exp std::lock_guard guard(prev_map->mutex_); if (prev_map->elf.get() == nullptr) { prev_map->elf = elf; + prev_map->memory_backed_elf = memory_backed_elf; } } return elf.get(); diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index f3d2b5e1c..26626b5cd 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -141,6 +141,7 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, frames_.clear(); last_error_.code = ERROR_NONE; last_error_.address = 0; + elf_from_memory_not_file_ = false; ArchEnum arch = regs_->Arch(); @@ -164,6 +165,12 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, break; } elf = map_info->GetElf(process_memory_, arch); + // If this elf is memory backed, and there is a valid file, then set + // an indicator that we couldn't open the file. + if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() && + map_info->name[0] != '[') { + elf_from_memory_not_file_ = true; + } step_pc = regs_->pc(); rel_pc = elf->GetRelPc(step_pc, map_info); // Everyone except elf data in gdb jit debug maps uses the relative pc. diff --git a/libunwindstack/include/unwindstack/MapInfo.h b/libunwindstack/include/unwindstack/MapInfo.h index e938986d8..025fd98da 100644 --- a/libunwindstack/include/unwindstack/MapInfo.h +++ b/libunwindstack/include/unwindstack/MapInfo.h @@ -75,6 +75,9 @@ struct MapInfo { // make it easier to move to a fine grained lock in the future. std::atomic_uintptr_t build_id; + // Set to true if the elf file data is coming from memory. + bool memory_backed_elf = false; + // This function guarantees it will never return nullptr. Elf* GetElf(const std::shared_ptr& process_memory, ArchEnum expected_arch); diff --git a/libunwindstack/include/unwindstack/Unwinder.h b/libunwindstack/include/unwindstack/Unwinder.h index 75be209a3..52b3578d8 100644 --- a/libunwindstack/include/unwindstack/Unwinder.h +++ b/libunwindstack/include/unwindstack/Unwinder.h @@ -111,6 +111,8 @@ class Unwinder { void SetDexFiles(DexFiles* dex_files, ArchEnum arch); #endif + bool elf_from_memory_not_file() { return elf_from_memory_not_file_; } + ErrorCode LastErrorCode() { return last_error_.code; } uint64_t LastErrorAddress() { return last_error_.address; } @@ -132,6 +134,9 @@ class Unwinder { bool resolve_names_ = true; bool embedded_soname_ = true; bool display_build_id_ = false; + // True if at least one elf file is coming from memory and not the related + // file. This is only true if there is an actual file backing up the elf. + bool elf_from_memory_not_file_ = false; ErrorData last_error_; }; diff --git a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp index 2ddadef37..6be8bdccb 100644 --- a/libunwindstack/tests/MapInfoCreateMemoryTest.cpp +++ b/libunwindstack/tests/MapInfoCreateMemoryTest.cpp @@ -108,6 +108,7 @@ TEST_F(MapInfoCreateMemoryTest, end_le_start) { info.end = 0x101; memory.reset(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); } // Verify that if the offset is non-zero but there is no elf at the offset, @@ -117,6 +118,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); ASSERT_EQ(0x100U, info.elf_offset); EXPECT_EQ(0x100U, info.elf_start_offset); @@ -140,32 +142,40 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_full_file) { // offset to zero. info.elf_offset = 0; info.elf_start_offset = 0; + info.memory_backed_elf = false; memory.reset(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); ASSERT_EQ(0x100U, info.elf_offset); EXPECT_EQ(0x100U, info.elf_start_offset); prev_info.offset = 0; info.elf_offset = 0; info.elf_start_offset = 0; + info.memory_backed_elf = false; memory.reset(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); ASSERT_EQ(0x100U, info.elf_offset); EXPECT_EQ(0x100U, info.elf_start_offset); prev_info.flags = PROT_READ; info.elf_offset = 0; info.elf_start_offset = 0; + info.memory_backed_elf = false; memory.reset(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); ASSERT_EQ(0x100U, info.elf_offset); EXPECT_EQ(0x100U, info.elf_start_offset); prev_info.name = info.name; info.elf_offset = 0; info.elf_start_offset = 0; + info.memory_backed_elf = false; memory.reset(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); ASSERT_EQ(0x100U, info.elf_offset); EXPECT_EQ(0U, info.elf_start_offset); } @@ -177,6 +187,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file) { std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); ASSERT_EQ(0U, info.elf_offset); EXPECT_EQ(0x1000U, info.elf_start_offset); @@ -201,6 +212,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); ASSERT_EQ(0U, info.elf_offset); EXPECT_EQ(0x1000U, info.elf_start_offset); @@ -218,6 +230,7 @@ TEST_F(MapInfoCreateMemoryTest, file_backed_non_zero_offset_partial_file_whole_e std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(info.memory_backed_elf); ASSERT_EQ(0U, info.elf_offset); EXPECT_EQ(0x2000U, info.elf_start_offset); @@ -259,6 +272,7 @@ TEST_F(MapInfoCreateMemoryTest, process_memory) { std::unique_ptr memory(info.CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_TRUE(info.memory_backed_elf); memset(buffer.data(), 0, buffer.size()); ASSERT_TRUE(memory->ReadFully(0, buffer.data(), buffer.size())); @@ -290,6 +304,7 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_zero_offset) { std::unique_ptr mem(map_info->CreateMemory(process_memory_)); ASSERT_TRUE(mem.get() != nullptr); + EXPECT_TRUE(map_info->memory_backed_elf); EXPECT_EQ(0x4000UL, map_info->elf_offset); EXPECT_EQ(0x4000UL, map_info->offset); EXPECT_EQ(0U, map_info->elf_start_offset); @@ -336,6 +351,7 @@ TEST_F(MapInfoCreateMemoryTest, valid_rosegment_non_zero_offset) { std::unique_ptr mem(map_info->CreateMemory(process_memory_)); ASSERT_TRUE(mem.get() != nullptr); + EXPECT_TRUE(map_info->memory_backed_elf); EXPECT_EQ(0x1000UL, map_info->elf_offset); EXPECT_EQ(0xb000UL, map_info->offset); EXPECT_EQ(0xa000UL, map_info->elf_start_offset); @@ -374,6 +390,7 @@ TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) { // extend over the executable segment. std::unique_ptr memory(map_info->CreateMemory(process_memory_)); ASSERT_TRUE(memory.get() != nullptr); + EXPECT_FALSE(map_info->memory_backed_elf); std::vector buffer(0x100); EXPECT_EQ(0x2000U, map_info->offset); EXPECT_EQ(0U, map_info->elf_offset); @@ -388,7 +405,9 @@ TEST_F(MapInfoCreateMemoryTest, rosegment_from_file) { ASSERT_EQ(0x1000, lseek(elf_at_1000_.fd, 0x1000, SEEK_SET)); ASSERT_TRUE(android::base::WriteFully(elf_at_1000_.fd, &ehdr, sizeof(ehdr))); + map_info->memory_backed_elf = false; memory.reset(map_info->CreateMemory(process_memory_)); + EXPECT_FALSE(map_info->memory_backed_elf); EXPECT_EQ(0x2000U, map_info->offset); EXPECT_EQ(0x1000U, map_info->elf_offset); EXPECT_EQ(0x1000U, map_info->elf_start_offset); diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index 48e038e9a..f6350216f 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -108,6 +108,24 @@ class UnwinderTest : public ::testing::Test { const auto& info2 = *--maps_->end(); info2->elf_offset = 0x8000; + elf = new ElfFake(new MemoryFake); + elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); + AddMapInfo(0xc0000, 0xc1000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/fake/unreadable.so", elf); + const auto& info3 = *--maps_->end(); + info3->memory_backed_elf = true; + + elf = new ElfFake(new MemoryFake); + elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); + AddMapInfo(0xc1000, 0xc2000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "[vdso]", elf); + const auto& info4 = *--maps_->end(); + info4->memory_backed_elf = true; + + elf = new ElfFake(new MemoryFake); + elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); + AddMapInfo(0xc2000, 0xc3000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "", elf); + const auto& info5 = *--maps_->end(); + info5->memory_backed_elf = true; + process_memory_.reset(new MemoryFake); } @@ -140,6 +158,7 @@ TEST_F(UnwinderTest, multiple_frames) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -204,6 +223,7 @@ TEST_F(UnwinderTest, multiple_frames_dont_resolve_names) { unwinder.SetResolveNames(false); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -263,6 +283,7 @@ TEST_F(UnwinderTest, non_zero_load_bias) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -292,6 +313,7 @@ TEST_F(UnwinderTest, non_zero_elf_offset) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -321,6 +343,7 @@ TEST_F(UnwinderTest, non_zero_map_offset) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -351,6 +374,7 @@ TEST_F(UnwinderTest, disable_embedded_soname) { unwinder.SetEmbeddedSoname(false); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -387,6 +411,7 @@ TEST_F(UnwinderTest, no_frames_after_finished) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -419,6 +444,7 @@ TEST_F(UnwinderTest, max_frames) { Unwinder unwinder(20, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(20U, unwinder.NumFrames()); @@ -461,6 +487,7 @@ TEST_F(UnwinderTest, verify_frames_skipped) { std::vector skip_libs{"libunwind.so", "libanother.so"}; unwinder.Unwind(&skip_libs); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -522,6 +549,7 @@ TEST_F(UnwinderTest, sp_not_in_map) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(2U, unwinder.NumFrames()); @@ -569,6 +597,7 @@ TEST_F(UnwinderTest, pc_in_device_stops_unwind) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); } @@ -588,6 +617,7 @@ TEST_F(UnwinderTest, sp_in_device_stops_unwind) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); } @@ -602,6 +632,7 @@ TEST_F(UnwinderTest, pc_without_map) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -638,6 +669,7 @@ TEST_F(UnwinderTest, speculative_frame) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -703,6 +735,7 @@ TEST_F(UnwinderTest, speculative_frame_removed) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_INVALID_MAP, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(2U, unwinder.NumFrames()); @@ -752,6 +785,7 @@ TEST_F(UnwinderTest, speculative_frame_not_removed_pc_bad) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(2U, unwinder.NumFrames()); @@ -799,6 +833,7 @@ TEST_F(UnwinderTest, speculative_frame_check_with_no_frames) { std::vector skip_names{"libanother.so"}; unwinder.Unwind(&skip_names); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(0U, unwinder.NumFrames()); } @@ -821,6 +856,7 @@ TEST_F(UnwinderTest, map_ignore_suffixes) { std::vector suffixes{"oat"}; unwinder.Unwind(nullptr, &suffixes); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(2U, unwinder.NumFrames()); // Make sure the elf was not initialized. @@ -879,6 +915,7 @@ TEST_F(UnwinderTest, sp_pc_do_not_change) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_REPEATED_FRAME, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -937,6 +974,7 @@ TEST_F(UnwinderTest, dex_pc_in_map) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(2U, unwinder.NumFrames()); @@ -980,6 +1018,7 @@ TEST_F(UnwinderTest, dex_pc_not_in_map) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(2U, unwinder.NumFrames()); @@ -1026,6 +1065,7 @@ TEST_F(UnwinderTest, dex_pc_multiple_frames) { Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(3U, unwinder.NumFrames()); @@ -1084,6 +1124,7 @@ TEST_F(UnwinderTest, dex_pc_max_frames) { Unwinder unwinder(1, maps_.get(), ®s_, process_memory_); unwinder.Unwind(); EXPECT_EQ(ERROR_MAX_FRAMES_EXCEEDED, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); ASSERT_EQ(1U, unwinder.NumFrames()); @@ -1103,6 +1144,96 @@ TEST_F(UnwinderTest, dex_pc_max_frames) { EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); } +TEST_F(UnwinderTest, elf_from_memory_not_file) { + ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); + + regs_.set_pc(0xc0050); + regs_.set_sp(0x10000); + ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); + + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); + unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_TRUE(unwinder.elf_from_memory_not_file()); + + ASSERT_EQ(1U, unwinder.NumFrames()); + + auto* frame = &unwinder.frames()[0]; + EXPECT_EQ(0U, frame->num); + EXPECT_EQ(0x50U, frame->rel_pc); + EXPECT_EQ(0xc0050U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("Frame0", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("/fake/unreadable.so", frame->map_name); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); + EXPECT_EQ(0xc0000U, frame->map_start); + EXPECT_EQ(0xc1000U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); +} + +TEST_F(UnwinderTest, elf_from_memory_but_no_valid_file_with_bracket) { + ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); + + regs_.set_pc(0xc1050); + regs_.set_sp(0x10000); + ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); + + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); + unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); + + ASSERT_EQ(1U, unwinder.NumFrames()); + + auto* frame = &unwinder.frames()[0]; + EXPECT_EQ(0U, frame->num); + EXPECT_EQ(0x50U, frame->rel_pc); + EXPECT_EQ(0xc1050U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("Frame0", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("[vdso]", frame->map_name); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); + EXPECT_EQ(0xc1000U, frame->map_start); + EXPECT_EQ(0xc2000U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); +} + +TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) { + ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); + + regs_.set_pc(0xc2050); + regs_.set_sp(0x10000); + ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); + + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); + unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); + + ASSERT_EQ(1U, unwinder.NumFrames()); + + auto* frame = &unwinder.frames()[0]; + EXPECT_EQ(0U, frame->num); + EXPECT_EQ(0x50U, frame->rel_pc); + EXPECT_EQ(0xc2050U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("Frame0", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("", frame->map_name); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); + EXPECT_EQ(0xc2000U, frame->map_start); + EXPECT_EQ(0xc3000U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); +} + // Verify format frame code. TEST_F(UnwinderTest, format_frame) { RegsFake regs_arm(10); From 630fcdf153f2066d070c9732f12e6a234cd40582 Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Thu, 11 Apr 2019 23:57:24 +0800 Subject: [PATCH 141/221] Copying debug ramdisk files to /debug_ramdisk/* In previous implementation, userdebug sepoilcy and property files are loaded from the system.img. This CL changes this to: - first-stage init copies userdebug files from ramdisk to /debug_ramisk/* - second-stage init loads files from /debug_ramdisk/*. Note: same as before, the above can only be triggered, if the device is UNLOCKED With this, we don't have to put userdebug related files into the USER system.img. Bug: 126493225 Test: boot device with a ramdisk with /force_debuggable, checks related files are loaded Change-Id: I63f5f846e82ba78427062bf7615c26173878d8f3 Merged-In: I63f5f846e82ba78427062bf7615c26173878d8f3 (cherry picked from commit 30afda71c0dac4d1d59a91b78256ebff76257ad8) --- init/Android.bp | 1 + init/Android.mk | 2 ++ init/debug_ramdisk.h | 26 ++++++++++++++++++++++++++ init/first_stage_init.cpp | 16 +++++++++++++++- init/init.cpp | 7 +++++++ init/property_service.cpp | 6 +++--- init/selinux.cpp | 7 +++---- rootdir/Android.mk | 2 +- 8 files changed, 58 insertions(+), 9 deletions(-) create mode 100644 init/debug_ramdisk.h diff --git a/init/Android.bp b/init/Android.bp index 69ee34f13..69498acba 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -61,6 +61,7 @@ cc_defaults { static_libs: [ "libseccomp_policy", "libavb", + "libc++fs", "libcgrouprc_format", "libprotobuf-cpp-lite", "libpropertyinfoserializer", diff --git a/init/Android.mk b/init/Android.mk index 39af0e686..efa8d87c8 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -68,12 +68,14 @@ LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED) # Set up the same mount points on the ramdisk that system-as-root contains. LOCAL_POST_INSTALL_CMD := mkdir -p \ $(TARGET_RAMDISK_OUT)/apex \ + $(TARGET_RAMDISK_OUT)/debug_ramdisk \ $(TARGET_RAMDISK_OUT)/dev \ $(TARGET_RAMDISK_OUT)/mnt \ $(TARGET_RAMDISK_OUT)/proc \ $(TARGET_RAMDISK_OUT)/sys \ LOCAL_STATIC_LIBRARIES := \ + libc++fs \ libfs_avb \ libfs_mgr \ libfec \ diff --git a/init/debug_ramdisk.h b/init/debug_ramdisk.h new file mode 100644 index 000000000..4e3a3955d --- /dev/null +++ b/init/debug_ramdisk.h @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#pragma once + +namespace android { +namespace init { + +constexpr const char kDebugRamdiskProp[] = "/debug_ramdisk/adb_debug.prop"; +constexpr const char kDebugRamdiskSEPolicy[] = "/debug_ramdisk/userdebug_plat_sepolicy.cil"; + +} // namespace init +} // namespace android diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index c56667653..8b95e3832 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -26,6 +26,7 @@ #include #include +#include #include #include @@ -35,6 +36,7 @@ #include #include +#include "debug_ramdisk.h" #include "first_stage_mount.h" #include "reboot_utils.h" #include "switch_root.h" @@ -44,6 +46,8 @@ using android::base::boot_clock; using namespace std::literals; +namespace fs = std::filesystem; + namespace android { namespace init { @@ -159,6 +163,9 @@ int FirstStageMain(int argc, char** argv) { CHECKCALL(mount("tmpfs", "/apex", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, "mode=0755,uid=0,gid=0")); + // /debug_ramdisk is used to preserve additional files from the debug ramdisk + CHECKCALL(mount("tmpfs", "/debug_ramdisk", "tmpfs", MS_NOEXEC | MS_NOSUID | MS_NODEV, + "mode=0755,uid=0,gid=0")); #undef CHECKCALL // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually @@ -202,7 +209,14 @@ int FirstStageMain(int argc, char** argv) { // If this file is present, the second-stage init will use a userdebug sepolicy // and load adb_debug.prop to allow adb root, if the device is unlocked. if (access("/force_debuggable", F_OK) == 0) { - setenv("INIT_FORCE_DEBUGGABLE", "true", 1); + std::error_code ec; // to invoke the overloaded copy_file() that won't throw. + if (!fs::copy_file("/adb_debug.prop", kDebugRamdiskProp, ec) || + !fs::copy_file("/userdebug_plat_sepolicy.cil", kDebugRamdiskSEPolicy, ec)) { + LOG(ERROR) << "Failed to setup debug ramdisk"; + } else { + // setenv for second-stage init to read above kDebugRamdisk* files. + setenv("INIT_FORCE_DEBUGGABLE", "true", 1); + } } if (!DoFirstStageMount()) { diff --git a/init/init.cpp b/init/init.cpp index ac0e67a80..c79e459eb 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -621,6 +621,12 @@ static void GlobalSeccomp() { }); } +static void UmountDebugRamdisk() { + if (umount("/debug_ramdisk") != 0) { + LOG(ERROR) << "Failed to umount /debug_ramdisk"; + } +} + int SecondStageMain(int argc, char** argv) { if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); @@ -690,6 +696,7 @@ int SecondStageMain(int argc, char** argv) { InstallSignalFdHandler(&epoll); property_load_boot_defaults(load_debug_prop); + UmountDebugRamdisk(); fs_mgr_vendor_overlay_mount_all(); export_oem_lock_status(); StartPropertyService(&epoll); diff --git a/init/property_service.cpp b/init/property_service.cpp index fc5538c51..bca73c950 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -56,6 +56,7 @@ #include #include +#include "debug_ramdisk.h" #include "epoll.h" #include "init.h" #include "persistent_properties.h" @@ -889,9 +890,8 @@ void property_load_boot_defaults(bool load_debug_prop) { load_properties_from_file("/factory/factory.prop", "ro.*", &properties); if (load_debug_prop) { - constexpr static const char kAdbDebugProp[] = "/system/etc/adb_debug.prop"; - LOG(INFO) << "Loading " << kAdbDebugProp; - load_properties_from_file(kAdbDebugProp, nullptr, &properties); + LOG(INFO) << "Loading " << kDebugRamdiskProp; + load_properties_from_file(kDebugRamdiskProp, nullptr, &properties); } for (const auto& [name, value] : properties) { diff --git a/init/selinux.cpp b/init/selinux.cpp index aa66baacf..132fc137d 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -64,6 +64,7 @@ #include #include +#include "debug_ramdisk.h" #include "reboot_utils.h" #include "util.h" @@ -271,8 +272,6 @@ bool GetVendorMappingVersion(std::string* plat_vers) { } constexpr const char plat_policy_cil_file[] = "/system/etc/selinux/plat_sepolicy.cil"; -constexpr const char userdebug_plat_policy_cil_file[] = - "/system/etc/selinux/userdebug_plat_sepolicy.cil"; bool IsSplitPolicyDevice() { return access(plat_policy_cil_file, R_OK) != -1; @@ -292,7 +291,7 @@ bool LoadSplitPolicy() { const char* force_debuggable_env = getenv("INIT_FORCE_DEBUGGABLE"); bool use_userdebug_policy = ((force_debuggable_env && "true"s == force_debuggable_env) && - AvbHandle::IsDeviceUnlocked() && access(userdebug_plat_policy_cil_file, F_OK) == 0); + AvbHandle::IsDeviceUnlocked() && access(kDebugRamdiskSEPolicy, F_OK) == 0); if (use_userdebug_policy) { LOG(WARNING) << "Using userdebug system sepolicy"; } @@ -367,7 +366,7 @@ bool LoadSplitPolicy() { // clang-format off std::vector compile_args { "/system/bin/secilc", - use_userdebug_policy ? userdebug_plat_policy_cil_file : plat_policy_cil_file, + use_userdebug_policy ? kDebugRamdiskSEPolicy: plat_policy_cil_file, "-m", "-M", "true", "-G", "-N", "-c", version_as_string.c_str(), plat_mapping_file.c_str(), diff --git a/rootdir/Android.mk b/rootdir/Android.mk index 5d307b859..a97858a93 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -97,7 +97,7 @@ endif # # create some directories (some are mount points) and symlinks LOCAL_POST_INSTALL_CMD := mkdir -p $(addprefix $(TARGET_ROOT_OUT)/, \ - sbin dev proc sys system data odm oem acct config storage mnt apex $(BOARD_ROOT_EXTRA_FOLDERS)); \ + sbin dev proc sys system data odm oem acct config storage mnt apex debug_ramdisk $(BOARD_ROOT_EXTRA_FOLDERS)); \ ln -sf /system/bin $(TARGET_ROOT_OUT)/bin; \ ln -sf /system/etc $(TARGET_ROOT_OUT)/etc; \ ln -sf /data/user_de/0/com.android.shell/files/bugreports $(TARGET_ROOT_OUT)/bugreports; \ From 949f10d7ef21b60a93b1fa386613c9ff4f56129e Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Thu, 14 Feb 2019 14:40:41 -0800 Subject: [PATCH 142/221] Re-enable file descriptor caching and add option to skip caching This reverts commit bee9f5718bd2dfedb615767bbd25147b4f3eed15 "libprocessgroup: Disable file descriptor caching temporarily" and adds option to use SetTaskProfiles and SetProcessProfiles without file caching. This option is used from JNI to avoid access denials because cached files are not whitelisted for JNI usage. Bug: 123868658 Bug: 123043091 Test: boot using svelte target Change-Id: I76b9d6af8a1dd4464cb3cf3e6dc327980efdf361 Signed-off-by: Suren Baghdasaryan --- .../include/processgroup/processgroup.h | 5 +- libprocessgroup/processgroup.cpp | 15 +++- libprocessgroup/sched_policy.cpp | 34 ++++---- libprocessgroup/task_profiles.cpp | 77 ++++++++++--------- libprocessgroup/task_profiles.h | 19 ++++- 5 files changed, 91 insertions(+), 59 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 86e60356b..8d150adb0 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -32,8 +32,9 @@ bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::s bool UsePerAppMemcg(); -bool SetTaskProfiles(int tid, const std::vector& profiles); -bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles); +bool SetTaskProfiles(int tid, const std::vector& profiles, bool use_fd_cache = false); +bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles, + bool use_fd_cache = false); // Return 0 and removes the cgroup if there are no longer any processes in it. // Returns -1 in the case of an error occurring or if there are processes still running diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index abe63dd70..1485ae986 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -112,12 +112,16 @@ static bool isMemoryCgroupSupported() { return memcg_supported; } -bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles) { +bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles, + bool use_fd_cache) { const TaskProfiles& tp = TaskProfiles::GetInstance(); for (const auto& name : profiles) { - const TaskProfile* profile = tp.GetProfile(name); + TaskProfile* profile = tp.GetProfile(name); if (profile != nullptr) { + if (use_fd_cache) { + profile->EnableResourceCaching(); + } if (!profile->ExecuteForProcess(uid, pid)) { PLOG(WARNING) << "Failed to apply " << name << " process profile"; } @@ -129,12 +133,15 @@ bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& pr return true; } -bool SetTaskProfiles(int tid, const std::vector& profiles) { +bool SetTaskProfiles(int tid, const std::vector& profiles, bool use_fd_cache) { const TaskProfiles& tp = TaskProfiles::GetInstance(); for (const auto& name : profiles) { - const TaskProfile* profile = tp.GetProfile(name); + TaskProfile* profile = tp.GetProfile(name); if (profile != nullptr) { + if (use_fd_cache) { + profile->EnableResourceCaching(); + } if (!profile->ExecuteForTask(tid)) { PLOG(WARNING) << "Failed to apply " << name << " task profile"; } diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp index ab0f1ca35..fe4f93b1e 100644 --- a/libprocessgroup/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -46,26 +46,34 @@ int set_cpuset_policy(int tid, SchedPolicy policy) { switch (policy) { case SP_BACKGROUND: - return SetTaskProfiles(tid, {"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority", - "TimerSlackHigh"}) + return SetTaskProfiles(tid, + {"HighEnergySaving", "ProcessCapacityLow", "LowIoPriority", + "TimerSlackHigh"}, + true) ? 0 : -1; case SP_FOREGROUND: case SP_AUDIO_APP: case SP_AUDIO_SYS: - return SetTaskProfiles(tid, {"HighPerformance", "ProcessCapacityHigh", "HighIoPriority", - "TimerSlackNormal"}) + return SetTaskProfiles(tid, + {"HighPerformance", "ProcessCapacityHigh", "HighIoPriority", + "TimerSlackNormal"}, + true) ? 0 : -1; case SP_TOP_APP: - return SetTaskProfiles(tid, {"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority", - "TimerSlackNormal"}) + return SetTaskProfiles(tid, + {"MaxPerformance", "ProcessCapacityMax", "MaxIoPriority", + "TimerSlackNormal"}, + true) ? 0 : -1; case SP_SYSTEM: - return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}) ? 0 : -1; + return SetTaskProfiles(tid, {"ServiceCapacityLow", "TimerSlackNormal"}, true) ? 0 : -1; case SP_RESTRICTED: - return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}) ? 0 : -1; + return SetTaskProfiles(tid, {"ServiceCapacityRestricted", "TimerSlackNormal"}, true) + ? 0 + : -1; default: break; } @@ -126,17 +134,17 @@ int set_sched_policy(int tid, SchedPolicy policy) { switch (policy) { case SP_BACKGROUND: - return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}) ? 0 : -1; + return SetTaskProfiles(tid, {"HighEnergySaving", "TimerSlackHigh"}, true) ? 0 : -1; case SP_FOREGROUND: case SP_AUDIO_APP: case SP_AUDIO_SYS: - return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}) ? 0 : -1; + return SetTaskProfiles(tid, {"HighPerformance", "TimerSlackNormal"}, true) ? 0 : -1; case SP_TOP_APP: - return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}) ? 0 : -1; + return SetTaskProfiles(tid, {"MaxPerformance", "TimerSlackNormal"}, true) ? 0 : -1; case SP_RT_APP: - return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}) ? 0 : -1; + return SetTaskProfiles(tid, {"RealtimePerformance", "TimerSlackNormal"}, true) ? 0 : -1; default: - return SetTaskProfiles(tid, {"TimerSlackNormal"}) ? 0 : -1; + return SetTaskProfiles(tid, {"TimerSlackNormal"}, true) ? 0 : -1; } return 0; diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 4b45c8765..40d8d902c 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -138,31 +138,38 @@ bool SetCgroupAction::IsAppDependentPath(const std::string& path) { SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p) : controller_(c), path_(p) { -#ifdef CACHE_FILE_DESCRIPTORS - // cache file descriptor only if path is app independent + // file descriptors for app-dependent paths can't be cached if (IsAppDependentPath(path_)) { // file descriptor is not cached - fd_.reset(-2); + fd_.reset(FDS_APP_DEPENDENT); return; } - std::string tasks_path = c.GetTasksFilePath(p); + // file descriptor can be cached later on request + fd_.reset(FDS_NOT_CACHED); +} + +void SetCgroupAction::EnableResourceCaching() { + if (fd_ != FDS_NOT_CACHED) { + return; + } + + std::string tasks_path = controller_.GetTasksFilePath(path_); if (access(tasks_path.c_str(), W_OK) != 0) { // file is not accessible - fd_.reset(-1); + fd_.reset(FDS_INACCESSIBLE); return; } unique_fd fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC))); if (fd < 0) { PLOG(ERROR) << "Failed to cache fd '" << tasks_path << "'"; - fd_.reset(-1); + fd_.reset(FDS_INACCESSIBLE); return; } fd_ = std::move(fd); -#endif } bool SetCgroupAction::AddTidToCgroup(int tid, int fd) { @@ -184,8 +191,7 @@ bool SetCgroupAction::AddTidToCgroup(int tid, int fd) { } bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { -#ifdef CACHE_FILE_DESCRIPTORS - if (fd_ >= 0) { + if (IsFdValid()) { // fd is cached, reuse it if (!AddTidToCgroup(pid, fd_)) { LOG(ERROR) << "Failed to add task into cgroup"; @@ -194,12 +200,12 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { return true; } - if (fd_ == -1) { + if (fd_ == FDS_INACCESSIBLE) { // no permissions to access the file, ignore return true; } - // this is app-dependent path, file descriptor is not cached + // this is app-dependent path and fd is not cached or cached fd can't be used std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid); unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC))); if (tmp_fd < 0) { @@ -212,25 +218,10 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { } return true; -#else - std::string procs_path = controller()->GetProcsFilePath(path_, uid, pid); - unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(procs_path.c_str(), O_WRONLY | O_CLOEXEC))); - if (tmp_fd < 0) { - // no permissions to access the file, ignore - return true; - } - if (!AddTidToCgroup(pid, tmp_fd)) { - LOG(ERROR) << "Failed to add task into cgroup"; - return false; - } - - return true; -#endif } bool SetCgroupAction::ExecuteForTask(int tid) const { -#ifdef CACHE_FILE_DESCRIPTORS - if (fd_ >= 0) { + if (IsFdValid()) { // fd is cached, reuse it if (!AddTidToCgroup(tid, fd_)) { LOG(ERROR) << "Failed to add task into cgroup"; @@ -239,20 +230,23 @@ bool SetCgroupAction::ExecuteForTask(int tid) const { return true; } - if (fd_ == -1) { + if (fd_ == FDS_INACCESSIBLE) { // no permissions to access the file, ignore return true; } - // application-dependent path can't be used with tid - LOG(ERROR) << "Application profile can't be applied to a thread"; - return false; -#else + if (fd_ == FDS_APP_DEPENDENT) { + // application-dependent path can't be used with tid + PLOG(ERROR) << "Application profile can't be applied to a thread"; + return false; + } + + // fd was not cached because cached fd can't be used std::string tasks_path = controller()->GetTasksFilePath(path_); unique_fd tmp_fd(TEMP_FAILURE_RETRY(open(tasks_path.c_str(), O_WRONLY | O_CLOEXEC))); if (tmp_fd < 0) { - // no permissions to access the file, ignore - return true; + PLOG(WARNING) << "Failed to open " << tasks_path << ": " << strerror(errno); + return false; } if (!AddTidToCgroup(tid, tmp_fd)) { LOG(ERROR) << "Failed to add task into cgroup"; @@ -260,7 +254,6 @@ bool SetCgroupAction::ExecuteForTask(int tid) const { } return true; -#endif } bool TaskProfile::ExecuteForProcess(uid_t uid, pid_t pid) const { @@ -284,6 +277,18 @@ bool TaskProfile::ExecuteForTask(int tid) const { return true; } +void TaskProfile::EnableResourceCaching() { + if (res_cached_) { + return; + } + + for (auto& element : elements_) { + element->EnableResourceCaching(); + } + + res_cached_ = true; +} + TaskProfiles& TaskProfiles::GetInstance() { // Deliberately leak this object to avoid a race between destruction on // process exit and concurrent access from another thread. @@ -411,7 +416,7 @@ bool TaskProfiles::Load(const CgroupMap& cg_map, const std::string& file_name) { return true; } -const TaskProfile* TaskProfiles::GetProfile(const std::string& name) const { +TaskProfile* TaskProfiles::GetProfile(const std::string& name) const { auto iter = profiles_.find(name); if (iter != profiles_.end()) { diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index 37cc305d5..445647dea 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -48,6 +48,8 @@ class ProfileAction { // Default implementations will fail virtual bool ExecuteForProcess(uid_t, pid_t) const { return false; }; virtual bool ExecuteForTask(int) const { return false; }; + + virtual void EnableResourceCaching() {} }; // Profile actions @@ -110,31 +112,40 @@ class SetCgroupAction : public ProfileAction { virtual bool ExecuteForProcess(uid_t uid, pid_t pid) const; virtual bool ExecuteForTask(int tid) const; + virtual void EnableResourceCaching(); const CgroupController* controller() const { return &controller_; } std::string path() const { return path_; } private: + enum FdState { + FDS_INACCESSIBLE = -1, + FDS_APP_DEPENDENT = -2, + FDS_NOT_CACHED = -3, + }; + CgroupController controller_; std::string path_; -#ifdef CACHE_FILE_DESCRIPTORS android::base::unique_fd fd_; -#endif static bool IsAppDependentPath(const std::string& path); static bool AddTidToCgroup(int tid, int fd); + + bool IsFdValid() const { return fd_ > FDS_INACCESSIBLE; } }; class TaskProfile { public: - TaskProfile() {} + TaskProfile() : res_cached_(false) {} void Add(std::unique_ptr e) { elements_.push_back(std::move(e)); } bool ExecuteForProcess(uid_t uid, pid_t pid) const; bool ExecuteForTask(int tid) const; + void EnableResourceCaching(); private: + bool res_cached_; std::vector> elements_; }; @@ -143,7 +154,7 @@ class TaskProfiles { // Should be used by all users static TaskProfiles& GetInstance(); - const TaskProfile* GetProfile(const std::string& name) const; + TaskProfile* GetProfile(const std::string& name) const; const ProfileAttribute* GetAttribute(const std::string& name) const; private: From 41616d88a2d951c226777574829ff45e28212b88 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Mon, 22 Apr 2019 13:12:13 -0700 Subject: [PATCH 143/221] libprocessgroup: limit libprocessgroup's VNDK API surface Limit libprocessgroup VNDK API to the minimum set required for task profiles usage. This API allows vendors to use cgroups without accessing cgroup files directly, therefore allowing Android to change cgroup arrangement details without breaking vendor code. Bug: 131098932 Test: build and boot Change-Id: I92463dfb44a108a133bafd2fe52237b6b1d50a69 Signed-off-by: Suren Baghdasaryan --- libprocessgroup/include/processgroup/processgroup.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/libprocessgroup/include/processgroup/processgroup.h b/libprocessgroup/include/processgroup/processgroup.h index 8d150adb0..7e6bf45cf 100644 --- a/libprocessgroup/include/processgroup/processgroup.h +++ b/libprocessgroup/include/processgroup/processgroup.h @@ -24,18 +24,21 @@ __BEGIN_DECLS static constexpr const char* CGROUPV2_CONTROLLER_NAME = "cgroup2"; -static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; bool CgroupGetControllerPath(const std::string& cgroup_name, std::string* path); bool CgroupGetAttributePath(const std::string& attr_name, std::string* path); bool CgroupGetAttributePathForTask(const std::string& attr_name, int tid, std::string* path); -bool UsePerAppMemcg(); - bool SetTaskProfiles(int tid, const std::vector& profiles, bool use_fd_cache = false); bool SetProcessProfiles(uid_t uid, pid_t pid, const std::vector& profiles, bool use_fd_cache = false); +#ifndef __ANDROID_VNDK__ + +static constexpr const char* CGROUPS_RC_PATH = "/dev/cgroup_info/cgroup.rc"; + +bool UsePerAppMemcg(); + // Return 0 and removes the cgroup if there are no longer any processes in it. // Returns -1 in the case of an error occurring or if there are processes still running // even after retrying for up to 200ms. @@ -55,4 +58,6 @@ bool setProcessGroupLimit(uid_t uid, int initialPid, int64_t limitInBytes); void removeAllProcessGroups(void); +#endif // __ANDROID_VNDK__ + __END_DECLS From ec78cca331fa651890c10c2746c2d99f4c800322 Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Fri, 19 Apr 2019 10:58:39 -0700 Subject: [PATCH 144/221] init.rc: set fsck log permission on post-fs-data Fixes: 130829745 Test: build and trigger fsck crosshatch:/ # ls -l /dev/fscklogs/log -rwxrwx--- 1 root system 1584 1970-04-08 14:48 /dev/fscklogs/log Change-Id: Ifd0734e121d07b941a73d7cabde04928ce5e5c59 Merged-In: Ifd0734e121d07b941a73d7cabde04928ce5e5c59 --- rootdir/init.rc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/rootdir/init.rc b/rootdir/init.rc index 17dd1457b..dfde53ccb 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -608,6 +608,10 @@ on post-fs-data # IOCTLs on ashmem fds any more. setprop sys.use_memfd false + # Set fscklog permission + chown root system /dev/fscklogs/log + chmod 0770 /dev/fscklogs/log + # It is recommended to put unnecessary data/ initialization from post-fs-data # to start-zygote in device's init.rc to unblock zygote start. on zygote-start && property:ro.crypto.state=unencrypted From 6386c3207b335bd587e145c231c38ee98135847e Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Fri, 19 Apr 2019 22:08:56 +0800 Subject: [PATCH 145/221] Adding adb_debug.prop into debug ramdisk The debug ramdisk can only be used if the device is unlocked. When it's used, init will load adb_debug.prop and the userdebug sepolicy from the debug ramdisk, to allow adb root on a user build. Bug: 126493225 Test: 'make' and checks the file is installed Change-Id: Id6962414197fc8f47f7c07818e8fb16107dc17a3 Merged-In: Id6962414197fc8f47f7c07818e8fb16107dc17a3 (cherry picked from commit 05f07d89a6b44eef1fcec020bf9020a3429fc3ad) --- init/Android.mk | 5 +++++ rootdir/Android.mk | 9 +++++++++ rootdir/adb_debug.prop | 12 ++++++++++++ 3 files changed, 26 insertions(+) create mode 100644 rootdir/adb_debug.prop diff --git a/init/Android.mk b/init/Android.mk index efa8d87c8..b02c926da 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -65,6 +65,11 @@ LOCAL_FORCE_STATIC_EXECUTABLE := true LOCAL_MODULE_PATH := $(TARGET_RAMDISK_OUT) LOCAL_UNSTRIPPED_PATH := $(TARGET_RAMDISK_OUT_UNSTRIPPED) +# Install adb_debug.prop into debug ramdisk. +# This allows adb root on a user build, when debug ramdisk is used. +LOCAL_REQUIRED_MODULES := \ + adb_debug.prop \ + # Set up the same mount points on the ramdisk that system-as-root contains. LOCAL_POST_INSTALL_CMD := mkdir -p \ $(TARGET_RAMDISK_OUT)/apex \ diff --git a/rootdir/Android.mk b/rootdir/Android.mk index a97858a93..7ff1588b2 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -377,4 +377,13 @@ $(LOCAL_BUILT_MODULE): $(hide) $(foreach lib,$(PRIVATE_VNDK_SAMEPROCESS_LIBRARIES), \ echo $(lib).so >> $@;) +####################################### +# adb_debug.prop in debug ramdisk +include $(CLEAR_VARS) +LOCAL_MODULE := adb_debug.prop +LOCAL_SRC_FILES := $(LOCAL_MODULE) +LOCAL_MODULE_CLASS := ETC +LOCAL_MODULE_PATH := $(TARGET_DEBUG_RAMDISK_OUT) +include $(BUILD_PREBUILT) + include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/rootdir/adb_debug.prop b/rootdir/adb_debug.prop new file mode 100644 index 000000000..37e2f2d71 --- /dev/null +++ b/rootdir/adb_debug.prop @@ -0,0 +1,12 @@ +# Note: This file will be loaded with highest priority to override +# other system properties, if a special ramdisk with "/force_debuggable" +# is used and the device is unlocked. + +# Disable adb authentication to allow test automation on user build GSI +ro.adb.secure=0 + +# Allow 'adb root' on user build GSI +ro.debuggable=1 + +# Introduce this property to indicate that init has loaded adb_debug.prop +ro.force.debuggable=1 From 9d7a979a996a74c7d1bd4d7fab8dfd8faf1c776a Mon Sep 17 00:00:00 2001 From: Dongwon Kang Date: Tue, 23 Apr 2019 14:56:21 -0700 Subject: [PATCH 146/221] Fix a warning on namespace.media.link.default.shared_libs Test: build & dumpsys media.extractor Bug: 130882530 Change-Id: Ifd46858b5a864f0fbed87baa3321f233ea12954e --- rootdir/etc/ld.config.legacy.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt index bd6327505..a5db3742c 100644 --- a/rootdir/etc/ld.config.legacy.txt +++ b/rootdir/etc/ld.config.legacy.txt @@ -97,7 +97,7 @@ namespace.media.asan.search.paths = /apex/com.android.media/${LIB} namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default -namespace.media.link.default.shared_libs += libbinder_ndk.so +namespace.media.link.default.shared_libs = libbinder_ndk.so namespace.media.link.default.shared_libs += libc.so namespace.media.link.default.shared_libs += libcgrouprc.so namespace.media.link.default.shared_libs += libdl.so From 917446b29d259d1ffcab314fae4fb9fee3e3fc73 Mon Sep 17 00:00:00 2001 From: SzuWei Lin Date: Mon, 22 Apr 2019 17:27:52 +0800 Subject: [PATCH 147/221] Remove the mount points defined in skip_mount.cfg from ReadDefaultFstab() The first stage init skips mounting the mount points defined in skip_mount.cfg, but these mount points still return from ReadDefaultFstab(). The behavior causes some error logic which try to access the partition which had been skipped. After applying the patch. ReadDefaultFstab() will not contain the skipped mount points. Bug: 128961335 Test: `fastboot delete-logical-partition product_a` Test: `fastboot flash system aosp_arm64-userdebug` Test: `fastboot -w reboot` and boot to home screen Change-Id: I3156260b5d37647dbecf98ca90601a089bea5c46 Merged-In: I3156260b5d37647dbecf98ca90601a089bea5c46 (cherry picked from commit 77c28476f19c910a869af878c8983d52e53c07b4) --- fs_mgr/fs_mgr_fstab.cpp | 33 ++++++++++++++++++++++++++++++ fs_mgr/include_fstab/fstab/fstab.h | 1 + init/first_stage_mount.cpp | 32 ++--------------------------- 3 files changed, 36 insertions(+), 30 deletions(-) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index 4043fc6a1..da049efa5 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -38,6 +38,7 @@ using android::base::ParseByteCount; using android::base::ParseInt; +using android::base::ReadFileToString; using android::base::Split; using android::base::StartsWith; @@ -660,6 +661,8 @@ bool ReadFstabFromFile(const std::string& path, Fstab* fstab) { TransformFstabForGsi(fstab); } + SkipMountingPartitions(fstab); + return true; } @@ -687,6 +690,36 @@ bool ReadFstabFromDt(Fstab* fstab, bool log) { return false; } + SkipMountingPartitions(fstab); + + return true; +} + +// For GSI to skip mounting /product and /product_services, until there are +// well-defined interfaces between them and /system. Otherwise, the GSI flashed +// on /system might not be able to work with /product and /product_services. +// When they're skipped here, /system/product and /system/product_services in +// GSI will be used. +bool SkipMountingPartitions(Fstab* fstab) { + constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg"; + + std::string skip_config; + if (!ReadFileToString(kSkipMountConfig, &skip_config)) { + return true; + } + + for (const auto& skip_mount_point : Split(skip_config, "\n")) { + if (skip_mount_point.empty()) { + continue; + } + auto it = std::remove_if(fstab->begin(), fstab->end(), + [&skip_mount_point](const auto& entry) { + return entry.mount_point == skip_mount_point; + }); + fstab->erase(it, fstab->end()); + LOG(INFO) << "Skip mounting partition: " << skip_mount_point; + } + return true; } diff --git a/fs_mgr/include_fstab/fstab/fstab.h b/fs_mgr/include_fstab/fstab/fstab.h index 88da41deb..d7afed654 100644 --- a/fs_mgr/include_fstab/fstab/fstab.h +++ b/fs_mgr/include_fstab/fstab/fstab.h @@ -99,6 +99,7 @@ using Fstab = std::vector; bool ReadFstabFromFile(const std::string& path, Fstab* fstab); bool ReadFstabFromDt(Fstab* fstab, bool log = true); bool ReadDefaultFstab(Fstab* fstab); +bool SkipMountingPartitions(Fstab* fstab); FstabEntry* GetEntryForMountPoint(Fstab* fstab, const std::string& path); diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index 3900f7246..3e76556ff 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -43,7 +43,6 @@ #include "uevent_listener.h" #include "util.h" -using android::base::ReadFileToString; using android::base::Split; using android::base::Timer; using android::fs_mgr::AvbHandle; @@ -55,6 +54,7 @@ using android::fs_mgr::Fstab; using android::fs_mgr::FstabEntry; using android::fs_mgr::ReadDefaultFstab; using android::fs_mgr::ReadFstabFromDt; +using android::fs_mgr::SkipMountingPartitions; using namespace std::literals; @@ -524,38 +524,10 @@ bool FirstStageMount::TrySwitchSystemAsRoot() { return true; } -// For GSI to skip mounting /product and /product_services, until there are -// well-defined interfaces between them and /system. Otherwise, the GSI flashed -// on /system might not be able to work with /product and /product_services. -// When they're skipped here, /system/product and /system/product_services in -// GSI will be used. -bool FirstStageMount::TrySkipMountingPartitions() { - constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg"; - - std::string skip_config; - if (!ReadFileToString(kSkipMountConfig, &skip_config)) { - return true; - } - - for (const auto& skip_mount_point : Split(skip_config, "\n")) { - if (skip_mount_point.empty()) { - continue; - } - auto it = std::remove_if(fstab_.begin(), fstab_.end(), - [&skip_mount_point](const auto& entry) { - return entry.mount_point == skip_mount_point; - }); - fstab_.erase(it, fstab_.end()); - LOG(INFO) << "Skip mounting partition: " << skip_mount_point; - } - - return true; -} - bool FirstStageMount::MountPartitions() { if (!TrySwitchSystemAsRoot()) return false; - if (!TrySkipMountingPartitions()) return false; + if (!SkipMountingPartitions(&fstab_)) return false; for (auto current = fstab_.begin(); current != fstab_.end();) { // We've already mounted /system above. From d0feaf9f79889f5991843fca9f9461096641b2a8 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 24 Apr 2019 14:28:25 -0700 Subject: [PATCH 148/221] adbd: reduce queue depths. Each operation we submit results in a contiguous allocation in the kernel which can trigger OOM-killing. Tune the queue depths to reduce the chances of this happening, with a minimal impact on performance. Bug: http://b/126582877 Test: ./benchmark_device.py with blueline Change-Id: I4b0f83d54a9a9a69f0ab48322d78fb137c94dd35 (cherry picked from commit 28293f16a80e3d7af442bc9817dae999f78beb57) --- adb/daemon/usb.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp index 3b29ab5fc..1e3701582 100644 --- a/adb/daemon/usb.cpp +++ b/adb/daemon/usb.cpp @@ -58,10 +58,12 @@ using android::base::StringPrintf; static std::optional gFfsAioSupported; // Not all USB controllers support operations larger than 16k, so don't go above that. -static constexpr size_t kUsbReadQueueDepth = 32; +// Also, each submitted operation does an allocation in the kernel of that size, so we want to +// minimize our queue depth while still maintaining a deep enough queue to keep the USB stack fed. +static constexpr size_t kUsbReadQueueDepth = 8; static constexpr size_t kUsbReadSize = 4 * PAGE_SIZE; -static constexpr size_t kUsbWriteQueueDepth = 32; +static constexpr size_t kUsbWriteQueueDepth = 8; static constexpr size_t kUsbWriteSize = 4 * PAGE_SIZE; static const char* to_string(enum usb_functionfs_event_type type) { From f0bc58a42dff06213b60676c034b0d345e2b5344 Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Tue, 23 Apr 2019 16:26:01 +0200 Subject: [PATCH 149/221] Support for stopping/starting post-data-mount class subsets. On devices that use FDE and APEX at the same time, we need to bring up a minimal framework to be able to mount the /data partition. During this period, a tmpfs /data filesystem is created, which doesn't contain any of the updated APEXEs. As a consequence, all those processes will be using the APEXes from the /system partition. This is obviously not desired, as APEXes in /system may be old and/or contain security issues. Additionally, it would create a difference between FBE and FDE devices at runtime. Ideally, we restart all processes that have started after we created the tmpfs /data. We can't (re)start based on class names alone, because some classes (eg 'hal') contain services that are required to start apexd itself and that shouldn't be killed (eg the graphics HAL). To address this, keep track of which processes are started after /data is mounted, with a new 'mark_post_data' keyword. Additionally, create 'class_reset_post_data', which resets all services in the class that were created after the initial /data mount, and 'class_start_post_data', which starts all services in the class that were started after /data was mounted. On a device with FBE, these keywords wouldn't be used; on a device with FDE, we'd use them to bring down the right processes after the user has entered the correct secret, and restart them. Bug: 118485723 Test: manually verified process list Change-Id: I16adb776dacf1dd1feeaff9e60639b99899905eb --- init/README.md | 12 ++++++++++++ init/builtins.cpp | 39 +++++++++++++++++++++++++++++++++++---- init/service.cpp | 18 +++++++++++++++++- init/service.h | 7 +++++++ rootdir/init.rc | 9 ++++++--- 5 files changed, 77 insertions(+), 8 deletions(-) diff --git a/init/README.md b/init/README.md index d86f077a7..f222dd405 100644 --- a/init/README.md +++ b/init/README.md @@ -412,6 +412,10 @@ Commands not already running. See the start entry for more information on starting services. +`class_start_post_data ` +> Like `class_start`, but only considers services that were started + after /data was mounted. Only used for FDE devices. + `class_stop ` > Stop and disable all services of the specified class if they are currently running. @@ -421,6 +425,10 @@ Commands currently running, without disabling them. They can be restarted later using `class_start`. +`class_reset_post_data ` +> Like `class_reset`, but only considers services that were started + after /data was mounted. Only used for FDE devices. + `class_restart ` > Restarts all services of the specified class. @@ -490,6 +498,10 @@ Commands `loglevel ` > Sets the kernel log level to level. Properties are expanded within _level_. +`mark_post_data` +> Used to mark the point right after /data is mounted. Used to implement the + `class_reset_post_data` and `class_start_post_data` commands. + `mkdir [mode] [owner] [group]` > Create a directory at _path_, optionally with the given mode, owner, and group. If not provided, the directory is created with permissions 755 and diff --git a/init/builtins.cpp b/init/builtins.cpp index fc75072b6..34f229b7f 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -104,23 +104,37 @@ static void ForEachServiceInClass(const std::string& classname, F function) { } } -static Result do_class_start(const BuiltinArguments& args) { +static Result class_start(const std::string& class_name, bool post_data_only) { // Do not start a class if it has a property persist.dont_start_class.CLASS set to 1. - if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false)) + if (android::base::GetBoolProperty("persist.init.dont_start_class." + class_name, false)) return Success(); // Starting a class does not start services which are explicitly disabled. // They must be started individually. for (const auto& service : ServiceList::GetInstance()) { - if (service->classnames().count(args[1])) { + if (service->classnames().count(class_name)) { + if (post_data_only && !service->is_post_data()) { + continue; + } if (auto result = service->StartIfNotDisabled(); !result) { LOG(ERROR) << "Could not start service '" << service->name() - << "' as part of class '" << args[1] << "': " << result.error(); + << "' as part of class '" << class_name << "': " << result.error(); } } } return Success(); } +static Result do_class_start(const BuiltinArguments& args) { + return class_start(args[1], false /* post_data_only */); +} + +static Result do_class_start_post_data(const BuiltinArguments& args) { + if (args.context != kInitContext) { + return Error() << "command 'class_start_post_data' only available in init context"; + } + return class_start(args[1], true /* post_data_only */); +} + static Result do_class_stop(const BuiltinArguments& args) { ForEachServiceInClass(args[1], &Service::Stop); return Success(); @@ -131,6 +145,14 @@ static Result do_class_reset(const BuiltinArguments& args) { return Success(); } +static Result do_class_reset_post_data(const BuiltinArguments& args) { + if (args.context != kInitContext) { + return Error() << "command 'class_reset_post_data' only available in init context"; + } + ForEachServiceInClass(args[1], &Service::ResetIfPostData); + return Success(); +} + static Result do_class_restart(const BuiltinArguments& args) { // Do not restart a class if it has a property persist.dont_start_class.CLASS set to 1. if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false)) @@ -1119,6 +1141,12 @@ static Result do_init_user0(const BuiltinArguments& args) { {{"exec", "/system/bin/vdc", "--wait", "cryptfs", "init_user0"}, args.context}); } +static Result do_mark_post_data(const BuiltinArguments& args) { + ServiceList::GetInstance().MarkPostData(); + + return Success(); +} + static Result do_parse_apex_configs(const BuiltinArguments& args) { glob_t glob_result; // @ is added to filter out the later paths, which are bind mounts of the places @@ -1170,8 +1198,10 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"chmod", {2, 2, {true, do_chmod}}}, {"chown", {2, 3, {true, do_chown}}}, {"class_reset", {1, 1, {false, do_class_reset}}}, + {"class_reset_post_data", {1, 1, {false, do_class_reset_post_data}}}, {"class_restart", {1, 1, {false, do_class_restart}}}, {"class_start", {1, 1, {false, do_class_start}}}, + {"class_start_post_data", {1, 1, {false, do_class_start_post_data}}}, {"class_stop", {1, 1, {false, do_class_stop}}}, {"copy", {2, 2, {true, do_copy}}}, {"domainname", {1, 1, {true, do_domainname}}}, @@ -1191,6 +1221,7 @@ const BuiltinFunctionMap::Map& BuiltinFunctionMap::map() const { {"load_persist_props", {0, 0, {false, do_load_persist_props}}}, {"load_system_props", {0, 0, {false, do_load_system_props}}}, {"loglevel", {1, 1, {false, do_loglevel}}}, + {"mark_post_data", {0, 0, {false, do_mark_post_data}}}, {"mkdir", {1, 4, {true, do_mkdir}}}, // TODO: Do mount operations in vendor_init. // mount_all is currently too complex to run in vendor_init as it queues action triggers, diff --git a/init/service.cpp b/init/service.cpp index f5c13b983..8c3e228a5 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -362,7 +362,7 @@ void Service::Reap(const siginfo_t& siginfo) { // Oneshot processes go into the disabled state on exit, // except when manually restarted. - if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART)) { + if ((flags_ & SVC_ONESHOT) && !(flags_ & SVC_RESTART) && !(flags_ & SVC_RESET)) { flags_ |= SVC_DISABLED; } @@ -947,6 +947,8 @@ Result Service::Start() { pre_apexd_ = true; } + post_data_ = ServiceList::GetInstance().IsPostData(); + LOG(INFO) << "starting service '" << name_ << "'..."; pid_t pid = -1; @@ -1146,6 +1148,12 @@ void Service::Reset() { StopOrReset(SVC_RESET); } +void Service::ResetIfPostData() { + if (post_data_) { + StopOrReset(SVC_RESET); + } +} + void Service::Stop() { StopOrReset(SVC_DISABLED); } @@ -1339,6 +1347,14 @@ void ServiceList::DumpState() const { } } +void ServiceList::MarkPostData() { + post_data_ = true; +} + +bool ServiceList::IsPostData() { + return post_data_; +} + void ServiceList::MarkServicesUpdate() { services_update_finished_ = true; diff --git a/init/service.h b/init/service.h index c42a5a371..dc2b12883 100644 --- a/init/service.h +++ b/init/service.h @@ -81,6 +81,7 @@ class Service { Result StartIfNotDisabled(); Result Enable(); void Reset(); + void ResetIfPostData(); void Stop(); void Terminate(); void Timeout(); @@ -124,6 +125,7 @@ class Service { std::optional timeout_period() const { return timeout_period_; } const std::vector& args() const { return args_; } bool is_updatable() const { return updatable_; } + bool is_post_data() const { return post_data_; } private: using OptionParser = Result (Service::*)(std::vector&& args); @@ -244,6 +246,8 @@ class Service { std::vector> reap_callbacks_; bool pre_apexd_ = false; + + bool post_data_ = false; }; class ServiceList { @@ -285,6 +289,8 @@ class ServiceList { const std::vector>& services() const { return services_; } const std::vector services_in_shutdown_order() const; + void MarkPostData(); + bool IsPostData(); void MarkServicesUpdate(); bool IsServicesUpdated() const { return services_update_finished_; } void DelayService(const Service& service); @@ -292,6 +298,7 @@ class ServiceList { private: std::vector> services_; + bool post_data_ = false; bool services_update_finished_ = false; std::vector delayed_service_names_; }; diff --git a/rootdir/init.rc b/rootdir/init.rc index dfde53ccb..cb45c42f8 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -405,6 +405,8 @@ on late-fs class_start early_hal on post-fs-data + mark_post_data + # Start checkpoint before we touch data start vold exec - system system -- /system/bin/vdc checkpoint prepareCheckpoint @@ -753,9 +755,6 @@ on property:sys.init_log_level=* on charger class_start charger -on property:vold.decrypt=trigger_reset_main - class_reset main - on property:vold.decrypt=trigger_load_persist_props load_persist_props start logd @@ -773,6 +772,8 @@ on property:vold.decrypt=trigger_restart_min_framework on property:vold.decrypt=trigger_restart_framework # A/B update verifier that marks a successful boot. exec_start update_verifier + class_start_post_data hal + class_start_post_data core class_start main class_start late_start setprop service.bootanim.exit 0 @@ -781,6 +782,8 @@ on property:vold.decrypt=trigger_restart_framework on property:vold.decrypt=trigger_shutdown_framework class_reset late_start class_reset main + class_reset_post_data core + class_reset_post_data hal on property:sys.boot_completed=1 bootchart stop From 25fe126fb0bb60f00e9aeb0c16123179976f63ae Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sun, 7 Apr 2019 23:24:03 -0700 Subject: [PATCH 150/221] adb: Recognize rescue mode. This CL adds client support to recognize the rescue mode (which will be served by recovery image). It also allows waiting for a device to enter rescue mode. The support for the actual rescue commands will be added in follow-up CLs. Bug: 128415917 Test: `adb devices` recognizes devices under rescue mode. Test: `adb wait-for-rescue` waits for device to be in rescue mode. Change-Id: I367d7339fe68006aba09a1e3db6370d472296676 Merged-In: I367d7339fe68006aba09a1e3db6370d472296676 (cherry picked from commit 55d407ec4a0b23f1e20db298b4989068a820087f) --- adb/adb.cpp | 3 +++ adb/adb.h | 2 ++ adb/client/commandline.cpp | 7 ++++--- adb/services.cpp | 2 ++ adb/transport.cpp | 2 ++ 5 files changed, 13 insertions(+), 3 deletions(-) diff --git a/adb/adb.cpp b/adb/adb.cpp index e417f05e3..2dd22b38b 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp @@ -280,6 +280,9 @@ void parse_banner(const std::string& banner, atransport* t) { } else if (type == "sideload") { D("setting connection_state to kCsSideload"); t->SetConnectionState(kCsSideload); + } else if (type == "rescue") { + D("setting connection_state to kCsRescue"); + t->SetConnectionState(kCsRescue); } else { D("setting connection_state to kCsHost"); t->SetConnectionState(kCsHost); diff --git a/adb/adb.h b/adb/adb.h index c60dcbc1c..3a6f059b8 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -107,6 +107,7 @@ enum ConnectionState { kCsHost, kCsRecovery, kCsSideload, + kCsRescue, }; inline bool ConnectionStateIsOnline(ConnectionState state) { @@ -116,6 +117,7 @@ inline bool ConnectionStateIsOnline(ConnectionState state) { case kCsHost: case kCsRecovery: case kCsSideload: + case kCsRescue: return true; default: return false; diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp index 43a3e5e94..f25955d85 100644 --- a/adb/client/commandline.cpp +++ b/adb/client/commandline.cpp @@ -190,7 +190,7 @@ static void help() { "scripting:\n" " wait-for[-TRANSPORT]-STATE\n" " wait for device to be in the given state\n" - " STATE: device, recovery, sideload, bootloader, or disconnect\n" + " STATE: device, recovery, rescue, sideload, bootloader, or disconnect\n" " TRANSPORT: usb, local, or any [default=any]\n" " get-state print offline | bootloader | device\n" " get-serialno print \n" @@ -1037,11 +1037,12 @@ static bool wait_for_device(const char* service, } if (components[3] != "any" && components[3] != "bootloader" && components[3] != "device" && - components[3] != "recovery" && components[3] != "sideload" && + components[3] != "recovery" && components[3] != "rescue" && components[3] != "sideload" && components[3] != "disconnect") { fprintf(stderr, "adb: unknown state %s; " - "expected 'any', 'bootloader', 'device', 'recovery', 'sideload', or 'disconnect'\n", + "expected 'any', 'bootloader', 'device', 'recovery', 'rescue', 'sideload', or " + "'disconnect'\n", components[3].c_str()); return false; } diff --git a/adb/services.cpp b/adb/services.cpp index cf346bade..335ffc49a 100644 --- a/adb/services.cpp +++ b/adb/services.cpp @@ -227,6 +227,8 @@ asocket* host_service_to_socket(std::string_view name, std::string_view serial, sinfo->state = kCsDevice; } else if (name == "-recovery") { sinfo->state = kCsRecovery; + } else if (name == "-rescue") { + sinfo->state = kCsRescue; } else if (name == "-sideload") { sinfo->state = kCsSideload; } else if (name == "-bootloader") { diff --git a/adb/transport.cpp b/adb/transport.cpp index 15c3a9a32..841865afc 100644 --- a/adb/transport.cpp +++ b/adb/transport.cpp @@ -1012,6 +1012,8 @@ std::string atransport::connection_state_name() const { return "host"; case kCsRecovery: return "recovery"; + case kCsRescue: + return "rescue"; case kCsNoPerm: return UsbNoPermissionsShortHelpText(); case kCsSideload: From fbeac4605c0e2fc6ce866e430252ce6fed1e5812 Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Sun, 7 Apr 2019 23:24:03 -0700 Subject: [PATCH 151/221] adb: Support rescue install and getprop. Bug: 128415917 Test: Enter rescue mode on taimen. Send the following commands: `adb rescue getprop ro.build.fingerprint` `adb rescue getprop ro.build.date.utc` `adb rescue getprop ro.build.invalid` `adb rescue install /path/to/package.zip` Test: Sideload on taimen w/ `adb sideload /path/to/package.zip`. Change-Id: Ia246b30314fbcd2bd4cc71a8085a280e33041967 Merged-In: Ia246b30314fbcd2bd4cc71a8085a280e33041967 (cherry picked from commit 11cf30b5edf839a353180b39ae4e55c544beaf56) --- adb/client/commandline.cpp | 71 ++++++++++++++++++++++++-------------- adb/services.h | 4 +++ 2 files changed, 50 insertions(+), 25 deletions(-) diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp index f25955d85..552df4181 100644 --- a/adb/client/commandline.cpp +++ b/adb/client/commandline.cpp @@ -838,26 +838,25 @@ static int adb_sideload_legacy(const char* filename, int in_fd, int size) { #define SIDELOAD_HOST_BLOCK_SIZE (CHUNK_SIZE) -/* - * The sideload-host protocol serves the data in a file (given on the - * command line) to the client, using a simple protocol: - * - * - The connect message includes the total number of bytes in the - * file and a block size chosen by us. - * - * - The other side sends the desired block number as eight decimal - * digits (eg "00000023" for block 23). Blocks are numbered from - * zero. - * - * - We send back the data of the requested block. The last block is - * likely to be partial; when the last block is requested we only - * send the part of the block that exists, it's not padded up to the - * block size. - * - * - When the other side sends "DONEDONE" instead of a block number, - * we hang up. - */ -static int adb_sideload_host(const char* filename) { +// Connects to the sideload / rescue service on the device (served by minadbd) and sends over the +// data in an OTA package. +// +// It uses a simple protocol as follows. +// +// - The connect message includes the total number of bytes in the file and a block size chosen by +// us. +// +// - The other side sends the desired block number as eight decimal digits (e.g. "00000023" for +// block 23). Blocks are numbered from zero. +// +// - We send back the data of the requested block. The last block is likely to be partial; when the +// last block is requested we only send the part of the block that exists, it's not padded up to +// the block size. +// +// - When the other side sends "DONEDONE" or "FAILFAIL" instead of a block number, we have done all +// the data transfer. +// +static int adb_sideload_install(const char* filename, bool rescue_mode) { // TODO: use a LinePrinter instead... struct stat sb; if (stat(filename, &sb) == -1) { @@ -870,14 +869,18 @@ static int adb_sideload_host(const char* filename) { return -1; } - std::string service = - android::base::StringPrintf("sideload-host:%" PRId64 ":%d", - static_cast(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE); + std::string service = android::base::StringPrintf( + "%s:%" PRId64 ":%d", rescue_mode ? "rescue-install" : "sideload-host", + static_cast(sb.st_size), SIDELOAD_HOST_BLOCK_SIZE); std::string error; unique_fd device_fd(adb_connect(service, &error)); if (device_fd < 0) { fprintf(stderr, "adb: sideload connection failed: %s\n", error.c_str()); + if (rescue_mode) { + return -1; + } + // If this is a small enough package, maybe this is an older device that doesn't // support sideload-host. Try falling back to the older (<= K) sideload method. if (sb.st_size > INT_MAX) { @@ -901,10 +904,14 @@ static int adb_sideload_host(const char* filename) { } buf[8] = '\0'; - if (strcmp("DONEDONE", buf) == 0) { + if (strcmp(kSideloadServiceExitSuccess, buf) == 0 || + strcmp(kSideloadServiceExitFailure, buf) == 0) { printf("\rTotal xfer: %.2fx%*s\n", static_cast(xfer) / (sb.st_size ? sb.st_size : 1), static_cast(strlen(filename) + 10), ""); + if (strcmp(kSideloadServiceExitFailure, buf) == 0) { + return 1; + } return 0; } @@ -1628,11 +1635,25 @@ int adb_commandline(int argc, const char** argv) { return adb_kill_server() ? 0 : 1; } else if (!strcmp(argv[0], "sideload")) { if (argc != 2) error_exit("sideload requires an argument"); - if (adb_sideload_host(argv[1])) { + if (adb_sideload_install(argv[1], false /* rescue_mode */)) { return 1; } else { return 0; } + } else if (!strcmp(argv[0], "rescue")) { + // adb rescue getprop + // adb rescue install + if (argc != 3) error_exit("rescue requires two arguments"); + if (!strcmp(argv[1], "getprop")) { + return adb_connect_command(android::base::StringPrintf("rescue-getprop:%s", argv[2])); + } else if (!strcmp(argv[1], "install")) { + if (adb_sideload_install(argv[2], true /* rescue_mode */) != 0) { + return 1; + } + } else { + error_exit("invalid rescue argument"); + } + return 0; } else if (!strcmp(argv[0], "tcpip")) { if (argc != 2) error_exit("tcpip requires an argument"); int port; diff --git a/adb/services.h b/adb/services.h index 0ce25ba73..8f3919b9b 100644 --- a/adb/services.h +++ b/adb/services.h @@ -23,5 +23,9 @@ constexpr char kShellServiceArgRaw[] = "raw"; constexpr char kShellServiceArgPty[] = "pty"; constexpr char kShellServiceArgShellProtocol[] = "v2"; +// Special flags sent by minadbd that indicate the end of sideload transfer and install result. +constexpr char kSideloadServiceExitSuccess[] = "DONEDONE"; +constexpr char kSideloadServiceExitFailure[] = "FAILFAIL"; + unique_fd create_service_thread(const char* service_name, std::function func); #endif // SERVICES_H_ From 151a06c25a72f2e62848e24a582c915acc54f878 Mon Sep 17 00:00:00 2001 From: Sandeep Patil Date: Wed, 17 Apr 2019 11:38:15 -0700 Subject: [PATCH 152/221] procrank: do not keep process maps around procrank's usage in its output shows 20x increase from last year. This is because it is keeping the process maps around until termination. Fix that by getting rid of ProcMemInfo objects when done parsing /proc//maps,pagemap. Note that the total allocations do not change and have not necessarily regressed from Pie. Bug: 130672819 Test: adb shell procrank | grep 'procrank\|cmdline' Change-Id: Ib7bf960ed1d053347fcfc0c8aee9019607a1eb01 Merged-In: Ib7bf960ed1d053347fcfc0c8aee9019607a1eb01 Signed-off-by: Sandeep Patil --- libmeminfo/tools/procrank.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/libmeminfo/tools/procrank.cpp b/libmeminfo/tools/procrank.cpp index 5e89254b9..cb3757dba 100644 --- a/libmeminfo/tools/procrank.cpp +++ b/libmeminfo/tools/procrank.cpp @@ -42,7 +42,6 @@ struct ProcessRecord { public: ProcessRecord(pid_t pid, bool get_wss = false, uint64_t pgflags = 0, uint64_t pgflags_mask = 0) : pid_(-1), - procmem_(nullptr), oomadj_(OOM_SCORE_ADJ_MAX + 1), cmdline_(""), proportional_swap_(0), @@ -79,15 +78,15 @@ struct ProcessRecord { // The .c_str() assignment below then takes care of trimming the cmdline at the first // 0x00. This is how original procrank worked (luckily) cmdline_.resize(strlen(cmdline_.c_str())); - procmem_ = std::move(procmem); + usage_or_wss_ = get_wss ? procmem->Wss() : procmem->Usage(); + swap_offsets_ = procmem->SwapOffsets(); pid_ = pid; } bool valid() const { return pid_ != -1; } void CalculateSwap(const uint16_t* swap_offset_array, float zram_compression_ratio) { - const std::vector& swp_offs = procmem_->SwapOffsets(); - for (auto& off : swp_offs) { + for (auto& off : swap_offsets_) { proportional_swap_ += getpagesize() / swap_offset_array[off]; unique_swap_ += swap_offset_array[off] == 1 ? getpagesize() : 0; zswap_ = proportional_swap_ * zram_compression_ratio; @@ -103,18 +102,19 @@ struct ProcessRecord { uint64_t zswap() const { return zswap_; } // Wrappers to ProcMemInfo - const std::vector& SwapOffsets() const { return procmem_->SwapOffsets(); } - const MemUsage& Usage() const { return procmem_->Usage(); } - const MemUsage& Wss() const { return procmem_->Wss(); } + const std::vector& SwapOffsets() const { return swap_offsets_; } + const MemUsage& Usage() const { return usage_or_wss_; } + const MemUsage& Wss() const { return usage_or_wss_; } private: pid_t pid_; - std::unique_ptr procmem_; int32_t oomadj_; std::string cmdline_; uint64_t proportional_swap_; uint64_t unique_swap_; uint64_t zswap_; + MemUsage usage_or_wss_; + std::vector swap_offsets_; }; // Show working set instead of memory consumption @@ -171,7 +171,7 @@ static bool read_all_pids(std::vector* pids, std::functiond_name, &pid)) continue; if (!for_each_pid(pid)) return false; - pids->push_back(pid); + pids->emplace_back(pid); } return true; @@ -471,7 +471,7 @@ int main(int argc, char* argv[]) { } // Skip processes with no memory mappings - uint64_t vss = proc.Usage().vss; + uint64_t vss = show_wss ? proc.Wss().vss : proc.Usage().vss; if (vss == 0) return true; // collect swap_offset counts from all processes in 1st pass @@ -481,7 +481,7 @@ int main(int argc, char* argv[]) { return false; } - procs.push_back(std::move(proc)); + procs.emplace_back(std::move(proc)); return true; }; From 1d0d6623238f9a0de8edbf8a59e64f90847e6e1f Mon Sep 17 00:00:00 2001 From: Misha Wagner Date: Thu, 18 Apr 2019 16:07:33 +0100 Subject: [PATCH 153/221] Add UID printing to tombstone headers This is for Android Telemetry to be able to categorise the processes that produce tombstones. Bug: 129933535 Test: atest debugerd_test:TombstoneTest Change-Id: Ie635347c9839eb58bfd27739050bd68cbdbf98da Merged-In: Ie635347c9839eb58bfd27739050bd68cbdbf98da (cherry picked from commit e5b7913d2c5da92c37233fef15ab3109e37d9c90) --- debuggerd/libdebuggerd/include/libdebuggerd/types.h | 3 +++ debuggerd/libdebuggerd/test/tombstone_test.cpp | 10 ++++++++++ debuggerd/libdebuggerd/tombstone.cpp | 3 +++ 3 files changed, 16 insertions(+) diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/types.h b/debuggerd/libdebuggerd/include/libdebuggerd/types.h index 70583af30..eb4b1b844 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/types.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/types.h @@ -23,6 +23,9 @@ struct ThreadInfo { std::unique_ptr registers; + + pid_t uid; + pid_t tid; std::string thread_name; diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp index 3196ce84b..88c206f8d 100644 --- a/debuggerd/libdebuggerd/test/tombstone_test.cpp +++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp @@ -343,6 +343,16 @@ TEST_F(TombstoneTest, dump_header_info) { ASSERT_STREQ(expected.c_str(), amfd_data_.c_str()); } +TEST_F(TombstoneTest, dump_thread_info_uid) { + dump_thread_info(&log_, ThreadInfo{.uid = 1, + .pid = 2, + .tid = 3, + .thread_name = "some_thread", + .process_name = "some_process"}); + std::string expected = "pid: 2, tid: 3, name: some_thread >>> some_process <<<\nuid: 1\n"; + ASSERT_STREQ(expected.c_str(), amfd_data_.c_str()); +} + TEST_F(TombstoneTest, dump_timestamp) { setenv("TZ", "UTC", 1); tzset(); diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index cc337ed30..89a5a455f 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -151,6 +151,7 @@ static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) { _LOG(log, logtype::HEADER, "pid: %d, tid: %d, name: %s >>> %s <<<\n", thread_info.pid, thread_info.tid, thread_info.thread_name.c_str(), thread_info.process_name.c_str()); + _LOG(log, logtype::HEADER, "uid: %d\n", thread_info.uid); } static void dump_stack_segment(log_t* log, unwindstack::Maps* maps, unwindstack::Memory* memory, @@ -622,6 +623,7 @@ static void dump_logs(log_t* log, pid_t pid, unsigned int tail) { void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, siginfo_t* siginfo, ucontext_t* ucontext) { + pid_t uid = getuid(); pid_t pid = getpid(); pid_t tid = gettid(); @@ -643,6 +645,7 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si std::map threads; threads[gettid()] = ThreadInfo{ .registers = std::move(regs), + .uid = uid, .tid = tid, .thread_name = thread_name, .pid = pid, From 0c3f120fc67a3cea8d706ea5cfeef85f6c8ad2bc Mon Sep 17 00:00:00 2001 From: Andreas Gampe Date: Fri, 26 Apr 2019 08:51:50 -0700 Subject: [PATCH 154/221] Nativeloader: Restrict anonymous namespace creation Create the anonymous namespace only from a non-empty library path. This is a better heuristic than the current "first-come" one. It allows creating classloaders that are not directly related to an app's "main" classloader, that is, do not have any library path. This is the case, for example, for shared libraries, including preloaded ones. Longer-term, the anonymous namespace creation should be made explicit, so that the framework can have full control. (cherry picked from commit b9df7d936c7dfd1741b56e722065a46ac1e50607) Bug: 130623656 Test: m Test: manual Merged-In: I8251363b372e365d10ae09d23df93d76388ac7f9 Change-Id: I8251363b372e365d10ae09d23df93d76388ac7f9 --- libnativeloader/native_loader.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/libnativeloader/native_loader.cpp b/libnativeloader/native_loader.cpp index 5cc0857f6..e460b1a30 100644 --- a/libnativeloader/native_loader.cpp +++ b/libnativeloader/native_loader.cpp @@ -220,7 +220,9 @@ class LibraryNamespaces { } } - if (!initialized_ && !InitPublicNamespace(library_path.c_str(), error_msg)) { + // Initialize the anonymous namespace with the first non-empty library path. + if (!library_path.empty() && !initialized_ && + !InitPublicNamespace(library_path.c_str(), error_msg)) { return nullptr; } From 40bf0f077220735fffcda9ede9fd8bae636218f7 Mon Sep 17 00:00:00 2001 From: xunchang Date: Mon, 22 Apr 2019 23:14:28 -0700 Subject: [PATCH 155/221] Support adb rescue wipe command Support `adb rescue wipe` command on the host side. This command runs under the rescue mode and wipes data (and cache/metadata). Bug: 131037235 Test: run adb rescue wipe Change-Id: Ib3a3f2d564cc19d0446540d616cc21489ba558c2 (cherry picked from commit c2265c53435bbfe7c44f1bc2cf56f208ef0edc2d) --- adb/client/commandline.cpp | 36 +++++++++++++++++++++++++++++++++--- adb/services.h | 7 ++++--- 2 files changed, 37 insertions(+), 6 deletions(-) diff --git a/adb/client/commandline.cpp b/adb/client/commandline.cpp index 552df4181..e2a17c553 100644 --- a/adb/client/commandline.cpp +++ b/adb/client/commandline.cpp @@ -904,12 +904,12 @@ static int adb_sideload_install(const char* filename, bool rescue_mode) { } buf[8] = '\0'; - if (strcmp(kSideloadServiceExitSuccess, buf) == 0 || - strcmp(kSideloadServiceExitFailure, buf) == 0) { + if (strcmp(kMinadbdServicesExitSuccess, buf) == 0 || + strcmp(kMinadbdServicesExitFailure, buf) == 0) { printf("\rTotal xfer: %.2fx%*s\n", static_cast(xfer) / (sb.st_size ? sb.st_size : 1), static_cast(strlen(filename) + 10), ""); - if (strcmp(kSideloadServiceExitFailure, buf) == 0) { + if (strcmp(kMinadbdServicesExitFailure, buf) == 0) { return 1; } return 0; @@ -961,6 +961,33 @@ static int adb_sideload_install(const char* filename, bool rescue_mode) { } } +static int adb_wipe_devices() { + auto wipe_devices_message_size = strlen(kMinadbdServicesExitSuccess); + std::string error; + unique_fd fd(adb_connect( + android::base::StringPrintf("rescue-wipe:userdata:%zu", wipe_devices_message_size), + &error)); + if (fd < 0) { + fprintf(stderr, "adb: wipe device connection failed: %s\n", error.c_str()); + return 1; + } + + std::string message(wipe_devices_message_size, '\0'); + if (!ReadFdExactly(fd, message.data(), wipe_devices_message_size)) { + fprintf(stderr, "adb: failed to read wipe result: %s\n", strerror(errno)); + return 1; + } + + if (message == kMinadbdServicesExitSuccess) { + return 0; + } + + if (message != kMinadbdServicesExitFailure) { + fprintf(stderr, "adb: got unexpected message from rescue wipe %s\n", message.c_str()); + } + return 1; +} + /** * Run ppp in "notty" mode against a resource listed as the first parameter * eg: @@ -1643,6 +1670,7 @@ int adb_commandline(int argc, const char** argv) { } else if (!strcmp(argv[0], "rescue")) { // adb rescue getprop // adb rescue install + // adb rescue wipe userdata if (argc != 3) error_exit("rescue requires two arguments"); if (!strcmp(argv[1], "getprop")) { return adb_connect_command(android::base::StringPrintf("rescue-getprop:%s", argv[2])); @@ -1650,6 +1678,8 @@ int adb_commandline(int argc, const char** argv) { if (adb_sideload_install(argv[2], true /* rescue_mode */) != 0) { return 1; } + } else if (!strcmp(argv[1], "wipe") && !strcmp(argv[2], "userdata")) { + return adb_wipe_devices(); } else { error_exit("invalid rescue argument"); } diff --git a/adb/services.h b/adb/services.h index 8f3919b9b..6fc89d71f 100644 --- a/adb/services.h +++ b/adb/services.h @@ -23,9 +23,10 @@ constexpr char kShellServiceArgRaw[] = "raw"; constexpr char kShellServiceArgPty[] = "pty"; constexpr char kShellServiceArgShellProtocol[] = "v2"; -// Special flags sent by minadbd that indicate the end of sideload transfer and install result. -constexpr char kSideloadServiceExitSuccess[] = "DONEDONE"; -constexpr char kSideloadServiceExitFailure[] = "FAILFAIL"; +// Special flags sent by minadbd. They indicate the end of sideload transfer and the result of +// installation or wipe. +constexpr char kMinadbdServicesExitSuccess[] = "DONEDONE"; +constexpr char kMinadbdServicesExitFailure[] = "FAILFAIL"; unique_fd create_service_thread(const char* service_name, std::function func); #endif // SERVICES_H_ From 80cc912e7aa8c523bcf339b3ddd8e66f1849f3cc Mon Sep 17 00:00:00 2001 From: Zimuzo Date: Sat, 27 Apr 2019 20:26:05 +0100 Subject: [PATCH 156/221] Attempt native rollback for frequent crashes before boot completed Before, if updatable processes crash 4 times in 4mins, a native rollback will be attempted. This behavior does not detect system_server early boot deadlocks because the system server requires at least a min to detect a deadlock, and crash itself. The crashes don't happen frequently enough for init to detect. After, this cl, the old behavior exists and additionally, init detects *any* 4 crashes of updatable processes before boot completed, regardless of if they happen within 4mins or not. Test: Manually tested by adding artificial sleep in system_server so deadlock is triggered before boot. system_server crashes 4 times in over 4mins and the ro.init.updatable_crashing prop is set to 1. Bug: 129597207 Merged-In: Ie6fb5693ff4be105bcbe139c22850fb076e40260 Change-Id: Ie6fb5693ff4be105bcbe139c22850fb076e40260 --- init/README.md | 2 +- init/service.cpp | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/init/README.md b/init/README.md index d86f077a7..9fcc6e49d 100644 --- a/init/README.md +++ b/init/README.md @@ -191,7 +191,7 @@ runs the service. `critical` > This is a device-critical service. If it exits more than four times in - four minutes, the device will reboot into bootloader. + four minutes or before boot completes, the device will reboot into bootloader. `disabled` > This service will not automatically start with its class. diff --git a/init/service.cpp b/init/service.cpp index f5c13b983..276c2aa92 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -372,16 +372,20 @@ void Service::Reap(const siginfo_t& siginfo) { return; } - // If we crash > 4 times in 4 minutes, reboot into bootloader or set crashing property + // If we crash > 4 times in 4 minutes or before boot_completed, + // reboot into bootloader or set crashing property boot_clock::time_point now = boot_clock::now(); if (((flags_ & SVC_CRITICAL) || !pre_apexd_) && !(flags_ & SVC_RESTART)) { - if (now < time_crashed_ + 4min) { + bool boot_completed = android::base::GetBoolProperty("sys.boot_completed", false); + if (now < time_crashed_ + 4min || !boot_completed) { if (++crash_count_ > 4) { if (flags_ & SVC_CRITICAL) { // Aborts into bootloader - LOG(FATAL) << "critical process '" << name_ << "' exited 4 times in 4 minutes"; + LOG(FATAL) << "critical process '" << name_ << "' exited 4 times " + << (boot_completed ? "in 4 minutes" : "before boot completed"); } else { - LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times in 4 minutes"; + LOG(ERROR) << "updatable process '" << name_ << "' exited 4 times " + << (boot_completed ? "in 4 minutes" : "before boot completed"); // Notifies update_verifier and apexd property_set("ro.init.updatable_crashing", "1"); } From 51eb0bb44704116581659043088653311f06da7d Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 17 Apr 2019 11:21:12 -0700 Subject: [PATCH 157/221] fs_mgr: overlayfs: suppress mkfs output After this change, all the noise from mkfs is suppressed: $ adb remount [libfs_mgr]superblock s_max_mnt_count:65535,/dev/block/by-name/system_b [libfs_mgr]__mount(source=/dev/block/by-name/system_b,target=/mnt/scratch,type=ext4)=-1: Invalid argument [libfs_mgr]__mount(source=/dev/block/by-name/system_b,target=/mnt/scratch,type=f2fs)=0: Success Using overlayfs for /system Using overlayfs for /vendor Using overlayfs for /product [libfs_mgr]__mount(source=overlay,target=/system,type=overlay,upperdir=/mnt/scratch/overlay/system/upper)=0 [libfs_mgr]__mount(source=overlay,target=/vendor,type=overlay,upperdir=/mnt/scratch/overlay/vendor/upper)=0 [libfs_mgr]__mount(source=overlay,target=/product,type=overlay,upperdir=/mnt/scratch/overlay/product/upper)=0 remount succeeded Test: manual as above Bug: 130739326 Change-Id: I7ed8842e42b74b6a487ce6324b28baf78f1f63bf Merged-In: I7ed8842e42b74b6a487ce6324b28baf78f1f63bf --- fs_mgr/fs_mgr_overlayfs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 730d3db68..dc2530ec0 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -631,7 +631,7 @@ bool fs_mgr_overlayfs_make_scratch(const std::string& scratch_device, const std: LERROR << mnt_type << " has no mkfs cookbook"; return false; } - command += " " + scratch_device; + command += " " + scratch_device + " >/dev/null 2>/dev/null Date: Thu, 18 Apr 2019 12:41:29 -0700 Subject: [PATCH 158/221] bootstat: Allow regex matches for boot reasons If the matching string contains a [, \ or *, then it is also checked with a regex match. Exact match is always tried firsts. If we do not find an exact string match, switch to iterate through the entire list for regex strings to find a match. This allows us to scale with details without consuming a large number of enums, permitting details that we do not necessarily want resolution on to propagate to TRON. The hierarchical nature of the boot reason ,,... can cause scenarios where the does not matter to TRON, but does matter to bugreport collection. Add a bootstat --boot_reason_enum function to expose and test the kBootReasonMap matchihg algorithm. Add a kBootReasonMap test that exhaustively tests all built-in entries, and an example of one regex entry. New regex entries added to bootstat.cpp will need a series of exact match examples added into filter_kBootReasonMap() function. Test: boot_reason_test.sh kBootReasonMap (or all tests) Bug: 116838876 Bug: 128929506 Change-Id: I3f7b5de22f99195b7ce99672a212174365960b3f Merged-In: I3f7b5de22f99195b7ce99672a212174365960b3f --- bootstat/boot_reason_test.sh | 208 ++++++++++++++++++++++++++++++----- bootstat/bootstat.cpp | 37 ++++++- 2 files changed, 213 insertions(+), 32 deletions(-) diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh index 71d3ecbeb..cb09433d1 100755 --- a/bootstat/boot_reason_test.sh +++ b/bootstat/boot_reason_test.sh @@ -25,6 +25,8 @@ NORMAL="${ESCAPE}[0m" # Best guess to an average device's reboot time, refined as tests return DURATION_DEFAULT=45 STOP_ON_FAILURE=false +progname="${0##*/}" +progpath="${0%${progname}}" # Helper functions @@ -42,11 +44,40 @@ inAdb() { adb devices | grep -v 'List of devices attached' | grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null } +[ "USAGE: adb_sh /dev/stdout 2>/dev/stderr + +Returns: true if the command succeeded" ] +adb_sh() { + local args= + for i in "${@}"; do + [ -z "${args}" ] || args="${args} " + if [ X"${i}" != X"${i#\'}" ]; then + args="${args}${i}" + elif [ X"${i}" != X"${i#*\\}" ]; then + args="${args}`echo ${i} | sed 's/\\\\/\\\\\\\\/g'`" + elif [ X"${i}" != X"${i#* }" ]; then + args="${args}'${i}'" + elif [ X"${i}" != X"${i#*${TAB}}" ]; then + args="${args}'${i}'" + else + args="${args}${i}" + fi + done + adb shell "${args}" +} + +[ "USAGE: adb_su /dev/stdout 2>/dev/stderr + +Returns: true if the command running as root succeeded" ] +adb_su() { + adb_sh su root "${@}" +} + [ "USAGE: hasPstore Returns: true if device (likely) has pstore data" ] hasPstore() { - if inAdb && [ 0 -eq `adb shell su root ls /sys/fs/pstore | wc -l` ]; then + if inAdb && [ 0 -eq `adb_su ls /sys/fs/pstore &1 &1 &2 ; false ) || return 1 - if [ -z "`adb shell ls /etc/init/bootstat-debug.rc 2>/dev/null`" ]; then + if [ -z "`adb_sh ls /etc/init/bootstat-debug.rc 2>/dev/null &2 return 1 fi checkDebugBuild || return 1 - if adb shell su root "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" | + if adb_su "cat /proc/cmdline | tr '\\0 ' '\\n\\n'" /dev/null; then echo "ERROR: '${TEST}' test requires a device with a bootloader that" >&2 echo " does not set androidboot.bootreason kernel parameter." >&2 return 1 fi - adb shell su root setprop persist.test.boot.reason "'${1}'" 2>/dev/null + adb_su setprop persist.test.boot.reason "'${1}'" 2>/dev/null &2 @@ -299,7 +330,14 @@ EXPECT_PROPERTY() { return ${save_ret} } -[ "USAGE: report_bootstat_logs ... +[ "USAGE: adb_date >/dev/stdout + +Returns: report device epoch time (suitable for logcat -t)" ] +adb_date() { + adb_sh date +%s.%N ] ... if not prefixed with a minus (-), will become a series of expected matches: @@ -314,8 +352,11 @@ Report any logs, minus a known blacklist, preserve the current exit status" ] report_bootstat_logs() { save_ret=${?} match= + timestamp=-d for i in "${@}"; do - if [ X"${i}" != X"${i#-}" ] ; then + if [ X"${i}" != X"${i#-t}" ]; then + timestamp="${i}" + elif [ X"${i}" != X"${i#-}" ]; then match="${match} ${i#-}" else @@ -323,12 +364,13 @@ ${i#-}" bootstat: Canonical boot reason: ${i}" fi done - adb logcat -b all -d | + adb logcat -b all ${timestamp} | grep bootstat[^e] | grep -v -F "bootstat: Service started: /system/bin/bootstat --record_boot_complete${match} bootstat: Failed to read /data/misc/bootstat/post_decrypt_time_elapsed: No such file or directory bootstat: Failed to parse boot time record: /data/misc/bootstat/post_decrypt_time_elapsed bootstat: Service started: /system/bin/bootstat --record_boot_reason +bootstat: Service started: /system/bin/bootstat --set_system_boot_reason bootstat: Service started: /system/bin/bootstat --record_time_since_factory_reset bootstat: Service started: /system/bin/bootstat -l bootstat: Service started: /system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l @@ -341,6 +383,8 @@ init : Command 'setprop ro.boot.bootreason \${persist.test.boot.reason}' acti init : processing action (post-fs-data) from (/system/etc/init/bootstat.rc init : processing action (boot) from (/system/etc/init/bootstat.rc init : processing action (ro.boot.bootreason=*) from (/system/etc/init/bootstat.rc +init : processing action (ro.boot.bootreason=* && post-fs) from (/system/etc/init/bootstat.rc +init : processing action (zygote-start) from (/system/etc/init/bootstat.rc init : processing action (sys.boot_completed=1 && sys.logbootcomplete=1) from (/system/etc/init/bootstat.rc (/system/bin/bootstat --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)' (/system/bin/bootstat --set_system_boot_reason --record_boot_complete --record_boot_reason --record_time_since_factory_reset -l)' @@ -355,6 +399,8 @@ init : Command 'exec_background - system log -- /system/bin/bootstat --set_sy (/system/bin/bootstat --record_boot_reason)' (pid${SPACE} (/system/bin/bootstat --record_time_since_factory_reset)'... (/system/bin/bootstat --record_time_since_factory_reset)' (pid${SPACE} + (/system/bin/bootstat --set_system_boot_reason)'... + (/system/bin/bootstat --set_system_boot_reason)' (pid${SPACE} (/system/bin/bootstat -l)'... (/system/bin/bootstat -l)' (pid " | grep -v 'bootstat: Unknown boot reason: $' # Hikey Special @@ -613,7 +659,7 @@ fast and fake (touch build_date on device to make it different)" ] test_optional_ota() { checkDebugBuild || return duration_test - adb shell su root touch /data/misc/bootstat/build_date >&2 + adb_su touch /data/misc/bootstat/build_date >&2 &2 + adb_su rm /data/misc/bootstat/build_date >&2 &2 wait_for_screen EXPECT_PROPERTY sys.boot.reason reboot,factory_reset @@ -715,7 +761,7 @@ test_optional_factory_reset() { wait_for_screen ( exit ${save_ret} ) # because one can not just do ?=${save_ret} EXPECT_PROPERTY sys.boot.reason reboot,factory_reset - EXPECT_PROPERTY sys.boot.reason.last "" + EXPECT_PROPERTY sys.boot.reason.last "\(\|bootloader\)" check_boilerplate_properties report_bootstat_logs reboot,factory_reset bootloader \ "-bootstat: Failed to read /data/misc/bootstat/last_boot_time_utc: No such file or directory" \ @@ -766,12 +812,12 @@ test_battery() { enterPstore # Send it _many_ times to combat devices with flakey pstore for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do - echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null + echo 'healthd: battery l=2 ' | adb_su tee /dev/kmsg >/dev/null done adb reboot cold >&2 adb wait-for-device wait_for_screen - adb shell su root \ + adb_su /dev/null | grep 'healthd: battery l=' | @@ -780,7 +826,7 @@ test_battery() { if ! EXPECT_PROPERTY sys.boot.reason reboot,battery >/dev/null 2>/dev/null; then # retry for i in a b c d e f g h i j k l m n o p q r s t u v w x y z; do - echo 'healthd: battery l=2 ' | adb shell su root tee /dev/kmsg >/dev/null + echo 'healthd: battery l=2 ' | adb_su tee /dev/kmsg >/dev/null done adb reboot cold >&2 adb wait-for-device @@ -806,7 +852,7 @@ battery shutdown test: test_optional_battery() { duration_test ">60" echo " power on request" >&2 - adb shell setprop sys.powerctl shutdown,battery + adb_sh setprop sys.powerctl shutdown,battery &2 wait_for_screen -n >&2 @@ -827,7 +873,7 @@ battery thermal shutdown test: test_optional_battery_thermal() { duration_test ">60" echo " power on request" >&2 - adb shell setprop sys.powerctl shutdown,thermal,battery + adb_sh setprop sys.powerctl shutdown,thermal,battery &2 wait_for_screen -n >&2 @@ -866,7 +912,7 @@ test_kernel_panic() { panic_msg="\(kernel_panic,sysrq\|kernel_panic\)" pstore_ok=true fi - echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null + echo c | adb_su tee /proc/sysrq-trigger >/dev/null wait_for_screen EXPECT_PROPERTY sys.boot.reason ${panic_msg} EXPECT_PROPERTY sys.boot.reason.last ${panic_msg} @@ -893,8 +939,8 @@ test_kernel_panic_subreason() { panic_msg="\(kernel_panic,sysrq,test\|kernel_panic\)" pstore_ok=true fi - echo "SysRq : Trigger a crash : 'test'" | adb shell su root tee /dev/kmsg - echo c | adb shell su root tee /proc/sysrq-trigger >/dev/null + echo "SysRq : Trigger a crash : 'test'" | adb_su tee /dev/kmsg + echo c | adb_su tee /proc/sysrq-trigger >/dev/null wait_for_screen EXPECT_PROPERTY sys.boot.reason ${panic_msg} EXPECT_PROPERTY sys.boot.reason.last ${panic_msg} @@ -924,7 +970,7 @@ test_kernel_panic_hung() { pstore_ok=true fi echo "Kernel panic - not syncing: hung_task: blocked tasks" | - adb shell su root tee /dev/kmsg + adb_su tee /dev/kmsg adb reboot warm wait_for_screen EXPECT_PROPERTY sys.boot.reason ${panic_msg} @@ -956,7 +1002,7 @@ thermal shutdown test: test_thermal_shutdown() { duration_test ">60" echo " power on request" >&2 - adb shell setprop sys.powerctl shutdown,thermal + adb_sh setprop sys.powerctl shutdown,thermal &2 wait_for_screen -n >&2 @@ -977,7 +1023,7 @@ userrequested shutdown test: test_userrequested_shutdown() { duration_test ">60" echo " power on request" >&2 - adb shell setprop sys.powerctl shutdown,userrequested + adb_sh setprop sys.powerctl shutdown,userrequested &2 wait_for_screen -n >&2 @@ -996,7 +1042,7 @@ shell reboot test: - NB: should report reboot,shell" ] test_shell_reboot() { duration_test - adb shell reboot + adb_sh reboot &2 - EXPECT_PROPERTY ro.boot.bootreason reboot,rescueparty + EXPECT_PROPERTY ro.boot.bootreason '\(reboot\|reboot,rescueparty\)' } [ "USAGE: test_Its_Just_So_Hard_reboot @@ -1049,7 +1095,7 @@ test_Its_Just_So_Hard_reboot() { else duration_test `expr ${DURATION_DEFAULT} + ${DURATION_DEFAULT}` fi - adb shell 'reboot "Its Just So Hard"' + adb_sh 'reboot "Its Just So Hard"' &2 + retval=1 + fi + done + exit ${retval} + ) + return + fi + local sys_expected="${1}" + shift + local enum_expected="${1}" + adb_su setprop sys.boot.reason "${sys_expected}" /dev/null` + [ "${enum_expected}" = "${result}" ] || + ( + [ -n "${result}" ] || result="" + echo "ERROR: ${enum_expected} ${sys_expected} got ${result}" >&2 + false + ) || + retval=${?} + return ${retval} +} + +[ "USAGE: filter_kBootReasonMap /dev/stdout + +convert any regex expressions into a series of non-regex test strings" ] +filter_kBootReasonMap() { + while read -r id match; do + case ${match} in + 'reboot,[empty]') + echo ${id} # matches b/c of special case + echo ${id} reboot,y # matches b/c of regex + echo 1 reboot,empty # negative test (ID for unknown is 1) + ;; + reboot) + echo 1 reboo # negative test (ID for unknown is 1) + ;; + esac + echo ${id} "${match}" # matches b/c of exact + done +} + +[ "USAGE: test_kBootReasonMap + +kBootReasonMap test +- (wait until screen is up, boot has completed) +- read bootstat for kBootReasonMap entries and test them all" ] +test_kBootReasonMap() { + local tempfile="`mktemp`" + local arg=--boot_reason_enum + adb_su bootstat ${arg} /dev/null | + filter_kBootReasonMap >${tempfile} + if [ ! -s "${tempfile}" ]; then + wait_for_screen + arg= + sed -n <${progpath}bootstat.cpp \ + '/kBootReasonMap = {/,/^};/s/.*{"\([^"]*\)", *\([0-9][0-9]*\)},.*/\2 \1/p' | + sed 's/\\\\/\\/g' | + filter_kBootReasonMap >${tempfile} + fi + T=`adb_date` + retval=0 + while read -r enum string; do + if [ X"${string}" != X"${string#*[[].[]]}" -o X"${string}" != X"${string#*\\.}" ]; then + if [ 'reboot\.empty' != "${string}" ]; then + echo "WARNING: regex snuck through filter_kBootReasonMap ${enum} ${string}" >&2 + enum=1 + fi + fi + run_kBootReasonMap ${arg} "${string}" "${enum}" Report the match to the kBootReasonMap table\n"); } // Constructs a readable, printable string from the givencommand line @@ -120,9 +121,10 @@ constexpr int32_t kUnknownBootReason = 1; // A mapping from boot reason string, as read from the ro.boot.bootreason // system property, to a unique integer ID. Viewers of log data dashboards for // the boot_reason metric may refer to this mapping to discern the histogram -// values. +// values. Regex matching, to manage the scale, as a minimum require either +// [, \ or * to be present in the string to switch to checking. const std::map kBootReasonMap = { - {"empty", kEmptyBootReason}, + {"reboot,[empty]", kEmptyBootReason}, {"__BOOTSTAT_UNKNOWN__", kUnknownBootReason}, {"normal", 2}, {"recovery", 3}, @@ -314,6 +316,16 @@ int32_t BootReasonStrToEnum(const std::string& boot_reason) { return kEmptyBootReason; } + for (const auto& [match, id] : kBootReasonMap) { + // Regex matches as a minimum require either [, \ or * to be present. + if (match.find_first_of("[\\*") == match.npos) continue; + // enforce match from beginning to end + auto exact = match; + if (exact[0] != '^') exact = "^" + exact; + if (exact[exact.size() - 1] != '$') exact = exact + "$"; + if (std::regex_search(boot_reason, std::regex(exact))) return id; + } + LOG(INFO) << "Unknown boot reason: " << boot_reason; return kUnknownBootReason; } @@ -1266,6 +1278,19 @@ void RecordFactoryReset() { boot_event_store.AddBootEventWithValue("time_since_factory_reset", time_since_factory_reset); } +// List the associated boot reason(s), if arg is nullptr then all. +void PrintBootReasonEnum(const char* arg) { + int value = -1; + if (arg != nullptr) { + value = BootReasonStrToEnum(arg); + } + for (const auto& [match, id] : kBootReasonMap) { + if ((value < 0) || (value == id)) { + printf("%u\t%s\n", id, match.c_str()); + } + } +} + } // namespace int main(int argc, char** argv) { @@ -1280,6 +1305,7 @@ int main(int argc, char** argv) { static const char boot_complete_str[] = "record_boot_complete"; static const char boot_reason_str[] = "record_boot_reason"; static const char factory_reset_str[] = "record_time_since_factory_reset"; + static const char boot_reason_enum_str[] = "boot_reason_enum"; static const struct option long_options[] = { // clang-format off { "help", no_argument, NULL, 'h' }, @@ -1291,6 +1317,7 @@ int main(int argc, char** argv) { { boot_complete_str, no_argument, NULL, 0 }, { boot_reason_str, no_argument, NULL, 0 }, { factory_reset_str, no_argument, NULL, 0 }, + { boot_reason_enum_str, optional_argument, NULL, 0 }, { NULL, 0, NULL, 0 } // clang-format on }; @@ -1315,6 +1342,8 @@ int main(int argc, char** argv) { RecordBootReason(); } else if (option_name == factory_reset_str) { RecordFactoryReset(); + } else if (option_name == boot_reason_enum_str) { + PrintBootReasonEnum(optarg); } else { LOG(ERROR) << "Invalid option: " << option_name; } From 3379be2a77055e84f4aed7cbb6085dbf776d4a24 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Thu, 11 Apr 2019 12:58:19 -0700 Subject: [PATCH 159/221] fs_mgr: overlay check shared blocks for / if /system is not For bringup devices that do not have right-sized partition, and if /system is now root, check / to be sure. Consider unshare blocks for ext4 as dead code, provide a strong message to caller to provide all the dependencies to overlayfs. Test: adb-remount-test.sh Bug: 130327601 Change-Id: Iffa7c5f24d8f409e71f89fe9ece274d8c476f6fc Merged-In: Iffa7c5f24d8f409e71f89fe9ece274d8c476f6fc --- fs_mgr/fs_mgr_overlayfs.cpp | 3 +++ fs_mgr/fs_mgr_remount.cpp | 14 +++++--------- 2 files changed, 8 insertions(+), 9 deletions(-) diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 730d3db68..012abd4dc 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -159,6 +159,9 @@ bool fs_mgr_overlayfs_enabled(FstabEntry* entry) { auto save_errno = errno; errno = 0; auto has_shared_blocks = fs_mgr_has_shared_blocks(entry->mount_point, entry->blk_device); + if (!has_shared_blocks && (entry->mount_point == "/system")) { + has_shared_blocks = fs_mgr_has_shared_blocks("/", entry->blk_device); + } // special case for first stage init for system as root (taimen) if (!has_shared_blocks && (errno == ENOENT) && (entry->blk_device == "/dev/root")) { has_shared_blocks = true; diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp index 093d44d41..cbe2008a0 100644 --- a/fs_mgr/fs_mgr_remount.cpp +++ b/fs_mgr/fs_mgr_remount.cpp @@ -371,17 +371,13 @@ int main(int argc, char* argv[]) { continue; } } - PLOG(WARNING) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point; - // If errno = EROFS at this point, we are dealing with r/o + PLOG(ERROR) << "failed to remount partition dev:" << blk_device << " mnt:" << mount_point; + // If errno is EROFS at this point, we are dealing with r/o // filesystem types like squashfs, erofs or ext4 dedupe. We will // consider such a device that does not have CONFIG_OVERLAY_FS - // in the kernel as a misconfigured; except for ext4 dedupe. - if ((errno == EROFS) && can_reboot) { - const std::vector msg = {"--fsck_unshare_blocks"}; - std::string err; - if (write_bootloader_message(msg, &err)) reboot(true); - LOG(ERROR) << "Failed to set bootloader message: " << err; - errno = EROFS; + // in the kernel as a misconfigured. + if (errno == EROFS) { + LOG(ERROR) << "Consider providing all the dependencies to enable overlayfs"; } retval = REMOUNT_FAILED; } From 94fb36bf779f185f812c7f46f86015d9988acf62 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 1 May 2019 16:53:53 -0700 Subject: [PATCH 160/221] adbd: avoid starting multiple worker threads. A previous patch intended to make receiving multiple FUNCTIONFS_ENABLEs non-fatal, but failed to do so because we would try to spawn another worker thread and hit a different assertion. Bug: http://b/130638368 Test: echo mem | adb shell "su 0 sh -c 'cat > /sys/power/state'" Change-Id: I53456112244d8b4f7d26df6ec6961389fca70498 (cherry picked from commit 910ce0ff0852418c1a1e126bf0b083dcf24d5899) --- adb/daemon/usb.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp index 3b29ab5fc..e6a19a521 100644 --- a/adb/daemon/usb.cpp +++ b/adb/daemon/usb.cpp @@ -308,11 +308,13 @@ struct UsbFfsConnection : public Connection { if (bound) { LOG(WARNING) << "received FUNCTIONFS_BIND while already bound?"; running = false; + break; } if (enabled) { LOG(WARNING) << "received FUNCTIONFS_BIND while already enabled?"; running = false; + break; } bound = true; @@ -322,11 +324,13 @@ struct UsbFfsConnection : public Connection { if (!bound) { LOG(WARNING) << "received FUNCTIONFS_ENABLE while not bound?"; running = false; + break; } if (enabled) { LOG(WARNING) << "received FUNCTIONFS_ENABLE while already enabled?"; running = false; + break; } enabled = true; From edf4682cae1cf34172faa5542b6f63c57742b627 Mon Sep 17 00:00:00 2001 From: Jone Chou Date: Thu, 18 Apr 2019 15:43:26 +0800 Subject: [PATCH 161/221] bootstat: add 3 pmic off reasons to known set regular expression: - "reboot,pmic_off_fault,.*" (175) - "reboot,pmic_off_s3rst,.*" (176) - "reboot,pmic_off_other,.*" (177) regex is dependent on: https://android-review.googlesource.com/947976 Test: none Bug: 116838876 Bug: 128929506 Change-Id: I7fae9ecee536f790c8f493c3f5e5f75b03efb1d6 Signed-off-by: Jone Chou --- bootstat/bootstat.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp index 617ea4fb8..558e6c4b2 100644 --- a/bootstat/bootstat.cpp +++ b/bootstat/bootstat.cpp @@ -301,6 +301,9 @@ const std::map kBootReasonMap = { {"reboot,dm-verity_device_corrupted", 172}, {"reboot,dm-verity_enforcing", 173}, {"reboot,keys_clear", 174}, + {"reboot,pmic_off_fault,.*", 175}, + {"reboot,pmic_off_s3rst,.*", 176}, + {"reboot,pmic_off_other,.*", 177}, }; // Converts a string value representing the reason the system booted to an From ebbbc1a6026923d993e95b1ab1946abe32891543 Mon Sep 17 00:00:00 2001 From: Christopher Ferris Date: Fri, 3 May 2019 11:13:17 -0700 Subject: [PATCH 162/221] Ignore memory from elf on /memfd: In ART, some of the maps are /memfd:/jit-cache and it triggers the warning about unreadable elf files. Do not set the elf from memory not file flag in this case. Bug: 131909548 Test: New unit tests pass. Test: No warnings dumping stacks with this change done. Change-Id: Ifba5e65da609525ded75430da173c614f6e4801e (cherry picked from commit 98aaf4cf086e2492796b11116e69e0ff01093663) --- libunwindstack/Unwinder.cpp | 3 ++- libunwindstack/tests/UnwinderTest.cpp | 36 +++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 1 deletion(-) diff --git a/libunwindstack/Unwinder.cpp b/libunwindstack/Unwinder.cpp index 26626b5cd..37323dc16 100644 --- a/libunwindstack/Unwinder.cpp +++ b/libunwindstack/Unwinder.cpp @@ -25,6 +25,7 @@ #include #include +#include #include @@ -168,7 +169,7 @@ void Unwinder::Unwind(const std::vector* initial_map_names_to_skip, // If this elf is memory backed, and there is a valid file, then set // an indicator that we couldn't open the file. if (!elf_from_memory_not_file_ && map_info->memory_backed_elf && !map_info->name.empty() && - map_info->name[0] != '[') { + map_info->name[0] != '[' && !android::base::StartsWith(map_info->name, "/memfd:")) { elf_from_memory_not_file_ = true; } step_pc = regs_->pc(); diff --git a/libunwindstack/tests/UnwinderTest.cpp b/libunwindstack/tests/UnwinderTest.cpp index f6350216f..30e57a142 100644 --- a/libunwindstack/tests/UnwinderTest.cpp +++ b/libunwindstack/tests/UnwinderTest.cpp @@ -126,6 +126,12 @@ class UnwinderTest : public ::testing::Test { const auto& info5 = *--maps_->end(); info5->memory_backed_elf = true; + elf = new ElfFake(new MemoryFake); + elf->FakeSetInterface(new ElfInterfaceFake(nullptr)); + AddMapInfo(0xc3000, 0xc4000, 0, PROT_READ | PROT_WRITE | PROT_EXEC, "/memfd:/jit-cache", elf); + const auto& info6 = *--maps_->end(); + info6->memory_backed_elf = true; + process_memory_.reset(new MemoryFake); } @@ -1234,6 +1240,36 @@ TEST_F(UnwinderTest, elf_from_memory_but_empty_filename) { EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); } +TEST_F(UnwinderTest, elf_from_memory_but_from_memfd) { + ElfInterfaceFake::FakePushFunctionData(FunctionData("Frame0", 0)); + + regs_.set_pc(0xc3050); + regs_.set_sp(0x10000); + ElfInterfaceFake::FakePushStepData(StepData(0, 0, true)); + + Unwinder unwinder(64, maps_.get(), ®s_, process_memory_); + unwinder.Unwind(); + EXPECT_EQ(ERROR_NONE, unwinder.LastErrorCode()); + EXPECT_FALSE(unwinder.elf_from_memory_not_file()); + + ASSERT_EQ(1U, unwinder.NumFrames()); + + auto* frame = &unwinder.frames()[0]; + EXPECT_EQ(0U, frame->num); + EXPECT_EQ(0x50U, frame->rel_pc); + EXPECT_EQ(0xc3050U, frame->pc); + EXPECT_EQ(0x10000U, frame->sp); + EXPECT_EQ("Frame0", frame->function_name); + EXPECT_EQ(0U, frame->function_offset); + EXPECT_EQ("/memfd:/jit-cache", frame->map_name); + EXPECT_EQ(0U, frame->map_elf_start_offset); + EXPECT_EQ(0U, frame->map_exact_offset); + EXPECT_EQ(0xc3000U, frame->map_start); + EXPECT_EQ(0xc4000U, frame->map_end); + EXPECT_EQ(0U, frame->map_load_bias); + EXPECT_EQ(PROT_READ | PROT_WRITE | PROT_EXEC, frame->map_flags); +} + // Verify format frame code. TEST_F(UnwinderTest, format_frame) { RegsFake regs_arm(10); From 79cfc7d5a8a5c4d308fa2315f42cf17f253c09fd Mon Sep 17 00:00:00 2001 From: Tao Bao Date: Tue, 7 May 2019 11:09:04 -0700 Subject: [PATCH 163/221] DO NOT MERGE Start update_verifier early in late-fs. We used to start update_verifier after mounting userdata (post-fs-data), as part of zygote-start. This leads to issues in practice for security updates, where an A/B device falls back into the old slot (for any reason, which unrelates to this change) but failing to boot due to upgraded key blob. It essentially breaks the fallback capability offered by A/B OTA. This CL mitigates the issue by starting update_verifier early, before mounting userdata. This avoids the device from falling back to the old slot with an already-upgraded key blob. update_verifier loses the opportunity of verifying _all_ the updated blocks based on the info that's stored in userdata. Instead it will only trigger the minimal read to finish the work of marking a successful boot. This is a trade-off in P to avoid putting the device in a bad state after fallback, which will be improved in Q by better handling the fallback path in vold. Bug: 131176531 Test: Flash and boot crosshatch. Check the start of update_verifier and it marks a successful boot. Change-Id: I3f4c4333ff38772a9a93c9d027d497db11de1d63 --- rootdir/init.rc | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index b9464e7fd..f4b208278 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -381,6 +381,10 @@ on late-fs # HALs required before storage encryption can get unlocked (FBE/FDE) class_start early_hal + # Check and mark a successful boot, before mounting userdata with mount_all. + # No-op for non-A/B device. + exec_start update_verifier_nonencrypted + on post-fs-data # We chown/chmod /data again so because mount is run as root + defaults chown system system /data @@ -558,22 +562,16 @@ on post-fs-data # It is recommended to put unnecessary data/ initialization from post-fs-data # to start-zygote in device's init.rc to unblock zygote start. on zygote-start && property:ro.crypto.state=unencrypted - # A/B update verifier that marks a successful boot. - exec_start update_verifier_nonencrypted start netd start zygote start zygote_secondary on zygote-start && property:ro.crypto.state=unsupported - # A/B update verifier that marks a successful boot. - exec_start update_verifier_nonencrypted start netd start zygote start zygote_secondary on zygote-start && property:ro.crypto.state=encrypted && property:ro.crypto.type=file - # A/B update verifier that marks a successful boot. - exec_start update_verifier_nonencrypted start netd start zygote start zygote_secondary @@ -700,15 +698,11 @@ on property:vold.decrypt=trigger_post_fs_data trigger zygote-start on property:vold.decrypt=trigger_restart_min_framework - # A/B update verifier that marks a successful boot. - exec_start update_verifier class_start main on property:vold.decrypt=trigger_restart_framework stop surfaceflinger start surfaceflinger - # A/B update verifier that marks a successful boot. - exec_start update_verifier class_start main class_start late_start From 9d7d26a5cf8d2ab67cbaf8a5553e72486c721d24 Mon Sep 17 00:00:00 2001 From: Iris Chang Date: Mon, 6 May 2019 15:20:16 +0800 Subject: [PATCH 164/221] Support booting a chained boot-debug.img boot-debug.img is introduced to allow 'adb root' if the device is unlocked, and it cannot be release signed. If /boot partition is chained in AVB signing and boot-debug.img is used, avb_slot_verify() in userspace will return AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED and fs_mgr will refuse to boot. This CL treats the public key rejection as non-fatal for chained vbmeta to continue booting, if the device is unlocked. Bug: 129508966 Test: can root with user load which /boot chained in AVB signing Change-Id: Idfa8caffbb96f33702b1749afd2e2a59616ddba7 Merged-In: Idfa8caffbb96f33702b1749afd2e2a59616ddba7 (cherry picked from commit 705fd7f52cae7a82faeee6a8de429d746a512f77) --- fs_mgr/libfs_avb/fs_avb.cpp | 28 ++++++++++++++++------------ 1 file changed, 16 insertions(+), 12 deletions(-) diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp index 04776edc5..c4d75110f 100644 --- a/fs_mgr/libfs_avb/fs_avb.cpp +++ b/fs_mgr/libfs_avb/fs_avb.cpp @@ -338,6 +338,7 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta() { nullptr /* custom_device_path */); } +// TODO(b/128807537): removes this function. AvbUniquePtr AvbHandle::Open() { bool is_device_unlocked = IsDeviceUnlocked(); @@ -353,25 +354,28 @@ AvbUniquePtr AvbHandle::Open() { AvbSlotVerifyResult verify_result = avb_ops.AvbSlotVerify(fs_mgr_get_slot_suffix(), flags, &avb_handle->vbmeta_images_); - // Only allow two verify results: + // Only allow the following verify results: // - AVB_SLOT_VERIFY_RESULT_OK. - // - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (for UNLOCKED state). - // If the device is UNLOCKED, i.e., |allow_verification_error| is true for - // AvbSlotVerify(), then the following return values are all non-fatal: - // * AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION - // * AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED - // * AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX - // The latter two results were checked by bootloader prior to start fs_mgr so - // we just need to handle the first result here. See *dummy* operations in - // FsManagerAvbOps and the comments in external/avb/libavb/avb_slot_verify.h - // for more details. + // - AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION (UNLOCKED only). + // Might occur in either the top-level vbmeta or a chained vbmeta. + // - AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED (UNLOCKED only). + // Could only occur in a chained vbmeta. Because we have *dummy* operations in + // FsManagerAvbOps such that avb_ops->validate_vbmeta_public_key() used to validate + // the public key of the top-level vbmeta always pass in userspace here. + // + // The following verify result won't happen, because the *dummy* operation + // avb_ops->read_rollback_index() always returns the minimum value zero. So rollbacked + // vbmeta images, which should be caught in the bootloader stage, won't be detected here. + // - AVB_SLOT_VERIFY_RESULT_ERROR_ROLLBACK_INDEX switch (verify_result) { case AVB_SLOT_VERIFY_RESULT_OK: avb_handle->status_ = AvbHandleStatus::kSuccess; break; case AVB_SLOT_VERIFY_RESULT_ERROR_VERIFICATION: + case AVB_SLOT_VERIFY_RESULT_ERROR_PUBLIC_KEY_REJECTED: if (!is_device_unlocked) { - LERROR << "ERROR_VERIFICATION isn't allowed when the device is LOCKED"; + LERROR << "ERROR_VERIFICATION / PUBLIC_KEY_REJECTED isn't allowed " + << "if the device is LOCKED"; return nullptr; } avb_handle->status_ = AvbHandleStatus::kVerificationError; From b562e685037e395b0526a9262977bb73318ff994 Mon Sep 17 00:00:00 2001 From: Vic Yang Date: Wed, 8 May 2019 12:50:56 -0700 Subject: [PATCH 165/221] Static link libjsoncpp in libprocessgroup The majority of libjsoncpp use is due to libprocessgroup. Static linking reduces relocations required at runtime as well as compacts the pages dirtied by relocations. On a 32-bit system, where this matters the most, this reduces 8KB of dirty pages per libprocessgroup load. Overall, the dirty page reduction on 32-bit cuttlefish is ~500KB. Bug: 132275636 Test: Boot on cuttlefish. Calculate total amount of dirty memory used for libprocessgroup and libjsoncpp. Change-Id: I1135bb45a3764f96a4a3a47c98fbcdee3913c988 --- libprocessgroup/Android.bp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libprocessgroup/Android.bp b/libprocessgroup/Android.bp index 78a02e5d4..0207a7540 100644 --- a/libprocessgroup/Android.bp +++ b/libprocessgroup/Android.bp @@ -32,6 +32,8 @@ cc_library { shared_libs: [ "libbase", "libcgrouprc", + ], + static_libs: [ "libjsoncpp", ], // for cutils/android_filesystem_config.h From c7bf1a01fdf0db57f46e25bd7af54e465a458929 Mon Sep 17 00:00:00 2001 From: Rick Yiu Date: Tue, 23 Apr 2019 21:33:56 +0800 Subject: [PATCH 166/221] Apply initial settings for blkio cgroup Bug: 117857342 Test: values are applied Change-Id: Id28d9619fc2fd2287fe656b8032025184ae7f631 (cherry picked from commit a8aaf198d5d5bf110df36309a7c679ed3a153d68) Merged-In: Id28d9619fc2fd2287fe656b8032025184ae7f631 --- rootdir/init.rc | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index cb45c42f8..1b7367c46 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -80,7 +80,9 @@ on init chmod 0664 /dev/stune/top-app/tasks chmod 0664 /dev/stune/rt/tasks - # Create blkio tuning nodes + # Create blkio group and apply initial settings. + # This feature needs kernel to support it, and the + # device's init.rc must actually set the correct values. mkdir /dev/blkio/background chown system system /dev/blkio chown system system /dev/blkio/background @@ -88,6 +90,10 @@ on init chown system system /dev/blkio/background/tasks chmod 0664 /dev/blkio/tasks chmod 0664 /dev/blkio/background/tasks + write /dev/blkio/blkio.weight 1000 + write /dev/blkio/background/blkio.weight 500 + write /dev/blkio/blkio.group_idle 0 + write /dev/blkio/background/blkio.group_idle 0 restorecon_recursive /mnt From f38e182fbfb0dbdde24c8d7a8c653d2046d12d39 Mon Sep 17 00:00:00 2001 From: Lorenzo Colitti Date: Wed, 10 Apr 2019 12:01:34 +0900 Subject: [PATCH 167/221] Make the SocketListener control pipe O_CLOEXEC. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Children of processes that use SocketListener should not be able to stop the SocketListener. Test: builds, boots Test: atest libsysutils_tests Test: atest --test-mapping system/netd Bug: 131268436 Signed-off-by: Maciej Å»enczykowski Change-Id: I64898d9966f62004468b8e8a43b59be4a81a8cc4 Merged-In: I64898d9966f62004468b8e8a43b59be4a81a8cc4 (cherry picked from commit dae0195380686dbec450e298f4acf47b5f9576e6) --- libsysutils/src/SocketListener.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libsysutils/src/SocketListener.cpp b/libsysutils/src/SocketListener.cpp index ded5adb6d..97806068e 100644 --- a/libsysutils/src/SocketListener.cpp +++ b/libsysutils/src/SocketListener.cpp @@ -95,7 +95,7 @@ int SocketListener::startListener(int backlog) { } else if (!mListen) mClients[mSock] = new SocketClient(mSock, false, mUseCmdNum); - if (pipe(mCtrlPipe)) { + if (pipe2(mCtrlPipe, O_CLOEXEC)) { SLOGE("pipe failed (%s)", strerror(errno)); return -1; } From d244a751fdd7e3aeaa37561956da67adbc329532 Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Thu, 9 May 2019 13:16:07 +0800 Subject: [PATCH 168/221] fs_mgr_remount: fix a typo Replacing "ro.boot.vbmeta.devices_state" with "ro.boot.vbmeta.device_state" to check if the device is locked. Bug: 132224452 Test: tree hugger Change-Id: If4f312730cc82ad5a5d5104a7aca8b9691cf6600 (cherry picked from commit 2badf73b99c91c94ade86a05e18ea94611abd457) --- fs_mgr/fs_mgr_remount.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp index cbe2008a0..fcacd2a43 100644 --- a/fs_mgr/fs_mgr_remount.cpp +++ b/fs_mgr/fs_mgr_remount.cpp @@ -255,7 +255,7 @@ int main(int argc, char* argv[]) { auto& mount_point = entry.mount_point; if (fs_mgr_is_verity_enabled(entry)) { retval = VERITY_PARTITION; - if (android::base::GetProperty("ro.boot.vbmeta.devices_state", "") != "locked") { + if (android::base::GetProperty("ro.boot.vbmeta.device_state", "") != "locked") { if (AvbOps* ops = avb_ops_user_new()) { auto ret = avb_user_verity_set( ops, android::base::GetProperty("ro.boot.slot_suffix", "").c_str(), From 7eeda6ba0307e70d977b7d1303270b5f25425db3 Mon Sep 17 00:00:00 2001 From: Michael Groover Date: Thu, 25 Apr 2019 18:33:35 -0700 Subject: [PATCH 169/221] Notify the framework when an adb key is authorized Bug: 124076524 Test: atest AdbDebuggingManagerTest Change-Id: If73b81ca73ba4d64763cf49c1bbe42de81fa1cb6 --- adb/adb.cpp | 8 ++- adb/adb.h | 1 + adb/adb_auth.h | 6 ++- adb/daemon/auth.cpp | 129 ++++++++++++++++++++++++++++++-------------- adb/transport.h | 3 ++ rootdir/init.usb.rc | 2 +- 6 files changed, 103 insertions(+), 46 deletions(-) diff --git a/adb/adb.cpp b/adb/adb.cpp index 2dd22b38b..050ba49ad 100644 --- a/adb/adb.cpp +++ b/adb/adb.cpp @@ -337,9 +337,12 @@ void handle_packet(apacket *p, atransport *t) case ADB_AUTH_SIGNATURE: { // TODO: Switch to string_view. std::string signature(p->payload.begin(), p->payload.end()); - if (adbd_auth_verify(t->token, sizeof(t->token), signature)) { + std::string auth_key; + if (adbd_auth_verify(t->token, sizeof(t->token), signature, &auth_key)) { adbd_auth_verified(t); t->failed_auth_attempts = 0; + t->auth_key = auth_key; + adbd_notify_framework_connected_key(t); } else { if (t->failed_auth_attempts++ > 256) std::this_thread::sleep_for(1s); send_auth_request(t); @@ -348,7 +351,8 @@ void handle_packet(apacket *p, atransport *t) } case ADB_AUTH_RSAPUBLICKEY: - adbd_auth_confirm_key(p->payload.data(), p->msg.data_length, t); + t->auth_key = std::string(p->payload.data()); + adbd_auth_confirm_key(t); break; #endif default: diff --git a/adb/adb.h b/adb/adb.h index 3a6f059b8..9324ceec5 100644 --- a/adb/adb.h +++ b/adb/adb.h @@ -33,6 +33,7 @@ constexpr size_t MAX_PAYLOAD_V1 = 4 * 1024; constexpr size_t MAX_PAYLOAD = 1024 * 1024; +constexpr size_t MAX_FRAMEWORK_PAYLOAD = 64 * 1024; constexpr size_t LINUX_MAX_SOCKET_SIZE = 4194304; diff --git a/adb/adb_auth.h b/adb/adb_auth.h index 2fc84789a..2be9a7684 100644 --- a/adb/adb_auth.h +++ b/adb/adb_auth.h @@ -50,8 +50,10 @@ void adbd_auth_init(void); void adbd_auth_verified(atransport *t); void adbd_cloexec_auth_socket(); -bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig); -void adbd_auth_confirm_key(const char* data, size_t len, atransport* t); +bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig, + std::string* auth_key); +void adbd_auth_confirm_key(atransport* t); +void adbd_notify_framework_connected_key(atransport* t); void send_auth_request(atransport *t); diff --git a/adb/daemon/auth.cpp b/adb/daemon/auth.cpp index a829bac0a..a18afa4ea 100644 --- a/adb/daemon/auth.cpp +++ b/adb/daemon/auth.cpp @@ -26,7 +26,9 @@ #include #include #include +#include +#include #include #include @@ -38,7 +40,9 @@ static fdevent* listener_fde = nullptr; static fdevent* framework_fde = nullptr; -static int framework_fd = -1; +static auto& framework_mutex = *new std::mutex(); +static int framework_fd GUARDED_BY(framework_mutex) = -1; +static auto& connected_keys GUARDED_BY(framework_mutex) = *new std::vector; static void adb_disconnected(void* unused, atransport* t); static struct adisconnect adb_disconnect = {adb_disconnected, nullptr}; @@ -47,13 +51,13 @@ static bool needs_retry = false; bool auth_required = true; -bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig) { +bool adbd_auth_verify(const char* token, size_t token_size, const std::string& sig, + std::string* auth_key) { static constexpr const char* key_paths[] = { "/adb_keys", "/data/misc/adb/adb_keys", nullptr }; for (const auto& path : key_paths) { if (access(path, R_OK) == 0) { LOG(INFO) << "Loading keys from " << path; - std::string content; if (!android::base::ReadFileToString(path, &content)) { PLOG(ERROR) << "Couldn't read " << path; @@ -61,6 +65,8 @@ bool adbd_auth_verify(const char* token, size_t token_size, const std::string& s } for (const auto& line : android::base::Split(content, "\n")) { + if (line.empty()) continue; + *auth_key = line; // TODO: do we really have to support both ' ' and '\t'? char* sep = strpbrk(const_cast(line.c_str()), " \t"); if (sep) *sep = '\0'; @@ -88,9 +94,31 @@ bool adbd_auth_verify(const char* token, size_t token_size, const std::string& s } } } + auth_key->clear(); return false; } +static bool adbd_send_key_message_locked(std::string_view msg_type, std::string_view key) + REQUIRES(framework_mutex) { + if (framework_fd < 0) { + LOG(ERROR) << "Client not connected to send msg_type " << msg_type; + return false; + } + std::string msg = std::string(msg_type) + std::string(key); + int msg_len = msg.length(); + if (msg_len >= static_cast(MAX_FRAMEWORK_PAYLOAD)) { + LOG(ERROR) << "Key too long (" << msg_len << ")"; + return false; + } + + LOG(DEBUG) << "Sending '" << msg << "'"; + if (!WriteFdExactly(framework_fd, msg.c_str(), msg_len)) { + PLOG(ERROR) << "Failed to write " << msg_type; + return false; + } + return true; +} + static bool adbd_auth_generate_token(void* token, size_t token_size) { FILE* fp = fopen("/dev/urandom", "re"); if (!fp) return false; @@ -103,12 +131,13 @@ static void adb_disconnected(void* unused, atransport* t) { LOG(INFO) << "ADB disconnect"; adb_transport = nullptr; needs_retry = false; - if (framework_fd >= 0) { - const char msg[] = "DC"; - LOG(DEBUG) << "Sending '" << msg << "'"; - if (!WriteFdExactly(framework_fd, msg, sizeof(msg))) { - PLOG(ERROR) << "Failed to send disconnected message"; + { + std::lock_guard lock(framework_mutex); + if (framework_fd >= 0) { + adbd_send_key_message_locked("DC", t->auth_key); } + connected_keys.erase(std::remove(connected_keys.begin(), connected_keys.end(), t->auth_key), + connected_keys.end()); } } @@ -116,7 +145,10 @@ static void framework_disconnected() { LOG(INFO) << "Framework disconnect"; if (framework_fde) { fdevent_destroy(framework_fde); - framework_fd = -1; + { + std::lock_guard lock(framework_mutex); + framework_fd = -1; + } } } @@ -134,34 +166,21 @@ static void adbd_auth_event(int fd, unsigned events, void*) { } } -void adbd_auth_confirm_key(const char* key, size_t len, atransport* t) { +void adbd_auth_confirm_key(atransport* t) { if (!adb_transport) { adb_transport = t; t->AddDisconnect(&adb_disconnect); } - if (framework_fd < 0) { - LOG(ERROR) << "Client not connected"; - needs_retry = true; - return; - } + { + std::lock_guard lock(framework_mutex); + if (framework_fd < 0) { + LOG(ERROR) << "Client not connected"; + needs_retry = true; + return; + } - if (key[len - 1] != '\0') { - LOG(ERROR) << "Key must be a null-terminated string"; - return; - } - - char msg[MAX_PAYLOAD_V1]; - int msg_len = snprintf(msg, sizeof(msg), "PK%s", key); - if (msg_len >= static_cast(sizeof(msg))) { - LOG(ERROR) << "Key too long (" << msg_len << ")"; - return; - } - LOG(DEBUG) << "Sending '" << msg << "'"; - - if (!WriteFdExactly(framework_fd, msg, msg_len)) { - PLOG(ERROR) << "Failed to write PK"; - return; + adbd_send_key_message_locked("PK", t->auth_key); } } @@ -172,18 +191,46 @@ static void adbd_auth_listener(int fd, unsigned events, void* data) { return; } - if (framework_fd >= 0) { - LOG(WARNING) << "adb received framework auth socket connection again"; - framework_disconnected(); + { + std::lock_guard lock(framework_mutex); + if (framework_fd >= 0) { + LOG(WARNING) << "adb received framework auth socket connection again"; + framework_disconnected(); + } + + framework_fd = s; + framework_fde = fdevent_create(framework_fd, adbd_auth_event, nullptr); + fdevent_add(framework_fde, FDE_READ); + + if (needs_retry) { + needs_retry = false; + send_auth_request(adb_transport); + } + + // if a client connected before the framework was available notify the framework of the + // connected key now. + if (!connected_keys.empty()) { + for (const auto& key : connected_keys) { + adbd_send_key_message_locked("CK", key); + } + } } +} - framework_fd = s; - framework_fde = fdevent_create(framework_fd, adbd_auth_event, nullptr); - fdevent_add(framework_fde, FDE_READ); - - if (needs_retry) { - needs_retry = false; - send_auth_request(adb_transport); +void adbd_notify_framework_connected_key(atransport* t) { + if (!adb_transport) { + adb_transport = t; + t->AddDisconnect(&adb_disconnect); + } + { + std::lock_guard lock(framework_mutex); + if (std::find(connected_keys.begin(), connected_keys.end(), t->auth_key) == + connected_keys.end()) { + connected_keys.push_back(t->auth_key); + } + if (framework_fd >= 0) { + adbd_send_key_message_locked("CK", t->auth_key); + } } } diff --git a/adb/transport.h b/adb/transport.h index f4490eded..3473ca2c4 100644 --- a/adb/transport.h +++ b/adb/transport.h @@ -274,6 +274,9 @@ class atransport { std::string device; std::string devpath; + // Used to provide the key to the framework. + std::string auth_key; + bool IsTcpDevice() const { return type == kTransportLocal; } #if ADB_HOST diff --git a/rootdir/init.usb.rc b/rootdir/init.usb.rc index f0681d2c2..b6cba901e 100644 --- a/rootdir/init.usb.rc +++ b/rootdir/init.usb.rc @@ -14,7 +14,7 @@ on post-fs-data # adbd is controlled via property triggers in init..usb.rc service adbd /system/bin/adbd --root_seclabel=u:r:su:s0 class core - socket adbd stream 660 system system + socket adbd seqpacket 660 system system disabled seclabel u:r:adbd:s0 From b80fe7a48dc14c59eefbe3eb8f54d777c1d4f54c Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Thu, 9 May 2019 12:48:17 -0700 Subject: [PATCH 170/221] crash_dump: populate uid field. Bug: http://b/132359035 Test: manual Change-Id: I99d8446024fc2d9395132dea45f03317976a9b62 (cherry picked from commit 5df504c5f8f6871f7ec79d735490176ba5179d2a) --- debuggerd/crash_dump.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/debuggerd/crash_dump.cpp b/debuggerd/crash_dump.cpp index c608a8c33..cb55745f1 100644 --- a/debuggerd/crash_dump.cpp +++ b/debuggerd/crash_dump.cpp @@ -463,6 +463,7 @@ int main(int argc, char** argv) { ThreadInfo info; info.pid = target_process; info.tid = thread; + info.uid = getuid(); info.process_name = process_name; info.thread_name = get_thread_name(thread); From b3462c123cd46f876652279915393c5a9a91590a Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Fri, 10 May 2019 10:39:54 +0200 Subject: [PATCH 171/221] Fix bug that would prevent us from reserving right amount of space. Bug: 132403230 Test: inspect dmesg output: [ 10.762678] init: [libfs_mgr]Setting reserved block count on /dev/block/dm-2 to 32768 [ 10.782652] tune2fs: Setting reserved blocks gid to 1065\x0a [ 10.782655] tune2fs: Setting reserved blocks count to 32768\x0a Change-Id: Id366d478bdd8a748bb1ba97d08a3b52e3cdd1efb --- fs_mgr/fs_mgr.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index c1aafdac9..3ea479e79 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -390,7 +390,7 @@ static void tune_quota(const std::string& blk_device, const FstabEntry& entry, // Set the number of reserved filesystem blocks if needed. static void tune_reserved_size(const std::string& blk_device, const FstabEntry& entry, const struct ext4_super_block* sb, int* fs_stat) { - if (entry.reserved_size != 0) { + if (entry.reserved_size == 0) { return; } From 9a8b9e01638df61061f7eabd0db93407ff0f549a Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 6 May 2019 16:59:41 -0700 Subject: [PATCH 172/221] Add a liblp test that we can parse the device's super partition. Bug: 132112489 Test: liblp_test gtest Change-Id: I1c0950dc30f42cd232e0616191d1365cdfc6512d Merged-In: I1c0950dc30f42cd232e0616191d1365cdfc6512d --- fs_mgr/liblp/io_test.cpp | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/fs_mgr/liblp/io_test.cpp b/fs_mgr/liblp/io_test.cpp index 8fc02cbde..fcef1f0d0 100644 --- a/fs_mgr/liblp/io_test.cpp +++ b/fs_mgr/liblp/io_test.cpp @@ -21,6 +21,8 @@ #include #include +#include +#include #include #include @@ -702,3 +704,19 @@ TEST(liblp, UpdateNonRetrofit) { ASSERT_EQ(updated->block_devices.size(), static_cast(1)); EXPECT_EQ(GetBlockDevicePartitionName(updated->block_devices[0]), "super"); } + +TEST(liblp, ReadSuperPartition) { + auto slot_suffix = fs_mgr_get_slot_suffix(); + auto slot_number = SlotNumberForSlotSuffix(slot_suffix); + auto super_name = fs_mgr_get_super_partition_name(slot_number); + auto metadata = ReadMetadata(super_name, slot_number); + ASSERT_NE(metadata, nullptr); + + if (!slot_suffix.empty()) { + auto other_slot_suffix = fs_mgr_get_other_slot_suffix(); + auto other_slot_number = SlotNumberForSlotSuffix(other_slot_suffix); + auto other_super_name = fs_mgr_get_super_partition_name(other_slot_number); + auto other_metadata = ReadMetadata(other_super_name, other_slot_number); + ASSERT_NE(other_metadata, nullptr); + } +} From 8471f92a2032e36f463d7df62c16668cb8086fca Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Mon, 13 May 2019 09:14:55 -0700 Subject: [PATCH 173/221] fs_mgr: overlayfs: ReadFstabFromFile touches errno (cherry picked from commit 98a0128e44baf60b630d39221de580716a98aa7f) Regression from commit 77c28476f19c910a869af878c8983d52e53c07b ("Remove the mount points defined in skip_mount.cfg from ReadDefaultFstab()") resulted in ReadFstabFromFile to report errno ENOENT even upon success, preventing clear error propagation for real failures (ReadFstabFromFile would _always_ report ENOENT). The bad error propagation resulted in an adb remount failure. Added immunization against future adjustments that may also result in a similar regression in adb remount behaviors. Test: adb-remount-test.sh Bug: 132594161 Bug: 128961335 Change-Id: Icf5d48bbfc6d938d4b9657ca8004a6a6ddaab5a6 --- fs_mgr/fs_mgr_fstab.cpp | 2 ++ fs_mgr/fs_mgr_overlayfs.cpp | 8 +++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index da049efa5..e7c175f7f 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -704,7 +704,9 @@ bool SkipMountingPartitions(Fstab* fstab) { constexpr const char kSkipMountConfig[] = "/system/etc/init/config/skip_mount.cfg"; std::string skip_config; + auto save_errno = errno; if (!ReadFileToString(kSkipMountConfig, &skip_config)) { + errno = save_errno; // missing file is expected return true; } diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 8a6df7d07..c252ab523 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -139,7 +139,11 @@ bool fs_mgr_filesystem_has_space(const std::string& mount_point) { // If we have access issues to find out space remaining, return true // to prevent us trying to override with overlayfs. struct statvfs vst; - if (statvfs(mount_point.c_str(), &vst)) return true; + auto save_errno = errno; + if (statvfs(mount_point.c_str(), &vst)) { + errno = save_errno; + return true; + } static constexpr int kPercentThreshold = 1; // 1% @@ -265,9 +269,11 @@ bool fs_mgr_rw_access(const std::string& path) { bool fs_mgr_overlayfs_already_mounted(const std::string& mount_point, bool overlay_only = true) { Fstab fstab; + auto save_errno = errno; if (!ReadFstabFromFile("/proc/mounts", &fstab)) { return false; } + errno = save_errno; const auto lowerdir = kLowerdirOption + mount_point; for (const auto& entry : fstab) { if (overlay_only && "overlay" != entry.fs_type && "overlayfs" != entry.fs_type) continue; From 1f7ae9d4e38096180c56a4fcc04759f10f117b2d Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Fri, 10 May 2019 11:37:34 -0700 Subject: [PATCH 174/221] adbd: don't abort on EOF on functionfs control fd. Also, improve the logging in the cases where we do abort. Bug: http://b/131867920 Test: treehugger Change-Id: If8ec9f4614ce146e6dbd21cc77587ea81658199b (cherry picked from commit 2916e148d9c333be253533968f407b73ebc017c2) --- adb/daemon/usb.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp index 3b29ab5fc..0fc4512c0 100644 --- a/adb/daemon/usb.cpp +++ b/adb/daemon/usb.cpp @@ -295,9 +295,15 @@ struct UsbFfsConnection : public Connection { } struct usb_functionfs_event event; - if (TEMP_FAILURE_RETRY(adb_read(control_fd_.get(), &event, sizeof(event))) != - sizeof(event)) { + rc = TEMP_FAILURE_RETRY(adb_read(control_fd_.get(), &event, sizeof(event))); + if (rc == -1) { PLOG(FATAL) << "failed to read functionfs event"; + } else if (rc == 0) { + LOG(WARNING) << "hit EOF on functionfs control fd"; + break; + } else if (rc != sizeof(event)) { + LOG(FATAL) << "read functionfs event of unexpected size, expected " + << sizeof(event) << ", got " << rc; } LOG(INFO) << "USB event: " From 78e6b181acfeec2a1ecf04d5b4a80349d1902cd4 Mon Sep 17 00:00:00 2001 From: Jiyong Park Date: Wed, 15 May 2019 12:41:01 +0900 Subject: [PATCH 175/221] Add asan.permitted.paths for the media namespace Permitted paths were empty for ASAN builds with the media namespace. Bug: 131625115 Test: no dlopen failure on libflacextractor.so in aosp_cf_x86_pasan Change-Id: I90050fc54820ba68d64931412572f3b0954e6616 --- rootdir/etc/ld.config.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt index 91a437363..72aaa84c6 100644 --- a/rootdir/etc/ld.config.txt +++ b/rootdir/etc/ld.config.txt @@ -174,6 +174,7 @@ namespace.media.search.paths = /apex/com.android.media/${LIB} namespace.media.asan.search.paths = /apex/com.android.media/${LIB} namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors +namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES% @@ -616,6 +617,7 @@ namespace.media.search.paths = /apex/com.android.media/${LIB} namespace.media.asan.search.paths = /apex/com.android.media/${LIB} namespace.media.permitted.paths = /apex/com.android.media/${LIB}/extractors +namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES% From fbaffb5deb16262d0a271141aa40c62853781a3c Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Tue, 14 May 2019 15:47:39 -0700 Subject: [PATCH 176/221] Allow CreateResizeDeleteLP test case to run on non-A/B devices Test: fuzzy_fastboot --gtest_filter=*Logical* Bug: 117220134 Change-Id: Ic7c2b246b7c5646d3589f8f57eceb9ba5feeef2b Merged-In: Ic7c2b246b7c5646d3589f8f57eceb9ba5feeef2b (cherry picked from commit f81bd17179c039ee19cbc5e0b32dafd4c7032d63) --- fastboot/fuzzy_fastboot/main.cpp | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp index 7ffc7d57c..4b238e890 100644 --- a/fastboot/fuzzy_fastboot/main.cpp +++ b/fastboot/fuzzy_fastboot/main.cpp @@ -234,16 +234,29 @@ TEST_F(LogicalPartitionCompliance, FastbootRebootTest) { // Testing creation/resize/delete of logical partitions TEST_F(LogicalPartitionCompliance, CreateResizeDeleteLP) { ASSERT_TRUE(UserSpaceFastboot()); + std::string test_partition_name = "test_partition"; + std::string slot_count; + // Add suffix to test_partition_name if device is slotted. + EXPECT_EQ(fb->GetVar("slot-count", &slot_count), SUCCESS) << "getvar slot-count failed"; + int32_t num_slots = strtol(slot_count.c_str(), nullptr, 10); + if (num_slots > 0) { + std::string current_slot; + EXPECT_EQ(fb->GetVar("current-slot", ¤t_slot), SUCCESS) + << "getvar current-slot failed"; + std::string slot_suffix = "_" + current_slot; + test_partition_name += slot_suffix; + } + GTEST_LOG_(INFO) << "Testing 'fastboot create-logical-partition' command"; - EXPECT_EQ(fb->CreatePartition("test_partition_a", "0"), SUCCESS) + EXPECT_EQ(fb->CreatePartition(test_partition_name, "0"), SUCCESS) << "create-logical-partition failed"; GTEST_LOG_(INFO) << "Testing 'fastboot resize-logical-partition' command"; - EXPECT_EQ(fb->ResizePartition("test_partition_a", "4096"), SUCCESS) + EXPECT_EQ(fb->ResizePartition(test_partition_name, "4096"), SUCCESS) << "resize-logical-partition failed"; std::vector buf(4096); GTEST_LOG_(INFO) << "Flashing a logical partition.."; - EXPECT_EQ(fb->FlashPartition("test_partition_a", buf), SUCCESS) + EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), SUCCESS) << "flash logical -partition failed"; GTEST_LOG_(INFO) << "Rebooting to bootloader mode"; // Reboot to bootloader mode and attempt to flash the logical partitions @@ -252,7 +265,7 @@ TEST_F(LogicalPartitionCompliance, CreateResizeDeleteLP) { ReconnectFastbootDevice(); ASSERT_FALSE(UserSpaceFastboot()); GTEST_LOG_(INFO) << "Attempt to flash a logical partition.."; - EXPECT_EQ(fb->FlashPartition("test_partition", buf), DEVICE_FAIL) + EXPECT_EQ(fb->FlashPartition(test_partition_name, buf), DEVICE_FAIL) << "flash logical partition must fail in bootloader"; GTEST_LOG_(INFO) << "Rebooting back to fastbootd mode"; fb->RebootTo("fastboot"); @@ -260,7 +273,7 @@ TEST_F(LogicalPartitionCompliance, CreateResizeDeleteLP) { ReconnectFastbootDevice(); ASSERT_TRUE(UserSpaceFastboot()); GTEST_LOG_(INFO) << "Testing 'fastboot delete-logical-partition' command"; - EXPECT_EQ(fb->DeletePartition("test_partition_a"), SUCCESS) + EXPECT_EQ(fb->DeletePartition(test_partition_name), SUCCESS) << "delete logical-partition failed"; } From ebce675b177f22a3248b1104b21c9c79937b8fda Mon Sep 17 00:00:00 2001 From: Martijn Coenen Date: Wed, 15 May 2019 22:04:13 +0200 Subject: [PATCH 177/221] class_start_post_data also starts disabled services. This keyword was introduced to support restarting services on devices using APEX and FDE. The current implementation is not a restart, but rather a 'reset' followed by a 'start', because the real /data must be mounted in-between those two actions. But we effectively want this to be a restart, which means that we also want to start 'disabled' services that were running at the time we called 'class_reset_post_data'. To implement this, keep track of whether a service was running when its class was reset at post-data, and start all those services. Bug: 132592548 Test: manual testing on FDE Taimen Change-Id: I1e81e2c8e0ab2782150073d74e50e4cd734af7b9 --- init/README.md | 3 ++- init/builtins.cpp | 25 +++++++++++++------------ init/service.cpp | 13 +++++++++++++ init/service.h | 3 +++ 4 files changed, 31 insertions(+), 13 deletions(-) diff --git a/init/README.md b/init/README.md index 929f0e413..1b8b84844 100644 --- a/init/README.md +++ b/init/README.md @@ -414,7 +414,8 @@ Commands `class_start_post_data ` > Like `class_start`, but only considers services that were started - after /data was mounted. Only used for FDE devices. + after /data was mounted, and that were running at the time + `class_reset_post_data` was called. Only used for FDE devices. `class_stop ` > Stop and disable all services of the specified class if they are diff --git a/init/builtins.cpp b/init/builtins.cpp index 34f229b7f..25f324ce5 100644 --- a/init/builtins.cpp +++ b/init/builtins.cpp @@ -104,35 +104,36 @@ static void ForEachServiceInClass(const std::string& classname, F function) { } } -static Result class_start(const std::string& class_name, bool post_data_only) { +static Result do_class_start(const BuiltinArguments& args) { // Do not start a class if it has a property persist.dont_start_class.CLASS set to 1. - if (android::base::GetBoolProperty("persist.init.dont_start_class." + class_name, false)) + if (android::base::GetBoolProperty("persist.init.dont_start_class." + args[1], false)) return Success(); // Starting a class does not start services which are explicitly disabled. // They must be started individually. for (const auto& service : ServiceList::GetInstance()) { - if (service->classnames().count(class_name)) { - if (post_data_only && !service->is_post_data()) { - continue; - } + if (service->classnames().count(args[1])) { if (auto result = service->StartIfNotDisabled(); !result) { LOG(ERROR) << "Could not start service '" << service->name() - << "' as part of class '" << class_name << "': " << result.error(); + << "' as part of class '" << args[1] << "': " << result.error(); } } } return Success(); } -static Result do_class_start(const BuiltinArguments& args) { - return class_start(args[1], false /* post_data_only */); -} - static Result do_class_start_post_data(const BuiltinArguments& args) { if (args.context != kInitContext) { return Error() << "command 'class_start_post_data' only available in init context"; } - return class_start(args[1], true /* post_data_only */); + for (const auto& service : ServiceList::GetInstance()) { + if (service->classnames().count(args[1])) { + if (auto result = service->StartIfPostData(); !result) { + LOG(ERROR) << "Could not start service '" << service->name() + << "' as part of class '" << args[1] << "': " << result.error(); + } + } + } + return Success(); } static Result do_class_stop(const BuiltinArguments& args) { diff --git a/init/service.cpp b/init/service.cpp index 2f9668107..ccc37b70c 100644 --- a/init/service.cpp +++ b/init/service.cpp @@ -1154,10 +1154,23 @@ void Service::Reset() { void Service::ResetIfPostData() { if (post_data_) { + if (flags_ & SVC_RUNNING) { + running_at_post_data_reset_ = true; + } StopOrReset(SVC_RESET); } } +Result Service::StartIfPostData() { + // Start the service, but only if it was started after /data was mounted, + // and it was still running when we reset the post-data services. + if (running_at_post_data_reset_) { + return Start(); + } + + return Success(); +} + void Service::Stop() { StopOrReset(SVC_DISABLED); } diff --git a/init/service.h b/init/service.h index dc2b12883..ae29f28c3 100644 --- a/init/service.h +++ b/init/service.h @@ -79,6 +79,7 @@ class Service { Result ExecStart(); Result Start(); Result StartIfNotDisabled(); + Result StartIfPostData(); Result Enable(); void Reset(); void ResetIfPostData(); @@ -248,6 +249,8 @@ class Service { bool pre_apexd_ = false; bool post_data_ = false; + + bool running_at_post_data_reset_ = false; }; class ServiceList { From 9da358d6d3d8b12e27b45c1581d0c2ad978f1f83 Mon Sep 17 00:00:00 2001 From: Evgenii Stepanov Date: Wed, 15 May 2019 18:45:01 -0700 Subject: [PATCH 178/221] Initialize all fields of struct iocb. Kernel does not accept non-zero value of iocb->aio_reserved2. Bug: 132803232 Test: initialize malloc() memory to non-zero pattern and see what breaks Change-Id: I65a7e89e3a2c1ba79df1dc2d011d6c76c41afb81 (cherry picked from commit fe7eca7b8fba6770ad36cadb4d89c87385f17451) --- adb/daemon/usb.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp index 0fc4512c0..565a3647e 100644 --- a/adb/daemon/usb.cpp +++ b/adb/daemon/usb.cpp @@ -117,7 +117,7 @@ struct TransferId { struct IoBlock { bool pending = false; - struct iocb control; + struct iocb control = {}; std::shared_ptr payload; TransferId id() const { return TransferId::from_value(control.aio_data); } From fd285d2b70537fd3ef239ae3843c30ccf07ac161 Mon Sep 17 00:00:00 2001 From: Suren Baghdasaryan Date: Wed, 8 May 2019 17:59:55 -0700 Subject: [PATCH 179/221] libprocessgroup: add flags to indicate when a controller failed to mount Controllers listed in cgroups.json file might fail to mount if kernel is not configured to support them. We need a way to indicate whether a controller was successfully mounted and is usable to avoid logging errors and warnings when a controller that failed to mount is being used. Add flags bitmask to cgrouprc controller descriptor and use a bit to indicate that controller is successfully mounted. Modify cpusets_enabled() and schedboost_enabled() functions to use this bit and report the actual availability of the controller. Bug: 124080437 Test: libcutils_test with cpuset and schedtune controllers disabled Change-Id: I770cc39fe50465146e3205aacf77dc3c56923c5d Signed-off-by: Suren Baghdasaryan --- libprocessgroup/cgroup_map.cpp | 8 ++++++++ libprocessgroup/cgroup_map.h | 1 + libprocessgroup/cgrouprc/Android.bp | 6 +++--- .../cgrouprc/cgroup_controller.cpp | 5 +++++ .../cgrouprc/include/android/cgrouprc.h | 12 +++++++++++ ...cgrouprc.map.txt => libcgrouprc.llndk.txt} | 1 + .../cgrouprc_format/cgroup_controller.cpp | 19 ++++++++++++++++-- .../processgroup/format/cgroup_controller.h | 9 +++++++-- libprocessgroup/processgroup.cpp | 3 +-- libprocessgroup/sched_policy.cpp | 6 +++--- libprocessgroup/setup/cgroup_descriptor.h | 2 ++ libprocessgroup/setup/cgroup_map_write.cpp | 20 +++++++++++++++---- 12 files changed, 76 insertions(+), 16 deletions(-) rename libprocessgroup/cgrouprc/{libcgrouprc.map.txt => libcgrouprc.llndk.txt} (88%) diff --git a/libprocessgroup/cgroup_map.cpp b/libprocessgroup/cgroup_map.cpp index 6cd6b6e50..92fcd1e71 100644 --- a/libprocessgroup/cgroup_map.cpp +++ b/libprocessgroup/cgroup_map.cpp @@ -67,6 +67,13 @@ bool CgroupController::HasValue() const { return controller_ != nullptr; } +bool CgroupController::IsUsable() const { + if (!HasValue()) return false; + + uint32_t flags = ACgroupController_getFlags(controller_); + return (flags & CGROUPRC_CONTROLLER_FLAG_MOUNTED) != 0; +} + std::string CgroupController::GetTasksFilePath(const std::string& rel_path) const { std::string tasks_path = path(); @@ -153,6 +160,7 @@ void CgroupMap::Print() const { const ACgroupController* controller = ACgroupFile_getController(i); LOG(INFO) << "\t" << ACgroupController_getName(controller) << " ver " << ACgroupController_getVersion(controller) << " path " + << ACgroupController_getFlags(controller) << " flags " << ACgroupController_getPath(controller); } } diff --git a/libprocessgroup/cgroup_map.h b/libprocessgroup/cgroup_map.h index d765e600c..935041242 100644 --- a/libprocessgroup/cgroup_map.h +++ b/libprocessgroup/cgroup_map.h @@ -38,6 +38,7 @@ class CgroupController { const char* path() const; bool HasValue() const; + bool IsUsable() const; std::string GetTasksFilePath(const std::string& path) const; std::string GetProcsFilePath(const std::string& path, uid_t uid, pid_t pid) const; diff --git a/libprocessgroup/cgrouprc/Android.bp b/libprocessgroup/cgrouprc/Android.bp index 6848620f9..9d5afebd3 100644 --- a/libprocessgroup/cgrouprc/Android.bp +++ b/libprocessgroup/cgrouprc/Android.bp @@ -42,19 +42,19 @@ cc_library { "libcgrouprc_format", ], stubs: { - symbol_file: "libcgrouprc.map.txt", + symbol_file: "libcgrouprc.llndk.txt", versions: ["29"], }, target: { linux: { - version_script: "libcgrouprc.map.txt", + version_script: "libcgrouprc.llndk.txt", }, }, } llndk_library { name: "libcgrouprc", - symbol_file: "libcgrouprc.map.txt", + symbol_file: "libcgrouprc.llndk.txt", export_include_dirs: [ "include", ], diff --git a/libprocessgroup/cgrouprc/cgroup_controller.cpp b/libprocessgroup/cgrouprc/cgroup_controller.cpp index d064d312e..5a326e55d 100644 --- a/libprocessgroup/cgrouprc/cgroup_controller.cpp +++ b/libprocessgroup/cgrouprc/cgroup_controller.cpp @@ -27,6 +27,11 @@ uint32_t ACgroupController_getVersion(const ACgroupController* controller) { return controller->version(); } +uint32_t ACgroupController_getFlags(const ACgroupController* controller) { + CHECK(controller != nullptr); + return controller->flags(); +} + const char* ACgroupController_getName(const ACgroupController* controller) { CHECK(controller != nullptr); return controller->name(); diff --git a/libprocessgroup/cgrouprc/include/android/cgrouprc.h b/libprocessgroup/cgrouprc/include/android/cgrouprc.h index 4edd239e2..ffc9f0b60 100644 --- a/libprocessgroup/cgrouprc/include/android/cgrouprc.h +++ b/libprocessgroup/cgrouprc/include/android/cgrouprc.h @@ -65,6 +65,18 @@ __attribute__((warn_unused_result)) const ACgroupController* ACgroupFile_getCont __attribute__((warn_unused_result)) uint32_t ACgroupController_getVersion(const ACgroupController*) __INTRODUCED_IN(29); +/** + * Flag bitmask used in ACgroupController_getFlags + */ +#define CGROUPRC_CONTROLLER_FLAG_MOUNTED 0x1 + +/** + * Returns the flags bitmask of the given controller. + * If the given controller is null, return 0. + */ +__attribute__((warn_unused_result)) uint32_t ACgroupController_getFlags(const ACgroupController*) + __INTRODUCED_IN(29); + /** * Returns the name of the given controller. * If the given controller is null, return nullptr. diff --git a/libprocessgroup/cgrouprc/libcgrouprc.map.txt b/libprocessgroup/cgrouprc/libcgrouprc.llndk.txt similarity index 88% rename from libprocessgroup/cgrouprc/libcgrouprc.map.txt rename to libprocessgroup/cgrouprc/libcgrouprc.llndk.txt index 91df3929d..ea3df33e6 100644 --- a/libprocessgroup/cgrouprc/libcgrouprc.map.txt +++ b/libprocessgroup/cgrouprc/libcgrouprc.llndk.txt @@ -4,6 +4,7 @@ LIBCGROUPRC { # introduced=29 ACgroupFile_getControllerCount; ACgroupFile_getController; ACgroupController_getVersion; + ACgroupController_getFlags; ACgroupController_getName; ACgroupController_getPath; local: diff --git a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp index 877eed872..202b23eed 100644 --- a/libprocessgroup/cgrouprc_format/cgroup_controller.cpp +++ b/libprocessgroup/cgrouprc_format/cgroup_controller.cpp @@ -20,12 +20,19 @@ namespace android { namespace cgrouprc { namespace format { -CgroupController::CgroupController(uint32_t version, const std::string& name, - const std::string& path) { +CgroupController::CgroupController() : version_(0), flags_(0) { + memset(name_, 0, sizeof(name_)); + memset(path_, 0, sizeof(path_)); +} + +CgroupController::CgroupController(uint32_t version, uint32_t flags, const std::string& name, + const std::string& path) + : CgroupController() { // strlcpy isn't available on host. Although there is an implementation // in licutils, libcutils itself depends on libcgrouprc_format, causing // a circular dependency. version_ = version; + flags_ = flags; strncpy(name_, name.c_str(), sizeof(name_) - 1); name_[sizeof(name_) - 1] = '\0'; strncpy(path_, path.c_str(), sizeof(path_) - 1); @@ -36,6 +43,10 @@ uint32_t CgroupController::version() const { return version_; } +uint32_t CgroupController::flags() const { + return flags_; +} + const char* CgroupController::name() const { return name_; } @@ -44,6 +55,10 @@ const char* CgroupController::path() const { return path_; } +void CgroupController::set_flags(uint32_t flags) { + flags_ = flags; +} + } // namespace format } // namespace cgrouprc } // namespace android diff --git a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h index 64c7532d9..40d85480b 100644 --- a/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h +++ b/libprocessgroup/cgrouprc_format/include/processgroup/format/cgroup_controller.h @@ -26,18 +26,23 @@ namespace format { // Minimal controller description to be mmapped into process address space struct CgroupController { public: - CgroupController() {} - CgroupController(uint32_t version, const std::string& name, const std::string& path); + CgroupController(); + CgroupController(uint32_t version, uint32_t flags, const std::string& name, + const std::string& path); uint32_t version() const; + uint32_t flags() const; const char* name() const; const char* path() const; + void set_flags(uint32_t flags); + private: static constexpr size_t CGROUP_NAME_BUF_SZ = 16; static constexpr size_t CGROUP_PATH_BUF_SZ = 32; uint32_t version_; + uint32_t flags_; char name_[CGROUP_NAME_BUF_SZ]; char path_[CGROUP_PATH_BUF_SZ]; }; diff --git a/libprocessgroup/processgroup.cpp b/libprocessgroup/processgroup.cpp index 1485ae986..d3ac26bd1 100644 --- a/libprocessgroup/processgroup.cpp +++ b/libprocessgroup/processgroup.cpp @@ -106,8 +106,7 @@ bool UsePerAppMemcg() { } static bool isMemoryCgroupSupported() { - std::string cgroup_name; - static bool memcg_supported = CgroupMap::GetInstance().FindController("memory").HasValue(); + static bool memcg_supported = CgroupMap::GetInstance().FindController("memory").IsUsable(); return memcg_supported; } diff --git a/libprocessgroup/sched_policy.cpp b/libprocessgroup/sched_policy.cpp index fe4f93b1e..15f8139b1 100644 --- a/libprocessgroup/sched_policy.cpp +++ b/libprocessgroup/sched_policy.cpp @@ -151,19 +151,19 @@ int set_sched_policy(int tid, SchedPolicy policy) { } bool cpusets_enabled() { - static bool enabled = (CgroupMap::GetInstance().FindController("cpuset").HasValue()); + static bool enabled = (CgroupMap::GetInstance().FindController("cpuset").IsUsable()); return enabled; } bool schedboost_enabled() { - static bool enabled = (CgroupMap::GetInstance().FindController("schedtune").HasValue()); + static bool enabled = (CgroupMap::GetInstance().FindController("schedtune").IsUsable()); return enabled; } static int getCGroupSubsys(int tid, const char* subsys, std::string& subgroup) { auto controller = CgroupMap::GetInstance().FindController(subsys); - if (!controller.HasValue()) return -1; + if (!controller.IsUsable()) return -1; if (!controller.GetTaskGroup(tid, &subgroup)) { LOG(ERROR) << "Failed to find cgroup for tid " << tid; diff --git a/libprocessgroup/setup/cgroup_descriptor.h b/libprocessgroup/setup/cgroup_descriptor.h index 597060e35..f029c4f12 100644 --- a/libprocessgroup/setup/cgroup_descriptor.h +++ b/libprocessgroup/setup/cgroup_descriptor.h @@ -32,6 +32,8 @@ class CgroupDescriptor { std::string uid() const { return uid_; } std::string gid() const { return gid_; } + void set_mounted(bool mounted); + private: format::CgroupController controller_; mode_t mode_ = 0; diff --git a/libprocessgroup/setup/cgroup_map_write.cpp b/libprocessgroup/setup/cgroup_map_write.cpp index da6094879..17ea06e09 100644 --- a/libprocessgroup/setup/cgroup_map_write.cpp +++ b/libprocessgroup/setup/cgroup_map_write.cpp @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -267,7 +268,17 @@ static bool WriteRcFile(const std::map& descripto CgroupDescriptor::CgroupDescriptor(uint32_t version, const std::string& name, const std::string& path, mode_t mode, const std::string& uid, const std::string& gid) - : controller_(version, name, path), mode_(mode), uid_(uid), gid_(gid) {} + : controller_(version, 0, name, path), mode_(mode), uid_(uid), gid_(gid) {} + +void CgroupDescriptor::set_mounted(bool mounted) { + uint32_t flags = controller_.flags(); + if (mounted) { + flags |= CGROUPRC_CONTROLLER_FLAG_MOUNTED; + } else { + flags &= ~CGROUPRC_CONTROLLER_FLAG_MOUNTED; + } + controller_.set_flags(flags); +} } // namespace cgrouprc } // namespace android @@ -296,10 +307,11 @@ bool CgroupSetup() { } // setup cgroups - for (const auto& [name, descriptor] : descriptors) { - if (!SetupCgroup(descriptor)) { + for (auto& [name, descriptor] : descriptors) { + if (SetupCgroup(descriptor)) { + descriptor.set_mounted(true); + } else { // issue a warning and proceed with the next cgroup - // TODO: mark the descriptor as invalid and skip it in WriteRcFile() LOG(WARNING) << "Failed to setup " << name << " cgroup"; } } From 12807c701240a42a2c3179b556a0a42bc0fc2de0 Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Wed, 15 May 2019 18:03:29 -0700 Subject: [PATCH 180/221] adbd: read, print, and ignore USB control transfers. It seems like we're blowing up when receiving a control transfer that's intended for Android Auto, because we're not expecting to get the data for the control transfer in a subsequent read. Bug: http://b/131867920 Test: none Change-Id: Icfd642e6dfc02d2ccbdd60c39f89e534298c944d --- adb/daemon/usb.cpp | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp index 565a3647e..da04db10b 100644 --- a/adb/daemon/usb.cpp +++ b/adb/daemon/usb.cpp @@ -364,6 +364,33 @@ struct UsbFfsConnection : public Connection { bound = false; running = false; break; + + case FUNCTIONFS_SETUP: { + LOG(INFO) << "received FUNCTIONFS_SETUP control transfer: bRequestType = " + << static_cast(event.u.setup.bRequestType) + << ", bRequest = " << static_cast(event.u.setup.bRequest) + << ", wValue = " << static_cast(event.u.setup.wValue) + << ", wIndex = " << static_cast(event.u.setup.wIndex) + << ", wLength = " << static_cast(event.u.setup.wLength); + + if ((event.u.setup.bRequestType & USB_DIR_IN)) { + LOG(WARNING) << "received a device-to-host control transfer, ignoring"; + } else { + std::string buf; + buf.resize(event.u.setup.wLength + 1); + + ssize_t rc = adb_read(control_fd_.get(), buf.data(), buf.size()); + if (rc != event.u.setup.wLength) { + LOG(ERROR) + << "read " << rc + << " bytes when trying to read control request, expected " + << event.u.setup.wLength; + } + + LOG(INFO) << "control request contents: " << buf; + break; + } + } } } From 32190f45e069d03fe2a5f8926a49dff80fb2d1c3 Mon Sep 17 00:00:00 2001 From: Victor Chang Date: Mon, 13 May 2019 16:14:03 +0100 Subject: [PATCH 181/221] Allow linking to libicuuc.so and libicui18n.so from executable in /data Executable in /data/ runs in default linker namespace, not classloader namespace. In Q, we moved libicuuc.so and libicui18n into the runtime namespace, and allow linking from runtime namespace and classloader namespace. This change further allows linking from default namespace, and tries to fix the regression temporarily. Bug: 130788466 Test: The app issue is fixed after this CL Merged-In: Ifae52b554124514e433cfe78875643a7450fbabd Change-Id: Ifae52b554124514e433cfe78875643a7450fbabd (cherry picked from commit 0c7edece9453db4f6c7be3058e64881b9805f94e) --- rootdir/etc/ld.config.legacy.txt | 3 +++ rootdir/etc/ld.config.txt | 9 +++++++++ rootdir/etc/ld.config.vndk_lite.txt | 9 +++++++++ 3 files changed, 21 insertions(+) diff --git a/rootdir/etc/ld.config.legacy.txt b/rootdir/etc/ld.config.legacy.txt index a5db3742c..5aac61bb9 100644 --- a/rootdir/etc/ld.config.legacy.txt +++ b/rootdir/etc/ld.config.legacy.txt @@ -58,6 +58,9 @@ namespace.default.link.runtime.shared_libs += libnativebridge.so namespace.default.link.runtime.shared_libs += libnativehelper.so namespace.default.link.runtime.shared_libs += libnativeloader.so namespace.default.link.runtime.shared_libs += libandroidicu.so +# libicuuc.so and libicui18n.so are kept for app compat reason. http://b/130788466 +namespace.default.link.runtime.shared_libs += libicui18n.so +namespace.default.link.runtime.shared_libs += libicuuc.so # TODO(b/122876336): Remove libpac.so once it's migrated to Webview namespace.default.link.runtime.shared_libs += libpac.so diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt index 91a437363..dc69920a8 100644 --- a/rootdir/etc/ld.config.txt +++ b/rootdir/etc/ld.config.txt @@ -133,6 +133,9 @@ namespace.default.links = runtime,resolv # libart. namespace.default.visible = true namespace.default.link.runtime.shared_libs = libdexfile_external.so +# libicuuc.so and libicui18n.so are kept for app compat reason. http://b/130788466 +namespace.default.link.runtime.shared_libs += libicui18n.so +namespace.default.link.runtime.shared_libs += libicuuc.so namespace.default.link.runtime.shared_libs += libnativebridge.so namespace.default.link.runtime.shared_libs += libnativehelper.so namespace.default.link.runtime.shared_libs += libnativeloader.so @@ -502,6 +505,9 @@ namespace.system.asan.search.paths += /%PRODUCT_SERVICES%/${LIB} namespace.system.links = runtime namespace.system.link.runtime.shared_libs = libdexfile_external.so +# libicuuc.so and libicui18n.so are kept for app compat reason. http://b/130788466 +namespace.system.link.runtime.shared_libs += libicui18n.so +namespace.system.link.runtime.shared_libs += libicuuc.so namespace.system.link.runtime.shared_libs += libnativebridge.so namespace.system.link.runtime.shared_libs += libnativehelper.so namespace.system.link.runtime.shared_libs += libnativeloader.so @@ -578,6 +584,9 @@ namespace.default.links = runtime,resolv namespace.default.visible = true namespace.default.link.runtime.shared_libs = libdexfile_external.so +# libicuuc.so and libicui18n.so are kept for app compat reason. http://b/130788466 +namespace.default.link.runtime.shared_libs += libicui18n.so +namespace.default.link.runtime.shared_libs += libicuuc.so namespace.default.link.runtime.shared_libs += libnativebridge.so namespace.default.link.runtime.shared_libs += libnativehelper.so namespace.default.link.runtime.shared_libs += libnativeloader.so diff --git a/rootdir/etc/ld.config.vndk_lite.txt b/rootdir/etc/ld.config.vndk_lite.txt index 11729eeb0..5db7698f4 100644 --- a/rootdir/etc/ld.config.vndk_lite.txt +++ b/rootdir/etc/ld.config.vndk_lite.txt @@ -74,6 +74,9 @@ namespace.default.links = runtime,resolv # libart. namespace.default.visible = true namespace.default.link.runtime.shared_libs = libdexfile_external.so +# libicuuc.so and libicui18n.so are kept for app compat reason. http://b/130788466 +namespace.default.link.runtime.shared_libs += libicui18n.so +namespace.default.link.runtime.shared_libs += libicuuc.so namespace.default.link.runtime.shared_libs += libnativebridge.so namespace.default.link.runtime.shared_libs += libnativehelper.so namespace.default.link.runtime.shared_libs += libnativeloader.so @@ -355,6 +358,9 @@ namespace.default.asan.search.paths += /system/${LIB}/vndk%VNDK_VER% namespace.default.links = runtime namespace.default.link.runtime.shared_libs = libdexfile_external.so +# libicuuc.so and libicui18n.so are kept for app compat reason. http://b/130788466 +namespace.default.link.runtime.shared_libs += libicui18n.so +namespace.default.link.runtime.shared_libs += libicuuc.so namespace.default.link.runtime.shared_libs += libnativebridge.so namespace.default.link.runtime.shared_libs += libnativehelper.so namespace.default.link.runtime.shared_libs += libnativeloader.so @@ -401,6 +407,9 @@ namespace.default.links = runtime,resolv namespace.default.visible = true namespace.default.link.runtime.shared_libs = libdexfile_external.so +# libicuuc.so and libicui18n.so are kept for app compat reason. http://b/130788466 +namespace.default.link.runtime.shared_libs += libicui18n.so +namespace.default.link.runtime.shared_libs += libicuuc.so namespace.default.link.runtime.shared_libs += libnativebridge.so namespace.default.link.runtime.shared_libs += libnativehelper.so namespace.default.link.runtime.shared_libs += libnativeloader.so From f929aaa7c045b91a4b50ca39fca90bb3d60f8662 Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Fri, 17 May 2019 14:24:19 -0700 Subject: [PATCH 182/221] Get max-download-size from device during fastbootd for flashall/update Currently, during a 'fastboot flashall/fastboot update', the 'getvar max-download-size' command is issued once to the device when it is in bootloader mode and the same value is used even after the device boots into fastbootd. If the max-download-size returned by bootloader is greater than the max-download-size in fastbootd, this could break flash as large images are broken down into chunks before downloading by using the max-download-size variable. This will cause fastbootd to return an error since it checks whether the buffer being downloaded has a size greater than the max-download-size limit. Test: fastboot flashall Bug: 132917902 Change-Id: Ife7c1ec0583d80d4a31ecf01f1fc14a8365afe0d Merged-In: Ife7c1ec0583d80d4a31ecf01f1fc14a8365afe0d (cherry picked from commit 83d856e4c59b6c02eeb7d468892b157a13f7cbf5) --- fastboot/fastboot.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 827db9671..e201186a5 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -1177,6 +1177,10 @@ static void reboot_to_userspace_fastboot() { if (!is_userspace_fastboot()) { die("Failed to boot into userspace fastboot; one or more components might be unbootable."); } + + // Reset target_sparse_limit after reboot to userspace fastboot. Max + // download sizes may differ in bootloader and fastbootd. + target_sparse_limit = -1; } class ImageSource { From af086e9a95cb52cdc7432c58e221ab86fafed87a Mon Sep 17 00:00:00 2001 From: Josh Gao Date: Tue, 21 May 2019 16:07:03 -0700 Subject: [PATCH 183/221] adbd: respond to device-to-host control transfers. Failing to write to the endpoint results in subsequent reads on ep0 to fail with EL2HLT, so do an empty write to fulfill the transfer. Bug: http://b/131867920 Test: manually tested with modified auto client Change-Id: If2eec162ca4b31a9974c7bd5802be51cee9e2708 --- adb/daemon/usb.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/adb/daemon/usb.cpp b/adb/daemon/usb.cpp index 806ed8cf8..1abae87c5 100644 --- a/adb/daemon/usb.cpp +++ b/adb/daemon/usb.cpp @@ -380,7 +380,12 @@ struct UsbFfsConnection : public Connection { << ", wLength = " << static_cast(event.u.setup.wLength); if ((event.u.setup.bRequestType & USB_DIR_IN)) { - LOG(WARNING) << "received a device-to-host control transfer, ignoring"; + LOG(INFO) << "acking device-to-host control transfer"; + ssize_t rc = adb_write(control_fd_.get(), "", 0); + if (rc != 0) { + PLOG(ERROR) << "failed to write empty packet to host"; + break; + } } else { std::string buf; buf.resize(event.u.setup.wLength + 1); From 3182ea132e917b197149fee74a7eeba5b6b5125d Mon Sep 17 00:00:00 2001 From: Bowgo Tsai Date: Fri, 17 May 2019 15:40:18 +0800 Subject: [PATCH 184/221] Moving /odm/build.prop to /odm/etc/buid.prop In device root directory, we have the following symlinks: - /odm/app -> /vendor/odm/app - /odm/bin -> /vendor/odm/bin - /odm/etc -> /vendor/odm/etc ... This allows the Generic System Image (GSI) to be used on both devices: 1) Has a physical odm partition, where those symlink will be hidden when /odm is used as the mount point 2) Has no physical odm partition and fallback to /vendor/odm/. We can't just have the symlink /odm -> /vendor/odm, because the former devices won't have /vendor/odm directory, which leads to mount failure when the mount point /odm is resolved to /vendor/odm. The existing /vendor/odm/build.prop won't be loaded in the latter devices, because there is no symlink - /odm/build.prop -> /vendor/odm/build.prop. Note that init blocks reading through direct symlinks (O_NOFOLLOW) so the above symlink won't work either. This CL moves the odm build.prop to /odm/etc/build.prop for init to load it (symlinks in earlier components of the path will still be followed by O_NOFOLLOW). Bug: 132128501 Test: boot a device and checks /odm/etc/build.prop is loaded Change-Id: I0733c277baa67c549bb45599abb70aba13fbdbcf Merged-In: I0733c277baa67c549bb45599abb70aba13fbdbcf (cherry picked from commit c49655b2a48eca2ab751b853a9a4692f322cafa2) --- init/property_service.cpp | 8 ++++++-- libcutils/fs_config.cpp | 5 +++-- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index bca73c950..fce8d578f 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -883,8 +883,12 @@ void property_load_boot_defaults(bool load_debug_prop) { load_properties_from_file("/system/build.prop", nullptr, &properties); load_properties_from_file("/vendor/default.prop", nullptr, &properties); load_properties_from_file("/vendor/build.prop", nullptr, &properties); - load_properties_from_file("/odm/default.prop", nullptr, &properties); - load_properties_from_file("/odm/build.prop", nullptr, &properties); + if (SelinuxGetVendorAndroidVersion() >= __ANDROID_API_Q__) { + load_properties_from_file("/odm/etc/build.prop", nullptr, &properties); + } else { + load_properties_from_file("/odm/default.prop", nullptr, &properties); + load_properties_from_file("/odm/build.prop", nullptr, &properties); + } load_properties_from_file("/product/build.prop", nullptr, &properties); load_properties_from_file("/product_services/build.prop", nullptr, &properties); load_properties_from_file("/factory/factory.prop", "ro.*", &properties); diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index 6217bc802..a5f4f0e55 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -159,8 +159,9 @@ static const struct fs_path_config android_files[] = { { 00750, AID_ROOT, AID_SHELL, 0, "data/nativetest64/*" }, { 00600, AID_ROOT, AID_ROOT, 0, "default.prop" }, // legacy { 00600, AID_ROOT, AID_ROOT, 0, "system/etc/prop.default" }, - { 00600, AID_ROOT, AID_ROOT, 0, "odm/build.prop" }, - { 00600, AID_ROOT, AID_ROOT, 0, "odm/default.prop" }, + { 00600, AID_ROOT, AID_ROOT, 0, "odm/build.prop" }, // legacy; only for P release + { 00600, AID_ROOT, AID_ROOT, 0, "odm/default.prop" }, // legacy; only for P release + { 00600, AID_ROOT, AID_ROOT, 0, "odm/etc/build.prop" }, { 00444, AID_ROOT, AID_ROOT, 0, odm_conf_dir + 1 }, { 00444, AID_ROOT, AID_ROOT, 0, odm_conf_file + 1 }, { 00444, AID_ROOT, AID_ROOT, 0, oem_conf_dir + 1 }, From 4472fdb4d010885c322ab85bdf9d24bd1469489c Mon Sep 17 00:00:00 2001 From: Hridya Valsaraju Date: Tue, 21 May 2019 13:03:24 -0700 Subject: [PATCH 185/221] fastbootd: reduce USB buffer size to 16K Some USB controllers can only support transfers upto 16K. Bug: 133208811 Test: fastboot flashall Change-Id: Ic025bdd8e7a6cf2634fc24524fd189e0cc9efbb5 Merged-In: Ic025bdd8e7a6cf2634fc24524fd189e0cc9efbb5 (cherry picked from commit d747dba9c0fd5bb81e4b616cfb562a10c64b9e54) --- fastboot/device/usb_client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp index fb51a900b..775d10c80 100644 --- a/fastboot/device/usb_client.cpp +++ b/fastboot/device/usb_client.cpp @@ -33,7 +33,7 @@ constexpr int kMaxPacketSizeHs = 512; constexpr int kMaxPacketsizeSs = 1024; constexpr size_t kFbFfsNumBufs = 16; -constexpr size_t kFbFfsBufSize = 32768; +constexpr size_t kFbFfsBufSize = 16384; constexpr const char* kUsbFfsFastbootEp0 = "/dev/usb-ffs/fastboot/ep0"; constexpr const char* kUsbFfsFastbootOut = "/dev/usb-ffs/fastboot/ep1"; From 699e342b3d77c4e2b7e856621e1ce1150859582f Mon Sep 17 00:00:00 2001 From: Wei Wang Date: Wed, 22 May 2019 09:46:02 -0700 Subject: [PATCH 186/221] Report non-empty system boot reason when bootloader reason is empty Bug: 133321647 Test: build Change-Id: Icd3ea4b69ef2ad040926e2b0e121a8f5f1c1b658 --- bootstat/bootstat.cpp | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/bootstat/bootstat.cpp b/bootstat/bootstat.cpp index 558e6c4b2..7b6052404 100644 --- a/bootstat/bootstat.cpp +++ b/bootstat/bootstat.cpp @@ -1086,17 +1086,8 @@ void RecordAbsoluteBootTime(BootEventRecordStore* boot_event_store, void LogBootInfoToStatsd(std::chrono::milliseconds end_time, std::chrono::milliseconds total_duration, int32_t bootloader_duration_ms, double time_since_last_boot_sec) { - const auto reason = android::base::GetProperty(bootloader_reboot_reason_property, ""); - - if (reason.empty()) { - android::util::stats_write(android::util::BOOT_SEQUENCE_REPORTED, "", "", - end_time.count(), total_duration.count(), - (int64_t)bootloader_duration_ms, - (int64_t)time_since_last_boot_sec * 1000); - return; - } - - const auto system_reason = android::base::GetProperty(system_reboot_reason_property, ""); + auto reason = android::base::GetProperty(bootloader_reboot_reason_property, ""); + auto system_reason = android::base::GetProperty(system_reboot_reason_property, ""); android::util::stats_write(android::util::BOOT_SEQUENCE_REPORTED, reason.c_str(), system_reason.c_str(), end_time.count(), total_duration.count(), (int64_t)bootloader_duration_ms, From c6ca823710d49754c3717e9cf3ba11b9c2648825 Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Fri, 17 May 2019 12:20:54 +0100 Subject: [PATCH 187/221] rootdir / sdcard : Stop creating /data/media/obb. This directory is no longer used. OBB content is placed in /data/media/$user/Android. Test: make Test: manually verify the path doesn't exist. Bug: 129167772 Change-Id: I8549826586b9a68c8cfa3fe2e51295363f9b4e11 --- rootdir/init.rc | 1 - sdcard/sdcard.cpp | 9 ++++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/rootdir/init.rc b/rootdir/init.rc index 1b7367c46..260199794 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -586,7 +586,6 @@ on post-fs-data symlink /data/data /data/user/0 mkdir /data/media 0770 media_rw media_rw - mkdir /data/media/obb 0770 media_rw media_rw mkdir /data/cache 0770 system cache mkdir /data/cache/recovery 0770 system cache diff --git a/sdcard/sdcard.cpp b/sdcard/sdcard.cpp index 2b358197a..0acea7266 100644 --- a/sdcard/sdcard.cpp +++ b/sdcard/sdcard.cpp @@ -214,7 +214,14 @@ static void run_sdcardfs(const std::string& source_path, const std::string& labe if (multi_user) { std::string obb_path = source_path + "/obb"; - fs_prepare_dir(obb_path.c_str(), 0775, uid, gid); + // Only attempt to prepare the /obb dir if it already exists. We want + // the legacy obb path "/data/media/obb" to be fixed up so that we can + // migrate it to its new location, but we don't want the directory to be + // created if it doesn't already exist. + struct stat sb; + if (TEMP_FAILURE_RETRY(lstat(obb_path.c_str(), &sb)) == 0) { + fs_prepare_dir(obb_path.c_str(), 0775, uid, gid); + } } exit(0); From d1531ac4e8dc8f57eddf06f1b4a9a93ca67a8ae0 Mon Sep 17 00:00:00 2001 From: Ryan Mitchell Date: Tue, 28 May 2019 15:42:14 -0700 Subject: [PATCH 188/221] Fix leak of mapped zip central directories Memory mapping the central directory of specific APKs caused memory mappings to build up over time because they were never unmapped correctly. This is because MappedFile is not calling munmap with the size of the data after aligning the mmap offset to a page boundary. Bug: 133463863 Test: install APKs and verify that the entire mapped CD is unmaped Test: ran aapt2 as daemon and confirmed that mapped CD is unmapped Change-Id: Icb6cfebe0e8d67160fee34c5e6423d0f05de526b --- base/mapped_file.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/base/mapped_file.cpp b/base/mapped_file.cpp index 7c65dc3c5..d26e8ba91 100644 --- a/base/mapped_file.cpp +++ b/base/mapped_file.cpp @@ -76,7 +76,7 @@ MappedFile::~MappedFile() { if (base_ != nullptr) UnmapViewOfFile(base_); if (handle_ != nullptr) CloseHandle(handle_); #else - if (base_ != nullptr) munmap(base_, size_); + if (base_ != nullptr) munmap(base_, size_ + offset_); #endif base_ = nullptr; From 5f8b966d960ff9cb403a167768c48c2aa4d76710 Mon Sep 17 00:00:00 2001 From: "chihhao.chen" Date: Mon, 20 May 2019 16:55:55 +0800 Subject: [PATCH 189/221] Fix non-aio USB read issue for fastbootd non-aio USB read function was stuck in a loop waiting for more data because data length parameter is always set 64 for fastbootd commands. It should be a normal case to get less data than expected since lengths of these commands are usually less than 64. Add logic to check this and one more parameter to distinguish fastbootd from general adbd case. Bug: 133189029 Test: try various fastbootd commands Change-Id: I6690324840d78f3f1e04235040301520329976db --- adb/daemon/include/adbd/usb.h | 2 +- adb/daemon/usb_legacy.cpp | 17 ++++++++++++++--- fastboot/device/usb_client.cpp | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/adb/daemon/include/adbd/usb.h b/adb/daemon/include/adbd/usb.h index 3213f6909..fca3c58e8 100644 --- a/adb/daemon/include/adbd/usb.h +++ b/adb/daemon/include/adbd/usb.h @@ -43,7 +43,7 @@ struct usb_handle { bool open_new_connection = true; int (*write)(usb_handle* h, const void* data, int len); - int (*read)(usb_handle* h, void* data, int len); + int (*read)(usb_handle* h, void* data, int len, bool allow_partial); void (*kick)(usb_handle* h); void (*close)(usb_handle* h); diff --git a/adb/daemon/usb_legacy.cpp b/adb/daemon/usb_legacy.cpp index b65727a0c..fe80e7d59 100644 --- a/adb/daemon/usb_legacy.cpp +++ b/adb/daemon/usb_legacy.cpp @@ -142,11 +142,12 @@ static int usb_ffs_write(usb_handle* h, const void* data, int len) { return orig_len; } -static int usb_ffs_read(usb_handle* h, void* data, int len) { +static int usb_ffs_read(usb_handle* h, void* data, int len, bool allow_partial) { D("about to read (fd=%d, len=%d)", h->bulk_out.get(), len); char* buf = static_cast(data); int orig_len = len; + unsigned count = 0; while (len > 0) { int read_len = std::min(USB_FFS_BULK_SIZE, len); int n = adb_read(h->bulk_out, buf, read_len); @@ -156,6 +157,16 @@ static int usb_ffs_read(usb_handle* h, void* data, int len) { } buf += n; len -= n; + count += n; + + // For fastbootd command such as "getvar all", len parameter is always set 64. + // But what we read is actually less than 64. + // For example, length 10 for "getvar all" command. + // If we get less data than expected, this means there should be no more data. + if (allow_partial && n < read_len) { + orig_len = count; + break; + } } D("[ done fd=%d ]", h->bulk_out.get()); @@ -221,7 +232,7 @@ static int usb_ffs_do_aio(usb_handle* h, const void* data, int len, bool read) { } } -static int usb_ffs_aio_read(usb_handle* h, void* data, int len) { +static int usb_ffs_aio_read(usb_handle* h, void* data, int len, bool allow_partial) { return usb_ffs_do_aio(h, data, len, true); } @@ -299,7 +310,7 @@ int usb_write(usb_handle* h, const void* data, int len) { } int usb_read(usb_handle* h, void* data, int len) { - return h->read(h, data, len); + return h->read(h, data, len, false /* allow_partial */); } int usb_close(usb_handle* h) { diff --git a/fastboot/device/usb_client.cpp b/fastboot/device/usb_client.cpp index fb51a900b..5921df958 100644 --- a/fastboot/device/usb_client.cpp +++ b/fastboot/device/usb_client.cpp @@ -255,7 +255,8 @@ ssize_t ClientUsbTransport::Read(void* data, size_t len) { size_t bytes_read_total = 0; while (bytes_read_total < len) { auto bytes_to_read = std::min(len - bytes_read_total, kFbFfsNumBufs * kFbFfsBufSize); - auto bytes_read_now = handle_->read(handle_.get(), char_data, bytes_to_read); + auto bytes_read_now = + handle_->read(handle_.get(), char_data, bytes_to_read, true /* allow_partial */); if (bytes_read_now < 0) { return bytes_read_total; } From 1fcd51255a8eb1bf2e114ab9fcda73ecc0ac05b4 Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Tue, 28 May 2019 10:19:44 -0700 Subject: [PATCH 190/221] init: dump stack when aborting Dump init stacks when aborting either due to LOG(FATAL) or in userdebug/eng builds due to signals, including signals from sanitizers. Doesn't work for static first stage init yet, b/133450393 tracks that. Also, ensure that LOG(FATAL) in child processes calls abort() in all stages of init, not just 2nd stage init. Bug: 131747478 Test: abort init in various ways and see stacks Test: hang or crash in backtrace handler and see child reboot Change-Id: Ib53b5d3e7e814244203f875de016ada9900dfce8 Merged-In: Ib53b5d3e7e814244203f875de016ada9900dfce8 (cherry picked from commit 59656fb37769b3c0de927c20f8e9f5855a0f7ac3) --- init/Android.bp | 1 + init/Android.mk | 4 ++++ init/first_stage_init.cpp | 8 ++----- init/host_init_stubs.h | 5 +++++ init/init.cpp | 16 ++------------ init/reboot_utils.cpp | 37 +++++++++++++++++++++++++++++--- init/reboot_utils.h | 1 + init/selinux.cpp | 5 +---- init/util.cpp | 44 ++++++++++++++++++++++++++++++++------- init/util.h | 3 ++- 10 files changed, 89 insertions(+), 35 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index 69498acba..6be7290e3 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -68,6 +68,7 @@ cc_defaults { "libpropertyinfoparser", ], shared_libs: [ + "libbacktrace", "libbase", "libbinder", "libbootloader_message", diff --git a/init/Android.mk b/init/Android.mk index b02c926da..c4f7d34b2 100644 --- a/init/Android.mk +++ b/init/Android.mk @@ -105,6 +105,10 @@ LOCAL_STATIC_LIBRARIES := \ libcap \ libgsi \ libcom.android.sysprop.apex \ + liblzma \ + libdexfile_support \ + libunwindstack \ + libbacktrace \ LOCAL_SANITIZE := signed-integer-overflow # First stage init is weird: it may start without stdout/stderr, and no /proc. diff --git a/init/first_stage_init.cpp b/init/first_stage_init.cpp index 8b95e3832..2b899408a 100644 --- a/init/first_stage_init.cpp +++ b/init/first_stage_init.cpp @@ -33,7 +33,6 @@ #include #include #include -#include #include #include "debug_ramdisk.h" @@ -168,13 +167,10 @@ int FirstStageMain(int argc, char** argv) { "mode=0755,uid=0,gid=0")); #undef CHECKCALL + SetStdioToDevNull(argv); // Now that tmpfs is mounted on /dev and we have /dev/kmsg, we can actually // talk to the outside world... - // We need to set up stdin/stdout/stderr for child processes forked from first - // stage init as part of the mount process. This closes /dev/console if the - // kernel had previously opened it. - auto reboot_bootloader = [](const char*) { RebootSystem(ANDROID_RB_RESTART2, "bootloader"); }; - InitKernelLogging(argv, reboot_bootloader); + InitKernelLogging(argv); if (!errors.empty()) { for (const auto& [error_string, error_errno] : errors) { diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h index 63ceead67..a711340fa 100644 --- a/init/host_init_stubs.h +++ b/init/host_init_stubs.h @@ -44,6 +44,11 @@ extern uint32_t (*property_set)(const std::string& name, const std::string& valu uint32_t HandlePropertySet(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr, std::string* error); +// reboot_utils.h +inline void __attribute__((noreturn)) InitFatalReboot() { + abort(); +} + // selinux.h int SelinuxGetVendorAndroidVersion(); void SelabelInitialize(); diff --git a/init/init.cpp b/init/init.cpp index c79e459eb..6b03bc94d 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -38,7 +38,6 @@ #include #include #include -#include #include #include #include @@ -601,17 +600,6 @@ void HandleKeychord(const std::vector& keycodes) { } } -static void InitAborter(const char* abort_message) { - // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to - // simply abort instead of trying to reboot the system. - if (getpid() != 1) { - android::base::DefaultAborter(abort_message); - return; - } - - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); -} - static void GlobalSeccomp() { import_kernel_cmdline(false, [](const std::string& key, const std::string& value, bool in_qemu) { @@ -632,8 +620,8 @@ int SecondStageMain(int argc, char** argv) { InstallRebootSignalHandlers(); } - // We need to set up stdin/stdout/stderr again now that we're running in init's context. - InitKernelLogging(argv, InitAborter); + SetStdioToDevNull(argv); + InitKernelLogging(argv); LOG(INFO) << "init second stage started!"; // Set init and its forked children's oom_adj. diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp index 961030409..4524f6983 100644 --- a/init/reboot_utils.cpp +++ b/init/reboot_utils.cpp @@ -19,8 +19,13 @@ #include #include -#include -#include +#include + +#include "android-base/file.h" +#include "android-base/logging.h" +#include "android-base/strings.h" +#include "backtrace/Backtrace.h" +#include "cutils/android_reboot.h" #include "capabilities.h" @@ -75,6 +80,32 @@ void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& abort(); } +void __attribute__((noreturn)) InitFatalReboot() { + auto pid = fork(); + + if (pid == -1) { + // Couldn't fork, don't even try to backtrace, just reboot. + RebootSystem(ANDROID_RB_RESTART2, "bootloader"); + } else if (pid == 0) { + // Fork a child for safety, since we always want to shut down if something goes wrong, but + // its worth trying to get the backtrace, even in the signal handler, since typically it + // does work despite not being async-signal-safe. + sleep(5); + RebootSystem(ANDROID_RB_RESTART2, "bootloader"); + } + + // In the parent, let's try to get a backtrace then shutdown. + std::unique_ptr backtrace( + Backtrace::Create(BACKTRACE_CURRENT_PROCESS, BACKTRACE_CURRENT_THREAD)); + if (!backtrace->Unwind(0)) { + LOG(ERROR) << __FUNCTION__ << ": Failed to unwind callstack."; + } + for (size_t i = 0; i < backtrace->NumFrames(); i++) { + LOG(ERROR) << backtrace->FormatFrameData(i); + } + RebootSystem(ANDROID_RB_RESTART2, "bootloader"); +} + void InstallRebootSignalHandlers() { // Instead of panic'ing the kernel as is the default behavior when init crashes, // we prefer to reboot to bootloader on development builds, as this will prevent @@ -94,7 +125,7 @@ void InstallRebootSignalHandlers() { // RebootSystem uses syscall() which isn't actually async-signal-safe, but our only option // and probably good enough given this is already an error case and only enabled for // development builds. - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); + InitFatalReboot(); }; action.sa_flags = SA_RESTART; sigaction(SIGABRT, &action, nullptr); diff --git a/init/reboot_utils.h b/init/reboot_utils.h index 073a16a68..c4d97d57b 100644 --- a/init/reboot_utils.h +++ b/init/reboot_utils.h @@ -26,6 +26,7 @@ namespace init { bool IsRebootCapable(); // This is a wrapper around the actual reboot calls. void __attribute__((noreturn)) RebootSystem(unsigned int cmd, const std::string& reboot_target); +void __attribute__((noreturn)) InitFatalReboot(); void InstallRebootSignalHandlers(); } // namespace init diff --git a/init/selinux.cpp b/init/selinux.cpp index 132fc137d..86238b430 100644 --- a/init/selinux.cpp +++ b/init/selinux.cpp @@ -60,7 +60,6 @@ #include #include #include -#include #include #include @@ -518,9 +517,7 @@ int SelinuxGetVendorAndroidVersion() { // This function initializes SELinux then execs init to run in the init SELinux context. int SetupSelinux(char** argv) { - android::base::InitLogging(argv, &android::base::KernelLogger, [](const char*) { - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); - }); + InitKernelLogging(argv); if (REBOOT_BOOTLOADER_ON_PANIC) { InstallRebootSignalHandlers(); diff --git a/init/util.cpp b/init/util.cpp index 29d7a7698..790ab927a 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -40,6 +40,7 @@ #include #if defined(__ANDROID__) +#include "reboot_utils.h" #include "selinux.h" #else #include "host_init_stubs.h" @@ -425,20 +426,49 @@ bool IsLegalPropertyName(const std::string& name) { return true; } -void InitKernelLogging(char** argv, std::function abort_function) { +static void InitAborter(const char* abort_message) { + // When init forks, it continues to use this aborter for LOG(FATAL), but we want children to + // simply abort instead of trying to reboot the system. + if (getpid() != 1) { + android::base::DefaultAborter(abort_message); + return; + } + + InitFatalReboot(); +} + +// The kernel opens /dev/console and uses that fd for stdin/stdout/stderr if there is a serial +// console enabled and no initramfs, otherwise it does not provide any fds for stdin/stdout/stderr. +// SetStdioToDevNull() is used to close these existing fds if they exist and replace them with +// /dev/null regardless. +// +// In the case that these fds are provided by the kernel, the exec of second stage init causes an +// SELinux denial as it does not have access to /dev/console. In the case that they are not +// provided, exec of any further process is potentially dangerous as the first fd's opened by that +// process will take the stdin/stdout/stderr fileno's, which can cause issues if printf(), etc is +// then used by that process. +// +// Lastly, simply calling SetStdioToDevNull() in first stage init is not enough, since first +// stage init still runs in kernel context, future child processes will not have permissions to +// access any fds that it opens, including the one opened below for /dev/null. Therefore, +// SetStdioToDevNull() must be called again in second stage init. +void SetStdioToDevNull(char** argv) { // Make stdin/stdout/stderr all point to /dev/null. int fd = open("/dev/null", O_RDWR); if (fd == -1) { int saved_errno = errno; - android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function)); + android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter); errno = saved_errno; PLOG(FATAL) << "Couldn't open /dev/null"; } - dup2(fd, 0); - dup2(fd, 1); - dup2(fd, 2); - if (fd > 2) close(fd); - android::base::InitLogging(argv, &android::base::KernelLogger, std::move(abort_function)); + dup2(fd, STDIN_FILENO); + dup2(fd, STDOUT_FILENO); + dup2(fd, STDERR_FILENO); + if (fd > STDERR_FILENO) close(fd); +} + +void InitKernelLogging(char** argv) { + android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter); } bool IsRecoveryMode() { diff --git a/init/util.h b/init/util.h index 2232a0f0b..767620b16 100644 --- a/init/util.h +++ b/init/util.h @@ -63,7 +63,8 @@ bool is_android_dt_value_expected(const std::string& sub_path, const std::string bool IsLegalPropertyName(const std::string& name); -void InitKernelLogging(char** argv, std::function abort_function); +void SetStdioToDevNull(char** argv); +void InitKernelLogging(char** argv); bool IsRecoveryMode(); } // namespace init } // namespace android From b80149d8bc5ec67fc1f22a1c248a4ff7d081f620 Mon Sep 17 00:00:00 2001 From: Tom Cherry Date: Tue, 21 May 2019 13:53:05 -0700 Subject: [PATCH 191/221] init: make fatal reboot target configurable Currently, if init encounters a fatal issues it reboots to fastboot but this may be not desirable in all cases, especially the case of critical services crashing. Therefore this change adds the ability for vendors to customize the reboot target via the androidboot.init_fatal_reboot_target= kernel command line. This applies to all LOG(FATAL) messages as well as fatal signals in userdebug/eng builds, except for signals before logging is enabled in first stage init. Bug: 121006328 Test: device reboots to configurable target with LOG(FATAL) Test: device reboots to configurable target after a segfault in the various stages of init Test: device reboots to fastboot without a configured target Change-Id: I16ea9e32e2fee08dece3d33b697d7a08191d607b Merged-In: I16ea9e32e2fee08dece3d33b697d7a08191d607b (cherry picked from commit 75e13baf32ae1a54a9e43b7d7d6bdcc6f8d545d7) --- init/host_init_stubs.h | 1 + init/reboot_utils.cpp | 27 ++++++++++++++++++++++++--- init/reboot_utils.h | 1 + init/util.cpp | 1 + 4 files changed, 27 insertions(+), 3 deletions(-) diff --git a/init/host_init_stubs.h b/init/host_init_stubs.h index a711340fa..f6e967653 100644 --- a/init/host_init_stubs.h +++ b/init/host_init_stubs.h @@ -45,6 +45,7 @@ uint32_t HandlePropertySet(const std::string& name, const std::string& value, const std::string& source_context, const ucred& cr, std::string* error); // reboot_utils.h +inline void SetFatalRebootTarget() {} inline void __attribute__((noreturn)) InitFatalReboot() { abort(); } diff --git a/init/reboot_utils.cpp b/init/reboot_utils.cpp index 4524f6983..d1a712f2e 100644 --- a/init/reboot_utils.cpp +++ b/init/reboot_utils.cpp @@ -32,6 +32,27 @@ namespace android { namespace init { +static std::string init_fatal_reboot_target = "bootloader"; + +void SetFatalRebootTarget() { + std::string cmdline; + android::base::ReadFileToString("/proc/cmdline", &cmdline); + cmdline = android::base::Trim(cmdline); + + const char kRebootTargetString[] = "androidboot.init_fatal_reboot_target="; + auto start_pos = cmdline.find(kRebootTargetString); + if (start_pos == std::string::npos) { + return; // We already default to bootloader if no setting is provided. + } + start_pos += sizeof(kRebootTargetString) - 1; + + auto end_pos = cmdline.find(' ', start_pos); + // if end_pos isn't found, then we've run off the end, but this is okay as this is the last + // entry, and -1 is a valid size for string::substr(); + auto size = end_pos == std::string::npos ? -1 : end_pos - start_pos; + init_fatal_reboot_target = cmdline.substr(start_pos, size); +} + bool IsRebootCapable() { if (!CAP_IS_SUPPORTED(CAP_SYS_BOOT)) { PLOG(WARNING) << "CAP_SYS_BOOT is not supported"; @@ -85,13 +106,13 @@ void __attribute__((noreturn)) InitFatalReboot() { if (pid == -1) { // Couldn't fork, don't even try to backtrace, just reboot. - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); + RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target); } else if (pid == 0) { // Fork a child for safety, since we always want to shut down if something goes wrong, but // its worth trying to get the backtrace, even in the signal handler, since typically it // does work despite not being async-signal-safe. sleep(5); - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); + RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target); } // In the parent, let's try to get a backtrace then shutdown. @@ -103,7 +124,7 @@ void __attribute__((noreturn)) InitFatalReboot() { for (size_t i = 0; i < backtrace->NumFrames(); i++) { LOG(ERROR) << backtrace->FormatFrameData(i); } - RebootSystem(ANDROID_RB_RESTART2, "bootloader"); + RebootSystem(ANDROID_RB_RESTART2, init_fatal_reboot_target); } void InstallRebootSignalHandlers() { diff --git a/init/reboot_utils.h b/init/reboot_utils.h index c4d97d57b..3fd969e69 100644 --- a/init/reboot_utils.h +++ b/init/reboot_utils.h @@ -21,6 +21,7 @@ namespace android { namespace init { +void SetFatalRebootTarget(); // Determines whether the system is capable of rebooting. This is conservative, // so if any of the attempts to determine this fail, it will still return true. bool IsRebootCapable(); diff --git a/init/util.cpp b/init/util.cpp index 790ab927a..63d2d4442 100644 --- a/init/util.cpp +++ b/init/util.cpp @@ -468,6 +468,7 @@ void SetStdioToDevNull(char** argv) { } void InitKernelLogging(char** argv) { + SetFatalRebootTarget(); android::base::InitLogging(argv, &android::base::KernelLogger, InitAborter); } From b62b3ef2ba049e20af632aa5a99bdf60b3b13f3b Mon Sep 17 00:00:00 2001 From: Tim Murray Date: Tue, 28 May 2019 12:15:34 -0700 Subject: [PATCH 192/221] lmkd: use ALOGE for logging kills Test: boots, works Bug: 133761317 Signed-off-by: Tim Murray Exempt-From-Owner-Approval: trivial change Change-Id: I1a4a3741694078eec124f1f560ea68e78754bca6 --- lmkd/lmkd.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lmkd/lmkd.c b/lmkd/lmkd.c index 2de73789a..c2ee061e9 100644 --- a/lmkd/lmkd.c +++ b/lmkd/lmkd.c @@ -1373,8 +1373,8 @@ static int kill_one_process(struct proc* procp, int min_oom_score) { set_process_group_and_prio(pid, SP_FOREGROUND, ANDROID_PRIORITY_HIGHEST); inc_killcnt(procp->oomadj); - ALOGI("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB", - taskname, pid, uid, procp->oomadj, tasksize * page_k); + ALOGE("Kill '%s' (%d), uid %d, oom_adj %d to free %ldkB", taskname, pid, uid, procp->oomadj, + tasksize * page_k); TRACE_KILL_END(); From ca0d4ffbe38a1997d8b1555210a184a5e0d112f4 Mon Sep 17 00:00:00 2001 From: Daichi Hirono Date: Fri, 31 May 2019 12:51:05 +0900 Subject: [PATCH 193/221] Fix BridgeEpollController to handles EAGAIN correctly When reading/writing proxy FD, if it returns EAGAIN, BridgeEpollController updates epoll entries to observe specific FD events. Before updating epoll entries, BridgeEpollController checks if it really needs to update by comparing |state_| and |last_state_|. |last_state_| has not been updated correctly so it resulted in wrong epoll settings and keeps blocking the event loop. Bug: 134104939 Test: atest libappfuse_test Change-Id: I1c4a0164c1c016baf24ecfd523476ced981d3b28 --- libappfuse/FuseBridgeLoop.cc | 1 + 1 file changed, 1 insertion(+) diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc index ac94e6917..da40ec3f7 100644 --- a/libappfuse/FuseBridgeLoop.cc +++ b/libappfuse/FuseBridgeLoop.cc @@ -86,6 +86,7 @@ class FuseBridgeEntry { const bool proxy_read_ready = last_proxy_events_.events & EPOLLIN; const bool proxy_write_ready = last_proxy_events_.events & EPOLLOUT; + last_state_ = state_; last_device_events_.events = 0; last_proxy_events_.events = 0; From c9e873f2747108cc6f010791c86569367d0bef44 Mon Sep 17 00:00:00 2001 From: Anton Hansson Date: Fri, 31 May 2019 13:22:34 +0100 Subject: [PATCH 194/221] Close /dev/fuse FD before calling onClosed This works around a deadlock when a bridge that is about to be closed is reused for a new call to openFile. The call to open() ends up holding the vold lock, waiting for appfuse to respond. The appfuse event loop calls onClosed(), which ends up calling vold.unmountAppFuse(), which cannot get the lock. Closing this file descriptor causes any current calls to open() on its mount path to fail with either ECONNABORTED or ENOTCONN, allowing the event loop to make progress, call onClosed() and unmount the path. Note that the failed call to open() will result in a retry, which will create a new appfuse bridge. This is not ideal but not a new problem -- the common case here is that that each call to openProxyFileDescriptor creates a new bridge. This should ideally be improved. Bug: 132344997 Test: flick through info of photos with location info attached Exempt-From-Owner-Approval: verbal approval of approach Change-Id: I878e5cf86f18c5233f8505f52eb9db076bd72d01 --- libappfuse/FuseBridgeLoop.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libappfuse/FuseBridgeLoop.cc b/libappfuse/FuseBridgeLoop.cc index ac94e6917..f1ca4463e 100644 --- a/libappfuse/FuseBridgeLoop.cc +++ b/libappfuse/FuseBridgeLoop.cc @@ -353,8 +353,8 @@ bool FuseBridgeLoop::ProcessEventLocked(const std::unordered_setIsClosing()) { const int mount_id = entry->mount_id(); - callback->OnClosed(mount_id); bridges_.erase(mount_id); + callback->OnClosed(mount_id); if (bridges_.size() == 0) { // All bridges are now closed. return false; From 0dff785221afbd51b92d46ba276018d0c977bc17 Mon Sep 17 00:00:00 2001 From: Mark Salyzyn Date: Wed, 29 May 2019 14:01:56 -0700 Subject: [PATCH 195/221] fs_mgr: overlayfs: pre-emptive filesystem setup If we just disabled verity, take the step to setup the backing storage for overlayfs. Test: adb-remount-test.sh Bug: 130131892 Change-Id: Ic56569eaf363e4417a0ce5df11ee5480a07b8b03 Merged-In: Ic56569eaf363e4417a0ce5df11ee5480a07b8b03 --- fs_mgr/fs_mgr_overlayfs.cpp | 7 ++++--- fs_mgr/fs_mgr_remount.cpp | 9 ++++++--- fs_mgr/include/fs_mgr_overlayfs.h | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index c252ab523..c13c3b11d 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -90,7 +90,7 @@ std::vector fs_mgr_overlayfs_required_devices(Fstab*) { return {}; } -bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change) { +bool fs_mgr_overlayfs_setup(const char*, const char*, bool* change, bool) { if (change) *change = false; return false; } @@ -873,7 +873,8 @@ std::vector fs_mgr_overlayfs_required_devices(Fstab* fstab) { // Returns false if setup not permitted, errno set to last error. // If something is altered, set *change. -bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change) { +bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* change, + bool force) { if (change) *change = false; auto ret = false; if (fs_mgr_overlayfs_valid() == OverlayfsValidResult::kNotSupported) return ret; @@ -897,7 +898,7 @@ bool fs_mgr_overlayfs_setup(const char* backing, const char* mount_point, bool* continue; } save_errno = errno; - auto verity_enabled = fs_mgr_is_verity_enabled(*it); + auto verity_enabled = !force && fs_mgr_is_verity_enabled(*it); if (errno == ENOENT || errno == ENXIO) errno = save_errno; if (verity_enabled) { it = candidates.erase(it); diff --git a/fs_mgr/fs_mgr_remount.cpp b/fs_mgr/fs_mgr_remount.cpp index fcacd2a43..967631b65 100644 --- a/fs_mgr/fs_mgr_remount.cpp +++ b/fs_mgr/fs_mgr_remount.cpp @@ -250,6 +250,7 @@ int main(int argc, char* argv[]) { // Check verity and optionally setup overlayfs backing. auto reboot_later = false; auto uses_overlayfs = fs_mgr_overlayfs_valid() != OverlayfsValidResult::kNotSupported; + auto just_disabled_verity = false; for (auto it = partitions.begin(); it != partitions.end();) { auto& entry = *it; auto& mount_point = entry.mount_point; @@ -262,7 +263,8 @@ int main(int argc, char* argv[]) { false); avb_ops_user_free(ops); if (ret) { - LOG(WARNING) << "Disable verity for " << mount_point; + LOG(WARNING) << "Disabling verity for " << mount_point; + just_disabled_verity = true; reboot_later = can_reboot; if (reboot_later) { // w/o overlayfs available, also check for dedupe @@ -275,7 +277,8 @@ int main(int argc, char* argv[]) { } else if (fs_mgr_set_blk_ro(entry.blk_device, false)) { fec::io fh(entry.blk_device.c_str(), O_RDWR); if (fh && fh.set_verity_status(false)) { - LOG(WARNING) << "Disable verity for " << mount_point; + LOG(WARNING) << "Disabling verity for " << mount_point; + just_disabled_verity = true; reboot_later = can_reboot; if (reboot_later && !uses_overlayfs) { ++it; @@ -292,7 +295,7 @@ int main(int argc, char* argv[]) { auto change = false; errno = 0; - if (fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change)) { + if (fs_mgr_overlayfs_setup(nullptr, mount_point.c_str(), &change, just_disabled_verity)) { if (change) { LOG(INFO) << "Using overlayfs for " << mount_point; } diff --git a/fs_mgr/include/fs_mgr_overlayfs.h b/fs_mgr/include/fs_mgr_overlayfs.h index 6aaf1f3c1..9a7381ffe 100644 --- a/fs_mgr/include/fs_mgr_overlayfs.h +++ b/fs_mgr/include/fs_mgr_overlayfs.h @@ -26,7 +26,7 @@ android::fs_mgr::Fstab fs_mgr_overlayfs_candidate_list(const android::fs_mgr::Fs bool fs_mgr_overlayfs_mount_all(android::fs_mgr::Fstab* fstab); std::vector fs_mgr_overlayfs_required_devices(android::fs_mgr::Fstab* fstab); bool fs_mgr_overlayfs_setup(const char* backing = nullptr, const char* mount_point = nullptr, - bool* change = nullptr); + bool* change = nullptr, bool force = true); bool fs_mgr_overlayfs_teardown(const char* mount_point = nullptr, bool* change = nullptr); bool fs_mgr_overlayfs_is_setup(); bool fs_mgr_has_shared_blocks(const std::string& mount_point, const std::string& dev); From 9b85e1fb20f9181625ac943e9a40f78aa41d2c03 Mon Sep 17 00:00:00 2001 From: Jaegeuk Kim Date: Wed, 5 Jun 2019 17:43:47 -0700 Subject: [PATCH 196/221] fs_mgr: support -o sync Bug: 134172577 Change-Id: I1ad8811b07657727d8227d3668f58b0fbc7e7609 Merged-In: I1ad8811b07657727d8227d3668f58b0fbc7e7609 Signed-off-by: Jaegeuk Kim --- fs_mgr/fs_mgr_fstab.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/fs_mgr/fs_mgr_fstab.cpp b/fs_mgr/fs_mgr_fstab.cpp index e7c175f7f..7df7cfd99 100644 --- a/fs_mgr/fs_mgr_fstab.cpp +++ b/fs_mgr/fs_mgr_fstab.cpp @@ -61,6 +61,7 @@ FlagList kMountFlagsList[] = { {"nodiratime", MS_NODIRATIME}, {"ro", MS_RDONLY}, {"rw", 0}, + {"sync", MS_SYNCHRONOUS}, {"remount", MS_REMOUNT}, {"bind", MS_BIND}, {"rec", MS_REC}, From 8d502fc15014f4cdbed9949b6ae9e30466b49141 Mon Sep 17 00:00:00 2001 From: Min Yun Date: Tue, 11 Jun 2019 14:49:57 +0900 Subject: [PATCH 197/221] Add libcgrouprc to ld.config.txt. - In GSI, media.extractor has follow dependency. media.extractor -> libmpeg2extractor (media ns) -> libprocessgroup (media ns) -> libcgrouprc (default ns). If libcgroupsrc can't link from libmpeg2extractor, media.extractor is crashed. Test: media.extractor didn't die. Bug: 134981805 Merged-In: I7d3e7e6477708a505b87a884e05cd719f5a3d496 (cherry picked from commit d695733df9047bb61bbe7301d34681aa805697d0) Change-Id: I7d3e7e6477708a505b87a884e05cd719f5a3d496 --- rootdir/etc/ld.config.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/rootdir/etc/ld.config.txt b/rootdir/etc/ld.config.txt index 2ac54e9fb..84b308d0e 100644 --- a/rootdir/etc/ld.config.txt +++ b/rootdir/etc/ld.config.txt @@ -182,6 +182,7 @@ namespace.media.asan.permitted.paths = /apex/com.android.media/${LIB}/extractors namespace.media.links = default namespace.media.link.default.shared_libs = %LLNDK_LIBRARIES% namespace.media.link.default.shared_libs += libbinder_ndk.so +namespace.media.link.default.shared_libs += libcgrouprc.so namespace.media.link.default.shared_libs += libmediametrics.so namespace.media.link.default.shared_libs += %SANITIZER_RUNTIME_LIBRARIES% From 540b1556c92204d6a553b6b2ac2a426a2042e390 Mon Sep 17 00:00:00 2001 From: mtk16036 Date: Fri, 31 May 2019 19:05:22 +0800 Subject: [PATCH 198/221] race condition in libprocessgroup while enable fdsan (file descriptor sanitizer), fdsan report use-after-close error after boot complete (sedom). Because, in SetCgroupAction::EnableResourceCaching() currently has a data race against all the use fd_ functions like SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) etc. ThreadA | ThreadB ------------------------------------------------------------------------------------------------- in SetCgroupAction::EnableResourceCaching() | in SetCgroupAction::ExecuteForProcess(...) ------------------------------------------------------------------------------------------------- | in SetCgroupAction::AddTidToCgroup(int tid, int fd) ------------------------------------------------------------------------------------------------- fd_ = std::move(fd); /*modified fd_ value*/ | ------------------------------------------------------------------------------------------------- | write(fd) /* crash here, fd is closed by ThreadA*/ ------------------------------------------------------------------------------------------------- So, add mutex lock to protect fd_ data race. Bug: 134120826 Test: auto test, run the adb reboot test 100 times and no fdsan error report on libprocessgroup Merged-In: Iccf2f705e030f79324f1164509e715dc5be825de Change-Id: Iccf2f705e030f79324f1164509e715dc5be825de --- libprocessgroup/task_profiles.cpp | 3 +++ libprocessgroup/task_profiles.h | 2 ++ 2 files changed, 5 insertions(+) diff --git a/libprocessgroup/task_profiles.cpp b/libprocessgroup/task_profiles.cpp index 40d8d902c..edc316a8d 100644 --- a/libprocessgroup/task_profiles.cpp +++ b/libprocessgroup/task_profiles.cpp @@ -150,6 +150,7 @@ SetCgroupAction::SetCgroupAction(const CgroupController& c, const std::string& p } void SetCgroupAction::EnableResourceCaching() { + std::lock_guard lock(fd_mutex_); if (fd_ != FDS_NOT_CACHED) { return; } @@ -191,6 +192,7 @@ bool SetCgroupAction::AddTidToCgroup(int tid, int fd) { } bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { + std::lock_guard lock(fd_mutex_); if (IsFdValid()) { // fd is cached, reuse it if (!AddTidToCgroup(pid, fd_)) { @@ -221,6 +223,7 @@ bool SetCgroupAction::ExecuteForProcess(uid_t uid, pid_t pid) const { } bool SetCgroupAction::ExecuteForTask(int tid) const { + std::lock_guard lock(fd_mutex_); if (IsFdValid()) { // fd is cached, reuse it if (!AddTidToCgroup(tid, fd_)) { diff --git a/libprocessgroup/task_profiles.h b/libprocessgroup/task_profiles.h index 445647dea..77bac2d94 100644 --- a/libprocessgroup/task_profiles.h +++ b/libprocessgroup/task_profiles.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -127,6 +128,7 @@ class SetCgroupAction : public ProfileAction { CgroupController controller_; std::string path_; android::base::unique_fd fd_; + mutable std::mutex fd_mutex_; static bool IsAppDependentPath(const std::string& path); static bool AddTidToCgroup(int tid, int fd); From b2d79c5e48684d3859481bcca0e967fc4021db12 Mon Sep 17 00:00:00 2001 From: Hemant Kumar Date: Tue, 21 May 2019 17:55:04 -0700 Subject: [PATCH 199/221] adb: daemon: Assign valid fd to usb_handle ep0 file descriptor Bug: http://b/129283234 Test: treehugger Change-Id: I2d005e17ccb45af95351c074cc53f6cfc53b5fdd Merged-In: I2d005e17ccb45af95351c074cc53f6cfc53b5fdd (cherry picked from commit 1cbe5edbc3b02213e4061bf443dcf1ac8a7ba8bf) --- adb/daemon/usb_ffs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/adb/daemon/usb_ffs.cpp b/adb/daemon/usb_ffs.cpp index 07b4ba898..954e53015 100644 --- a/adb/daemon/usb_ffs.cpp +++ b/adb/daemon/usb_ffs.cpp @@ -257,6 +257,7 @@ bool open_functionfs(android::base::unique_fd* out_control, android::base::uniqu } // Signal only when writing the descriptors to ffs android::base::SetProperty("sys.usb.ffs.ready", "1"); + *out_control = std::move(control); } bulk_out.reset(adb_open(USB_FFS_ADB_OUT, O_RDONLY)); @@ -271,7 +272,6 @@ bool open_functionfs(android::base::unique_fd* out_control, android::base::uniqu return false; } - *out_control = std::move(control); *out_bulk_in = std::move(bulk_in); *out_bulk_out = std::move(bulk_out); return true; From ea9e783b4b44533dce0c741c84f6e6c8f916a538 Mon Sep 17 00:00:00 2001 From: Dongcheol Shin Date: Wed, 12 Jun 2019 09:31:35 +0900 Subject: [PATCH 200/221] Support importing property file with expanded name This change is to support importing property file with its path variations. By substitute its filename with another, it can be used to handle runtime varying filename within single binary. Here's an example of usage in property defined file. import /odm/build_${ro.boot.product.hardware.sku}.prop Bug: 132592551 Test: boot a device and checks above example import statement in "/odm/build.prop" loading expanded filename correctly Merged-In: If3fdcf620a5d717e0930b1e4e58261bc8f79ec24 (cherry picked from commit a87c0f99adb742cd2b9a5d9911f04836eed79f05) Change-Id: If3fdcf620a5d717e0930b1e4e58261bc8f79ec24 --- init/property_service.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/init/property_service.cpp b/init/property_service.cpp index fce8d578f..f2c7462ab 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -642,8 +642,14 @@ static void LoadProperties(char* data, const char* filter, const char* filename, while (isspace(*key)) key++; } - load_properties_from_file(fn, key, properties); + std::string raw_filename(fn); + std::string expanded_filename; + if (!expand_props(raw_filename, &expanded_filename)) { + LOG(ERROR) << "Could not expand filename '" << raw_filename << "'"; + continue; + } + load_properties_from_file(expanded_filename.c_str(), key, properties); } else { value = strchr(key, '='); if (!value) continue; From 9b90198887462249a293f242560e00993206a4e8 Mon Sep 17 00:00:00 2001 From: Steve Muckle Date: Fri, 14 Jun 2019 11:35:53 -0700 Subject: [PATCH 201/221] VtsKernelLiblpTest: use static test To avoid introducing dependencies on target libraries, use a statically compiled test instead. Bug: 134912860 Test: run vts-kernel -m VtsKernelLiblpTest Change-Id: Ie24cc8532c7821cb225c024c240c4d485557bfa7 --- fs_mgr/liblp/Android.bp | 38 +++++++++++++++++++++--------------- fs_mgr/liblp/AndroidTest.xml | 4 ++-- 2 files changed, 24 insertions(+), 18 deletions(-) diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp index 70399942e..b5041613a 100644 --- a/fs_mgr/liblp/Android.bp +++ b/fs_mgr/liblp/Android.bp @@ -14,6 +14,16 @@ // limitations under the License. // +liblp_lib_deps = [ + "libbase", + "liblog", + "libcrypto", + "libcrypto_utils", + "libsparse", + "libext4_utils", + "libz", +] + cc_library { name: "liblp", host_supported: true, @@ -30,15 +40,7 @@ cc_library { "utility.cpp", "writer.cpp", ], - shared_libs: [ - "libbase", - "liblog", - "libcrypto", - "libcrypto_utils", - "libsparse", - "libext4_utils", - "libz", - ], + shared_libs: liblp_lib_deps, target: { windows: { enabled: true, @@ -53,24 +55,28 @@ cc_library { } cc_test { - name: "liblp_test", + name: "liblp_test_static", defaults: ["fs_mgr_defaults"], cppflags: [ "-Wno-unused-parameter", ], static_libs: [ "libgmock", - ], - shared_libs: [ - "liblp", - "libbase", "libfs_mgr", - "libsparse", - ], + "liblp", + ] + liblp_lib_deps, + stl: "libc++_static", srcs: [ "builder_test.cpp", "io_test.cpp", "test_partition_opener.cpp", "utility_test.cpp", ], + target: { + android: { + static_libs: [ + "libcutils", + ], + }, + }, } diff --git a/fs_mgr/liblp/AndroidTest.xml b/fs_mgr/liblp/AndroidTest.xml index 007a302e0..fe1002c4e 100644 --- a/fs_mgr/liblp/AndroidTest.xml +++ b/fs_mgr/liblp/AndroidTest.xml @@ -21,8 +21,8 @@