diff options
125 files changed, 2412 insertions, 1263 deletions
diff --git a/TEST_MAPPING b/TEST_MAPPING index 79336291ab..89bd66a57e 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -16,18 +16,27 @@ "name": "adb_tls_connection_test" }, { + "name": "CtsFsMgrTestCases" + }, + { "name": "CtsInitTestCases" }, { - "name": "debuggerd_test" + "name": "CtsLiblogTestCases" }, { - "name": "CtsFsMgrTestCases" + "name": "CtsLogdTestCases" + }, + { + "name": "debuggerd_test" }, { "name": "fs_mgr_vendor_overlay_test" }, { + "name": "init_kill_services_test" + }, + { "name": "libpackagelistparser_test" }, { @@ -58,5 +67,10 @@ { "name": "propertyinfoserializer_tests" } + ], + "imports": [ + { + "path": "frameworks/base/tests/StagedInstallTest" + } ] } diff --git a/adb/Android.bp b/adb/Android.bp index 2fc205faed..87ac54d06e 100644 --- a/adb/Android.bp +++ b/adb/Android.bp @@ -12,6 +12,11 @@ // See the License for the specific language governing permissions and // limitations under the License. +tidy_errors = [ + "-*", + "bugprone-inaccurate-erase", +] + cc_defaults { name: "adb_defaults", @@ -73,6 +78,10 @@ cc_defaults { ], }, }, + + tidy: true, + tidy_checks: tidy_errors, + tidy_checks_as_errors: tidy_errors, } cc_defaults { diff --git a/adb/adb_utils.h b/adb/adb_utils.h index 66cba121b2..e72d8b6f87 100644 --- a/adb/adb_utils.h +++ b/adb/adb_utils.h @@ -55,7 +55,7 @@ std::string perror_str(const char* msg); bool set_file_block_mode(borrowed_fd fd, bool block); -// Given forward/reverse targets, returns true if they look sane. If an error is found, fills +// Given forward/reverse targets, returns true if they look valid. If an error is found, fills // |error| and returns false. // Currently this only checks "tcp:" targets. Additional checking could be added for other targets // if needed. diff --git a/adb/client/incremental.cpp b/adb/client/incremental.cpp index 3033059d01..60735f8c5e 100644 --- a/adb/client/incremental.cpp +++ b/adb/client/incremental.cpp @@ -55,9 +55,10 @@ static std::pair<unique_fd, std::vector<char>> read_signature(Size file_size, return {}; } - std::vector<char> invalid_signature; + auto [signature, tree_size] = read_id_sig_headers(fd); - if (st.st_size > kMaxSignatureSize) { + std::vector<char> invalid_signature; + if (signature.size() > kMaxSignatureSize) { if (!silent) { fprintf(stderr, "Signature is too long. Max allowed is %d. Abort.\n", kMaxSignatureSize); @@ -65,7 +66,6 @@ static std::pair<unique_fd, std::vector<char>> read_signature(Size file_size, return {std::move(fd), std::move(invalid_signature)}; } - auto [signature, tree_size] = read_id_sig_headers(fd); if (auto expected = verity_tree_size_for_file(file_size); tree_size != expected) { if (!silent) { fprintf(stderr, diff --git a/adb/fdevent/fdevent_test.h b/adb/fdevent/fdevent_test.h index ecda4da979..fcbf181dc0 100644 --- a/adb/fdevent/fdevent_test.h +++ b/adb/fdevent/fdevent_test.h @@ -65,7 +65,7 @@ class FdeventTest : public ::testing::Test { ASSERT_EQ(0u, fdevent_installed_count()); } - // Register a dummy socket used to wake up the fdevent loop to tell it to die. + // Register a placeholder socket used to wake up the fdevent loop to tell it to die. void PrepareThread() { int dummy_fds[2]; if (adb_socketpair(dummy_fds) != 0) { @@ -84,7 +84,7 @@ class FdeventTest : public ::testing::Test { } size_t GetAdditionalLocalSocketCount() { - // dummy socket installed in PrepareThread() + // placeholder socket installed in PrepareThread() return 1; } diff --git a/adb/sockets.cpp b/adb/sockets.cpp index 13a473776c..33b9524182 100644 --- a/adb/sockets.cpp +++ b/adb/sockets.cpp @@ -856,7 +856,7 @@ static int smart_socket_enqueue(asocket* s, apacket::payload_type data) { s->peer->shutdown = nullptr; s->peer->close = local_socket_close_notify; s->peer->peer = nullptr; - /* give him our transport and upref it */ + /* give them our transport and upref it */ s->peer->transport = s->transport; connect_to_remote(s->peer, std::string_view(s->smart_socket_data).substr(4)); diff --git a/bootstat/boot_reason_test.sh b/bootstat/boot_reason_test.sh index 2f2919f2ab..7cff7dc9f4 100755 --- a/bootstat/boot_reason_test.sh +++ b/bootstat/boot_reason_test.sh @@ -1331,7 +1331,7 @@ if [ X"--macros" != X"${1}" ]; then shift fi - # Check if all conditions for the script are sane + # Check if all conditions for the script are valid if [ -z "${ANDROID_SERIAL}" ]; then ndev=`( diff --git a/debuggerd/Android.bp b/debuggerd/Android.bp index 31c2d5d64b..ad10a1f370 100644 --- a/debuggerd/Android.bp +++ b/debuggerd/Android.bp @@ -253,7 +253,6 @@ cc_test { "libcutils", "libdebuggerd_client", "liblog", - "libminijail", "libnativehelper", "libunwindstack", ], @@ -261,6 +260,7 @@ cc_test { static_libs: [ "libdebuggerd", "libgmock", + "libminijail", ], header_libs: [ diff --git a/debuggerd/client/debuggerd_client.cpp b/debuggerd/client/debuggerd_client.cpp index 5c027387c7..6bfb5f2c2f 100644 --- a/debuggerd/client/debuggerd_client.cpp +++ b/debuggerd/client/debuggerd_client.cpp @@ -70,36 +70,6 @@ static void populate_timeval(struct timeval* tv, const Duration& duration) { tv->tv_usec = static_cast<long>(microseconds.count()); } -static void get_wchan_header(pid_t pid, std::stringstream& buffer) { - struct tm now; - time_t t = time(nullptr); - localtime_r(&t, &now); - char timestamp[32]; - strftime(timestamp, sizeof(timestamp), "%Y-%m-%d %H:%M:%S", &now); - std::string time_now(timestamp); - - std::string path = "/proc/" + std::to_string(pid) + "/cmdline"; - - char proc_name_buf[1024]; - const char* proc_name = nullptr; - std::unique_ptr<FILE, decltype(&fclose)> fp(fopen(path.c_str(), "r"), &fclose); - - if (fp) { - proc_name = fgets(proc_name_buf, sizeof(proc_name_buf), fp.get()); - } - - if (!proc_name) { - proc_name = "<unknown>"; - } - - buffer << "\n----- Waiting Channels: pid " << pid << " at " << time_now << " -----\n" - << "Cmd line: " << proc_name << "\n"; -} - -static void get_wchan_footer(pid_t pid, std::stringstream& buffer) { - buffer << "----- end " << std::to_string(pid) << " -----\n"; -} - /** * Returns the wchan data for each thread in the process, * or empty string if unable to obtain any data. @@ -125,9 +95,10 @@ static std::string get_wchan_data(pid_t pid) { } if (std::string str = data.str(); !str.empty()) { - get_wchan_header(pid, buffer); + buffer << "\n----- Waiting Channels: pid " << pid << " at " << get_timestamp() << " -----\n" + << "Cmd line: " << get_process_name(pid) << "\n"; buffer << "\n" << str << "\n"; - get_wchan_footer(pid, buffer); + buffer << "----- end " << std::to_string(pid) << " -----\n"; buffer << "\n"; } diff --git a/debuggerd/debuggerd_test.cpp b/debuggerd/debuggerd_test.cpp index 9d7658eb03..108787e4ab 100644 --- a/debuggerd/debuggerd_test.cpp +++ b/debuggerd/debuggerd_test.cpp @@ -18,6 +18,7 @@ #include <fcntl.h> #include <stdlib.h> #include <sys/capability.h> +#include <sys/mman.h> #include <sys/prctl.h> #include <sys/ptrace.h> #include <sys/resource.h> @@ -172,6 +173,8 @@ class CrasherTest : public ::testing::Test { void StartCrasher(const std::string& crash_type); void FinishCrasher(); void AssertDeath(int signo); + + static void Trap(void* ptr); }; CrasherTest::CrasherTest() { @@ -334,6 +337,48 @@ TEST_F(CrasherTest, tagged_fault_addr) { R"(signal 11 \(SIGSEGV\), code 1 \(SEGV_MAPERR\), fault addr (0x100000000000dead|0xdead))"); } +// Marked as weak to prevent the compiler from removing the malloc in the caller. In theory, the +// compiler could still clobber the argument register before trapping, but that's unlikely. +__attribute__((weak)) void CrasherTest::Trap(void* ptr ATTRIBUTE_UNUSED) { + __builtin_trap(); +} + +TEST_F(CrasherTest, heap_addr_in_register) { +#if defined(__i386__) + GTEST_SKIP() << "architecture does not pass arguments in registers"; +#endif + int intercept_result; + unique_fd output_fd; + StartProcess([]() { + // Crash with a heap pointer in the first argument register. + Trap(malloc(1)); + }); + + StartIntercept(&output_fd); + FinishCrasher(); + int status; + ASSERT_EQ(crasher_pid, TIMEOUT(30, waitpid(crasher_pid, &status, 0))); + ASSERT_TRUE(WIFSIGNALED(status)) << "crasher didn't terminate via a signal"; + // Don't test the signal number because different architectures use different signals for + // __builtin_trap(). + FinishIntercept(&intercept_result); + + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + +#if defined(__aarch64__) + ASSERT_MATCH(result, "memory near x0"); +#elif defined(__arm__) + ASSERT_MATCH(result, "memory near r0"); +#elif defined(__x86_64__) + ASSERT_MATCH(result, "memory near rdi"); +#else + ASSERT_TRUE(false) << "unsupported architecture"; +#endif +} + #if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE) static void SetTagCheckingLevelSync() { int tagged_addr_ctrl = prctl(PR_GET_TAGGED_ADDR_CTRL, 0, 0, 0, 0); @@ -512,6 +557,55 @@ TEST_F(CrasherTest, mte_multiple_causes) { #endif } +#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE) +static uintptr_t CreateTagMapping() { + uintptr_t mapping = + reinterpret_cast<uintptr_t>(mmap(nullptr, getpagesize(), PROT_READ | PROT_WRITE | PROT_MTE, + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0)); + if (reinterpret_cast<void*>(mapping) == MAP_FAILED) { + return 0; + } + __asm__ __volatile__(".arch_extension mte; stg %0, [%0]" + : + : "r"(mapping + (1ULL << 56)) + : "memory"); + return mapping; +} +#endif + +TEST_F(CrasherTest, mte_tag_dump) { +#if defined(__aarch64__) && defined(ANDROID_EXPERIMENTAL_MTE) + if (!mte_supported()) { + GTEST_SKIP() << "Requires MTE"; + } + + int intercept_result; + unique_fd output_fd; + StartProcess([&]() { + SetTagCheckingLevelSync(); + Trap(reinterpret_cast<void *>(CreateTagMapping())); + }); + + StartIntercept(&output_fd); + FinishCrasher(); + AssertDeath(SIGTRAP); + FinishIntercept(&intercept_result); + + ASSERT_EQ(1, intercept_result) << "tombstoned reported failure"; + + std::string result; + ConsumeFd(std::move(output_fd), &result); + + ASSERT_MATCH(result, R"(memory near x0: +.* +.* + 01.............0 0000000000000000 0000000000000000 ................ + 00.............0)"); +#else + GTEST_SKIP() << "Requires aarch64 + ANDROID_EXPERIMENTAL_MTE"; +#endif +} + TEST_F(CrasherTest, LD_PRELOAD) { int intercept_result; unique_fd output_fd; diff --git a/debuggerd/libdebuggerd/backtrace.cpp b/debuggerd/libdebuggerd/backtrace.cpp index c606970995..f5a873c4d3 100644 --- a/debuggerd/libdebuggerd/backtrace.cpp +++ b/debuggerd/libdebuggerd/backtrace.cpp @@ -27,7 +27,6 @@ #include <string.h> #include <sys/ptrace.h> #include <sys/types.h> -#include <time.h> #include <unistd.h> #include <map> @@ -40,14 +39,10 @@ #include "libdebuggerd/types.h" #include "libdebuggerd/utility.h" +#include "util.h" static void dump_process_header(log_t* log, pid_t pid, const char* process_name) { - time_t t = time(NULL); - struct tm tm; - localtime_r(&t, &tm); - char timestr[64]; - strftime(timestr, sizeof(timestr), "%F %T", &tm); - _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, timestr); + _LOG(log, logtype::BACKTRACE, "\n\n----- pid %d at %s -----\n", pid, get_timestamp().c_str()); if (process_name) { _LOG(log, logtype::BACKTRACE, "Cmd line: %s\n", process_name); @@ -106,9 +101,8 @@ void dump_backtrace_header(int output_fd) { log.tfd = output_fd; log.amfd_data = nullptr; - char process_name[128]; - read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>"); - dump_process_header(&log, getpid(), process_name); + pid_t pid = getpid(); + dump_process_header(&log, pid, get_process_name(pid).c_str()); } void dump_backtrace_footer(int output_fd) { diff --git a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h index 7bfcf5d6e8..76155b183d 100644 --- a/debuggerd/libdebuggerd/include/libdebuggerd/utility.h +++ b/debuggerd/libdebuggerd/include/libdebuggerd/utility.h @@ -83,8 +83,6 @@ void log_backtrace(log_t* log, unwindstack::Unwinder* unwinder, const char* pref 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); - void drop_capabilities(); bool signal_has_sender(const siginfo_t*, pid_t caller_pid); diff --git a/debuggerd/libdebuggerd/test/dump_memory_test.cpp b/debuggerd/libdebuggerd/test/dump_memory_test.cpp index be395824b8..f16f578a46 100644 --- a/debuggerd/libdebuggerd/test/dump_memory_test.cpp +++ b/debuggerd/libdebuggerd/test/dump_memory_test.cpp @@ -30,39 +30,39 @@ const char g_expected_full_dump[] = "\nmemory near r1:\n" #if defined(__LP64__) -" 0000000012345658 0706050403020100 0f0e0d0c0b0a0908 ................\n" -" 0000000012345668 1716151413121110 1f1e1d1c1b1a1918 ................\n" -" 0000000012345678 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" -" 0000000012345688 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" -" 0000000012345698 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" -" 00000000123456a8 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" -" 00000000123456b8 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" -" 00000000123456c8 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" -" 00000000123456d8 8786858483828180 8f8e8d8c8b8a8988 ................\n" -" 00000000123456e8 9796959493929190 9f9e9d9c9b9a9998 ................\n" -" 00000000123456f8 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" -" 0000000012345708 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" -" 0000000012345718 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" -" 0000000012345728 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" -" 0000000012345738 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" -" 0000000012345748 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; +" 0000000012345650 0706050403020100 0f0e0d0c0b0a0908 ................\n" +" 0000000012345660 1716151413121110 1f1e1d1c1b1a1918 ................\n" +" 0000000012345670 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" +" 0000000012345680 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" +" 0000000012345690 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" +" 00000000123456a0 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" +" 00000000123456b0 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" +" 00000000123456c0 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" +" 00000000123456d0 8786858483828180 8f8e8d8c8b8a8988 ................\n" +" 00000000123456e0 9796959493929190 9f9e9d9c9b9a9998 ................\n" +" 00000000123456f0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" +" 0000000012345700 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" +" 0000000012345710 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" +" 0000000012345720 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" +" 0000000012345730 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" +" 0000000012345740 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; #else -" 12345658 03020100 07060504 0b0a0908 0f0e0d0c ................\n" -" 12345668 13121110 17161514 1b1a1918 1f1e1d1c ................\n" -" 12345678 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" -" 12345688 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" -" 12345698 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" -" 123456a8 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" -" 123456b8 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n" -" 123456c8 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n" -" 123456d8 83828180 87868584 8b8a8988 8f8e8d8c ................\n" -" 123456e8 93929190 97969594 9b9a9998 9f9e9d9c ................\n" -" 123456f8 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" -" 12345708 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" -" 12345718 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" -" 12345728 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" -" 12345738 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" -" 12345748 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n"; +" 12345650 03020100 07060504 0b0a0908 0f0e0d0c ................\n" +" 12345660 13121110 17161514 1b1a1918 1f1e1d1c ................\n" +" 12345670 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" +" 12345680 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" +" 12345690 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" +" 123456a0 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" +" 123456b0 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n" +" 123456c0 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n" +" 123456d0 83828180 87868584 8b8a8988 8f8e8d8c ................\n" +" 123456e0 93929190 97969594 9b9a9998 9f9e9d9c ................\n" +" 123456f0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" +" 12345700 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" +" 12345710 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" +" 12345720 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" +" 12345730 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" +" 12345740 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n"; #endif const char g_expected_partial_dump[] = \ @@ -112,7 +112,10 @@ class MemoryMock : public unwindstack::Memory { if (last_read_addr_ > 0) { offset = addr - last_read_addr_; } - size_t bytes_available = buffer_.size() - offset; + size_t bytes_available = 0; + if (offset < buffer_.size()) { + bytes_available = buffer_.size() - offset; + } if (partial_read_) { bytes = std::min(bytes, bytes_partial_read_); @@ -258,44 +261,7 @@ TEST_F(DumpMemoryTest, memory_unreadable) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - const char* expected_dump = \ -"\nmemory near pc:\n" -#if defined(__LP64__) -" 00000000a2345658 ---------------- ---------------- ................\n" -" 00000000a2345668 ---------------- ---------------- ................\n" -" 00000000a2345678 ---------------- ---------------- ................\n" -" 00000000a2345688 ---------------- ---------------- ................\n" -" 00000000a2345698 ---------------- ---------------- ................\n" -" 00000000a23456a8 ---------------- ---------------- ................\n" -" 00000000a23456b8 ---------------- ---------------- ................\n" -" 00000000a23456c8 ---------------- ---------------- ................\n" -" 00000000a23456d8 ---------------- ---------------- ................\n" -" 00000000a23456e8 ---------------- ---------------- ................\n" -" 00000000a23456f8 ---------------- ---------------- ................\n" -" 00000000a2345708 ---------------- ---------------- ................\n" -" 00000000a2345718 ---------------- ---------------- ................\n" -" 00000000a2345728 ---------------- ---------------- ................\n" -" 00000000a2345738 ---------------- ---------------- ................\n" -" 00000000a2345748 ---------------- ---------------- ................\n"; -#else -" a2345658 -------- -------- -------- -------- ................\n" -" a2345668 -------- -------- -------- -------- ................\n" -" a2345678 -------- -------- -------- -------- ................\n" -" a2345688 -------- -------- -------- -------- ................\n" -" a2345698 -------- -------- -------- -------- ................\n" -" a23456a8 -------- -------- -------- -------- ................\n" -" a23456b8 -------- -------- -------- -------- ................\n" -" a23456c8 -------- -------- -------- -------- ................\n" -" a23456d8 -------- -------- -------- -------- ................\n" -" a23456e8 -------- -------- -------- -------- ................\n" -" a23456f8 -------- -------- -------- -------- ................\n" -" a2345708 -------- -------- -------- -------- ................\n" -" a2345718 -------- -------- -------- -------- ................\n" -" a2345728 -------- -------- -------- -------- ................\n" -" a2345738 -------- -------- -------- -------- ................\n" -" a2345748 -------- -------- -------- -------- ................\n"; -#endif - ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); + ASSERT_STREQ("", tombstone_contents.c_str()); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -429,57 +395,17 @@ TEST_F(DumpMemoryTest, address_low_fence) { ASSERT_STREQ("", getFakeLogPrint().c_str()); } -TEST_F(DumpMemoryTest, memory_address_too_low) { - uint8_t buffer[256]; - memset(buffer, 0, sizeof(buffer)); - memory_mock_->SetReadData(buffer, sizeof(buffer)); - - dump_memory(&log_, memory_mock_.get(), 0, "memory near r1"); - - std::string tombstone_contents; - ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); - ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - ASSERT_STREQ("", tombstone_contents.c_str()); - - // Verify that the log buf is empty, and no error messages. - ASSERT_STREQ("", getFakeLogBuf().c_str()); - ASSERT_STREQ("", getFakeLogPrint().c_str()); -} - TEST_F(DumpMemoryTest, memory_address_too_high) { uint8_t buffer[256]; memset(buffer, 0, sizeof(buffer)); memory_mock_->SetReadData(buffer, sizeof(buffer)); #if defined(__LP64__) - dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL, "memory near r1"); - dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 32, "memory near r1"); - dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 216, "memory near r1"); -#else - dump_memory(&log_, memory_mock_.get(), 0xffff0000, "memory near r1"); - dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 32, "memory near r1"); - dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 220, "memory near r1"); -#endif - - std::string tombstone_contents; - ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); - ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - ASSERT_STREQ("", tombstone_contents.c_str()); - - // Verify that the log buf is empty, and no error messages. - ASSERT_STREQ("", getFakeLogBuf().c_str()); - ASSERT_STREQ("", getFakeLogPrint().c_str()); -} - -TEST_F(DumpMemoryTest, memory_address_would_overflow) { - uint8_t buffer[256]; - memset(buffer, 0, sizeof(buffer)); - memory_mock_->SetReadData(buffer, sizeof(buffer)); - -#if defined(__LP64__) - dump_memory(&log_, memory_mock_.get(), 0xfffffffffffffff0, "memory near r1"); + dump_memory(&log_, memory_mock_.get(), -32, "memory near r1"); + dump_memory(&log_, memory_mock_.get(), -208, "memory near r1"); #else - dump_memory(&log_, memory_mock_.get(), 0xfffffff0, "memory near r1"); + dump_memory(&log_, memory_mock_.get(), 0x100000000 - 32, "memory near r1"); + dump_memory(&log_, memory_mock_.get(), 0x100000000 - 208, "memory near r1"); #endif std::string tombstone_contents; @@ -500,9 +426,9 @@ TEST_F(DumpMemoryTest, memory_address_nearly_too_high) { memory_mock_->SetReadData(buffer, sizeof(buffer)); #if defined(__LP64__) - dump_memory(&log_, memory_mock_.get(), 0x4000000000000000UL - 224, "memory near r4"); + dump_memory(&log_, memory_mock_.get(), -224, "memory near r4"); #else - dump_memory(&log_, memory_mock_.get(), 0xffff0000 - 224, "memory near r4"); + dump_memory(&log_, memory_mock_.get(), 0x100000000 - 224, "memory near r4"); #endif std::string tombstone_contents; @@ -510,40 +436,57 @@ TEST_F(DumpMemoryTest, memory_address_nearly_too_high) { ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); const char* expected_dump = \ "\nmemory near r4:\n" -#if defined(__LP64__) -" 3fffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n" -" 3fffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n" -" 3fffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" -" 3fffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" -" 3fffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" -" 3fffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" -" 3fffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" -" 3fffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" -" 3fffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n" -" 3fffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n" -" 3fffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" -" 3fffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" -" 3fffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" -" 3fffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" -" 3fffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" -" 3ffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; +#if defined(__aarch64__) +" 00ffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n" +" 00ffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n" +" 00ffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" +" 00ffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" +" 00ffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" +" 00ffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" +" 00ffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" +" 00ffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" +" 00ffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n" +" 00ffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n" +" 00ffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" +" 00ffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" +" 00ffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" +" 00ffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" +" 00ffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" +" 00fffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; +#elif defined(__LP64__) +" ffffffffffffff00 0706050403020100 0f0e0d0c0b0a0908 ................\n" +" ffffffffffffff10 1716151413121110 1f1e1d1c1b1a1918 ................\n" +" ffffffffffffff20 2726252423222120 2f2e2d2c2b2a2928 !\"#$%&'()*+,-./\n" +" ffffffffffffff30 3736353433323130 3f3e3d3c3b3a3938 0123456789:;<=>?\n" +" ffffffffffffff40 4746454443424140 4f4e4d4c4b4a4948 @ABCDEFGHIJKLMNO\n" +" ffffffffffffff50 5756555453525150 5f5e5d5c5b5a5958 PQRSTUVWXYZ[\\]^_\n" +" ffffffffffffff60 6766656463626160 6f6e6d6c6b6a6968 `abcdefghijklmno\n" +" ffffffffffffff70 7776757473727170 7f7e7d7c7b7a7978 pqrstuvwxyz{|}~.\n" +" ffffffffffffff80 8786858483828180 8f8e8d8c8b8a8988 ................\n" +" ffffffffffffff90 9796959493929190 9f9e9d9c9b9a9998 ................\n" +" ffffffffffffffa0 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" +" ffffffffffffffb0 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" +" ffffffffffffffc0 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" +" ffffffffffffffd0 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" +" ffffffffffffffe0 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" +" fffffffffffffff0 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; #else -" fffeff00 03020100 07060504 0b0a0908 0f0e0d0c ................\n" -" fffeff10 13121110 17161514 1b1a1918 1f1e1d1c ................\n" -" fffeff20 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" -" fffeff30 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" -" fffeff40 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" -" fffeff50 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" -" fffeff60 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n" -" fffeff70 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n" -" fffeff80 83828180 87868584 8b8a8988 8f8e8d8c ................\n" -" fffeff90 93929190 97969594 9b9a9998 9f9e9d9c ................\n" -" fffeffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" -" fffeffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" -" fffeffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" -" fffeffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" -" fffeffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" -" fffefff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n"; +" ffffff00 03020100 07060504 0b0a0908 0f0e0d0c ................\n" +" ffffff10 13121110 17161514 1b1a1918 1f1e1d1c ................\n" +" ffffff20 23222120 27262524 2b2a2928 2f2e2d2c !\"#$%&'()*+,-./\n" +" ffffff30 33323130 37363534 3b3a3938 3f3e3d3c 0123456789:;<=>?\n" +" ffffff40 43424140 47464544 4b4a4948 4f4e4d4c @ABCDEFGHIJKLMNO\n" +" ffffff50 53525150 57565554 5b5a5958 5f5e5d5c PQRSTUVWXYZ[\\]^_\n" +" ffffff60 63626160 67666564 6b6a6968 6f6e6d6c `abcdefghijklmno\n" +" ffffff70 73727170 77767574 7b7a7978 7f7e7d7c pqrstuvwxyz{|}~.\n" +" ffffff80 83828180 87868584 8b8a8988 8f8e8d8c ................\n" +" ffffff90 93929190 97969594 9b9a9998 9f9e9d9c ................\n" +" ffffffa0 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" +" ffffffb0 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" +" ffffffc0 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" +" ffffffd0 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" +" ffffffe0 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" +" fffffff0 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n"; #endif ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); @@ -570,39 +513,41 @@ TEST_F(DumpMemoryTest, first_read_empty) { const char* expected_dump = \ "\nmemory near r4:\n" #if defined(__LP64__) -" 0000000010000f88 ---------------- ---------------- ................\n" -" 0000000010000f98 ---------------- ---------------- ................\n" -" 0000000010000fa8 ---------------- ---------------- ................\n" -" 0000000010000fb8 ---------------- ---------------- ................\n" -" 0000000010000fc8 ---------------- ---------------- ................\n" -" 0000000010000fd8 ---------------- ---------------- ................\n" -" 0000000010000fe8 ---------------- ---------------- ................\n" -" 0000000010000ff8 ---------------- 7f7e7d7c7b7a7978 ........xyz{|}~.\n" -" 0000000010001008 8786858483828180 8f8e8d8c8b8a8988 ................\n" -" 0000000010001018 9796959493929190 9f9e9d9c9b9a9998 ................\n" -" 0000000010001028 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................\n" -" 0000000010001038 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................\n" -" 0000000010001048 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................\n" -" 0000000010001058 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................\n" -" 0000000010001068 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................\n" -" 0000000010001078 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................\n"; +R"( 0000000010000f80 ---------------- ---------------- ................ + 0000000010000f90 ---------------- ---------------- ................ + 0000000010000fa0 ---------------- ---------------- ................ + 0000000010000fb0 ---------------- ---------------- ................ + 0000000010000fc0 ---------------- ---------------- ................ + 0000000010000fd0 ---------------- ---------------- ................ + 0000000010000fe0 ---------------- ---------------- ................ + 0000000010000ff0 ---------------- ---------------- ................ + 0000000010001000 8786858483828180 8f8e8d8c8b8a8988 ................ + 0000000010001010 9796959493929190 9f9e9d9c9b9a9998 ................ + 0000000010001020 a7a6a5a4a3a2a1a0 afaeadacabaaa9a8 ................ + 0000000010001030 b7b6b5b4b3b2b1b0 bfbebdbcbbbab9b8 ................ + 0000000010001040 c7c6c5c4c3c2c1c0 cfcecdcccbcac9c8 ................ + 0000000010001050 d7d6d5d4d3d2d1d0 dfdedddcdbdad9d8 ................ + 0000000010001060 e7e6e5e4e3e2e1e0 efeeedecebeae9e8 ................ + 0000000010001070 f7f6f5f4f3f2f1f0 fffefdfcfbfaf9f8 ................ +)"; #else -" 10000f88 -------- -------- -------- -------- ................\n" -" 10000f98 -------- -------- -------- -------- ................\n" -" 10000fa8 -------- -------- -------- -------- ................\n" -" 10000fb8 -------- -------- -------- -------- ................\n" -" 10000fc8 -------- -------- -------- -------- ................\n" -" 10000fd8 -------- -------- -------- -------- ................\n" -" 10000fe8 -------- -------- -------- -------- ................\n" -" 10000ff8 -------- -------- 7b7a7978 7f7e7d7c ........xyz{|}~.\n" -" 10001008 83828180 87868584 8b8a8988 8f8e8d8c ................\n" -" 10001018 93929190 97969594 9b9a9998 9f9e9d9c ................\n" -" 10001028 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................\n" -" 10001038 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................\n" -" 10001048 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................\n" -" 10001058 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................\n" -" 10001068 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................\n" -" 10001078 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................\n"; +R"( 10000f80 -------- -------- -------- -------- ................ + 10000f90 -------- -------- -------- -------- ................ + 10000fa0 -------- -------- -------- -------- ................ + 10000fb0 -------- -------- -------- -------- ................ + 10000fc0 -------- -------- -------- -------- ................ + 10000fd0 -------- -------- -------- -------- ................ + 10000fe0 -------- -------- -------- -------- ................ + 10000ff0 -------- -------- -------- -------- ................ + 10001000 83828180 87868584 8b8a8988 8f8e8d8c ................ + 10001010 93929190 97969594 9b9a9998 9f9e9d9c ................ + 10001020 a3a2a1a0 a7a6a5a4 abaaa9a8 afaeadac ................ + 10001030 b3b2b1b0 b7b6b5b4 bbbab9b8 bfbebdbc ................ + 10001040 c3c2c1c0 c7c6c5c4 cbcac9c8 cfcecdcc ................ + 10001050 d3d2d1d0 d7d6d5d4 dbdad9d8 dfdedddc ................ + 10001060 e3e2e1e0 e7e6e5e4 ebeae9e8 efeeedec ................ + 10001070 f3f2f1f0 f7f6f5f4 fbfaf9f8 fffefdfc ................ +)"; #endif ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); @@ -684,44 +629,7 @@ TEST_F(DumpMemoryTest, first_read_empty_next_page_out_of_range) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - const char* expected_dump = \ -"\nmemory near r4:\n" -#if defined(__LP64__) -" 0000000010000000 ---------------- ---------------- ................\n" -" 0000000010000010 ---------------- ---------------- ................\n" -" 0000000010000020 ---------------- ---------------- ................\n" -" 0000000010000030 ---------------- ---------------- ................\n" -" 0000000010000040 ---------------- ---------------- ................\n" -" 0000000010000050 ---------------- ---------------- ................\n" -" 0000000010000060 ---------------- ---------------- ................\n" -" 0000000010000070 ---------------- ---------------- ................\n" -" 0000000010000080 ---------------- ---------------- ................\n" -" 0000000010000090 ---------------- ---------------- ................\n" -" 00000000100000a0 ---------------- ---------------- ................\n" -" 00000000100000b0 ---------------- ---------------- ................\n" -" 00000000100000c0 ---------------- ---------------- ................\n" -" 00000000100000d0 ---------------- ---------------- ................\n" -" 00000000100000e0 ---------------- ---------------- ................\n" -" 00000000100000f0 ---------------- ---------------- ................\n"; -#else -" 10000000 -------- -------- -------- -------- ................\n" -" 10000010 -------- -------- -------- -------- ................\n" -" 10000020 -------- -------- -------- -------- ................\n" -" 10000030 -------- -------- -------- -------- ................\n" -" 10000040 -------- -------- -------- -------- ................\n" -" 10000050 -------- -------- -------- -------- ................\n" -" 10000060 -------- -------- -------- -------- ................\n" -" 10000070 -------- -------- -------- -------- ................\n" -" 10000080 -------- -------- -------- -------- ................\n" -" 10000090 -------- -------- -------- -------- ................\n" -" 100000a0 -------- -------- -------- -------- ................\n" -" 100000b0 -------- -------- -------- -------- ................\n" -" 100000c0 -------- -------- -------- -------- ................\n" -" 100000d0 -------- -------- -------- -------- ................\n" -" 100000e0 -------- -------- -------- -------- ................\n" -" 100000f0 -------- -------- -------- -------- ................\n"; -#endif - ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); + ASSERT_STREQ("", tombstone_contents.c_str()); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); @@ -744,44 +652,7 @@ TEST_F(DumpMemoryTest, first_read_empty_next_page_out_of_range_fence_post) { std::string tombstone_contents; ASSERT_TRUE(lseek(log_.tfd, 0, SEEK_SET) == 0); ASSERT_TRUE(android::base::ReadFdToString(log_.tfd, &tombstone_contents)); - const char* expected_dump = \ -"\nmemory near r4:\n" -#if defined(__LP64__) -" 0000000010000f00 ---------------- ---------------- ................\n" -" 0000000010000f10 ---------------- ---------------- ................\n" -" 0000000010000f20 ---------------- ---------------- ................\n" -" 0000000010000f30 ---------------- ---------------- ................\n" -" 0000000010000f40 ---------------- ---------------- ................\n" -" 0000000010000f50 ---------------- ---------------- ................\n" -" 0000000010000f60 ---------------- ---------------- ................\n" -" 0000000010000f70 ---------------- ---------------- ................\n" -" 0000000010000f80 ---------------- ---------------- ................\n" -" 0000000010000f90 ---------------- ---------------- ................\n" -" 0000000010000fa0 ---------------- ---------------- ................\n" -" 0000000010000fb0 ---------------- ---------------- ................\n" -" 0000000010000fc0 ---------------- ---------------- ................\n" -" 0000000010000fd0 ---------------- ---------------- ................\n" -" 0000000010000fe0 ---------------- ---------------- ................\n" -" 0000000010000ff0 ---------------- ---------------- ................\n"; -#else -" 10000f00 -------- -------- -------- -------- ................\n" -" 10000f10 -------- -------- -------- -------- ................\n" -" 10000f20 -------- -------- -------- -------- ................\n" -" 10000f30 -------- -------- -------- -------- ................\n" -" 10000f40 -------- -------- -------- -------- ................\n" -" 10000f50 -------- -------- -------- -------- ................\n" -" 10000f60 -------- -------- -------- -------- ................\n" -" 10000f70 -------- -------- -------- -------- ................\n" -" 10000f80 -------- -------- -------- -------- ................\n" -" 10000f90 -------- -------- -------- -------- ................\n" -" 10000fa0 -------- -------- -------- -------- ................\n" -" 10000fb0 -------- -------- -------- -------- ................\n" -" 10000fc0 -------- -------- -------- -------- ................\n" -" 10000fd0 -------- -------- -------- -------- ................\n" -" 10000fe0 -------- -------- -------- -------- ................\n" -" 10000ff0 -------- -------- -------- -------- ................\n"; -#endif - ASSERT_STREQ(expected_dump, tombstone_contents.c_str()); + ASSERT_STREQ("", tombstone_contents.c_str()); // Verify that the log buf is empty, and no error messages. ASSERT_STREQ("", getFakeLogBuf().c_str()); diff --git a/debuggerd/libdebuggerd/test/tombstone_test.cpp b/debuggerd/libdebuggerd/test/tombstone_test.cpp index aec8c60308..b42d70ce83 100644 --- a/debuggerd/libdebuggerd/test/tombstone_test.cpp +++ b/debuggerd/libdebuggerd/test/tombstone_test.cpp @@ -359,13 +359,6 @@ TEST_F(TombstoneTest, dump_thread_info_uid) { ASSERT_STREQ(expected.c_str(), amfd_data_.c_str()); } -TEST_F(TombstoneTest, dump_timestamp) { - setenv("TZ", "UTC", 1); - tzset(); - dump_timestamp(&log_, 0); - ASSERT_STREQ("Timestamp: 1970-01-01 00:00:00+0000\n", amfd_data_.c_str()); -} - class GwpAsanCrashDataTest : public GwpAsanCrashData { public: GwpAsanCrashDataTest( diff --git a/debuggerd/libdebuggerd/tombstone.cpp b/debuggerd/libdebuggerd/tombstone.cpp index ab65dd15a1..7af99c94c1 100644 --- a/debuggerd/libdebuggerd/tombstone.cpp +++ b/debuggerd/libdebuggerd/tombstone.cpp @@ -58,6 +58,7 @@ #include "libdebuggerd/open_files_list.h" #include "libdebuggerd/scudo.h" #include "libdebuggerd/utility.h" +#include "util.h" #include "gwp_asan/common.h" #include "gwp_asan/crash_handler.h" @@ -80,15 +81,6 @@ static void dump_header_info(log_t* log) { _LOG(log, logtype::HEADER, "ABI: '%s'\n", ABI_STRING); } -static void dump_timestamp(log_t* log, time_t time) { - struct tm tm; - localtime_r(&time, &tm); - - char buf[strlen("1970-01-01 00:00:00+0830") + 1]; - strftime(buf, sizeof(buf), "%F %T%z", &tm); - _LOG(log, logtype::HEADER, "Timestamp: %s\n", buf); -} - static std::string get_stack_overflow_cause(uint64_t fault_addr, uint64_t sp, unwindstack::Maps* maps) { static constexpr uint64_t kMaxDifferenceBytes = 256; @@ -182,12 +174,8 @@ static void dump_signal_info(log_t* log, const ThreadInfo& thread_info, } static void dump_thread_info(log_t* log, const ThreadInfo& thread_info) { - // Blacklist logd, logd.reader, logd.writer, logd.auditd, logd.control ... - // TODO: Why is this controlled by thread name? - if (thread_info.thread_name == "logd" || - android::base::StartsWith(thread_info.thread_name, "logd.")) { - log->should_retrieve_logcat = false; - } + // Don't try to collect logs from the threads that implement the logging system itself. + if (thread_info.uid == AID_LOGD) log->should_retrieve_logcat = false; _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()); @@ -507,10 +495,9 @@ static void dump_log_file(log_t* log, pid_t pid, const char* filename, unsigned // (although in this case the pid is redundant). char timeBuf[32]; time_t sec = static_cast<time_t>(log_entry.entry.sec); - struct tm tmBuf; - struct tm* ptm; - ptm = localtime_r(&sec, &tmBuf); - strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", ptm); + tm tm; + localtime_r(&sec, &tm); + strftime(timeBuf, sizeof(timeBuf), "%m-%d %H:%M:%S", &tm); char* msg = log_entry.msg(); if (msg == nullptr) { @@ -571,23 +558,20 @@ void engrave_tombstone_ucontext(int tombstone_fd, uint64_t abort_msg_address, si log.tfd = tombstone_fd; log.amfd_data = nullptr; - char thread_name[16]; - char process_name[128]; - - read_with_default("/proc/self/comm", thread_name, sizeof(thread_name), "<unknown>"); - read_with_default("/proc/self/cmdline", process_name, sizeof(process_name), "<unknown>"); + std::string thread_name = get_thread_name(tid); + std::string process_name = get_process_name(pid); std::unique_ptr<unwindstack::Regs> regs( unwindstack::Regs::CreateFromUcontext(unwindstack::Regs::CurrentArch(), ucontext)); std::map<pid_t, ThreadInfo> threads; - threads[gettid()] = ThreadInfo{ + threads[tid] = ThreadInfo{ .registers = std::move(regs), .uid = uid, .tid = tid, - .thread_name = thread_name, + .thread_name = thread_name.c_str(), .pid = pid, - .process_name = process_name, + .process_name = process_name.c_str(), .siginfo = siginfo, }; @@ -606,8 +590,8 @@ void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder, const std::map<pid_t, ThreadInfo>& threads, pid_t target_thread, const ProcessInfo& process_info, OpenFilesList* open_files, std::string* amfd_data) { - // don't copy log messages to tombstone unless this is a dev device - bool want_logs = android::base::GetBoolProperty("ro.debuggable", false); + // Don't copy log messages to tombstone unless this is a development device. + bool want_logs = GetBoolProperty("ro.debuggable", false); log_t log; log.current_tid = target_thread; @@ -617,7 +601,7 @@ void engrave_tombstone(unique_fd output_fd, unwindstack::Unwinder* unwinder, _LOG(&log, logtype::HEADER, "*** *** *** *** *** *** *** *** *** *** *** *** *** *** *** ***\n"); dump_header_info(&log); - dump_timestamp(&log, time(nullptr)); + _LOG(&log, logtype::HEADER, "Timestamp: %s\n", get_timestamp().c_str()); auto it = threads.find(target_thread); if (it == threads.end()) { diff --git a/debuggerd/libdebuggerd/utility.cpp b/debuggerd/libdebuggerd/utility.cpp index c8a3431b70..4e6df09c9a 100644 --- a/debuggerd/libdebuggerd/utility.cpp +++ b/debuggerd/libdebuggerd/utility.cpp @@ -44,7 +44,6 @@ using android::base::unique_fd; -// Whitelist output desired in the logcat output. bool is_allowed_in_logcat(enum logtype ltype) { if ((ltype == HEADER) || (ltype == REGISTERS) @@ -129,24 +128,23 @@ void _VLOG(log_t* log, enum logtype ltype, const char* fmt, va_list ap) { #define MEMORY_BYTES_PER_LINE 16 void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const std::string& label) { - // Align the address to sizeof(long) and start 32 bytes before the address. - addr &= ~(sizeof(long) - 1); + // Align the address to the number of bytes per line to avoid confusing memory tag output if + // memory is tagged and we start from a misaligned address. Start 32 bytes before the address. + addr &= ~(MEMORY_BYTES_PER_LINE - 1); if (addr >= 4128) { addr -= 32; } - // Don't bother if the address looks too low, or looks too high. - if (addr < 4096 || -#if defined(__LP64__) - addr > 0x4000000000000000UL - MEMORY_BYTES_TO_DUMP) { -#else - addr > 0xffff0000 - MEMORY_BYTES_TO_DUMP) { -#endif + // We don't want the address tag to appear in the addresses in the memory dump. + addr = untag_address(addr); + + // Don't bother if the address would overflow, taking tag bits into account. Note that + // untag_address truncates to 32 bits on 32-bit platforms as a side effect of returning a + // uintptr_t, so this also checks for 32-bit overflow. + if (untag_address(addr + MEMORY_BYTES_TO_DUMP - 1) < addr) { return; } - _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str()); - // Dump 256 bytes uintptr_t data[MEMORY_BYTES_TO_DUMP/sizeof(uintptr_t)]; memset(data, 0, MEMORY_BYTES_TO_DUMP); @@ -187,6 +185,15 @@ void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const s } } + // If we were unable to read anything, it probably means that the register doesn't contain a + // valid pointer. In that case, skip the output for this register entirely rather than emitting 16 + // lines of dashes. + if (bytes == 0) { + return; + } + + _LOG(log, logtype::MEMORY, "\n%s:\n", label.c_str()); + // Dump the code around memory as: // addr contents ascii // 0000000000008d34 ef000000e8bd0090 e1b00000512fff1e ............../Q @@ -197,8 +204,13 @@ void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const s size_t current = 0; size_t total_bytes = start + bytes; for (size_t line = 0; line < MEMORY_BYTES_TO_DUMP / MEMORY_BYTES_PER_LINE; line++) { + uint64_t tagged_addr = addr; + long tag = memory->ReadTag(addr); + if (tag >= 0) { + tagged_addr |= static_cast<uint64_t>(tag) << 56; + } std::string logline; - android::base::StringAppendF(&logline, " %" PRIPTR, addr); + android::base::StringAppendF(&logline, " %" PRIPTR, tagged_addr); addr += MEMORY_BYTES_PER_LINE; std::string ascii; @@ -226,23 +238,6 @@ void dump_memory(log_t* log, unwindstack::Memory* memory, uint64_t addr, const s } } -void read_with_default(const char* path, char* buf, size_t len, const char* default_value) { - unique_fd fd(open(path, O_RDONLY | O_CLOEXEC)); - if (fd != -1) { - int rc = TEMP_FAILURE_RETRY(read(fd.get(), buf, len - 1)); - if (rc != -1) { - buf[rc] = '\0'; - - // Trim trailing newlines. - if (rc > 0 && buf[rc - 1] == '\n') { - buf[rc - 1] = '\0'; - } - return; - } - } - strcpy(buf, default_value); -} - void drop_capabilities() { __user_cap_header_struct capheader; memset(&capheader, 0, sizeof(capheader)); diff --git a/debuggerd/util.cpp b/debuggerd/util.cpp index a37b3b93ba..9d09210f58 100644 --- a/debuggerd/util.cpp +++ b/debuggerd/util.cpp @@ -17,6 +17,7 @@ #include "util.h" #include <sys/socket.h> +#include <time.h> #include <string> #include <utility> @@ -38,3 +39,19 @@ std::string get_thread_name(pid_t tid) { android::base::ReadFileToString(android::base::StringPrintf("/proc/%d/comm", tid), &result); return android::base::Trim(result); } + +std::string get_timestamp() { + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + + tm tm; + localtime_r(&ts.tv_sec, &tm); + + char buf[strlen("1970-01-01 00:00:00.123456789+0830") + 1]; + char* s = buf; + size_t sz = sizeof(buf), n; + n = strftime(s, sz, "%F %H:%M", &tm), s += n, sz -= n; + n = snprintf(s, sz, ":%02d.%09ld", tm.tm_sec, ts.tv_nsec), s += n, sz -= n; + n = strftime(s, sz, "%z", &tm), s += n, sz -= n; + return buf; +} diff --git a/debuggerd/util.h b/debuggerd/util.h index e964423607..07e7e992cc 100644 --- a/debuggerd/util.h +++ b/debuggerd/util.h @@ -23,3 +23,5 @@ std::string get_process_name(pid_t pid); std::string get_thread_name(pid_t tid); + +std::string get_timestamp(); diff --git a/diagnose_usb/diagnose_usb.cpp b/diagnose_usb/diagnose_usb.cpp index 5695ecec5f..35edb5e05d 100644 --- a/diagnose_usb/diagnose_usb.cpp +++ b/diagnose_usb/diagnose_usb.cpp @@ -49,7 +49,7 @@ static std::string GetUdevProblem() { // additionally just to be sure. if (group_member(plugdev_group->gr_gid) || getegid() == plugdev_group->gr_gid) { // The user is in plugdev so the problem is likely with the udev rules. - return "user in plugdev group; are your udev rules wrong?"; + return "missing udev rules? user is in the plugdev group"; } passwd* pwd = getpwuid(getuid()); return android::base::StringPrintf("user %s is not in the plugdev group", diff --git a/fastboot/fastboot.bash b/fastboot/fastboot.bash index cc1366cf4c..406e8b8d78 100644 --- a/fastboot/fastboot.bash +++ b/fastboot/fastboot.bash @@ -109,7 +109,7 @@ _fastboot_cmd_flash() { cur="${COMP_WORDS[COMP_CWORD]}" if [[ $i -eq $COMP_CWORD ]]; then - partitions="boot bootloader dtbo modem odm oem product radio recovery system vbmeta vendor vendor_dlkm" + partitions="boot bootloader dtbo modem odm odm_dlkm oem product radio recovery system vbmeta vendor vendor_dlkm" COMPREPLY=( $(compgen -W "$partitions" -- $cur) ) else _fastboot_util_complete_local_file "${cur}" '!*.img' diff --git a/fastboot/fastboot.cpp b/fastboot/fastboot.cpp index 4ca6a6a695..d33c987704 100644 --- a/fastboot/fastboot.cpp +++ b/fastboot/fastboot.cpp @@ -145,6 +145,7 @@ static Image images[] = { { "dtbo", "dtbo.img", "dtbo.sig", "dtbo", true, ImageType::BootCritical }, { "dts", "dt.img", "dt.sig", "dts", true, ImageType::BootCritical }, { "odm", "odm.img", "odm.sig", "odm", true, ImageType::Normal }, + { "odm_dlkm", "odm_dlkm.img", "odm_dlkm.sig", "odm_dlkm", true, ImageType::Normal }, { "product", "product.img", "product.sig", "product", true, ImageType::Normal }, { "recovery", "recovery.img", "recovery.sig", "recovery", true, ImageType::BootCritical }, { "super", "super.img", "super.sig", "super", true, ImageType::Extra }, diff --git a/fastboot/fuzzy_fastboot/main.cpp b/fastboot/fuzzy_fastboot/main.cpp index e7f785b837..34ab32c12b 100644 --- a/fastboot/fuzzy_fastboot/main.cpp +++ b/fastboot/fuzzy_fastboot/main.cpp @@ -1286,7 +1286,7 @@ TEST_P(UserdataPartition, UnlockErases) { ASSERT_TRUE(PartitionHash(fb.get(), "userdata", &hash_buf, &retcode, &err_msg)) << err_msg; ASSERT_EQ(retcode, 0) << err_msg; - // Sanity check of hash + // Validity check of hash EXPECT_NE(hash_before, hash_buf) << "Writing a random buffer to 'userdata' had the same hash as after erasing it"; SetLockState(true); // Lock the device diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 0ae57870fa..88bb2344c0 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -607,7 +607,7 @@ static void tune_metadata_csum(const std::string& blk_device, const FstabEntry& LINFO << "Enabling ext4 metadata_csum on " << blk_device; - // requires to give last_fsck_time to current to avoid insane time. + // Must give `-T now` to prevent last_fsck_time from growing too large, // otherwise, tune2fs won't enable metadata_csum. const char* tune2fs_args[] = {TUNE2FS_BIN, "-O", "metadata_csum,64bit,extent", "-T", "now", blk_device.c_str()}; diff --git a/fs_mgr/fs_mgr_overlayfs.cpp b/fs_mgr/fs_mgr_overlayfs.cpp index 1fa1aa1042..a7704de696 100644 --- a/fs_mgr/fs_mgr_overlayfs.cpp +++ b/fs_mgr/fs_mgr_overlayfs.cpp @@ -809,15 +809,26 @@ bool fs_mgr_overlayfs_mount_scratch(const std::string& device_path, const std::s entry.fs_type = mnt_type; if ((mnt_type == "f2fs") && !f2fs) entry.fs_type = "ext4"; if ((mnt_type == "ext4") && !ext4) entry.fs_type = "f2fs"; - entry.flags = MS_NOATIME; - if (readonly) { - entry.flags |= MS_RDONLY; - } else { + entry.flags = MS_NOATIME | MS_RDONLY; + auto mounted = true; + if (!readonly) { + if (entry.fs_type == "ext4") { + // check if ext4 de-dupe + entry.flags |= MS_RDONLY; + auto save_errno = errno; + mounted = fs_mgr_do_mount_one(entry) == 0; + if (mounted) { + mounted = !fs_mgr_has_shared_blocks(entry.mount_point, entry.blk_device); + fs_mgr_overlayfs_umount_scratch(); + } + errno = save_errno; + } + entry.flags &= ~MS_RDONLY; fs_mgr_set_blk_ro(device_path, false); } entry.fs_mgr_flags.check = true; auto save_errno = errno; - auto mounted = fs_mgr_do_mount_one(entry) == 0; + if (mounted) mounted = fs_mgr_do_mount_one(entry) == 0; if (!mounted) { if ((entry.fs_type == "f2fs") && ext4) { entry.fs_type = "ext4"; diff --git a/fs_mgr/libdm/Android.bp b/fs_mgr/libdm/Android.bp index 58241b3f83..e4252845c5 100644 --- a/fs_mgr/libdm/Android.bp +++ b/fs_mgr/libdm/Android.bp @@ -42,6 +42,7 @@ cc_library_static { enabled: false, }, }, + ramdisk_available: true, } filegroup { diff --git a/fs_mgr/libfiemap/fiemap_writer.cpp b/fs_mgr/libfiemap/fiemap_writer.cpp index 4dd4bcc14b..621031ada6 100644 --- a/fs_mgr/libfiemap/fiemap_writer.cpp +++ b/fs_mgr/libfiemap/fiemap_writer.cpp @@ -45,7 +45,7 @@ namespace fiemap { using namespace android::dm; -// We cap the maximum number of extents as a sanity measure. +// We cap the maximum number of extents as a robustness measure. static constexpr uint32_t kMaxExtents = 50000; // TODO: Fallback to using fibmap if FIEMAP_EXTENT_MERGED is set. diff --git a/fs_mgr/libfiemap/split_fiemap_writer.cpp b/fs_mgr/libfiemap/split_fiemap_writer.cpp index 12c73979d5..36bb3dfeee 100644 --- a/fs_mgr/libfiemap/split_fiemap_writer.cpp +++ b/fs_mgr/libfiemap/split_fiemap_writer.cpp @@ -266,7 +266,7 @@ bool SplitFiemap::Write(const void* data, uint64_t bytes) { cursor_file_pos_ += bytes_to_write; } - // If we've reached the end of the current file, close it for sanity. + // If we've reached the end of the current file, close it. if (cursor_file_pos_ == file->size()) { cursor_fd_ = {}; } diff --git a/fs_mgr/libfiemap/utility.cpp b/fs_mgr/libfiemap/utility.cpp index bbb0510faf..c1898556e4 100644 --- a/fs_mgr/libfiemap/utility.cpp +++ b/fs_mgr/libfiemap/utility.cpp @@ -139,8 +139,7 @@ bool BlockDeviceToName(uint32_t major, uint32_t minor, std::string* bdev_name) { } *bdev_name = ::android::base::Basename(sysfs_bdev); - // Paranoid sanity check to make sure we just didn't get the - // input in return as-is. + // Check that the symlink doesn't point to itself. if (sysfs_bdev == *bdev_name) { LOG(ERROR) << "Malformed symlink for block device: " << sysfs_bdev; return false; diff --git a/fs_mgr/libfs_avb/avb_ops.cpp b/fs_mgr/libfs_avb/avb_ops.cpp index c192bf572e..46072bb701 100644 --- a/fs_mgr/libfs_avb/avb_ops.cpp +++ b/fs_mgr/libfs_avb/avb_ops.cpp @@ -52,16 +52,16 @@ static AvbIOResult read_from_partition(AvbOps* ops, const char* partition, int64 partition, offset, num_bytes, buffer, out_num_read); } -static AvbIOResult dummy_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED, - size_t rollback_index_location ATTRIBUTE_UNUSED, - uint64_t* out_rollback_index) { +static AvbIOResult no_op_read_rollback_index(AvbOps* ops ATTRIBUTE_UNUSED, + size_t rollback_index_location ATTRIBUTE_UNUSED, + uint64_t* out_rollback_index) { // rollback_index has been checked in bootloader phase. // In user-space, returns the smallest value 0 to pass the check. *out_rollback_index = 0; return AVB_IO_RESULT_OK; } -static AvbIOResult dummy_validate_vbmeta_public_key( +static AvbIOResult no_op_validate_vbmeta_public_key( AvbOps* ops ATTRIBUTE_UNUSED, const uint8_t* public_key_data ATTRIBUTE_UNUSED, size_t public_key_length ATTRIBUTE_UNUSED, const uint8_t* public_key_metadata ATTRIBUTE_UNUSED, @@ -76,8 +76,8 @@ static AvbIOResult dummy_validate_vbmeta_public_key( return AVB_IO_RESULT_OK; } -static AvbIOResult dummy_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED, - bool* out_is_unlocked) { +static AvbIOResult no_op_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED, + bool* out_is_unlocked) { // The function is for bootloader to update the value into // androidboot.vbmeta.device_state in kernel cmdline. // In user-space, returns true as we don't need to update it anymore. @@ -85,9 +85,9 @@ static AvbIOResult dummy_read_is_device_unlocked(AvbOps* ops ATTRIBUTE_UNUSED, return AVB_IO_RESULT_OK; } -static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED, - const char* partition ATTRIBUTE_UNUSED, - char* guid_buf, size_t guid_buf_size) { +static AvbIOResult no_op_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNUSED, + const char* partition ATTRIBUTE_UNUSED, + char* guid_buf, size_t guid_buf_size) { // The function is for bootloader to set the correct UUID // for a given partition in kernel cmdline. // In user-space, returns a faking one as we don't need to update @@ -96,9 +96,9 @@ static AvbIOResult dummy_get_unique_guid_for_partition(AvbOps* ops ATTRIBUTE_UNU return AVB_IO_RESULT_OK; } -static AvbIOResult dummy_get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED, - const char* partition ATTRIBUTE_UNUSED, - uint64_t* out_size_num_byte) { +static AvbIOResult no_op_get_size_of_partition(AvbOps* ops ATTRIBUTE_UNUSED, + const char* partition ATTRIBUTE_UNUSED, + uint64_t* out_size_num_byte) { // The function is for bootloader to load entire content of AVB HASH partitions. // In user-space, returns 0 as we only need to set up AVB HASHTHREE partitions. *out_size_num_byte = 0; @@ -123,15 +123,15 @@ 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(). // Other I/O operations are only required in bootloader but not in - // user-space so we set them as dummy operations. Also zero the entire + // user-space so we set them as no-op operations. Also zero the entire // struct so operations added in the future will be set to NULL. memset(&avb_ops_, 0, sizeof(AvbOps)); avb_ops_.read_from_partition = read_from_partition; - avb_ops_.read_rollback_index = dummy_read_rollback_index; - avb_ops_.validate_vbmeta_public_key = dummy_validate_vbmeta_public_key; - avb_ops_.read_is_device_unlocked = dummy_read_is_device_unlocked; - avb_ops_.get_unique_guid_for_partition = dummy_get_unique_guid_for_partition; - avb_ops_.get_size_of_partition = dummy_get_size_of_partition; + avb_ops_.read_rollback_index = no_op_read_rollback_index; + avb_ops_.validate_vbmeta_public_key = no_op_validate_vbmeta_public_key; + avb_ops_.read_is_device_unlocked = no_op_read_is_device_unlocked; + avb_ops_.get_unique_guid_for_partition = no_op_get_unique_guid_for_partition; + avb_ops_.get_size_of_partition = no_op_get_size_of_partition; // Sets user_data for GetInstanceFromAvbOps() to convert it back to FsManagerAvbOps. avb_ops_.user_data = this; diff --git a/fs_mgr/libfs_avb/fs_avb.cpp b/fs_mgr/libfs_avb/fs_avb.cpp index 5d504ab0dc..49333a13b2 100644 --- a/fs_mgr/libfs_avb/fs_avb.cpp +++ b/fs_mgr/libfs_avb/fs_avb.cpp @@ -226,7 +226,7 @@ AvbUniquePtr AvbHandle::LoadAndVerifyVbmeta( return nullptr; } - // Sanity check here because we have to use vbmeta_images_[0] below. + // Validity check here because we have to use vbmeta_images_[0] below. if (avb_handle->vbmeta_images_.size() < 1) { LERROR << "LoadAndVerifyVbmetaByPartition failed, no vbmeta loaded"; return nullptr; @@ -405,11 +405,11 @@ AvbUniquePtr AvbHandle::Open() { // - 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 + // Could only occur in a chained vbmeta. Because we have *no-op* 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 + // The following verify result won't happen, because the *no-op* 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 diff --git a/fs_mgr/libfs_avb/tests/util_test.cpp b/fs_mgr/libfs_avb/tests/util_test.cpp index 5c388aaeb3..a52a00d276 100644 --- a/fs_mgr/libfs_avb/tests/util_test.cpp +++ b/fs_mgr/libfs_avb/tests/util_test.cpp @@ -222,7 +222,7 @@ TEST(BasicUtilTest, ListFiles) { base::FilePath test_dir; ASSERT_TRUE(base::CreateTemporaryDirInDir(tmp_dir, "list-file-tests.", &test_dir)); - // Generates dummy files to list. + // Generates test files to list. base::FilePath file_path_1 = test_dir.Append("1.txt"); ASSERT_TRUE(base::WriteFile(file_path_1, "1", 1)); base::FilePath file_path_2 = test_dir.Append("2.txt"); @@ -253,7 +253,7 @@ TEST(BasicUtilTest, ListFilesShouldDiscardSymlink) { base::FilePath test_dir; ASSERT_TRUE(base::CreateTemporaryDirInDir(tmp_dir, "list-file-tests.", &test_dir)); - // Generates dummy files to list. + // Generates test files to list. base::FilePath file_path_1 = test_dir.Append("1.txt"); ASSERT_TRUE(base::WriteFile(file_path_1, "1", 1)); base::FilePath file_path_2 = test_dir.Append("2.txt"); @@ -281,7 +281,7 @@ TEST(BasicUtilTest, ListFilesOpenDirFailure) { base::FilePath tmp_dir; ASSERT_TRUE(GetTempDir(&tmp_dir)); - // Generates dummy files to list. + // Generates test files to list. base::FilePath no_such_dir = tmp_dir.Append("not_such_dir"); auto fail = ListFiles(no_such_dir.value()); diff --git a/fs_mgr/liblp/builder_test.cpp b/fs_mgr/liblp/builder_test.cpp index a21e09e4f2..e4b617a51b 100644 --- a/fs_mgr/liblp/builder_test.cpp +++ b/fs_mgr/liblp/builder_test.cpp @@ -234,7 +234,7 @@ TEST_F(BuilderTest, InternalPartitionAlignment) { EXPECT_EQ(lba, aligned_lba); } - // Sanity check one extent. + // Check one extent. EXPECT_EQ(exported->extents.back().target_data, 3072); } diff --git a/fs_mgr/liblp/device_test.cpp b/fs_mgr/liblp/device_test.cpp index 6af9d94db7..236fd8dd3b 100644 --- a/fs_mgr/liblp/device_test.cpp +++ b/fs_mgr/liblp/device_test.cpp @@ -47,7 +47,7 @@ TEST_F(DeviceTest, BlockDeviceInfo) { BlockDeviceInfo device_info; ASSERT_TRUE(opener.GetInfo(fs_mgr_get_super_partition_name(), &device_info)); - // Sanity check that the device doesn't give us some weird inefficient + // Check that the device doesn't give us some weird inefficient // alignment. EXPECT_EQ(device_info.alignment % LP_SECTOR_SIZE, 0); EXPECT_EQ(device_info.logical_block_size % LP_SECTOR_SIZE, 0); diff --git a/fs_mgr/liblp/partition_opener.cpp b/fs_mgr/liblp/partition_opener.cpp index 1d4db85250..3d3dde6f2f 100644 --- a/fs_mgr/liblp/partition_opener.cpp +++ b/fs_mgr/liblp/partition_opener.cpp @@ -49,7 +49,7 @@ std::string GetPartitionAbsolutePath(const std::string& path) { // Dynamic System Update is installed to an sdcard, which won't be in // the boot device list. // - // We whitelist because most devices in /dev/block are not valid for + // mmcblk* is allowed because most devices in /dev/block are not valid for // storing fiemaps. if (android::base::StartsWith(path, "mmcblk")) { return "/dev/block/" + path; diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp index e6fd9f72a4..24ccc0f9de 100644 --- a/fs_mgr/liblp/reader.cpp +++ b/fs_mgr/liblp/reader.cpp @@ -174,7 +174,7 @@ static bool ReadMetadataHeader(Reader* reader, LpMetadata* metadata) { return false; } - // Do basic sanity checks before computing the checksum. + // Do basic validity checks before computing the checksum. if (header.magic != LP_METADATA_HEADER_MAGIC) { LERROR << "Logical partition metadata has invalid magic value."; return false; @@ -255,7 +255,7 @@ static std::unique_ptr<LpMetadata> ParseMetadata(const LpMetadataGeometry& geome LpMetadataHeader& header = metadata->header; - // Sanity check the table size. + // Check the table size. if (header.tables_size > geometry.metadata_max_size) { LERROR << "Invalid partition metadata header table size."; return nullptr; diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp index 8bf1ee9232..2708efa156 100644 --- a/fs_mgr/liblp/writer.cpp +++ b/fs_mgr/liblp/writer.cpp @@ -81,8 +81,8 @@ std::string SerializeMetadata(const LpMetadata& input) { return header_blob + tables; } -// Perform sanity checks so we don't accidentally overwrite valid metadata -// with potentially invalid metadata, or random partition data with metadata. +// Perform checks so we don't accidentally overwrite valid metadata with +// potentially invalid metadata, or random partition data with metadata. static bool ValidateAndSerializeMetadata([[maybe_unused]] const IPartitionOpener& opener, const LpMetadata& metadata, const std::string& slot_suffix, std::string* blob) { diff --git a/fs_mgr/libsnapshot/Android.bp b/fs_mgr/libsnapshot/Android.bp index 95301ff71a..eaef180377 100644 --- a/fs_mgr/libsnapshot/Android.bp +++ b/fs_mgr/libsnapshot/Android.bp @@ -310,3 +310,36 @@ cc_test { auto_gen_config: true, require_root: true, } + +cc_defaults { + name: "snapuserd_defaults", + srcs: [ + "snapuserd.cpp", + ], + + cflags: [ + "-Wall", + "-Werror" + ], + + static_libs: [ + "libbase", + "liblog", + "libdm", + ], +} + +cc_binary { + name: "snapuserd", + defaults: ["snapuserd_defaults"], +} + +cc_binary { + name: "snapuserd_ramdisk", + stem: "snapuserd", + defaults: ["snapuserd_defaults"], + + ramdisk: true, + static_executable: true, + system_shared_libs: [], +} diff --git a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h index 3c2c77683b..a4a31507ee 100644 --- a/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h +++ b/fs_mgr/libsnapshot/include/libsnapshot/snapshot.h @@ -553,9 +553,8 @@ class SnapshotManager final : public ISnapshotManager { // This should only be called in recovery. bool UnmapAllPartitions(); - // Sanity check no snapshot overflows. Note that this returns false negatives if the snapshot - // overflows, then is remapped and not written afterwards. Hence, the function may only serve - // as a sanity check. + // Check no snapshot overflows. Note that this returns false negatives if the snapshot + // overflows, then is remapped and not written afterwards. bool EnsureNoOverflowSnapshot(LockedFile* lock); enum class Slot { Unknown, Source, Target }; diff --git a/fs_mgr/libsnapshot/snapshot.cpp b/fs_mgr/libsnapshot/snapshot.cpp index 7488bdaca8..b49f99ea45 100644 --- a/fs_mgr/libsnapshot/snapshot.cpp +++ b/fs_mgr/libsnapshot/snapshot.cpp @@ -300,9 +300,9 @@ bool SnapshotManager::CreateSnapshot(LockedFile* lock, SnapshotStatus* status) { LOG(ERROR) << "SnapshotStatus has no name."; return false; } - // Sanity check these sizes. Like liblp, we guarantee the partition size - // is respected, which means it has to be sector-aligned. (This guarantee - // is useful for locating avb footers correctly). The COW file size, however, + // Check these sizes. Like liblp, we guarantee the partition size is + // respected, which means it has to be sector-aligned. (This guarantee is + // useful for locating avb footers correctly). The COW file size, however, // can be arbitrarily larger than specified, so we can safely round it up. if (status->device_size() % kSectorSize != 0) { LOG(ERROR) << "Snapshot " << status->name() @@ -351,7 +351,6 @@ Return SnapshotManager::CreateCowImage(LockedFile* lock, const std::string& name } // The COW file size should have been rounded up to the nearest sector in CreateSnapshot. - // Sanity check this. if (status.cow_file_size() % kSectorSize != 0) { LOG(ERROR) << "Snapshot " << name << " COW file size is not a multiple of the sector size: " << status.cow_file_size(); diff --git a/fs_mgr/libsnapshot/snapshot_fuzz.cpp b/fs_mgr/libsnapshot/snapshot_fuzz.cpp index 5b145c31f2..aced3edf58 100644 --- a/fs_mgr/libsnapshot/snapshot_fuzz.cpp +++ b/fs_mgr/libsnapshot/snapshot_fuzz.cpp @@ -141,7 +141,7 @@ SNAPSHOT_FUZZ_FUNCTION(RecoveryCreateSnapshotDevicesWithMetadata, CreateResult, const RecoveryCreateSnapshotDevicesArgs& args) { std::unique_ptr<AutoDevice> device; if (args.has_metadata_device_object()) { - device = std::make_unique<DummyAutoDevice>(args.metadata_mounted()); + device = std::make_unique<NoOpAutoDevice>(args.metadata_mounted()); } return snapshot->RecoveryCreateSnapshotDevices(device); } diff --git a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h index fa327b8a74..5319e69de0 100644 --- a/fs_mgr/libsnapshot/snapshot_fuzz_utils.h +++ b/fs_mgr/libsnapshot/snapshot_fuzz_utils.h @@ -35,9 +35,9 @@ namespace android::snapshot { class AutoMemBasedDir; class SnapshotFuzzDeviceInfo; -class DummyAutoDevice : public AutoDevice { +class NoOpAutoDevice : public AutoDevice { public: - DummyAutoDevice(bool mounted) : AutoDevice(mounted ? "dummy" : "") {} + NoOpAutoDevice(bool mounted) : AutoDevice(mounted ? "no_op" : "") {} }; struct SnapshotTestModule { diff --git a/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp b/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp index 051584c341..17a0c96a89 100644 --- a/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp +++ b/fs_mgr/libsnapshot/snapshot_metadata_updater.cpp @@ -39,6 +39,8 @@ namespace snapshot { SnapshotMetadataUpdater::SnapshotMetadataUpdater(MetadataBuilder* builder, uint32_t target_slot, const DeltaArchiveManifest& manifest) : builder_(builder), target_suffix_(SlotSuffixForSlotNumber(target_slot)) { + partial_update_ = manifest.partial_update(); + if (!manifest.has_dynamic_partition_metadata()) { return; } @@ -63,7 +65,6 @@ SnapshotMetadataUpdater::SnapshotMetadataUpdater(MetadataBuilder* builder, uint3 } } - partial_update_ = manifest.partial_update(); } bool SnapshotMetadataUpdater::ShrinkPartitions() const { @@ -173,9 +174,9 @@ bool SnapshotMetadataUpdater::DeleteGroups() const { if (iter != groups_.end()) { continue; } - // Update package metadata doesn't have this group. Before deleting it, sanity check that it - // doesn't have any partitions left. Update metadata shouldn't assign any partitions to this - // group, so all partitions that originally belong to this group should be moved by + // Update package metadata doesn't have this group. Before deleting it, check that it + // doesn't have any partitions left. Update metadata shouldn't assign any partitions to + // this group, so all partitions that originally belong to this group should be moved by // MovePartitionsToDefault at this point. auto existing_partitions_in_group = builder_->ListPartitionsInGroup(existing_group_name); if (!existing_partitions_in_group.empty()) { diff --git a/fs_mgr/libsnapshot/snapuserd.cpp b/fs_mgr/libsnapshot/snapuserd.cpp new file mode 100644 index 0000000000..a6ff4fd046 --- /dev/null +++ b/fs_mgr/libsnapshot/snapuserd.cpp @@ -0,0 +1,126 @@ +/* + * Copyright (C) 2020 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 <linux/types.h> + +#include <android-base/file.h> +#include <android-base/logging.h> +#include <android-base/stringprintf.h> +#include <android-base/unique_fd.h> +#include <libdm/dm.h> + +using android::base::unique_fd; + +#define DM_USER_MAP_READ 0 +#define DM_USER_MAP_WRITE 1 + +struct dm_user_message { + __u64 seq; + __u64 type; + __u64 flags; + __u64 sector; + __u64 len; + __u8 buf[]; +}; + +using namespace android::dm; + +static int daemon_main(const std::string& device) { + unique_fd block_fd(open(device.c_str(), O_RDWR)); + if (block_fd < 0) { + PLOG(ERROR) << "Unable to open " << device; + return 1; + } + + unique_fd ctrl_fd(open("/dev/dm-user", O_RDWR)); + if (ctrl_fd < 0) { + PLOG(ERROR) << "Unable to open /dev/dm-user"; + return 1; + } + + size_t buf_size = 1UL << 16; + auto buf = std::make_unique<char>(buf_size); + + /* Just keeps pumping messages between userspace and the kernel. We won't + * actually be doing anything, but the sequence numbers line up so it'll at + * least make forward progress. */ + while (true) { + struct dm_user_message* msg = (struct dm_user_message*)buf.get(); + + memset(buf.get(), 0, buf_size); + + ssize_t readed = read(ctrl_fd.get(), buf.get(), buf_size); + if (readed < 0) { + PLOG(ERROR) << "Control read failed, trying with more space"; + buf_size *= 2; + buf = std::make_unique<char>(buf_size); + continue; + } + + LOG(DEBUG) << android::base::StringPrintf("read() from dm-user returned %d bytes:", + (int)readed); + LOG(DEBUG) << android::base::StringPrintf(" msg->seq: 0x%016llx", msg->seq); + LOG(DEBUG) << android::base::StringPrintf(" msg->type: 0x%016llx", msg->type); + LOG(DEBUG) << android::base::StringPrintf(" msg->flags: 0x%016llx", msg->flags); + LOG(DEBUG) << android::base::StringPrintf(" msg->sector: 0x%016llx", msg->sector); + LOG(DEBUG) << android::base::StringPrintf(" msg->len: 0x%016llx", msg->len); + + switch (msg->type) { + case DM_USER_MAP_READ: { + LOG(DEBUG) << android::base::StringPrintf( + "Responding to read of sector %lld with %lld bytes data", msg->sector, + msg->len); + + if ((sizeof(*msg) + msg->len) > buf_size) { + auto old_buf = std::move(buf); + buf_size = sizeof(*msg) + msg->len; + buf = std::make_unique<char>(buf_size); + memcpy(buf.get(), old_buf.get(), sizeof(*msg)); + msg = (struct dm_user_message*)buf.get(); + } + + if (lseek(block_fd.get(), msg->sector * 512, SEEK_SET) < 0) { + PLOG(ERROR) << "lseek failed: " << device; + return 7; + } + if (!android::base::ReadFully(block_fd.get(), msg->buf, msg->len)) { + PLOG(ERROR) << "read failed: " << device; + return 7; + } + + if (!android::base::WriteFully(ctrl_fd.get(), buf.get(), sizeof(*msg) + msg->len)) { + PLOG(ERROR) << "write control failed"; + return 3; + } + break; + } + + case DM_USER_MAP_WRITE: + abort(); + break; + } + + LOG(DEBUG) << "read() finished, next message"; + } + + return 0; +} + +int main([[maybe_unused]] int argc, char** argv) { + android::base::InitLogging(argv, &android::base::KernelLogger); + daemon_main(argv[1]); + return 0; +} diff --git a/fs_mgr/tests/adb-remount-test.sh b/fs_mgr/tests/adb-remount-test.sh index 82c42629d8..d56f7f25af 100755 --- a/fs_mgr/tests/adb-remount-test.sh +++ b/fs_mgr/tests/adb-remount-test.sh @@ -15,13 +15,17 @@ USAGE="USAGE: `basename ${0}` [--help] [--serial <SerialNumber>] [options] adb remount tests ---color Dress output with highlighting colors ---help This help ---no-wait-screen Do not wait for display screen to settle ---print-time Report the test duration ---serial Specify device (must if multiple are present) ---wait-adb <duration> adb wait timeout ---wait-fastboot <duration> fastboot wait timeout +-c --color Dress output with highlighting colors +-h --help This help +-D --no-wait-screen Do not wait for display screen to settle +-t --print-time Report the test duration +-s --serial Specify device (must if multiple are present)" +if [ -n "`which timeout`" ]; then + USAGE="${USAGE} +-a --wait-adb <duration> adb wait timeout +-f --wait-fastboot <duration> fastboot wait timeout" +fi +USAGE="${USAGE} Conditions: - Must be a userdebug build. @@ -46,10 +50,10 @@ TAB="`echo | tr '\n' '\t'`" ESCAPE="`echo | tr '\n' '\033'`" # A _real_ embedded carriage return character CR="`echo | tr '\n' '\r'`" -GREEN="${ESCAPE}[38;5;40m" -RED="${ESCAPE}[38;5;196m" -ORANGE="${ESCAPE}[38;5;255:165:0m" -BLUE="${ESCAPE}[35m" +GREEN="${ESCAPE}[32m" +RED="${ESCAPE}[31m" +YELLOW="${ESCAPE}[33m" +BLUE="${ESCAPE}[34m" NORMAL="${ESCAPE}[0m" TMPDIR=${TMPDIR:-/tmp} print_time=false @@ -72,7 +76,7 @@ inFastboot() { if [ -n "${ANDROID_SERIAL}" ]; then grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null else - wc -l | grep '^1$' >/dev/null + wc -l | grep "^[${SPACE}${TAB}]*1\$" >/dev/null fi } @@ -85,7 +89,7 @@ inAdb() { if [ -n "${ANDROID_SERIAL}" ]; then grep "^${ANDROID_SERIAL}[${SPACE}${TAB}]" > /dev/null else - wc -l | grep '^1$' >/dev/null + wc -l | grep "^[${SPACE}${TAB}]*1\$" >/dev/null fi } @@ -100,7 +104,7 @@ inRecovery() { grep "^${ANDROID_SERIAL}[${SPACE}${TAB}][${SPACE}${TAB}]*recovery\$" >/dev/null return ${?} fi - if echo "${list}" | wc -l | grep '^1$' >/dev/null; then + if echo "${list}" | wc -l | grep "^[${SPACE}${TAB}]*1\$" >/dev/null; then echo "${list}" | grep "[${SPACE}${TAB}]recovery\$" >/dev/null return ${?} @@ -143,7 +147,7 @@ adb_logcat() { adb logcat "${@}" </dev/null | tr -d '\r' | grep -v 'logd : logdr: UID=' | - sed -e '${/------- beginning of kernel/d}' -e 's/^[0-1][0-9]-[0-3][0-9] //' + sed -e '${ /------- beginning of kernel/d }' -e 's/^[0-1][0-9]-[0-3][0-9] //' } [ "USAGE: avc_check >/dev/stderr @@ -160,7 +164,7 @@ avc_check() { if [ -z "${L}" ]; then return fi - echo "${ORANGE}[ WARNING ]${NORMAL} unlabeled sepolicy violations:" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} unlabeled sepolicy violations:" >&2 echo "${L}" | sed "s/^/${INDENT}/" >&2 } @@ -284,7 +288,7 @@ adb_wait() { local start=`date +%s` local duration= local ret - if [ -n "${1}" ]; then + if [ -n "${1}" -a -n "`which timeout`" ]; then USB_DEVICE=`usb_devnum --next` duration=`format_duration ${1}` echo -n ". . . waiting ${duration}" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}" @@ -299,7 +303,7 @@ adb_wait() { if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then local active_slot=`get_active_slot` if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" >&2 fi fi local end=`date +%s` @@ -359,18 +363,22 @@ usb_status() { echo "(In adb mode `adb_user`)" else echo "(USB stack borken for ${USB_ADDRESS})" - USB_DEVICE=`usb_devnum` - if [ -n "${USB_DEVICE}" ]; then - echo "# lsusb -v -s ${USB_DEVICE#dev}" - local D=`lsusb -v -s ${USB_DEVICE#dev} 2>&1` - if [ -n "${D}" ]; then - echo "${D}" - else - lsusb -v + if [ -n "`which usb_devnum`" ]; then + USB_DEVICE=`usb_devnum` + if [ -n "`which lsusb`" ]; then + if [ -n "${USB_DEVICE}" ]; then + echo "# lsusb -v -s ${USB_DEVICE#dev}" + local D=`lsusb -v -s ${USB_DEVICE#dev} 2>&1` + if [ -n "${D}" ]; then + echo "${D}" + else + lsusb -v + fi + else + echo "# lsusb -v (expected device missing)" + lsusb -v + fi fi - else - echo "# lsusb -v (expected device missing)" - lsusb -v fi >&2 fi } @@ -382,7 +390,7 @@ fastboot_wait() { local ret # fastboot has no wait-for-device, but it does an automatic # wait and requires (even a nonsensical) command to do so. - if [ -n "${1}" ]; then + if [ -n "${1}" -a -n "`which timeout`" ]; then USB_DEVICE=`usb_devnum --next` echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}" timeout --preserve-status --signal=KILL ${1} fastboot wait-for-device >/dev/null 2>/dev/null @@ -398,7 +406,7 @@ fastboot_wait() { if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then local active_slot=`get_active_slot` if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" + echo "${YELLOW}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" fi >&2 fi return ${ret} @@ -409,7 +417,7 @@ fastboot_wait() { Returns: waits until the device has returned for recovery or optional timeout" ] recovery_wait() { local ret - if [ -n "${1}" ]; then + if [ -n "${1}" -a -n "`which timeout`" ]; then USB_DEVICE=`usb_devnum --next` echo -n ". . . waiting `format_duration ${1}`" ${ANDROID_SERIAL} ${USB_ADDRESS} ${USB_DEVICE} "${CR}" timeout --preserve-status --signal=KILL ${1} adb wait-for-recovery 2>/dev/null @@ -423,7 +431,7 @@ recovery_wait() { if [ 0 = ${ret} -a -n "${ACTIVE_SLOT}" ]; then local active_slot=`get_active_slot` if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" + echo "${YELLOW}[ WARNING ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" fi >&2 fi return ${ret} @@ -732,6 +740,7 @@ skip_administrative_mounts() { grep -v \ -e "^\(overlay\|tmpfs\|none\|sysfs\|proc\|selinuxfs\|debugfs\|bpf\) " \ -e "^\(binfmt_misc\|cg2_bpf\|pstore\|tracefs\|adb\|mtp\|ptp\|devpts\) " \ + -e "^\(ramdumpfs\) " \ -e " functionfs " \ -e "^\(/data/media\|/dev/block/loop[0-9]*\) " \ -e "^rootfs / rootfs rw," \ @@ -753,13 +762,28 @@ skip_unrelated_mounts() { ## MAINLINE ## -OPTIONS=`getopt --alternative --unquoted \ - --longoptions help,serial:,colour,color,no-colour,no-color \ - --longoptions wait-adb:,wait-fastboot: \ - --longoptions wait-screen,wait-display \ - --longoptions no-wait-screen,no-wait-display \ - --longoptions gtest_print_time,print-time \ - -- "?hs:" ${*}` || +HOSTOS=`uname` +GETOPTS="--alternative --unquoted + --longoptions help,serial:,colour,color,no-colour,no-color + --longoptions wait-adb:,wait-fastboot: + --longoptions wait-screen,wait-display + --longoptions no-wait-screen,no-wait-display + --longoptions gtest_print_time,print-time + --" +if [ "Darwin" = "${HOSTOS}" ]; then + GETOPTS= + USAGE="`echo \"${USAGE}\" | + sed 's/--color/ /g + 1s/--help/-h/ + s/--help/ /g + s/--no-wait-screen/ /g + s/--print-time/ /g + 1s/--serial/-s/ + s/--serial/ /g + s/--wait-adb/ /g + s/--wait-fastboot/ /g'`" +fi +OPTIONS=`getopt ${GETOPTS} "?a:cCdDf:hs:t" ${*}` || ( echo "${USAGE}" >&2 ; false ) || die "getopt failure" set -- ${OPTIONS} @@ -775,26 +799,26 @@ while [ ${#} -gt 0 ]; do export ANDROID_SERIAL=${2} shift ;; - --color | --colour) + -c | --color | --colour) color=true ;; - --no-color | --no-colour) + -C | --no-color | --no-colour) color=false ;; - --no-wait-display | --no-wait-screen) + -D | --no-wait-display | --no-wait-screen) screen_wait=false ;; - --wait-display | --wait-screen) + -d | --wait-display | --wait-screen) screen_wait=true ;; - --print-time | --gtest_print_time) + -t | --print-time | --gtest_print_time) print_time=true ;; - --wait-adb) + -a | --wait-adb) ADB_WAIT=${2} shift ;; - --wait-fastboot) + -f | --wait-fastboot) FASTBOOT_WAIT=${2} shift ;; @@ -815,7 +839,7 @@ done if ! ${color}; then GREEN="" RED="" - ORANGE="" + YELLOW="" BLUE="" NORMAL="" fi @@ -827,14 +851,14 @@ fi inFastboot && die "device in fastboot mode" inRecovery && die "device in recovery mode" if ! inAdb; then - echo "${ORANGE}[ WARNING ]${NORMAL} device not in adb mode" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} device not in adb mode" >&2 adb_wait ${ADB_WAIT} fi inAdb || die "specified device not in adb mode" isDebuggable || die "device not a debug build" enforcing=true if ! adb_su getenforce </dev/null | grep 'Enforcing' >/dev/null; then - echo "${ORANGE}[ WARNING ]${NORMAL} device does not have sepolicy in enforcing mode" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} device does not have sepolicy in enforcing mode" >&2 enforcing=false fi @@ -846,9 +870,13 @@ D=`get_property ro.serialno` [ -n "${D}" ] || D=`get_property ro.boot.serialno` [ -z "${D}" -o -n "${ANDROID_SERIAL}" ] || ANDROID_SERIAL=${D} USB_SERIAL= -[ -z "${ANDROID_SERIAL}" ] || USB_SERIAL=`find /sys/devices -name serial | - grep usb | - xargs -r grep -l ${ANDROID_SERIAL}` +if [ -n "${ANDROID_SERIAL}" -a "Darwin" != "${HOSTOS}" ]; then + USB_SERIAL="`find /sys/devices -name serial | grep usb`" + if [ -n "${USB_SERIAL}" ]; then + USB_SERIAL=`echo "${USB_SERIAL}" | + xargs grep -l ${ANDROID_SERIAL}` + fi +fi USB_ADDRESS= if [ -n "${USB_SERIAL}" ]; then USB_ADDRESS=${USB_SERIAL%/serial} @@ -860,13 +888,16 @@ fi BUILD_DESCRIPTION=`get_property ro.build.description` [ -z "${BUILD_DESCRIPTION}" ] || echo "${BLUE}[ INFO ]${NORMAL} ${BUILD_DESCRIPTION}" >&2 +KERNEL_VERSION="`adb_su cat /proc/version </dev/null 2>/dev/null`" +[ -z "${KERNEL_VERSION}" ] || + echo "${BLUE}[ INFO ]${NORMAL} ${KERNEL_VERSION}" >&2 ACTIVE_SLOT=`get_active_slot` [ -z "${ACTIVE_SLOT}" ] || echo "${BLUE}[ INFO ]${NORMAL} active slot is ${ACTIVE_SLOT}" >&2 # Acquire list of system partitions -PARTITIONS=`adb_su cat /vendor/etc/fstab* | +PARTITIONS=`adb_su cat /vendor/etc/fstab* </dev/null | skip_administrative_mounts | sed -n "s@^\([^ ${TAB}/][^ ${TAB}/]*\)[ ${TAB}].*[, ${TAB}]ro[, ${TAB}].*@\1@p" | sort -u | @@ -903,9 +934,12 @@ adb_sh ls -l /dev/block/by-name/ /dev/block/mapper/ </dev/null 2>/dev/null | done # If reboot too soon after fresh flash, could trip device update failure logic +if ${screen_wait}; then + echo "${YELLOW}[ WARNING ]${NORMAL} waiting for screen to come up. Consider --no-wait-screen option" >&2 +fi if ! wait_for_screen && ${screen_wait}; then screen_wait=false - echo "${ORANGE}[ WARNING ]${NORMAL} not healthy, no launcher, skipping wait for screen" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} not healthy, no launcher, skipping wait for screen" >&2 fi # Can we test remount -R command? @@ -954,7 +988,7 @@ else adb_su remount -R system </dev/null err=${?} if [ "${err}" != 0 ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} adb shell su root remount -R system = ${err}, likely did not reboot!" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} adb shell su root remount -R system = ${err}, likely did not reboot!" >&2 T="-t ${T}" else # Rebooted, logcat will be meaningless, and last logcat will likely be clear @@ -980,7 +1014,7 @@ adb_sh ls -d /sys/module/overlay </dev/null >/dev/null 2>/dev/null || adb_sh grep "nodev${TAB}overlay" /proc/filesystems </dev/null >/dev/null 2>/dev/null && echo "${GREEN}[ OK ]${NORMAL} overlay module present" >&2 || ( - echo "${ORANGE}[ WARNING ]${NORMAL} overlay module not present" >&2 && + echo "${YELLOW}[ WARNING ]${NORMAL} overlay module not present" >&2 && false ) || overlayfs_supported=false @@ -989,7 +1023,7 @@ if ${overlayfs_supported}; then echo "${GREEN}[ OK ]${NORMAL} overlay module supports override_creds" >&2 || case `adb_sh uname -r </dev/null` in 4.[456789].* | 4.[1-9][0-9]* | [56789].*) - echo "${ORANGE}[ WARNING ]${NORMAL} overlay module does not support override_creds" >&2 && + echo "${YELLOW}[ WARNING ]${NORMAL} overlay module does not support override_creds" >&2 && overlayfs_supported=false ;; *) @@ -1011,14 +1045,14 @@ echo "${GREEN}[ RUN ]${NORMAL} Checking current overlayfs status" >&2 reboot=false for d in ${OVERLAYFS_BACKING}; do if adb_sh ls -d /${d}/overlay </dev/null >/dev/null 2>/dev/null; then - echo "${ORANGE}[ WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} /${d}/overlay is setup, surgically wiping" >&2 adb_sh rm -rf /${d}/overlay </dev/null || die "/${d}/overlay wipe" reboot=true fi done if ${reboot}; then - echo "${ORANGE}[ WARNING ]${NORMAL} rebooting before test" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} rebooting before test" >&2 adb_reboot && adb_wait ${ADB_WAIT} || die "lost device after reboot after wipe `usb_status`" @@ -1030,7 +1064,7 @@ D=`adb_sh df -k </dev/null` && D=`echo "${D}" | grep -v " /vendor/..*$" | grep "^overlay "` && echo "${H}" && echo "${D}" && - echo "${ORANGE}[ WARNING ]${NORMAL} overlays present before setup" >&2 || + echo "${YELLOW}[ WARNING ]${NORMAL} overlays present before setup" >&2 || echo "${GREEN}[ OK ]${NORMAL} no overlay present before setup" >&2 overlayfs_needed=true D=`adb_sh cat /proc/mounts </dev/null | @@ -1083,7 +1117,7 @@ rebooted=false if [ X"${D}" != X"${H}" ]; then echo "${H}" if [ X"${D}" != X"${D##*setup failed}" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} overlayfs setup whined" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} overlayfs setup whined" >&2 fi D=`adb_sh df -k </dev/null` && H=`echo "${D}" | head -1` && @@ -1130,7 +1164,7 @@ if [ X"${D}" != X"${D##*Successfully disabled verity}" ]; then elif ${rebooted}; then echo "${GREEN}[ OK ]${NORMAL} verity already disabled" >&2 else - echo "${ORANGE}[ WARNING ]${NORMAL} verity already disabled" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} verity already disabled" >&2 fi echo "${GREEN}[ RUN ]${NORMAL} remount" >&2 @@ -1160,7 +1194,7 @@ if ${overlayfs_needed}; then die -t ${T} "overlay takeover failed" fi echo "${D}" | grep "^overlay .* /system\$" >/dev/null || - echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover not complete" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} overlay takeover not complete" >&2 if [ -z "${virtual_ab}" ]; then scratch_partition=scratch fi @@ -1292,7 +1326,7 @@ echo "${GREEN}[ RUN ]${NORMAL} reboot to confirm content persistent" >&2 fixup_from_recovery() { inRecovery || return 1 - echo "${ORANGE}[ ERROR ]${NORMAL} Device in recovery" >&2 + echo "${YELLOW}[ ERROR ]${NORMAL} Device in recovery" >&2 adb reboot </dev/null adb_wait ${ADB_WAIT} } @@ -1312,7 +1346,7 @@ if ${overlayfs_needed}; then adb_su sed -n '1,/overlay \/system/p' /proc/mounts </dev/null | skip_administrative_mounts | grep -v ' \(erofs\|squashfs\|ext4\|f2fs\|vfat\) ' && - echo "${ORANGE}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 || + echo "${YELLOW}[ WARNING ]${NORMAL} overlay takeover after first stage init" >&2 || echo "${GREEN}[ OK ]${NORMAL} overlay takeover in first stage init" >&2 fi @@ -1373,20 +1407,20 @@ is_bootloader_fastboot=false is_userspace_fastboot=false if ! ${is_bootloader_fastboot}; then - echo "${ORANGE}[ WARNING ]${NORMAL} does not support fastboot, skipping" + echo "${YELLOW}[ WARNING ]${NORMAL} does not support fastboot, skipping" elif [ -z "${ANDROID_PRODUCT_OUT}" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} build tree not setup, skipping" + echo "${YELLOW}[ WARNING ]${NORMAL} build tree not setup, skipping" elif [ ! -s "${ANDROID_PRODUCT_OUT}/vendor.img" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} vendor image missing, skipping" + echo "${YELLOW}[ WARNING ]${NORMAL} vendor image missing, skipping" elif [ "${ANDROID_PRODUCT_OUT}" = "${ANDROID_PRODUCT_OUT%*/${H}}" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} wrong vendor image, skipping" + echo "${YELLOW}[ WARNING ]${NORMAL} wrong vendor image, skipping" elif [ -z "${ANDROID_HOST_OUT}" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} please run lunch, skipping" + echo "${YELLOW}[ WARNING ]${NORMAL} please run lunch, skipping" elif ! ( adb_cat /vendor/build.prop | cmp -s ${ANDROID_PRODUCT_OUT}/vendor/build.prop ) >/dev/null 2>/dev/null; then - echo "${ORANGE}[ WARNING ]${NORMAL} vendor image signature mismatch, skipping" + echo "${YELLOW}[ WARNING ]${NORMAL} vendor image signature mismatch, skipping" else wait_for_screen avc_check @@ -1432,7 +1466,7 @@ else fi fastboot reboot || die "can not reboot out of fastboot" - echo "${ORANGE}[ WARNING ]${NORMAL} adb after fastboot" + echo "${YELLOW}[ WARNING ]${NORMAL} adb after fastboot" adb_wait ${ADB_WAIT} || fixup_from_recovery || die "did not reboot after formatting ${scratch_partition} `usb_status`" @@ -1449,8 +1483,8 @@ else if ${is_userspace_fastboot}; then die "overlay supposed to be minus /vendor takeover after flash vendor" else - echo "${ORANGE}[ WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2 - echo "${ORANGE}[ WARNING ]${NORMAL} overlay supposed to be minus /vendor takeover after flash vendor" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} overlay supposed to be minus /vendor takeover after flash vendor" >&2 fi fi B="`adb_cat /system/hello`" @@ -1468,7 +1502,7 @@ else check_eq "cat: /vendor/hello: No such file or directory" "${B}" \ vendor content after flash vendor else - echo "${ORANGE}[ WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2 + echo "${YELLOW}[ WARNING ]${NORMAL} user fastboot missing required to invalidate, ignoring a failure" >&2 check_eq "cat: /vendor/hello: No such file or directory" "${B}" \ --warning vendor content after flash vendor fi @@ -1489,7 +1523,7 @@ err=${?} L= D="${H%?Now reboot your device for settings to take effect*}" if [ X"${H}" != X"${D}" ]; then - echo "${ORANGE}[ WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)" + echo "${YELLOW}[ WARNING ]${NORMAL} adb remount requires a reboot after partial flash (legacy avb)" L=`adb_logcat -b all -v nsec -t ${T} 2>&1` adb_reboot && adb_wait ${ADB_WAIT} && @@ -1547,7 +1581,7 @@ if ${is_bootloader_fastboot} && [ -n "${scratch_partition}" ]; then err=${?} if [ X"${D}" != "${D%?Now reboot your device for settings to take effect*}" ] then - echo "${ORANGE}[ WARNING ]${NORMAL} adb disable-verity requires a reboot after partial flash" + echo "${YELLOW}[ WARNING ]${NORMAL} adb disable-verity requires a reboot after partial flash" adb_reboot && adb_wait ${ADB_WAIT} && adb_root || @@ -1580,9 +1614,9 @@ fixup_from_fastboot() { if [ -n "${ACTIVE_SLOT}" ]; then local active_slot=`get_active_slot` if [ X"${ACTIVE_SLOT}" != X"${active_slot}" ]; then - echo "${ORANGE}[ ERROR ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" + echo "${YELLOW}[ ERROR ]${NORMAL} Active slot changed from ${ACTIVE_SLOT} to ${active_slot}" else - echo "${ORANGE}[ ERROR ]${NORMAL} Active slot to be set to ${ACTIVE_SLOT}" + echo "${YELLOW}[ ERROR ]${NORMAL} Active slot to be set to ${ACTIVE_SLOT}" fi >&2 fastboot --set-active=${ACTIVE_SLOT} fi diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index b423f864e3..8db9793f5e 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -37,7 +37,15 @@ BlockDevInitializer::BlockDevInitializer() : uevent_listener_(16 * 1024 * 1024) } bool BlockDevInitializer::InitDeviceMapper() { - const std::string dm_path = "/devices/virtual/misc/device-mapper"; + return InitMiscDevice("device-mapper"); +} + +bool BlockDevInitializer::InitDmUser() { + return InitMiscDevice("dm-user"); +} + +bool BlockDevInitializer::InitMiscDevice(const std::string& name) { + const std::string dm_path = "/devices/virtual/misc/" + name; bool found = false; auto dm_callback = [this, &dm_path, &found](const Uevent& uevent) { if (uevent.path == dm_path) { @@ -49,13 +57,13 @@ bool BlockDevInitializer::InitDeviceMapper() { }; uevent_listener_.RegenerateUeventsForPath("/sys" + dm_path, dm_callback); if (!found) { - LOG(INFO) << "device-mapper device not found in /sys, waiting for its uevent"; + LOG(INFO) << name << " device not found in /sys, waiting for its uevent"; Timer t; uevent_listener_.Poll(dm_callback, 10s); - LOG(INFO) << "Wait for device-mapper returned after " << t; + LOG(INFO) << "Wait for " << name << " returned after " << t; } if (!found) { - LOG(ERROR) << "device-mapper device not found after polling timeout"; + LOG(ERROR) << name << " device not found after polling timeout"; return false; } return true; diff --git a/init/block_dev_initializer.h b/init/block_dev_initializer.h index 0d4c6e9fc8..b8dd3f172f 100644 --- a/init/block_dev_initializer.h +++ b/init/block_dev_initializer.h @@ -27,12 +27,15 @@ class BlockDevInitializer final { BlockDevInitializer(); bool InitDeviceMapper(); + bool InitDmUser(); bool InitDevices(std::set<std::string> devices); bool InitDmDevice(const std::string& device); private: ListenerAction HandleUevent(const Uevent& uevent, std::set<std::string>* devices); + bool InitMiscDevice(const std::string& name); + std::unique_ptr<DeviceHandler> device_handler_; UeventListener uevent_listener_; }; diff --git a/init/init.cpp b/init/init.cpp index ba880ea32f..cb5bbbab97 100644 --- a/init/init.cpp +++ b/init/init.cpp @@ -18,6 +18,7 @@ #include <dirent.h> #include <fcntl.h> +#include <paths.h> #include <pthread.h> #include <signal.h> #include <stdlib.h> @@ -727,6 +728,12 @@ int SecondStageMain(int argc, char** argv) { InitSecondStageLogging(argv); LOG(INFO) << "init second stage started!"; + // Update $PATH in the case the second stage init is newer than first stage init, where it is + // first set. + if (setenv("PATH", _PATH_DEFPATH, 1) != 0) { + PLOG(FATAL) << "Could not set $PATH to '" << _PATH_DEFPATH << "' in second stage"; + } + // Init should not crash because of a dependence on any other process, therefore we ignore // SIGPIPE and handle EPIPE at the call site directly. Note that setting a signal to SIG_IGN // is inherited across exec, but custom signal handlers are not. Since we do not want to diff --git a/init/mount_namespace.cpp b/init/mount_namespace.cpp index f8359bc64c..59cc140e42 100644 --- a/init/mount_namespace.cpp +++ b/init/mount_namespace.cpp @@ -44,50 +44,17 @@ namespace android { namespace init { namespace { -static bool BindMount(const std::string& source, const std::string& mount_point, - bool recursive = false) { - unsigned long mountflags = MS_BIND; - if (recursive) { - mountflags |= MS_REC; - } - if (mount(source.c_str(), mount_point.c_str(), nullptr, mountflags, nullptr) == -1) { +static bool BindMount(const std::string& source, const std::string& mount_point) { + if (mount(source.c_str(), mount_point.c_str(), nullptr, MS_BIND | MS_REC, nullptr) == -1) { PLOG(ERROR) << "Failed to bind mount " << source; return false; } return true; } -static bool MakeShared(const std::string& mount_point, bool recursive = false) { - unsigned long mountflags = MS_SHARED; - if (recursive) { - mountflags |= MS_REC; - } - if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) { - PLOG(ERROR) << "Failed to change propagation type to shared"; - return false; - } - return true; -} - -static bool MakeSlave(const std::string& mount_point, bool recursive = false) { - unsigned long mountflags = MS_SLAVE; - if (recursive) { - mountflags |= MS_REC; - } - if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) { - PLOG(ERROR) << "Failed to change propagation type to slave"; - return false; - } - return true; -} - -static bool MakePrivate(const std::string& mount_point, bool recursive = false) { - unsigned long mountflags = MS_PRIVATE; - if (recursive) { - mountflags |= MS_REC; - } +static bool ChangeMount(const std::string& mount_point, unsigned long mountflags) { if (mount(nullptr, mount_point.c_str(), nullptr, mountflags, nullptr) == -1) { - PLOG(ERROR) << "Failed to change propagation type to private"; + PLOG(ERROR) << "Failed to remount " << mount_point << " as " << std::hex << mountflags; return false; } return true; @@ -225,17 +192,17 @@ bool SetupMountNamespaces() { // needed for /foo/bar, then we will make /foo/bar as a mount point (by // bind-mounting by to itself) and set the propagation type of the mount // point to private. - if (!MakeShared("/", true /*recursive*/)) return false; + if (!ChangeMount("/", MS_SHARED | MS_REC)) return false; // /apex is a private mountpoint to give different sets of APEXes for // the bootstrap and default mount namespaces. The processes running with // the bootstrap namespace get APEXes from the read-only partition. - if (!(MakePrivate("/apex"))) return false; + if (!(ChangeMount("/apex", MS_PRIVATE))) return false; // /linkerconfig is a private mountpoint to give a different linker configuration // based on the mount namespace. Subdirectory will be bind-mounted based on current mount // namespace - if (!(MakePrivate("/linkerconfig"))) return false; + if (!(ChangeMount("/linkerconfig", MS_PRIVATE))) return false; // The two mount namespaces present challenges for scoped storage, because // vold, which is responsible for most of the mounting, lives in the @@ -266,15 +233,15 @@ bool SetupMountNamespaces() { if (!mkdir_recursive("/mnt/user", 0755)) return false; if (!mkdir_recursive("/mnt/installer", 0755)) return false; if (!mkdir_recursive("/mnt/androidwritable", 0755)) return false; - if (!(BindMount("/mnt/user", "/mnt/installer", true))) return false; - if (!(BindMount("/mnt/user", "/mnt/androidwritable", true))) return false; + if (!(BindMount("/mnt/user", "/mnt/installer"))) return false; + if (!(BindMount("/mnt/user", "/mnt/androidwritable"))) return false; // First, make /mnt/installer and /mnt/androidwritable a slave bind mount - if (!(MakeSlave("/mnt/installer"))) return false; - if (!(MakeSlave("/mnt/androidwritable"))) return false; + if (!(ChangeMount("/mnt/installer", MS_SLAVE))) return false; + if (!(ChangeMount("/mnt/androidwritable", MS_SLAVE))) return false; // Then, make it shared again - effectively creating a new peer group, that // will be inherited by new mount namespaces. - if (!(MakeShared("/mnt/installer"))) return false; - if (!(MakeShared("/mnt/androidwritable"))) return false; + if (!(ChangeMount("/mnt/installer", MS_SHARED))) return false; + if (!(ChangeMount("/mnt/androidwritable", MS_SHARED))) return false; bootstrap_ns_fd.reset(OpenMountNamespace()); bootstrap_ns_id = GetMountNamespaceId(); diff --git a/init/property_service.cpp b/init/property_service.cpp index 0c4a3c4989..a1e0969ede 100644 --- a/init/property_service.cpp +++ b/init/property_service.cpp @@ -632,10 +632,11 @@ static void LoadProperties(char* data, const char* filter, const char* filename, char *key, *value, *eol, *sol, *tmp, *fn; size_t flen = 0; - static constexpr const char* const kVendorPathPrefixes[3] = { + static constexpr const char* const kVendorPathPrefixes[4] = { "/vendor", "/odm", "/vendor_dlkm", + "/odm_dlkm", }; const char* context = kInitContext; @@ -941,6 +942,7 @@ void PropertyLoadBootDefaults() { // } load_properties_from_file("/vendor/build.prop", nullptr, &properties); load_properties_from_file("/vendor_dlkm/etc/build.prop", nullptr, &properties); + load_properties_from_file("/odm_dlkm/etc/build.prop", nullptr, &properties); load_properties_from_partition("odm", /* support_legacy_path_until */ 28); load_properties_from_partition("product", /* support_legacy_path_until */ 30); @@ -992,7 +994,7 @@ void CreateSerializedPropertyInfo() { &property_infos)) { return; } - // Don't check for failure here, so we always have a sane list of properties. + // Don't check for failure here, since we don't always have all of these partitions. // E.g. In case of recovery, the vendor partition will not have mounted and we // still need the system / platform properties to function. if (access("/system_ext/etc/selinux/system_ext_property_contexts", R_OK) != -1) { diff --git a/init/service_utils.cpp b/init/service_utils.cpp index 05e632b68c..f2383d7a6e 100644 --- a/init/service_utils.cpp +++ b/init/service_utils.cpp @@ -60,13 +60,14 @@ Result<void> EnterNamespace(int nstype, const char* path) { Result<void> SetUpMountNamespace(bool remount_proc, bool remount_sys) { constexpr unsigned int kSafeFlags = MS_NODEV | MS_NOEXEC | MS_NOSUID; - // Recursively remount / as slave like zygote does so unmounting and mounting /proc - // doesn't interfere with the parent namespace's /proc mount. This will also - // prevent any other mounts/unmounts initiated by the service from interfering - // with the parent namespace but will still allow mount events from the parent + // Recursively remount / as MS_SLAVE like zygote does so that + // unmounting and mounting /proc doesn't interfere with the parent + // namespace's /proc mount. This will also prevent any other + // mounts/unmounts initiated by the service from interfering with the + // parent namespace but will still allow mount events from the parent // namespace to propagate to the child. if (mount("rootfs", "/", nullptr, (MS_SLAVE | MS_REC), nullptr) == -1) { - return ErrnoError() << "Could not remount(/) recursively as slave"; + return ErrnoError() << "Could not remount(/) recursively as MS_SLAVE"; } // umount() then mount() /proc and/or /sys diff --git a/init/test_kill_services/init_kill_services_test.cpp b/init/test_kill_services/init_kill_services_test.cpp index 7e543f232c..66a332892d 100644 --- a/init/test_kill_services/init_kill_services_test.cpp +++ b/init/test_kill_services/init_kill_services_test.cpp @@ -54,7 +54,7 @@ class InitKillServicesTest : public ::testing::TestWithParam<std::string> {}; TEST_P(InitKillServicesTest, KillCriticalProcesses) { ExpectKillingServiceRecovers(GetParam()); - // sanity check init is still responding + // Ensure that init is still responding EXPECT_TRUE(SetProperty("test.death.test", "asdf")); EXPECT_EQ(GetProperty("test.death.test", ""), "asdf"); EXPECT_TRUE(SetProperty("test.death.test", "")); diff --git a/init/uevent_listener.cpp b/init/uevent_listener.cpp index d8d9b36ff4..7cd396a8b0 100644 --- a/init/uevent_listener.cpp +++ b/init/uevent_listener.cpp @@ -95,20 +95,18 @@ UeventListener::UeventListener(size_t uevent_socket_rcvbuf_size) { fcntl(device_fd_, F_SETFL, O_NONBLOCK); } -bool UeventListener::ReadUevent(Uevent* uevent) const { +ReadUeventResult UeventListener::ReadUevent(Uevent* uevent) const { char msg[UEVENT_MSG_LEN + 2]; int n = uevent_kernel_multicast_recv(device_fd_, msg, UEVENT_MSG_LEN); if (n <= 0) { if (errno != EAGAIN && errno != EWOULDBLOCK) { PLOG(ERROR) << "Error reading from Uevent Fd"; } - return false; + return ReadUeventResult::kFailed; } if (n >= UEVENT_MSG_LEN) { LOG(ERROR) << "Uevent overflowed buffer, discarding"; - // Return true here even if we discard as we may have more uevents pending and we - // want to keep processing them. - return true; + return ReadUeventResult::kInvalid; } msg[n] = '\0'; @@ -116,7 +114,7 @@ bool UeventListener::ReadUevent(Uevent* uevent) const { ParseEvent(msg, uevent); - return true; + return ReadUeventResult::kSuccess; } // RegenerateUevents*() walks parts of the /sys tree and pokes the uevent files to cause the kernel @@ -137,7 +135,10 @@ ListenerAction UeventListener::RegenerateUeventsForDir(DIR* d, close(fd); Uevent uevent; - while (ReadUevent(&uevent)) { + ReadUeventResult result; + while ((result = ReadUevent(&uevent)) != ReadUeventResult::kFailed) { + // Skip processing the uevent if it is invalid. + if (result == ReadUeventResult::kInvalid) continue; if (callback(uevent) == ListenerAction::kStop) return ListenerAction::kStop; } } @@ -212,7 +213,10 @@ void UeventListener::Poll(const ListenerCallback& callback, // We're non-blocking, so if we receive a poll event keep processing until // we have exhausted all uevent messages. Uevent uevent; - while (ReadUevent(&uevent)) { + ReadUeventResult result; + while ((result = ReadUevent(&uevent)) != ReadUeventResult::kFailed) { + // Skip processing the uevent if it is invalid. + if (result == ReadUeventResult::kInvalid) continue; if (callback(uevent) == ListenerAction::kStop) return; } } diff --git a/init/uevent_listener.h b/init/uevent_listener.h index aea094e776..2772860642 100644 --- a/init/uevent_listener.h +++ b/init/uevent_listener.h @@ -27,7 +27,7 @@ #include "uevent.h" -#define UEVENT_MSG_LEN 2048 +#define UEVENT_MSG_LEN 8192 namespace android { namespace init { @@ -37,6 +37,12 @@ enum class ListenerAction { kContinue, // Continue regenerating uevents as we haven't seen the one(s) we're interested in. }; +enum class ReadUeventResult { + kSuccess = 0, // Uevent was successfully read. + kFailed, // Uevent reading has failed. + kInvalid, // An Invalid Uevent was read (like say, the msg received is >= UEVENT_MSG_LEN). +}; + using ListenerCallback = std::function<ListenerAction(const Uevent&)>; class UeventListener { @@ -50,7 +56,7 @@ class UeventListener { const std::optional<std::chrono::milliseconds> relative_timeout = {}) const; private: - bool ReadUevent(Uevent* uevent) const; + ReadUeventResult ReadUevent(Uevent* uevent) const; ListenerAction RegenerateUeventsForDir(DIR* d, const ListenerCallback& callback) const; android::base::unique_fd device_fd_; diff --git a/libbacktrace/backtrace_test.cpp b/libbacktrace/backtrace_test.cpp index f4191b9087..cc32b6dc0e 100644 --- a/libbacktrace/backtrace_test.cpp +++ b/libbacktrace/backtrace_test.cpp @@ -1584,7 +1584,7 @@ static void UnwindFromDevice(Backtrace* backtrace, void* device_map) { // Verify the flag is set. ASSERT_EQ(PROT_DEVICE_MAP, map.flags & PROT_DEVICE_MAP); - // Quick sanity checks. + // Quick basic checks of functionality. uint64_t offset; ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset)); ASSERT_EQ(std::string(""), backtrace->GetFunctionName(device_map_uint, &offset, &map)); diff --git a/libcutils/ashmem-dev.cpp b/libcutils/ashmem-dev.cpp index 8c232f0cd0..20cd6592d8 100644 --- a/libcutils/ashmem-dev.cpp +++ b/libcutils/ashmem-dev.cpp @@ -122,7 +122,8 @@ static bool check_vendor_memfd_allowed() { return true; } - /* If its not a number, assume string, but check if its a sane string */ + // Non-numeric should be a single ASCII character. Characters after the + // first are ignored. if (tolower(vndk_version[0]) < 'a' || tolower(vndk_version[0]) > 'z') { ALOGE("memfd: ro.vndk.version not defined or invalid (%s), this is mandated since P.\n", vndk_version.c_str()); diff --git a/libcutils/fs_config.cpp b/libcutils/fs_config.cpp index 5805a4d19b..b9fc82eaea 100644 --- a/libcutils/fs_config.cpp +++ b/libcutils/fs_config.cpp @@ -203,6 +203,7 @@ static const struct fs_path_config android_files[] = { { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/e2fsck" }, { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/tune2fs" }, { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/resize2fs" }, + { 00755, AID_ROOT, AID_ROOT, 0, "first_stage_ramdisk/system/bin/snapuserd" }, // generic defaults { 00755, AID_ROOT, AID_ROOT, 0, "bin/*" }, { 00640, AID_ROOT, AID_SHELL, 0, "fstab.*" }, diff --git a/libcutils/include/private/android_filesystem_config.h b/libcutils/include/private/android_filesystem_config.h index e4f45a85e4..b4fe2e6878 100644 --- a/libcutils/include/private/android_filesystem_config.h +++ b/libcutils/include/private/android_filesystem_config.h @@ -36,7 +36,7 @@ #pragma once -/* This is the master Users and Groups config for the platform. +/* This is the main Users and Groups config for the platform. * DO NOT EVER RENUMBER */ diff --git a/libcutils/qtaguid.cpp b/libcutils/qtaguid.cpp index b94d134be5..2fe877c4e2 100644 --- a/libcutils/qtaguid.cpp +++ b/libcutils/qtaguid.cpp @@ -38,24 +38,24 @@ class netdHandler { int (*netdDeleteTagData)(uint32_t, uid_t); }; -int dummyTagSocket(int, uint32_t, uid_t) { +int stubTagSocket(int, uint32_t, uid_t) { return -EREMOTEIO; } -int dummyUntagSocket(int) { +int stubUntagSocket(int) { return -EREMOTEIO; } -int dummySetCounterSet(uint32_t, uid_t) { +int stubSetCounterSet(uint32_t, uid_t) { return -EREMOTEIO; } -int dummyDeleteTagData(uint32_t, uid_t) { +int stubDeleteTagData(uint32_t, uid_t) { return -EREMOTEIO; } netdHandler initHandler(void) { - netdHandler handler = {dummyTagSocket, dummyUntagSocket, dummySetCounterSet, dummyDeleteTagData}; + netdHandler handler = {stubTagSocket, stubUntagSocket, stubSetCounterSet, stubDeleteTagData}; void* netdClientHandle = dlopen("libnetd_client.so", RTLD_NOW); if (!netdClientHandle) { diff --git a/libkeyutils/keyutils_test.cpp b/libkeyutils/keyutils_test.cpp index d41c91b682..d03747b3ec 100644 --- a/libkeyutils/keyutils_test.cpp +++ b/libkeyutils/keyutils_test.cpp @@ -33,7 +33,7 @@ #include <gtest/gtest.h> TEST(keyutils, smoke) { - // Check that the exported type is sane. + // Check that the exported type is the right size. ASSERT_EQ(4U, sizeof(key_serial_t)); // Check that all the functions actually exist. diff --git a/liblog/Android.bp b/liblog/Android.bp index 6051ac7fa6..3a91969771 100644 --- a/liblog/Android.bp +++ b/liblog/Android.bp @@ -17,6 +17,7 @@ liblog_sources = [ "log_event_list.cpp", "log_event_write.cpp", + "log_size.cpp", "logger_name.cpp", "logger_read.cpp", "logger_write.cpp", diff --git a/liblog/include/log/log_properties.h b/liblog/include/log/log_properties.h index 3497d63dca..2a0230f75e 100644 --- a/liblog/include/log/log_properties.h +++ b/liblog/include/log/log_properties.h @@ -20,6 +20,7 @@ extern "C" { #endif +/* Returns `1` if the device is debuggable or `0` if not. */ int __android_log_is_debuggable(); #ifdef __cplusplus diff --git a/liblog/include/private/android_logger.h b/liblog/include/private/android_logger.h index d3b72bcee8..de4c430e31 100644 --- a/liblog/include/private/android_logger.h +++ b/liblog/include/private/android_logger.h @@ -144,14 +144,6 @@ int __android_log_security_bwrite(int32_t tag, const void* payload, size_t len); int __android_log_security_bswrite(int32_t tag, const char* payload); int __android_log_security(); /* Device Owner is present */ -#define BOOL_DEFAULT_FLAG_TRUE_FALSE 0x1 -#define BOOL_DEFAULT_FALSE 0x0 /* false if property not present */ -#define BOOL_DEFAULT_TRUE 0x1 /* true if property not present */ -#define BOOL_DEFAULT_FLAG_PERSIST 0x2 /* <key>, persist.<key>, ro.<key> */ -#define BOOL_DEFAULT_FLAG_ENG 0x4 /* off for user */ -#define BOOL_DEFAULT_FLAG_SVELTE 0x8 /* off for low_ram */ -bool __android_logger_property_get_bool(const char* key, int flag); - #define LOG_BUFFER_SIZE (256 * 1024) /* Tuned with ro.logd.size per-platform \ */ #define LOG_BUFFER_MIN_SIZE (64 * 1024UL) diff --git a/liblog/liblog.map.txt b/liblog/liblog.map.txt index 161fcf1a96..2e0110171e 100644 --- a/liblog/liblog.map.txt +++ b/liblog/liblog.map.txt @@ -85,7 +85,6 @@ LIBLOG_PRIVATE { __android_log_pmsg_file_read; __android_log_pmsg_file_write; __android_logger_get_buffer_size; - __android_logger_property_get_bool; android_openEventTagMap; android_log_processBinaryLogBuffer; android_log_processLogBuffer; diff --git a/liblog/log_size.cpp b/liblog/log_size.cpp new file mode 100644 index 0000000000..7f13c8c2b4 --- /dev/null +++ b/liblog/log_size.cpp @@ -0,0 +1,83 @@ +/* + * Copyright 2020 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 <private/android_logger.h> + +#include <array> +#include <optional> +#include <string> + +#include <android-base/parseint.h> + +#ifdef __ANDROID__ +#include <sys/system_properties.h> +#endif + +bool __android_logger_valid_buffer_size(unsigned long value) { + return LOG_BUFFER_MIN_SIZE <= value && value <= LOG_BUFFER_MAX_SIZE; +} + +#ifdef __ANDROID__ + +static std::optional<unsigned long> GetBufferSizeProperty(const std::string& key) { + char value[PROP_VALUE_MAX] = {}; + if (__system_property_get(key.c_str(), value) <= 0) { + return {}; + } + + uint32_t size; + if (!android::base::ParseByteCount(value, &size)) { + return {}; + } + + if (!__android_logger_valid_buffer_size(size)) { + return {}; + } + + return size; +} + +unsigned long __android_logger_get_buffer_size(log_id_t log_id) { + std::string buffer_name = android_log_id_to_name(log_id); + std::array<std::string, 4> properties = { + "persist.logd.size." + buffer_name, + "ro.logd.size." + buffer_name, + "persist.logd.size", + "ro.logd.size", + }; + + for (const auto& property : properties) { + if (auto size = GetBufferSizeProperty(property)) { + return *size; + } + } + + char value[PROP_VALUE_MAX] = {}; + if (__system_property_get("ro.config.low_ram", value) > 0 && !strcmp(value, "true")) { + return LOG_BUFFER_MIN_SIZE; + } + + return LOG_BUFFER_SIZE; +} + +#else + +// Default to 1MB for host. +unsigned long __android_logger_get_buffer_size(log_id_t) { + return 1024 * 1024; +} + +#endif
\ No newline at end of file diff --git a/liblog/properties.cpp b/liblog/properties.cpp index 2392112736..88f0bf1eee 100644 --- a/liblog/properties.cpp +++ b/liblog/properties.cpp @@ -294,33 +294,12 @@ int __android_log_is_loggable(int prio, const char* tag, int default_prio) { } int __android_log_is_debuggable() { - static uint32_t serial; - static struct cache_char tag_cache; - static const char key[] = "ro.debuggable"; - int ret; - - if (tag_cache.c) { /* ro property does not change after set */ - ret = tag_cache.c == '1'; - } else if (lock()) { - struct cache_char temp_cache = {{NULL, 0xFFFFFFFF}, '\0'}; - refresh_cache(&temp_cache, key); - ret = temp_cache.c == '1'; - } else { - int change_detected = check_cache(&tag_cache.cache); - uint32_t current_serial = __system_property_area_serial(); - if (current_serial != serial) { - change_detected = 1; - } - if (change_detected) { - refresh_cache(&tag_cache, key); - serial = current_serial; - } - ret = tag_cache.c == '1'; - - unlock(); - } + static int is_debuggable = [] { + char value[PROP_VALUE_MAX] = {}; + return __system_property_get("ro.debuggable", value) > 0 && !strcmp(value, "1"); + }(); - return ret; + return is_debuggable; } /* @@ -385,216 +364,6 @@ int __android_log_security() { return do_cache2_char(&security); } -/* - * Interface that represents the logd buffer size determination so that others - * need not guess our intentions. - */ - -/* Property helper */ -static bool check_flag(const char* prop, const char* flag) { - const char* cp = strcasestr(prop, flag); - if (!cp) { - return false; - } - /* We only will document comma (,) */ - static const char sep[] = ",:;|+ \t\f"; - if ((cp != prop) && !strchr(sep, cp[-1])) { - return false; - } - cp += strlen(flag); - return !*cp || !!strchr(sep, *cp); -} - -/* cache structure */ -struct cache_property { - struct cache cache; - char property[PROP_VALUE_MAX]; -}; - -static void refresh_cache_property(struct cache_property* cache, const char* key) { - if (!cache->cache.pinfo) { - cache->cache.pinfo = __system_property_find(key); - if (!cache->cache.pinfo) { - return; - } - } - cache->cache.serial = __system_property_serial(cache->cache.pinfo); - __system_property_read(cache->cache.pinfo, 0, cache->property); -} - -/* get boolean with the logger twist that supports eng adjustments */ -bool __android_logger_property_get_bool(const char* key, int flag) { - struct cache_property property = {{NULL, 0xFFFFFFFF}, {0}}; - if (flag & BOOL_DEFAULT_FLAG_PERSIST) { - char newkey[strlen("persist.") + strlen(key) + 1]; - snprintf(newkey, sizeof(newkey), "ro.%s", key); - refresh_cache_property(&property, newkey); - property.cache.pinfo = NULL; - property.cache.serial = 0xFFFFFFFF; - snprintf(newkey, sizeof(newkey), "persist.%s", key); - refresh_cache_property(&property, newkey); - property.cache.pinfo = NULL; - property.cache.serial = 0xFFFFFFFF; - } - - refresh_cache_property(&property, key); - - if (check_flag(property.property, "true")) { - return true; - } - if (check_flag(property.property, "false")) { - return false; - } - if (property.property[0]) { - flag &= ~(BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE); - } - if (check_flag(property.property, "eng")) { - flag |= BOOL_DEFAULT_FLAG_ENG; - } - /* this is really a "not" flag */ - if (check_flag(property.property, "svelte")) { - flag |= BOOL_DEFAULT_FLAG_SVELTE; - } - - /* Sanity Check */ - if (flag & (BOOL_DEFAULT_FLAG_SVELTE | BOOL_DEFAULT_FLAG_ENG)) { - flag &= ~BOOL_DEFAULT_FLAG_TRUE_FALSE; - flag |= BOOL_DEFAULT_TRUE; - } - - if ((flag & BOOL_DEFAULT_FLAG_SVELTE) && - __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE)) { - return false; - } - if ((flag & BOOL_DEFAULT_FLAG_ENG) && !__android_log_is_debuggable()) { - return false; - } - - return (flag & BOOL_DEFAULT_FLAG_TRUE_FALSE) != BOOL_DEFAULT_FALSE; -} - -bool __android_logger_valid_buffer_size(unsigned long value) { - return LOG_BUFFER_MIN_SIZE <= value && value <= LOG_BUFFER_MAX_SIZE; -} - -struct cache2_property_size { - pthread_mutex_t lock; - uint32_t serial; - const char* key_persist; - struct cache_property cache_persist; - const char* key_ro; - struct cache_property cache_ro; - unsigned long (*const evaluate)(const struct cache2_property_size* self); -}; - -static inline unsigned long do_cache2_property_size(struct cache2_property_size* self) { - uint32_t current_serial; - int change_detected; - unsigned long v; - - if (pthread_mutex_trylock(&self->lock)) { - /* We are willing to accept some race in this context */ - return self->evaluate(self); - } - - change_detected = check_cache(&self->cache_persist.cache) || check_cache(&self->cache_ro.cache); - current_serial = __system_property_area_serial(); - if (current_serial != self->serial) { - change_detected = 1; - } - if (change_detected) { - refresh_cache_property(&self->cache_persist, self->key_persist); - refresh_cache_property(&self->cache_ro, self->key_ro); - self->serial = current_serial; - } - v = self->evaluate(self); - - pthread_mutex_unlock(&self->lock); - - return v; -} - -static unsigned long property_get_size_from_cache(const struct cache_property* cache) { - char* cp; - unsigned long value = strtoul(cache->property, &cp, 10); - - switch (*cp) { - case 'm': - case 'M': - value *= 1024; - [[fallthrough]]; - case 'k': - case 'K': - value *= 1024; - [[fallthrough]]; - case '\0': - break; - - default: - value = 0; - } - - if (!__android_logger_valid_buffer_size(value)) { - value = 0; - } - - return value; -} - -static unsigned long evaluate_property_get_size(const struct cache2_property_size* self) { - unsigned long size = property_get_size_from_cache(&self->cache_persist); - if (size) { - return size; - } - return property_get_size_from_cache(&self->cache_ro); -} - -unsigned long __android_logger_get_buffer_size(log_id_t logId) { - static const char global_tunable[] = "persist.logd.size"; /* Settings App */ - static const char global_default[] = "ro.logd.size"; /* BoardConfig.mk */ - static struct cache2_property_size global = { - /* clang-format off */ - PTHREAD_MUTEX_INITIALIZER, 0, - global_tunable, { { NULL, 0xFFFFFFFF }, {} }, - global_default, { { NULL, 0xFFFFFFFF }, {} }, - evaluate_property_get_size - /* clang-format on */ - }; - char key_persist[strlen(global_tunable) + strlen(".security") + 1]; - char key_ro[strlen(global_default) + strlen(".security") + 1]; - struct cache2_property_size local = { - /* clang-format off */ - PTHREAD_MUTEX_INITIALIZER, 0, - key_persist, { { NULL, 0xFFFFFFFF }, {} }, - key_ro, { { NULL, 0xFFFFFFFF }, {} }, - evaluate_property_get_size - /* clang-format on */ - }; - unsigned long property_size, default_size; - - default_size = do_cache2_property_size(&global); - if (!default_size) { - default_size = __android_logger_property_get_bool("ro.config.low_ram", BOOL_DEFAULT_FALSE) - ? LOG_BUFFER_MIN_SIZE /* 64K */ - : LOG_BUFFER_SIZE; /* 256K */ - } - - snprintf(key_persist, sizeof(key_persist), "%s.%s", global_tunable, - android_log_id_to_name(logId)); - snprintf(key_ro, sizeof(key_ro), "%s.%s", global_default, android_log_id_to_name(logId)); - property_size = do_cache2_property_size(&local); - - if (!property_size) { - property_size = default_size; - } - - if (!property_size) { - property_size = LOG_BUFFER_SIZE; - } - - return property_size; -} - #else int __android_log_is_loggable(int prio, const char*, int) { @@ -613,4 +382,4 @@ int __android_log_is_debuggable() { return 1; } -#endif
\ No newline at end of file +#endif diff --git a/liblog/tests/Android.bp b/liblog/tests/Android.bp index 2a6424b05d..a17d90cc0c 100644 --- a/liblog/tests/Android.bp +++ b/liblog/tests/Android.bp @@ -97,6 +97,7 @@ cc_test { cflags: ["-DNO_PSTORE"], test_suites: [ "cts", + "device-tests", "vts10", ], } diff --git a/liblog/tests/liblog_global_state.cpp b/liblog/tests/liblog_global_state.cpp index 3508818f25..1d7ff9f227 100644 --- a/liblog/tests/liblog_global_state.cpp +++ b/liblog/tests/liblog_global_state.cpp @@ -153,56 +153,65 @@ TEST(liblog_global_state, SetAborter_with_liblog) { message_seen = false; } +static std::string UniqueLogTag() { + std::string tag = LOG_TAG; + tag += "-" + std::to_string(getpid()); + return tag; +} + TEST(liblog_global_state, is_loggable_both_default) { - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + auto tag = UniqueLogTag(); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); } TEST(liblog_global_state, is_loggable_minimum_log_priority_only) { - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + auto tag = UniqueLogTag(); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN)); - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); EXPECT_EQ(android::base::WARNING, android::base::SetMinimumLogSeverity(android::base::DEBUG)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); EXPECT_EQ(android::base::DEBUG, android::base::SetMinimumLogSeverity(android::base::WARNING)); - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); } TEST(liblog_global_state, is_loggable_tag_log_priority_only) { #ifdef __ANDROID__ - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); - - auto log_tag_property = std::string("log.tag.") + LOG_TAG; - android::base::SetProperty(log_tag_property, "d"); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); - - android::base::SetProperty(log_tag_property, "w"); - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); - - android::base::SetProperty(log_tag_property, ""); + auto tag = UniqueLogTag(); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); + + auto log_tag_property = std::string("log.tag.") + tag; + ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d")); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); + + ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w")); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); + + ASSERT_TRUE(android::base::SetProperty(log_tag_property, "")); #else GTEST_SKIP() << "No log tag properties on host"; #endif @@ -210,39 +219,40 @@ TEST(liblog_global_state, is_loggable_tag_log_priority_only) { TEST(liblog_global_state, is_loggable_both_set) { #ifdef __ANDROID__ - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + auto tag = UniqueLogTag(); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); // When both a tag and a minimum priority are set, we use the lower value of the two. // tag = warning, minimum_priority = debug, expect 'debug' - auto log_tag_property = std::string("log.tag.") + LOG_TAG; - android::base::SetProperty(log_tag_property, "w"); + auto log_tag_property = std::string("log.tag.") + tag; + ASSERT_TRUE(android::base::SetProperty(log_tag_property, "w")); EXPECT_EQ(ANDROID_LOG_DEFAULT, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); // tag = warning, minimum_priority = warning, expect 'warning' EXPECT_EQ(ANDROID_LOG_DEBUG, __android_log_set_minimum_priority(ANDROID_LOG_WARN)); - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(0, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); // tag = debug, minimum_priority = warning, expect 'debug' - android::base::SetProperty(log_tag_property, "d"); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + ASSERT_TRUE(android::base::SetProperty(log_tag_property, "d")); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); // tag = debug, minimum_priority = debug, expect 'debug' EXPECT_EQ(ANDROID_LOG_WARN, __android_log_set_minimum_priority(ANDROID_LOG_DEBUG)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, LOG_TAG, ANDROID_LOG_INFO)); - EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, LOG_TAG, ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_DEBUG, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_INFO, tag.c_str(), ANDROID_LOG_INFO)); + EXPECT_EQ(1, __android_log_is_loggable(ANDROID_LOG_WARN, tag.c_str(), ANDROID_LOG_INFO)); - android::base::SetProperty(log_tag_property, ""); + ASSERT_TRUE(android::base::SetProperty(log_tag_property, "")); #else GTEST_SKIP() << "No log tag properties on host"; #endif diff --git a/liblog/tests/log_read_test.cpp b/liblog/tests/log_read_test.cpp index 3e09617495..7acd363dc0 100644 --- a/liblog/tests/log_read_test.cpp +++ b/liblog/tests/log_read_test.cpp @@ -20,6 +20,7 @@ #include <string> +#include <android-base/properties.h> #include <android-base/stringprintf.h> #include <android/log.h> // minimal logging API #include <gtest/gtest.h> @@ -29,6 +30,8 @@ // Do not use anything in log/log_time.h despite side effects of the above. #include <private/android_logger.h> +using android::base::GetBoolProperty; + TEST(liblog, android_logger_get_) { #ifdef __ANDROID__ // This test assumes the log buffers are filled with noise from @@ -38,31 +41,27 @@ TEST(liblog, android_logger_get_) { for (int i = LOG_ID_MIN; i < LOG_ID_MAX; ++i) { log_id_t id = static_cast<log_id_t>(i); - const char* name = android_log_id_to_name(id); - if (id != android_name_to_log_id(name)) { - continue; - } - fprintf(stderr, "log buffer %s\r", name); + std::string name = android_log_id_to_name(id); + fprintf(stderr, "log buffer %s\r", name.c_str()); struct logger* logger; EXPECT_TRUE(NULL != (logger = android_logger_open(logger_list, id))); EXPECT_EQ(id, android_logger_get_id(logger)); ssize_t get_log_size = android_logger_get_log_size(logger); /* security buffer is allowed to be denied */ - if (strcmp("security", name)) { - EXPECT_LT(0, get_log_size); + if (name != "security") { + EXPECT_GT(get_log_size, 0); // crash buffer is allowed to be empty, that is actually healthy! - // kernel buffer is allowed to be empty on "user" builds - // stats buffer is allowed to be empty TEMPORARILY. - // TODO: remove stats buffer from here once we start to use it in - // framework (b/68266385). - EXPECT_LE( // boolean 1 or 0 depending on expected content or empty - !!((strcmp("crash", name) != 0) && - ((strcmp("kernel", name) != 0) || - __android_logger_property_get_bool( - "ro.logd.kernel", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | - BOOL_DEFAULT_FLAG_SVELTE)) && - (strcmp("stats", name) != 0)), - android_logger_get_log_readable_size(logger)); + // stats buffer is no longer in use. + if (name == "crash" || name == "stats") { + continue; + } + + // kernel buffer is empty if ro.logd.kernel is false + if (name == "kernel" && !GetBoolProperty("ro.logd.kernel", false)) { + continue; + } + + EXPECT_LE(0, android_logger_get_log_readable_size(logger)); } else { EXPECT_NE(0, get_log_size); if (get_log_size < 0) { @@ -71,7 +70,6 @@ TEST(liblog, android_logger_get_) { EXPECT_LE(0, android_logger_get_log_readable_size(logger)); } } - EXPECT_LT(0, android_logger_get_log_version(logger)); } android_logger_list_close(logger_list); diff --git a/libsysutils/src/NetlinkEvent.cpp b/libsysutils/src/NetlinkEvent.cpp index 9c1621bc8e..3b6cfd830e 100644 --- a/libsysutils/src/NetlinkEvent.cpp +++ b/libsysutils/src/NetlinkEvent.cpp @@ -185,7 +185,6 @@ bool NetlinkEvent::parseIfAddrMessage(const struct nlmsghdr *nh) { if (!checkRtNetlinkLength(nh, sizeof(*ifaddr))) return false; - // Sanity check. int type = nh->nlmsg_type; if (type != RTM_NEWADDR && type != RTM_DELADDR) { SLOGE("parseIfAddrMessage on incorrect message type 0x%x\n", type); @@ -349,7 +348,6 @@ bool NetlinkEvent::parseRtMessage(const struct nlmsghdr *nh) { uint8_t type = nh->nlmsg_type; const char *msgname = rtMessageName(type); - // Sanity check. if (type != RTM_NEWROUTE && type != RTM_DELROUTE) { SLOGE("%s: incorrect message type %d (%s)\n", __func__, type, msgname); return false; diff --git a/libsysutils/src/SocketClient.cpp b/libsysutils/src/SocketClient.cpp index fe2f3d668d..e90afcd189 100644 --- a/libsysutils/src/SocketClient.cpp +++ b/libsysutils/src/SocketClient.cpp @@ -201,50 +201,31 @@ int SocketClient::sendDataLockedv(struct iovec *iov, int iovcnt) { return 0; } - int ret = 0; - int e = 0; // SLOGW and sigaction are not inert regarding errno int current = 0; - struct sigaction new_action, old_action; - memset(&new_action, 0, sizeof(new_action)); - new_action.sa_handler = SIG_IGN; - sigaction(SIGPIPE, &new_action, &old_action); - for (;;) { - ssize_t rc = TEMP_FAILURE_RETRY( - writev(mSocket, iov + current, iovcnt - current)); - - if (rc > 0) { - size_t written = rc; - while ((current < iovcnt) && (written >= iov[current].iov_len)) { - written -= iov[current].iov_len; - current++; - } - if (current == iovcnt) { - break; - } - iov[current].iov_base = (char *)iov[current].iov_base + written; - iov[current].iov_len -= written; - continue; - } + ssize_t rc = TEMP_FAILURE_RETRY(writev(mSocket, iov + current, iovcnt - current)); if (rc == 0) { - e = EIO; + errno = EIO; SLOGW("0 length write :("); - } else { - e = errno; - SLOGW("write error (%s)", strerror(e)); + return -1; + } else if (rc < 0) { + SLOGW("write error (%s)", strerror(errno)); + return -1; } - ret = -1; - break; - } - sigaction(SIGPIPE, &old_action, &new_action); - - if (e != 0) { - errno = e; + size_t written = rc; + while (current < iovcnt && written >= iov[current].iov_len) { + written -= iov[current].iov_len; + current++; + } + if (current == iovcnt) { + return 0; + } + iov[current].iov_base = (char*)iov[current].iov_base + written; + iov[current].iov_len -= written; } - return ret; } void SocketClient::incRef() { diff --git a/libunwindstack/DwarfCfa.cpp b/libunwindstack/DwarfCfa.cpp index c128b9bb7a..c6db209dbd 100644 --- a/libunwindstack/DwarfCfa.cpp +++ b/libunwindstack/DwarfCfa.cpp @@ -26,7 +26,9 @@ #include <unwindstack/DwarfError.h> #include <unwindstack/DwarfLocation.h> +#include <unwindstack/Elf.h> #include <unwindstack/Log.h> +#include <unwindstack/MachineArm64.h> #include "DwarfCfa.h" #include "DwarfEncoding.h" @@ -204,8 +206,12 @@ template <typename AddressType> bool DwarfCfa<AddressType>::LogInstruction(uint32_t indent, uint64_t cfa_offset, uint8_t op, uint64_t* cur_pc) { const auto* cfa = &DwarfCfaInfo::kTable[op]; - if (cfa->name[0] == '\0') { - log(indent, "Illegal"); + if (cfa->name[0] == '\0' || (arch_ != ARCH_ARM64 && op == 0x2d)) { + if (op == 0x2d) { + log(indent, "Illegal (Only valid on aarch64)"); + } else { + log(indent, "Illegal"); + } log(indent, "Raw Data: 0x%02x", op); return true; } @@ -514,6 +520,24 @@ bool DwarfCfa<AddressType>::cfa_gnu_negative_offset_extended(dwarf_loc_regs_t* l return true; } +template <typename AddressType> +bool DwarfCfa<AddressType>::cfa_aarch64_negate_ra_state(dwarf_loc_regs_t* loc_regs) { + // Only supported on aarch64. + if (arch_ != ARCH_ARM64) { + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; + return false; + } + + auto cfa_location = loc_regs->find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE); + if (cfa_location == loc_regs->end()) { + (*loc_regs)[Arm64Reg::ARM64_PREG_RA_SIGN_STATE] = {.type = DWARF_LOCATION_PSEUDO_REGISTER, + .values = {1}}; + } else { + cfa_location->second.values[0] ^= 1; + } + return true; +} + const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { { // 0x00 DW_CFA_nop @@ -699,7 +723,13 @@ const DwarfCfaInfo::Info DwarfCfaInfo::kTable[64] = { {"", 0, 0, {}, {}}, // 0x2a illegal cfa {"", 0, 0, {}, {}}, // 0x2b illegal cfa {"", 0, 0, {}, {}}, // 0x2c illegal cfa - {"", 0, 0, {}, {}}, // 0x2d DW_CFA_GNU_window_save (Treat as illegal) + { + "DW_CFA_AARCH64_negate_ra_state", // 0x2d DW_CFA_AARCH64_negate_ra_state + 3, + 0, + {}, + {}, + }, { "DW_CFA_GNU_args_size", // 0x2e DW_CFA_GNU_args_size 2, diff --git a/libunwindstack/DwarfCfa.h b/libunwindstack/DwarfCfa.h index 569c17ceff..d627e156b7 100644 --- a/libunwindstack/DwarfCfa.h +++ b/libunwindstack/DwarfCfa.h @@ -31,6 +31,9 @@ namespace unwindstack { +// Forward declarations. +enum ArchEnum : uint8_t; + // DWARF Standard home: http://dwarfstd.org/ // This code is based on DWARF 4: http://http://dwarfstd.org/doc/DWARF4.pdf // See section 6.4.2.1 for a description of the DW_CFA_xxx values. @@ -72,7 +75,8 @@ class DwarfCfa { typedef typename std::make_signed<AddressType>::type SignedType; public: - DwarfCfa(DwarfMemory* memory, const DwarfFde* fde) : memory_(memory), fde_(fde) {} + DwarfCfa(DwarfMemory* memory, const DwarfFde* fde, ArchEnum arch) + : memory_(memory), fde_(fde), arch_(arch) {} virtual ~DwarfCfa() = default; bool GetLocationInfo(uint64_t pc, uint64_t start_offset, uint64_t end_offset, @@ -99,6 +103,7 @@ class DwarfCfa { DwarfErrorData last_error_; DwarfMemory* memory_; const DwarfFde* fde_; + ArchEnum arch_; AddressType cur_pc_; const dwarf_loc_regs_t* cie_loc_regs_ = nullptr; @@ -128,6 +133,7 @@ class DwarfCfa { bool cfa_val_offset_sf(dwarf_loc_regs_t*); bool cfa_val_expression(dwarf_loc_regs_t*); bool cfa_gnu_negative_offset_extended(dwarf_loc_regs_t*); + bool cfa_aarch64_negate_ra_state(dwarf_loc_regs_t*); using process_func = bool (DwarfCfa::*)(dwarf_loc_regs_t*); constexpr static process_func kCallbackTable[64] = { @@ -221,8 +227,9 @@ class DwarfCfa { nullptr, // 0x2c illegal cfa nullptr, - // 0x2d DW_CFA_GNU_window_save (Treat this as illegal) - nullptr, + // 0x2d DW_CFA_AARCH64_negate_ra_state (aarch64 only) + // DW_CFA_GNU_window_save on other architectures. + &DwarfCfa::cfa_aarch64_negate_ra_state, // 0x2e DW_CFA_GNU_args_size &DwarfCfa::cfa_nop, // 0x2f DW_CFA_GNU_negative_offset_extended diff --git a/libunwindstack/DwarfSection.cpp b/libunwindstack/DwarfSection.cpp index 18bd490f9b..9e2a3cda7e 100644 --- a/libunwindstack/DwarfSection.cpp +++ b/libunwindstack/DwarfSection.cpp @@ -21,6 +21,7 @@ #include <unwindstack/DwarfMemory.h> #include <unwindstack/DwarfSection.h> #include <unwindstack/DwarfStructs.h> +#include <unwindstack/Elf.h> #include <unwindstack/Log.h> #include <unwindstack/Memory.h> #include <unwindstack/Regs.h> @@ -49,7 +50,7 @@ bool DwarfSection::Step(uint64_t pc, Regs* regs, Memory* process_memory, bool* f // Now get the location information for this pc. dwarf_loc_regs_t loc_regs; - if (!GetCfaLocationInfo(pc, fde, &loc_regs)) { + if (!GetCfaLocationInfo(pc, fde, &loc_regs, regs->Arch())) { return false; } loc_regs.cie = fde->cie; @@ -464,6 +465,13 @@ bool DwarfSectionImpl<AddressType>::EvalRegister(const DwarfLocation* loc, uint3 eval_info->return_address_undefined = true; } break; + case DWARF_LOCATION_PSEUDO_REGISTER: { + if (!eval_info->regs_info.regs->SetPseudoRegister(reg, loc->values[0])) { + last_error_.code = DWARF_ERROR_ILLEGAL_VALUE; + return false; + } + break; + } default: break; } @@ -491,6 +499,10 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me // Always set the dex pc to zero when evaluating. cur_regs->set_dex_pc(0); + // Reset necessary pseudo registers before evaluation. + // This is needed for ARM64, for example. + regs->ResetPseudoRegisters(); + EvalInfo<AddressType> eval_info{.loc_regs = &loc_regs, .cie = cie, .regular_memory = regular_memory, @@ -527,8 +539,10 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me AddressType* reg_ptr; if (reg >= cur_regs->total_regs()) { - // Skip this unknown register. - continue; + if (entry.second.type != DWARF_LOCATION_PSEUDO_REGISTER) { + // Skip this unknown register. + continue; + } } reg_ptr = eval_info.regs_info.Save(reg); @@ -554,8 +568,8 @@ bool DwarfSectionImpl<AddressType>::Eval(const DwarfCie* cie, Memory* regular_me template <typename AddressType> bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, - dwarf_loc_regs_t* loc_regs) { - DwarfCfa<AddressType> cfa(&memory_, fde); + dwarf_loc_regs_t* loc_regs, ArchEnum arch) { + DwarfCfa<AddressType> cfa(&memory_, fde, arch); // Look for the cached copy of the cie data. auto reg_entry = cie_loc_regs_.find(fde->cie_offset); @@ -576,8 +590,9 @@ bool DwarfSectionImpl<AddressType>::GetCfaLocationInfo(uint64_t pc, const DwarfF } template <typename AddressType> -bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) { - DwarfCfa<AddressType> cfa(&memory_, fde); +bool DwarfSectionImpl<AddressType>::Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, + ArchEnum arch) { + DwarfCfa<AddressType> cfa(&memory_, fde, arch); // Always print the cie information. const DwarfCie* cie = fde->cie; diff --git a/libunwindstack/RegsArm64.cpp b/libunwindstack/RegsArm64.cpp index 5b7431a57c..b496187cb1 100644 --- a/libunwindstack/RegsArm64.cpp +++ b/libunwindstack/RegsArm64.cpp @@ -30,7 +30,10 @@ namespace unwindstack { RegsArm64::RegsArm64() - : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) {} + : RegsImpl<uint64_t>(ARM64_REG_LAST, Location(LOCATION_REGISTER, ARM64_REG_LR)) { + ResetPseudoRegisters(); + pac_mask_ = 0; +} ArchEnum RegsArm64::Arch() { return ARCH_ARM64; @@ -45,6 +48,23 @@ uint64_t RegsArm64::sp() { } void RegsArm64::set_pc(uint64_t pc) { + // If the target is aarch64 then the return address may have been + // signed using the Armv8.3-A Pointer Authentication extension. The + // original return address can be restored by stripping out the + // authentication code using a mask or xpaclri. xpaclri is a NOP on + // pre-Armv8.3-A architectures. + if ((0 != pc) && IsRASigned()) { + if (pac_mask_) { + pc &= ~pac_mask_; +#if defined(__aarch64__) + } else { + register uint64_t x30 __asm("x30") = pc; + // This is XPACLRI. + asm("hint 0x7" : "+r"(x30)); + pc = x30; +#endif + } + } regs_[ARM64_REG_PC] = pc; } @@ -144,6 +164,37 @@ bool RegsArm64::StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* proce return true; } +void RegsArm64::ResetPseudoRegisters(void) { + // DWARF for AArch64 says RA_SIGN_STATE should be initialized to 0. + this->SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 0); +} + +bool RegsArm64::SetPseudoRegister(uint16_t id, uint64_t value) { + if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) { + pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST] = value; + return true; + } + return false; +} + +bool RegsArm64::GetPseudoRegister(uint16_t id, uint64_t* value) { + if ((id >= Arm64Reg::ARM64_PREG_FIRST) && (id < Arm64Reg::ARM64_PREG_LAST)) { + *value = pseudo_regs_[id - Arm64Reg::ARM64_PREG_FIRST]; + return true; + } + return false; +} + +bool RegsArm64::IsRASigned() { + uint64_t value; + auto result = this->GetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, &value); + return (result && (value != 0)); +} + +void RegsArm64::SetPACMask(uint64_t mask) { + pac_mask_ = mask; +} + Regs* RegsArm64::Clone() { return new RegsArm64(*this); } diff --git a/libunwindstack/include/unwindstack/DwarfLocation.h b/libunwindstack/include/unwindstack/DwarfLocation.h index 3d50ccf369..bf45bc7528 100644 --- a/libunwindstack/include/unwindstack/DwarfLocation.h +++ b/libunwindstack/include/unwindstack/DwarfLocation.h @@ -33,6 +33,7 @@ enum DwarfLocationEnum : uint8_t { DWARF_LOCATION_REGISTER, DWARF_LOCATION_EXPRESSION, DWARF_LOCATION_VAL_EXPRESSION, + DWARF_LOCATION_PSEUDO_REGISTER, }; struct DwarfLocation { diff --git a/libunwindstack/include/unwindstack/DwarfSection.h b/libunwindstack/include/unwindstack/DwarfSection.h index c244749c19..af823da5f9 100644 --- a/libunwindstack/include/unwindstack/DwarfSection.h +++ b/libunwindstack/include/unwindstack/DwarfSection.h @@ -31,6 +31,7 @@ namespace unwindstack { // Forward declarations. +enum ArchEnum : uint8_t; class Memory; class Regs; template <typename AddressType> @@ -90,13 +91,14 @@ class DwarfSection { virtual bool Eval(const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*) = 0; - virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) = 0; + virtual bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, ArchEnum arch) = 0; virtual void GetFdes(std::vector<const DwarfFde*>* fdes) = 0; virtual const DwarfFde* GetFdeFromPc(uint64_t pc) = 0; - virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) = 0; + virtual bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs, + ArchEnum arch) = 0; virtual uint64_t GetCieOffsetFromFde32(uint32_t pointer) = 0; @@ -140,9 +142,10 @@ class DwarfSectionImpl : public DwarfSection { bool Eval(const DwarfCie* cie, Memory* regular_memory, const dwarf_loc_regs_t& loc_regs, Regs* regs, bool* finished) override; - bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs) override; + bool GetCfaLocationInfo(uint64_t pc, const DwarfFde* fde, dwarf_loc_regs_t* loc_regs, + ArchEnum arch) override; - bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde) override; + bool Log(uint8_t indent, uint64_t pc, const DwarfFde* fde, ArchEnum arch) override; protected: bool GetNextCieOrFde(const DwarfFde** fde_entry); diff --git a/libunwindstack/include/unwindstack/MachineArm64.h b/libunwindstack/include/unwindstack/MachineArm64.h index e953335101..358e3d9898 100644 --- a/libunwindstack/include/unwindstack/MachineArm64.h +++ b/libunwindstack/include/unwindstack/MachineArm64.h @@ -60,6 +60,13 @@ enum Arm64Reg : uint16_t { ARM64_REG_SP = ARM64_REG_R31, ARM64_REG_LR = ARM64_REG_R30, + + // Pseudo registers. These are not machine registers. + + // AARCH64 Return address signed state pseudo-register + ARM64_PREG_RA_SIGN_STATE = 34, + ARM64_PREG_FIRST = ARM64_PREG_RA_SIGN_STATE, + ARM64_PREG_LAST, }; } // namespace unwindstack diff --git a/libunwindstack/include/unwindstack/Regs.h b/libunwindstack/include/unwindstack/Regs.h index a367e6cf17..5f42565676 100644 --- a/libunwindstack/include/unwindstack/Regs.h +++ b/libunwindstack/include/unwindstack/Regs.h @@ -64,6 +64,10 @@ class Regs { uint64_t dex_pc() { return dex_pc_; } void set_dex_pc(uint64_t dex_pc) { dex_pc_ = dex_pc; } + virtual void ResetPseudoRegisters() {} + virtual bool SetPseudoRegister(uint16_t, uint64_t) { return false; } + virtual bool GetPseudoRegister(uint16_t, uint64_t*) { return false; } + virtual bool StepIfSignalHandler(uint64_t elf_offset, Elf* elf, Memory* process_memory) = 0; virtual bool SetPcFromReturnAddress(Memory* process_memory) = 0; diff --git a/libunwindstack/include/unwindstack/RegsArm64.h b/libunwindstack/include/unwindstack/RegsArm64.h index 2b3ddeb77a..bf7ab15275 100644 --- a/libunwindstack/include/unwindstack/RegsArm64.h +++ b/libunwindstack/include/unwindstack/RegsArm64.h @@ -22,6 +22,7 @@ #include <functional> #include <unwindstack/Elf.h> +#include <unwindstack/MachineArm64.h> #include <unwindstack/Regs.h> namespace unwindstack { @@ -48,11 +49,25 @@ class RegsArm64 : public RegsImpl<uint64_t> { void set_pc(uint64_t pc) override; void set_sp(uint64_t sp) override; + void ResetPseudoRegisters() override; + + bool SetPseudoRegister(uint16_t id, uint64_t value) override; + + bool GetPseudoRegister(uint16_t id, uint64_t* value) override; + + bool IsRASigned(); + + void SetPACMask(uint64_t mask); + Regs* Clone() override final; static Regs* Read(void* data); static Regs* CreateFromUcontext(void* ucontext); + + protected: + uint64_t pseudo_regs_[Arm64Reg::ARM64_PREG_LAST - Arm64Reg::ARM64_PREG_FIRST]; + uint64_t pac_mask_; }; } // namespace unwindstack diff --git a/libunwindstack/tests/DwarfCfaLogTest.cpp b/libunwindstack/tests/DwarfCfaLogTest.cpp index def408875b..2b5a8dc834 100644 --- a/libunwindstack/tests/DwarfCfaLogTest.cpp +++ b/libunwindstack/tests/DwarfCfaLogTest.cpp @@ -26,6 +26,7 @@ #include <unwindstack/DwarfLocation.h> #include <unwindstack/DwarfMemory.h> #include <unwindstack/DwarfStructs.h> +#include <unwindstack/Elf.h> #include <unwindstack/Log.h> #include "DwarfCfa.h" @@ -57,7 +58,7 @@ class DwarfCfaLogTest : public ::testing::Test { fde_.pc_end = 0x2000; fde_.pc_end = 0x10000; fde_.cie = &cie_; - cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_)); + cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_, ARCH_UNKNOWN)); } MemoryFake memory_; @@ -72,8 +73,8 @@ TYPED_TEST_SUITE_P(DwarfCfaLogTest); TYPED_TEST_P(DwarfCfaLogTest, cfa_illegal) { for (uint8_t i = 0x17; i < 0x3f; i++) { - if (i == 0x2e || i == 0x2f) { - // Skip gnu extension ops. + if (i == 0x2d || i == 0x2e || i == 0x2f) { + // Skip gnu extension ops and aarch64 specialized op. continue; } this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i}); @@ -763,6 +764,26 @@ TYPED_TEST_P(DwarfCfaLogTest, cfa_register_override) { ASSERT_EQ("", GetFakeLogBuf()); } +TYPED_TEST_P(DwarfCfaLogTest, cfa_aarch64_negate_ra_state) { + // Verify that if the cfa op is handled properly depending on aarch. + this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2d}); + + ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001)); + std::string expected = "4 unwind Illegal (Only valid on aarch64)\n"; + expected += "4 unwind Raw Data: 0x2d\n"; + ASSERT_EQ(expected, GetFakeLogPrint()); + ASSERT_EQ("", GetFakeLogBuf()); + + ResetLogs(); + this->cfa_.reset(new DwarfCfa<TypeParam>(this->dmem_.get(), &this->fde_, ARCH_ARM64)); + + ASSERT_TRUE(this->cfa_->Log(0, this->fde_.pc_start, 0x2000, 0x2001)); + expected = "4 unwind DW_CFA_AARCH64_negate_ra_state\n"; + expected += "4 unwind Raw Data: 0x2d\n"; + ASSERT_EQ(expected, GetFakeLogPrint()); + ASSERT_EQ("", GetFakeLogBuf()); +} + REGISTER_TYPED_TEST_SUITE_P(DwarfCfaLogTest, cfa_illegal, cfa_nop, cfa_offset, cfa_offset_extended, cfa_offset_extended_sf, cfa_restore, cfa_restore_extended, cfa_set_loc, cfa_advance_loc, cfa_advance_loc1, cfa_advance_loc2, cfa_advance_loc4, @@ -771,7 +792,8 @@ REGISTER_TYPED_TEST_SUITE_P(DwarfCfaLogTest, cfa_illegal, cfa_nop, cfa_offset, c cfa_def_cfa_register, cfa_def_cfa_offset, cfa_def_cfa_offset_sf, cfa_def_cfa_expression, cfa_expression, cfa_val_offset, cfa_val_offset_sf, cfa_val_expression, cfa_gnu_args_size, - cfa_gnu_negative_offset_extended, cfa_register_override); + cfa_gnu_negative_offset_extended, cfa_register_override, + cfa_aarch64_negate_ra_state); typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaLogTestTypes; INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaLogTest, DwarfCfaLogTestTypes); diff --git a/libunwindstack/tests/DwarfCfaTest.cpp b/libunwindstack/tests/DwarfCfaTest.cpp index 9c6ab05e63..ea7e70807e 100644 --- a/libunwindstack/tests/DwarfCfaTest.cpp +++ b/libunwindstack/tests/DwarfCfaTest.cpp @@ -25,7 +25,9 @@ #include <unwindstack/DwarfLocation.h> #include <unwindstack/DwarfMemory.h> #include <unwindstack/DwarfStructs.h> +#include <unwindstack/Elf.h> #include <unwindstack/Log.h> +#include <unwindstack/MachineArm64.h> #include "DwarfCfa.h" @@ -55,7 +57,7 @@ class DwarfCfaTest : public ::testing::Test { fde_.pc_start = 0x2000; fde_.cie = &cie_; - cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_)); + cfa_.reset(new DwarfCfa<TypeParam>(dmem_.get(), &fde_, ARCH_UNKNOWN)); } MemoryFake memory_; @@ -70,8 +72,8 @@ TYPED_TEST_SUITE_P(DwarfCfaTest); TYPED_TEST_P(DwarfCfaTest, cfa_illegal) { for (uint8_t i = 0x17; i < 0x3f; i++) { - if (i == 0x2e || i == 0x2f) { - // Skip gnu extension ops. + if (i == 0x2d || i == 0x2e || i == 0x2f) { + // Skip gnu extension ops and aarch64 specialized op. continue; } this->memory_.SetMemory(0x2000, std::vector<uint8_t>{i}); @@ -952,6 +954,57 @@ TYPED_TEST_P(DwarfCfaTest, cfa_register_override) { ASSERT_EQ("", GetFakeLogBuf()); } +TYPED_TEST_P(DwarfCfaTest, cfa_aarch64_negate_ra_state) { + this->memory_.SetMemory(0x2000, std::vector<uint8_t>{0x2d}); + dwarf_loc_regs_t loc_regs; + + ASSERT_FALSE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs)); + ASSERT_EQ(DWARF_ERROR_ILLEGAL_VALUE, this->cfa_->LastErrorCode()); + ASSERT_EQ(0x2001U, this->dmem_->cur_offset()); + + ASSERT_EQ("", GetFakeLogPrint()); + ASSERT_EQ("", GetFakeLogBuf()); + + ResetLogs(); + this->cfa_.reset(new DwarfCfa<TypeParam>(this->dmem_.get(), &this->fde_, ARCH_ARM64)); + ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs)); + ASSERT_EQ(0x2001U, this->dmem_->cur_offset()); + + auto location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE); + ASSERT_NE(loc_regs.end(), location); + ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type); + ASSERT_EQ(1U, location->second.values[0]); + + ASSERT_EQ("", GetFakeLogPrint()); + ASSERT_EQ("", GetFakeLogBuf()); + + // Verify that the value is set to 0 after another evaluation. + ResetLogs(); + ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs)); + ASSERT_EQ(0x2001U, this->dmem_->cur_offset()); + + location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE); + ASSERT_NE(loc_regs.end(), location); + ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type); + ASSERT_EQ(0U, location->second.values[0]); + + ASSERT_EQ("", GetFakeLogPrint()); + ASSERT_EQ("", GetFakeLogBuf()); + + // Verify that the value is set to 1 again after a third op. + ResetLogs(); + ASSERT_TRUE(this->cfa_->GetLocationInfo(this->fde_.pc_start, 0x2000, 0x2001, &loc_regs)); + ASSERT_EQ(0x2001U, this->dmem_->cur_offset()); + + location = loc_regs.find(Arm64Reg::ARM64_PREG_RA_SIGN_STATE); + ASSERT_NE(loc_regs.end(), location); + ASSERT_EQ(DWARF_LOCATION_PSEUDO_REGISTER, location->second.type); + ASSERT_EQ(1U, location->second.values[0]); + + ASSERT_EQ("", GetFakeLogPrint()); + ASSERT_EQ("", GetFakeLogBuf()); +} + REGISTER_TYPED_TEST_SUITE_P(DwarfCfaTest, cfa_illegal, cfa_nop, cfa_offset, cfa_offset_extended, cfa_offset_extended_sf, cfa_restore, cfa_restore_extended, cfa_set_loc, cfa_advance_loc1, cfa_advance_loc2, cfa_advance_loc4, cfa_undefined, @@ -960,7 +1013,7 @@ REGISTER_TYPED_TEST_SUITE_P(DwarfCfaTest, cfa_illegal, cfa_nop, cfa_offset, cfa_ cfa_def_cfa_offset_sf, cfa_def_cfa_expression, cfa_expression, cfa_val_offset, cfa_val_offset_sf, cfa_val_expression, cfa_gnu_args_size, cfa_gnu_negative_offset_extended, - cfa_register_override); + cfa_register_override, cfa_aarch64_negate_ra_state); typedef ::testing::Types<uint32_t, uint64_t> DwarfCfaTestTypes; INSTANTIATE_TYPED_TEST_SUITE_P(Libunwindstack, DwarfCfaTest, DwarfCfaTestTypes); diff --git a/libunwindstack/tests/DwarfSectionImplTest.cpp b/libunwindstack/tests/DwarfSectionImplTest.cpp index cac59b7e9c..d57cd339dd 100644 --- a/libunwindstack/tests/DwarfSectionImplTest.cpp +++ b/libunwindstack/tests/DwarfSectionImplTest.cpp @@ -20,6 +20,7 @@ #include <unwindstack/DwarfError.h> #include <unwindstack/DwarfSection.h> +#include <unwindstack/Elf.h> #include "DwarfEncoding.h" @@ -505,7 +506,7 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_not_cached) { this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0x09, 0x04, 0x03}); dwarf_loc_regs_t loc_regs; - ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs)); + ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs, ARCH_UNKNOWN)); ASSERT_EQ(2U, loc_regs.size()); auto entry = loc_regs.find(2); @@ -535,7 +536,7 @@ TYPED_TEST_P(DwarfSectionImplTest, GetCfaLocationInfo_cie_cached) { this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0x09, 0x04, 0x03}); dwarf_loc_regs_t loc_regs; - ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs)); + ASSERT_TRUE(this->section_->GetCfaLocationInfo(0x100, &fde, &loc_regs, ARCH_UNKNOWN)); ASSERT_EQ(2U, loc_regs.size()); auto entry = loc_regs.find(6); @@ -560,7 +561,7 @@ TYPED_TEST_P(DwarfSectionImplTest, Log) { this->memory_.SetMemory(0x5000, std::vector<uint8_t>{0x00}); this->memory_.SetMemory(0x6000, std::vector<uint8_t>{0xc2}); - ASSERT_TRUE(this->section_->Log(2, 0x1000, &fde)); + ASSERT_TRUE(this->section_->Log(2, 0x1000, &fde, ARCH_UNKNOWN)); ASSERT_EQ( "4 unwind DW_CFA_nop\n" diff --git a/libunwindstack/tests/DwarfSectionTest.cpp b/libunwindstack/tests/DwarfSectionTest.cpp index 953dc75637..febd6d326c 100644 --- a/libunwindstack/tests/DwarfSectionTest.cpp +++ b/libunwindstack/tests/DwarfSectionTest.cpp @@ -20,8 +20,10 @@ #include <gtest/gtest.h> #include <unwindstack/DwarfSection.h> +#include <unwindstack/Elf.h> #include "MemoryFake.h" +#include "RegsFake.h" namespace unwindstack { @@ -35,13 +37,14 @@ class MockDwarfSection : public DwarfSection { MOCK_METHOD(bool, Eval, (const DwarfCie*, Memory*, const dwarf_loc_regs_t&, Regs*, bool*), (override)); - MOCK_METHOD(bool, Log, (uint8_t, uint64_t, const DwarfFde*), (override)); + MOCK_METHOD(bool, Log, (uint8_t, uint64_t, const DwarfFde*, ArchEnum arch), (override)); MOCK_METHOD(void, GetFdes, (std::vector<const DwarfFde*>*), (override)); MOCK_METHOD(const DwarfFde*, GetFdeFromPc, (uint64_t), (override)); - MOCK_METHOD(bool, GetCfaLocationInfo, (uint64_t, const DwarfFde*, dwarf_loc_regs_t*), (override)); + MOCK_METHOD(bool, GetCfaLocationInfo, + (uint64_t, const DwarfFde*, dwarf_loc_regs_t*, ArchEnum arch), (override)); MOCK_METHOD(uint64_t, GetCieOffsetFromFde32, (uint32_t), (override)); @@ -56,8 +59,11 @@ class DwarfSectionTest : public ::testing::Test { MemoryFake memory_; std::unique_ptr<MockDwarfSection> section_; + static RegsFake regs_; }; +RegsFake DwarfSectionTest::regs_(10); + TEST_F(DwarfSectionTest, Step_fail_fde) { EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(nullptr)); @@ -73,7 +79,7 @@ TEST_F(DwarfSectionTest, Step_fail_cie_null) { EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde)); bool finished; - ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished)); + ASSERT_FALSE(section_->Step(0x1000, ®s_, nullptr, &finished)); } TEST_F(DwarfSectionTest, Step_fail_cfa_location) { @@ -83,11 +89,11 @@ TEST_F(DwarfSectionTest, Step_fail_cfa_location) { fde.cie = &cie; EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde)); - EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_)) + EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_)) .WillOnce(::testing::Return(false)); bool finished; - ASSERT_FALSE(section_->Step(0x1000, nullptr, nullptr, &finished)); + ASSERT_FALSE(section_->Step(0x1000, ®s_, nullptr, &finished)); } TEST_F(DwarfSectionTest, Step_pass) { @@ -97,19 +103,19 @@ TEST_F(DwarfSectionTest, Step_pass) { fde.cie = &cie; EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde)); - EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_)) + EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_)) .WillOnce(::testing::Return(true)); MemoryFake process; - EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_)) + EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, ®s_, ::testing::_)) .WillOnce(::testing::Return(true)); bool finished; - ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished)); + ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished)); } static bool MockGetCfaLocationInfo(::testing::Unused, const DwarfFde* fde, - dwarf_loc_regs_t* loc_regs) { + dwarf_loc_regs_t* loc_regs, ArchEnum) { loc_regs->pc_start = fde->pc_start; loc_regs->pc_end = fde->pc_end; return true; @@ -123,17 +129,17 @@ TEST_F(DwarfSectionTest, Step_cache) { fde.cie = &cie; EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde)); - EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_)) + EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde, ::testing::_, ::testing::_)) .WillOnce(::testing::Invoke(MockGetCfaLocationInfo)); MemoryFake process; - EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_)) + EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, ®s_, ::testing::_)) .WillRepeatedly(::testing::Return(true)); bool finished; - ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished)); - ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished)); - ASSERT_TRUE(section_->Step(0x1500, nullptr, &process, &finished)); + ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished)); + ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished)); + ASSERT_TRUE(section_->Step(0x1500, ®s_, &process, &finished)); } TEST_F(DwarfSectionTest, Step_cache_not_in_pc) { @@ -143,26 +149,26 @@ TEST_F(DwarfSectionTest, Step_cache_not_in_pc) { fde0.pc_end = 0x2000; fde0.cie = &cie; EXPECT_CALL(*section_, GetFdeFromPc(0x1000)).WillOnce(::testing::Return(&fde0)); - EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_)) + EXPECT_CALL(*section_, GetCfaLocationInfo(0x1000, &fde0, ::testing::_, ::testing::_)) .WillOnce(::testing::Invoke(MockGetCfaLocationInfo)); MemoryFake process; - EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, nullptr, ::testing::_)) + EXPECT_CALL(*section_, Eval(&cie, &process, ::testing::_, ®s_, ::testing::_)) .WillRepeatedly(::testing::Return(true)); bool finished; - ASSERT_TRUE(section_->Step(0x1000, nullptr, &process, &finished)); + ASSERT_TRUE(section_->Step(0x1000, ®s_, &process, &finished)); DwarfFde fde1{}; fde1.pc_start = 0x500; fde1.pc_end = 0x800; fde1.cie = &cie; EXPECT_CALL(*section_, GetFdeFromPc(0x600)).WillOnce(::testing::Return(&fde1)); - EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_)) + EXPECT_CALL(*section_, GetCfaLocationInfo(0x600, &fde1, ::testing::_, ::testing::_)) .WillOnce(::testing::Invoke(MockGetCfaLocationInfo)); - ASSERT_TRUE(section_->Step(0x600, nullptr, &process, &finished)); - ASSERT_TRUE(section_->Step(0x700, nullptr, &process, &finished)); + ASSERT_TRUE(section_->Step(0x600, ®s_, &process, &finished)); + ASSERT_TRUE(section_->Step(0x700, ®s_, &process, &finished)); } } // namespace unwindstack diff --git a/libunwindstack/tests/RegsTest.cpp b/libunwindstack/tests/RegsTest.cpp index e4fc6f0706..acf72de2c5 100644 --- a/libunwindstack/tests/RegsTest.cpp +++ b/libunwindstack/tests/RegsTest.cpp @@ -247,6 +247,14 @@ TEST_F(RegsTest, mips64_verify_sp_pc) { EXPECT_EQ(0xc200000000U, mips64.pc()); } +TEST_F(RegsTest, arm64_strip_pac_mask) { + RegsArm64 arm64; + arm64.SetPseudoRegister(Arm64Reg::ARM64_PREG_RA_SIGN_STATE, 1); + arm64.SetPACMask(0x007fff8000000000ULL); + arm64.set_pc(0x0020007214bb3a04ULL); + EXPECT_EQ(0x0000007214bb3a04ULL, arm64.pc()); +} + TEST_F(RegsTest, machine_type) { RegsArm arm_regs; EXPECT_EQ(ARCH_ARM, arm_regs.Arch()); diff --git a/libunwindstack/tests/VerifyBionicTerminationTest.cpp b/libunwindstack/tests/VerifyBionicTerminationTest.cpp index 6a3e91a2ad..eb2b01d297 100644 --- a/libunwindstack/tests/VerifyBionicTerminationTest.cpp +++ b/libunwindstack/tests/VerifyBionicTerminationTest.cpp @@ -55,7 +55,7 @@ static DwarfLocationEnum GetReturnAddressLocation(uint64_t rel_pc, DwarfSection* return DWARF_LOCATION_INVALID; } dwarf_loc_regs_t regs; - if (!section->GetCfaLocationInfo(rel_pc, fde, ®s)) { + if (!section->GetCfaLocationInfo(rel_pc, fde, ®s, ARCH_UNKNOWN)) { return DWARF_LOCATION_INVALID; } diff --git a/libunwindstack/tools/unwind_info.cpp b/libunwindstack/tools/unwind_info.cpp index 7a6d8ba464..a5002f2268 100644 --- a/libunwindstack/tools/unwind_info.cpp +++ b/libunwindstack/tools/unwind_info.cpp @@ -96,7 +96,7 @@ void DumpDwarfSection(Elf* elf, DwarfSection* section, uint64_t) { printf(" <%s>", name.c_str()); } printf("\n"); - if (!section->Log(2, UINT64_MAX, fde)) { + if (!section->Log(2, UINT64_MAX, fde, elf->arch())) { printf("Failed to process cfa information for entry at 0x%" PRIx64 "\n", fde->pc_start); } } diff --git a/libunwindstack/tools/unwind_reg_info.cpp b/libunwindstack/tools/unwind_reg_info.cpp index 0cbcac5a05..68e02735d9 100644 --- a/libunwindstack/tools/unwind_reg_info.cpp +++ b/libunwindstack/tools/unwind_reg_info.cpp @@ -64,7 +64,8 @@ void PrintExpression(Memory* memory, uint8_t class_type, uint64_t end, uint64_t } } -void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uint8_t class_type) { +void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uint8_t class_type, + ArchEnum arch) { const DwarfFde* fde = section->GetFdeFromPc(pc); if (fde == nullptr) { printf(" No fde found.\n"); @@ -72,7 +73,7 @@ void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uin } dwarf_loc_regs_t regs; - if (!section->GetCfaLocationInfo(pc, fde, ®s)) { + if (!section->GetCfaLocationInfo(pc, fde, ®s, arch)) { printf(" Cannot get location information.\n"); return; } @@ -128,6 +129,11 @@ void PrintRegInformation(DwarfSection* section, Memory* memory, uint64_t pc, uin break; } + case DWARF_LOCATION_PSEUDO_REGISTER: { + printf("%" PRId64 " (pseudo)\n", loc->values[0]); + break; + } + case DWARF_LOCATION_UNDEFINED: printf("undefine\n"); break; @@ -199,7 +205,7 @@ int GetInfo(const char* file, uint64_t offset, uint64_t pc) { DwarfSection* section = interface->eh_frame(); if (section != nullptr) { printf("\neh_frame:\n"); - PrintRegInformation(section, elf.memory(), pc, elf.class_type()); + PrintRegInformation(section, elf.memory(), pc, elf.class_type(), elf.arch()); } else { printf("\nno eh_frame information\n"); } @@ -207,7 +213,7 @@ int GetInfo(const char* file, uint64_t offset, uint64_t pc) { section = interface->debug_frame(); if (section != nullptr) { printf("\ndebug_frame:\n"); - PrintRegInformation(section, elf.memory(), pc, elf.class_type()); + PrintRegInformation(section, elf.memory(), pc, elf.class_type(), elf.arch()); printf("\n"); } else { printf("\nno debug_frame information\n"); @@ -219,7 +225,8 @@ int GetInfo(const char* file, uint64_t offset, uint64_t pc) { section = gnu_debugdata_interface->eh_frame(); if (section != nullptr) { printf("\ngnu_debugdata (eh_frame):\n"); - PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type()); + PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type(), + elf.arch()); printf("\n"); } else { printf("\nno gnu_debugdata (eh_frame)\n"); @@ -228,7 +235,8 @@ int GetInfo(const char* file, uint64_t offset, uint64_t pc) { section = gnu_debugdata_interface->debug_frame(); if (section != nullptr) { printf("\ngnu_debugdata (debug_frame):\n"); - PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type()); + PrintRegInformation(section, gnu_debugdata_interface->memory(), pc, elf.class_type(), + elf.arch()); printf("\n"); } else { printf("\nno gnu_debugdata (debug_frame)\n"); diff --git a/libutils/Unicode.cpp b/libutils/Unicode.cpp index b08e061c0f..b6e457b04c 100644 --- a/libutils/Unicode.cpp +++ b/libutils/Unicode.cpp @@ -162,9 +162,9 @@ int32_t utf32_from_utf8_at(const char *src, size_t src_len, size_t index, size_t if (index >= src_len) { return -1; } - size_t dummy_index; + size_t unused_index; if (next_index == nullptr) { - next_index = &dummy_index; + next_index = &unused_index; } size_t num_read; int32_t ret = utf32_at_internal(src + index, &num_read); diff --git a/libutils/include/utils/Vector.h b/libutils/include/utils/Vector.h index ddf71de240..be35ea2f04 100644 --- a/libutils/include/utils/Vector.h +++ b/libutils/include/utils/Vector.h @@ -23,15 +23,13 @@ #include <log/log.h> #include <utils/TypeHelpers.h> #include <utils/VectorImpl.h> - -/* - * Used to blacklist some functions from CFI. - * - */ #ifndef __has_attribute #define __has_attribute(x) 0 #endif +/* + * Used to exclude some functions from CFI. + */ #if __has_attribute(no_sanitize) #define UTILS_VECTOR_NO_CFI __attribute__((no_sanitize("cfi"))) #else diff --git a/logcat/logcat.cpp b/logcat/logcat.cpp index d15fa2be7c..c7d16347bf 100644 --- a/logcat/logcat.cpp +++ b/logcat/logcat.cpp @@ -616,15 +616,15 @@ int Logcat::Run(int argc, char** argv) { if (long_options[option_index].name == wrap_str) { mode |= ANDROID_LOG_WRAP | ANDROID_LOG_NONBLOCK; // ToDo: implement API that supports setting a wrap timeout - size_t dummy = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT; - if (optarg && (!ParseUint(optarg, &dummy) || dummy < 1)) { + size_t timeout = ANDROID_LOG_WRAP_DEFAULT_TIMEOUT; + if (optarg && (!ParseUint(optarg, &timeout) || timeout < 1)) { error(EXIT_FAILURE, 0, "%s %s out of range.", long_options[option_index].name, optarg); } - if (dummy != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) { + if (timeout != ANDROID_LOG_WRAP_DEFAULT_TIMEOUT) { fprintf(stderr, "WARNING: %s %u seconds, ignoring %zu\n", long_options[option_index].name, ANDROID_LOG_WRAP_DEFAULT_TIMEOUT, - dummy); + timeout); } break; } diff --git a/logd/Android.bp b/logd/Android.bp index 036cb7e448..265e19e8fd 100644 --- a/logd/Android.bp +++ b/logd/Android.bp @@ -177,6 +177,27 @@ cc_test { }, test_suites: [ "cts", + "device-tests", "vts10", ], } + +cc_binary { + name: "replay_messages", + defaults: ["logd_defaults"], + host_supported: true, + + srcs: [ + "ReplayMessages.cpp", + ], + + static_libs: [ + "libbase", + "libcutils", + "liblog", + "liblogd", + "libselinux", + "libz", + "libzstd", + ], +} diff --git a/logd/LogAudit.cpp b/logd/LogAudit.cpp index 0ce9796b0a..0e17476ea6 100644 --- a/logd/LogAudit.cpp +++ b/logd/LogAudit.cpp @@ -32,7 +32,7 @@ #include <sstream> #include <android-base/macros.h> -#include <log/log_properties.h> +#include <android-base/properties.h> #include <private/android_filesystem_config.h> #include <private/android_logger.h> @@ -40,6 +40,8 @@ #include "LogUtils.h" #include "libaudit.h" +using android::base::GetBoolProperty; + #define KMSG_PRIORITY(PRI) \ '<', '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) / 10, \ '0' + LOG_MAKEPRI(LOG_AUTH, LOG_PRI(PRI)) % 10, '>' @@ -48,8 +50,8 @@ LogAudit::LogAudit(LogBuffer* buf, int fdDmesg, LogStatistics* stats) : SocketListener(getLogSocket(), false), logbuf(buf), fdDmesg(fdDmesg), - main(__android_logger_property_get_bool("ro.logd.auditd.main", BOOL_DEFAULT_TRUE)), - events(__android_logger_property_get_bool("ro.logd.auditd.events", BOOL_DEFAULT_TRUE)), + main(GetBoolProperty("ro.logd.auditd.main", true)), + events(GetBoolProperty("ro.logd.auditd.events", true)), initialized(false), stats_(stats) { static const char auditd_message[] = { KMSG_PRIORITY(LOG_INFO), diff --git a/logd/LogBufferTest.cpp b/logd/LogBufferTest.cpp index 47d2a2f920..191110522e 100644 --- a/logd/LogBufferTest.cpp +++ b/logd/LogBufferTest.cpp @@ -34,16 +34,6 @@ using android::base::Join; using android::base::Split; using android::base::StringPrintf; -#ifndef __ANDROID__ -unsigned long __android_logger_get_buffer_size(log_id_t) { - return 1024 * 1024; -} - -bool __android_logger_valid_buffer_size(unsigned long) { - return true; -} -#endif - char* android::uidToName(uid_t) { return nullptr; } diff --git a/logd/LogKlog.cpp b/logd/LogKlog.cpp index dbdf7fdd0c..d6c7d25275 100644 --- a/logd/LogKlog.cpp +++ b/logd/LogKlog.cpp @@ -381,8 +381,8 @@ pid_t LogKlog::sniffPid(const char*& buf, ssize_t len) { } if ((i == 9) && (cp[i] == ' ')) { int pid = 0; - char dummy; - if (sscanf(cp + 4, "%d%c", &pid, &dummy) == 2) { + char placeholder; + if (sscanf(cp + 4, "%d%c", &pid, &placeholder) == 2) { buf = cp + 10; // skip-it-all return pid; } @@ -392,8 +392,8 @@ pid_t LogKlog::sniffPid(const char*& buf, ssize_t len) { // Mediatek kernels with modified printk if (*cp == '[') { int pid = 0; - char dummy; - if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &dummy) == 2) { + char placeholder; + if (sscanf(cp, "[%d:%*[a-z_./0-9:A-Z]]%c", &pid, &placeholder) == 2) { return pid; } break; // Only the first one @@ -703,7 +703,7 @@ int LogKlog::log(const char* buf, ssize_t len) { p = " "; b = 1; } - // paranoid sanity check, can not happen ... + // This shouldn't happen, but clamp the size if it does. if (b > LOGGER_ENTRY_MAX_PAYLOAD) { b = LOGGER_ENTRY_MAX_PAYLOAD; } @@ -712,7 +712,7 @@ int LogKlog::log(const char* buf, ssize_t len) { } // calculate buffer copy requirements ssize_t n = 1 + taglen + 1 + b + 1; - // paranoid sanity check, first two just can not happen ... + // Extra checks for likely impossible cases. if ((taglen > n) || (b > n) || (n > (ssize_t)USHRT_MAX) || (n <= 0)) { return -EINVAL; } @@ -722,7 +722,7 @@ int LogKlog::log(const char* buf, ssize_t len) { // If we malloc'd this buffer, we could get away without n's USHRT_MAX // test above, but we would then required a max(n, USHRT_MAX) as // truncating length argument to logbuf->log() below. Gain is protection - // of stack sanity and speedup, loss is truncated long-line content. + // against stack corruption and speedup, loss is truncated long-line content. char newstr[n]; char* np = newstr; diff --git a/logd/LogStatistics.cpp b/logd/LogStatistics.cpp index 1705d48088..87069b3ed2 100644 --- a/logd/LogStatistics.cpp +++ b/logd/LogStatistics.cpp @@ -26,8 +26,10 @@ #include <unistd.h> #include <list> +#include <vector> #include <android-base/logging.h> +#include <android-base/strings.h> #include <private/android_logger.h> #include "LogBufferElement.h" @@ -61,7 +63,8 @@ static std::string TagNameKey(const LogStatisticsElement& element) { return std::string(msg, len); } -LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size) +LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size, + std::optional<log_time> start_time) : enable(enable_statistics), track_total_size_(track_total_size) { log_time now(CLOCK_REALTIME); log_id_for_each(id) { @@ -70,8 +73,13 @@ LogStatistics::LogStatistics(bool enable_statistics, bool track_total_size) mDroppedElements[id] = 0; mSizesTotal[id] = 0; mElementsTotal[id] = 0; - mOldest[id] = now; - mNewest[id] = now; + if (start_time) { + mOldest[id] = *start_time; + mNewest[id] = *start_time; + } else { + mOldest[id] = now; + mNewest[id] = now; + } mNewestDropped[id] = now; } } @@ -784,6 +792,31 @@ std::string LogStatistics::FormatTable(const LogHashtable<TKey, TEntry>& table, return output; } +std::string LogStatistics::ReportInteresting() const { + auto lock = std::lock_guard{lock_}; + + std::vector<std::string> items; + + log_id_for_each(i) { items.emplace_back(std::to_string(mElements[i])); } + + log_id_for_each(i) { items.emplace_back(std::to_string(mSizes[i])); } + + log_id_for_each(i) { + items.emplace_back(std::to_string(overhead_[i] ? *overhead_[i] : mSizes[i])); + } + + log_id_for_each(i) { + uint64_t oldest = mOldest[i].msec() / 1000; + uint64_t newest = mNewest[i].msec() / 1000; + + int span = newest - oldest; + + items.emplace_back(std::to_string(span)); + } + + return android::base::Join(items, ","); +} + std::string LogStatistics::Format(uid_t uid, pid_t pid, unsigned int logMask) const { auto lock = std::lock_guard{lock_}; diff --git a/logd/LogStatistics.h b/logd/LogStatistics.h index d440a8c61b..e222d3f244 100644 --- a/logd/LogStatistics.h +++ b/logd/LogStatistics.h @@ -515,7 +515,8 @@ class LogStatistics { } public: - LogStatistics(bool enable_statistics, bool track_total_size); + LogStatistics(bool enable_statistics, bool track_total_size, + std::optional<log_time> start_time = {}); void AddTotal(log_id_t log_id, uint16_t size) EXCLUDES(lock_); @@ -556,6 +557,7 @@ class LogStatistics { return SizesTotal; } + std::string ReportInteresting() const EXCLUDES(lock_); std::string Format(uid_t uid, pid_t pid, unsigned int logMask) const EXCLUDES(lock_); const char* PidToName(pid_t pid) const EXCLUDES(lock_); diff --git a/logd/README.property b/logd/README.property index 1d7d990224..8fd7f481bd 100644 --- a/logd/README.property +++ b/logd/README.property @@ -7,8 +7,8 @@ ro.logd.auditd.main bool true selinux audit messages sent to main. ro.logd.auditd.events bool true selinux audit messages sent to events. persist.logd.security bool false Enable security buffer. ro.organization_owned bool false Override persist.logd.security to false -ro.logd.kernel bool+ svelte+ Enable klogd daemon -ro.logd.statistics bool+ svelte+ Enable logcat -S statistics. +ro.logd.kernel bool svelte+ Enable klogd daemon +logd.statistics bool svelte+ Enable logcat -S statistics. ro.debuggable number if not "1", logd.statistics & ro.logd.kernel default false. logd.logpersistd.enable bool auto Safe to start logpersist daemon service @@ -57,11 +57,8 @@ logd.buffer_type string (empty) Set the log buffer type. Current choi NB: - auto - managed by /init -- bool+ - "true", "false" and comma separated list of "eng" (forced false if - ro.debuggable is not "1") or "svelte" (forced false if ro.config.low_ram is - true). - svelte - see ro.config.low_ram for details. -- svelte+ - see ro.config.low_ram and ro.debuggable for details. +- svelte+ - If empty, default to true if `ro.config.low_ram == false && ro.debuggable == true` - ro - <base property> temporary override, ro.<base property> platform default. - persist - <base property> override, persist.<base property> platform default. - build - VERBOSE for native, DEBUG for jvm isLoggable, or developer option. diff --git a/logd/README.replay.md b/logd/README.replay.md new file mode 100644 index 0000000000..5f7ec9eef1 --- /dev/null +++ b/logd/README.replay.md @@ -0,0 +1,46 @@ +logd can record and replay log messages for offline analysis. + +Recording Messages +------------------ + +logd has a `RecordingLogBuffer` buffer that records messages to /data/misc/logd/recorded-messages. +It stores messages in memory until that file is accessible, in order to capture all messages since +the beginning of boot. It is only meant for logging developers to use and must be manually enabled +in by adding `RecordingLogBuffer.cpp` to `Android.bp` and setting +`log_buffer = new SimpleLogBuffer(&reader_list, &log_tags, &log_statistics);` in `main.cpp`. + +Recording messages may delay the Log() function from completing and it is highly recommended to make +the logd socket in `liblog` blocking, by removing `SOCK_NONBLOCK` from the `socket()` call in +`liblog/logd_writer.cpp`. + +Replaying Messages +------------------ + +Recorded messages can be replayed offline with the `replay_messages` tool. It runs on host and +device and supports the following options: + +1. `interesting` - this prints 'interesting' statistics for each of the log buffer types (simple, + chatty, serialized). The statistics are: + 1. Log Entry Count + 2. Size (the uncompressed size of the log messages in bytes) + 3. Overhead (the total cost of the log messages in memory in bytes) + 4. Range (the range of time that the logs cover in seconds) +2. `memory_usage BUFFER_TYPE` - this prints the memory usage (sum of private dirty pages of the + `replay_messages` process). Note that the input file is mmap()'ed as RO/Shared so it does not + appear in these dirty pages, and a baseline is taken before allocating the log buffers, so only + their contributions are measured. The tool outputs the memory usage every 100,000 messages. +3. `latency BUFFER_TYPE` - this prints statistics of the latency of the Log() function for the given + buffer type. It specifically prints the 1st, 2nd, and 3rd quartiles; the 95th, 99th, and 99.99th + percentiles; and the maximum latency. +4. `print_logs BUFFER_TYPE [buffers] [print_point]` - this prints the logs as processed by the given + buffer_type from the buffers specified by `buffers` starting after the number of logs specified by + `print_point` have been logged. This acts as if a user called `logcat` immediately after the + specified logs have been logged, which is particularly useful since it will show the chatty + pruning messages at that point. It additionally prints the statistics from `logcat -S` after the + logs. + `buffers` is a comma separated list of the numeric buffer id values from `<android/log.h>`. For + example, `0,1,3` represents the main, radio, and system buffers. It can can also be `all`. + `print_point` is an positive integer. If it is unspecified, logs are printed after the entire + input file is consumed. +5. `nothing BUFFER_TYPE` - this does nothing other than read the input file and call Log() for the + given buffer type. This is used for profiling CPU usage of strictly the log buffer. diff --git a/trusty/libtrusty/tipc_ioctl.h b/logd/RecordedLogMessage.h index 27da56a9e7..f18c422c85 100644 --- a/trusty/libtrusty/tipc_ioctl.h +++ b/logd/RecordedLogMessage.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2020 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. @@ -14,13 +14,17 @@ * limitations under the License. */ -#ifndef _TIPC_IOCTL_H -#define _TIPC_IOCTL_H +#pragma once -#include <linux/ioctl.h> -#include <linux/types.h> +#include <inttypes.h> -#define TIPC_IOC_MAGIC 'r' -#define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char *) +#include <log/log_time.h> -#endif +struct __attribute__((packed)) RecordedLogMessage { + uint32_t uid; + uint32_t pid; + uint32_t tid; + log_time realtime; + uint16_t msg_len; + uint8_t log_id; +}; diff --git a/logd/RecordingLogBuffer.cpp b/logd/RecordingLogBuffer.cpp new file mode 100644 index 0000000000..f5991f3701 --- /dev/null +++ b/logd/RecordingLogBuffer.cpp @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2020 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 "RecordingLogBuffer.h" + +#include <android-base/file.h> + +static void WriteLogMessage(int fd, const RecordedLogMessage& meta, const std::string& msg) { + android::base::WriteFully(fd, &meta, sizeof(meta)); + android::base::WriteFully(fd, msg.c_str(), meta.msg_len); +} + +void RecordingLogBuffer::RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, + pid_t tid, const char* msg, uint16_t len) { + auto lock = std::lock_guard{lock_}; + if (len > LOGGER_ENTRY_MAX_PAYLOAD) { + len = LOGGER_ENTRY_MAX_PAYLOAD; + } + + RecordedLogMessage recorded_log_message = { + .uid = uid, + .pid = static_cast<uint32_t>(pid), + .tid = static_cast<uint32_t>(tid), + .realtime = realtime, + .msg_len = len, + .log_id = static_cast<uint8_t>(log_id), + }; + + if (!fd_.ok()) { + fd_.reset(open("/data/misc/logd/recorded-messages", + O_WRONLY | O_CREAT | O_APPEND | O_CLOEXEC, 0666)); + if (!fd_.ok()) { + since_boot_messages_.emplace_back(recorded_log_message, std::string(msg, len)); + return; + } else { + for (const auto& [meta, msg] : since_boot_messages_) { + WriteLogMessage(fd_.get(), meta, msg); + } + } + } + + WriteLogMessage(fd_.get(), recorded_log_message, std::string(msg, len)); +} + +int RecordingLogBuffer::Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, + const char* msg, uint16_t len) { + RecordLogMessage(log_id, realtime, uid, pid, tid, msg, len); + return SimpleLogBuffer::Log(log_id, realtime, uid, pid, tid, msg, len); +}
\ No newline at end of file diff --git a/logd/RecordingLogBuffer.h b/logd/RecordingLogBuffer.h new file mode 100644 index 0000000000..49a0aba373 --- /dev/null +++ b/logd/RecordingLogBuffer.h @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2020 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 "SimpleLogBuffer.h" + +#include <string> +#include <tuple> +#include <vector> + +#include <android-base/unique_fd.h> + +#include "RecordedLogMessage.h" + +class RecordingLogBuffer : public SimpleLogBuffer { + public: + RecordingLogBuffer(LogReaderList* reader_list, LogTags* tags, LogStatistics* stats) + : SimpleLogBuffer(reader_list, tags, stats) {} + + int Log(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, const char* msg, + uint16_t len) override; + + private: + void RecordLogMessage(log_id_t log_id, log_time realtime, uid_t uid, pid_t pid, pid_t tid, + const char* msg, uint16_t len); + + std::vector<std::pair<RecordedLogMessage, std::string>> since_boot_messages_; + android::base::unique_fd fd_; +}; diff --git a/logd/ReplayMessages.cpp b/logd/ReplayMessages.cpp new file mode 100644 index 0000000000..56509ecad0 --- /dev/null +++ b/logd/ReplayMessages.cpp @@ -0,0 +1,472 @@ +/* + * Copyright (C) 2020 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 <inttypes.h> + +#include <chrono> +#include <map> + +#include <android-base/file.h> +#include <android-base/mapped_file.h> +#include <android-base/parseint.h> +#include <android-base/strings.h> +#include <android-base/unique_fd.h> +#include <android/log.h> +#include <log/log_time.h> +#include <log/logprint.h> + +#include "ChattyLogBuffer.h" +#include "LogBuffer.h" +#include "LogStatistics.h" +#include "RecordedLogMessage.h" +#include "SerializedLogBuffer.h" +#include "SimpleLogBuffer.h" + +using android::base::MappedFile; +using android::base::ParseInt; +using android::base::ParseUint; +using android::base::Split; + +char* android::uidToName(uid_t) { + return nullptr; +} + +static size_t GetPrivateDirty() { + // Allocate once and hope that we don't need to reallocate >40000, to prevent heap fragmentation + static std::string smaps(40000, '\0'); + android::base::ReadFileToString("/proc/self/smaps", &smaps); + + size_t result = 0; + size_t base = 0; + size_t found; + while (true) { + found = smaps.find("Private_Dirty:", base); + if (found == smaps.npos) break; + + found += sizeof("Private_Dirty:"); + + result += atoi(&smaps[found]); + + base = found + 1; + } + + return result; +} + +static AndroidLogFormat* GetLogFormat() { + static AndroidLogFormat* format = [] { + auto* format = android_log_format_new(); + android_log_setPrintFormat(format, android_log_formatFromString("threadtime")); + android_log_setPrintFormat(format, android_log_formatFromString("uid")); + return format; + }(); + return format; +} + +static void PrintMessage(struct log_msg* buf) { + bool is_binary = + buf->id() == LOG_ID_EVENTS || buf->id() == LOG_ID_STATS || buf->id() == LOG_ID_SECURITY; + + AndroidLogEntry entry; + int err; + if (is_binary) { + char binaryMsgBuf[1024]; + err = android_log_processBinaryLogBuffer(&buf->entry, &entry, nullptr, binaryMsgBuf, + sizeof(binaryMsgBuf)); + } else { + err = android_log_processLogBuffer(&buf->entry, &entry); + } + if (err < 0) { + fprintf(stderr, "Error parsing log message\n"); + } + + android_log_printLogLine(GetLogFormat(), STDOUT_FILENO, &entry); +} + +static log_time GetFirstTimeStamp(const MappedFile& recorded_messages) { + if (sizeof(RecordedLogMessage) >= recorded_messages.size()) { + fprintf(stderr, "At least one log message must be present in the input\n"); + exit(1); + } + + auto* meta = reinterpret_cast<RecordedLogMessage*>(recorded_messages.data()); + return meta->realtime; +} + +static LogMask BuffersToLogMask(const char* buffers) { + if (buffers == nullptr || !strcmp(buffers, "all")) { + return kLogMaskAll; + } + auto string_ids = Split(buffers, ","); + LogMask log_mask = 0; + for (const auto& string_id : string_ids) { + int buffer_id; + if (!ParseInt(string_id, &buffer_id, 0, 7)) { + fprintf(stderr, "Could not parse buffer_id '%s'\n", string_id.c_str()); + exit(1); + } + log_mask |= 1 << buffer_id; + } + return log_mask; +} + +class StdoutWriter : public LogWriter { + public: + StdoutWriter() : LogWriter(0, true) {} + bool Write(const logger_entry& entry, const char* message) override { + struct log_msg log_msg; + log_msg.entry = entry; + if (log_msg.entry.len > LOGGER_ENTRY_MAX_PAYLOAD) { + fprintf(stderr, "payload too large %" PRIu16, log_msg.entry.len); + exit(1); + } + memcpy(log_msg.msg(), message, log_msg.entry.len); + + PrintMessage(&log_msg); + + return true; + } + + void Shutdown() override { + fprintf(stderr, "LogWriter::Shutdown() called\n"); + exit(1); + } + + std::string name() const override { return "stdout writer"; } +}; + +class Operation { + public: + virtual ~Operation() {} + + virtual void Begin() {} + virtual void Log(const RecordedLogMessage& meta, const char* msg) = 0; + virtual void End() {} +}; + +class PrintInteresting : public Operation { + public: + PrintInteresting(log_time first_log_timestamp) + : stats_simple_{false, false, first_log_timestamp}, + stats_chatty_{false, false, first_log_timestamp}, + stats_serialized_{false, true, first_log_timestamp} {} + + void Begin() override { + printf("message_count,simple_main_lines,simple_radio_lines,simple_events_lines,simple_" + "system_lines,simple_crash_lines,simple_stats_lines,simple_security_lines,simple_" + "kernel_lines,simple_main_size,simple_radio_size,simple_events_size,simple_system_" + "size,simple_crash_size,simple_stats_size,simple_security_size,simple_kernel_size," + "simple_main_overhead,simple_radio_overhead,simple_events_overhead,simple_system_" + "overhead,simple_crash_overhead,simple_stats_overhead,simple_security_overhead," + "simple_kernel_overhead,simple_main_range,simple_radio_range,simple_events_range," + "simple_system_range,simple_crash_range,simple_stats_range,simple_security_range," + "simple_kernel_range,chatty_main_lines,chatty_radio_lines,chatty_events_lines," + "chatty_system_lines,chatty_crash_lines,chatty_stats_lines,chatty_security_lines," + "chatty_" + "kernel_lines,chatty_main_size,chatty_radio_size,chatty_events_size,chatty_system_" + "size,chatty_crash_size,chatty_stats_size,chatty_security_size,chatty_kernel_size," + "chatty_main_overhead,chatty_radio_overhead,chatty_events_overhead,chatty_system_" + "overhead,chatty_crash_overhead,chatty_stats_overhead,chatty_security_overhead," + "chatty_kernel_overhead,chatty_main_range,chatty_radio_range,chatty_events_range," + "chatty_system_range,chatty_crash_range,chatty_stats_range,chatty_security_range," + "chatty_kernel_range,serialized_main_lines,serialized_radio_lines,serialized_events_" + "lines,serialized_" + "system_lines,serialized_crash_lines,serialized_stats_lines,serialized_security_" + "lines,serialized_" + "kernel_lines,serialized_main_size,serialized_radio_size,serialized_events_size," + "serialized_system_" + "size,serialized_crash_size,serialized_stats_size,serialized_security_size," + "serialized_kernel_size," + "serialized_main_overhead,serialized_radio_overhead,serialized_events_overhead," + "serialized_system_" + "overhead,serialized_crash_overhead,serialized_stats_overhead,serialized_security_" + "overhead," + "serialized_kernel_overhead,serialized_main_range,serialized_radio_range,serialized_" + "events_range," + "serialized_system_range,serialized_crash_range,serialized_stats_range,serialized_" + "security_range," + "serialized_kernel_range\n"); + } + + void Log(const RecordedLogMessage& meta, const char* msg) override { + simple_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, + meta.pid, meta.tid, msg, meta.msg_len); + + chatty_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, + meta.pid, meta.tid, msg, meta.msg_len); + + serialized_log_buffer_.Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, + meta.pid, meta.tid, msg, meta.msg_len); + + if (num_message_ % 10000 == 0) { + printf("%" PRIu64 ",%s,%s,%s\n", num_message_, + stats_simple_.ReportInteresting().c_str(), + stats_chatty_.ReportInteresting().c_str(), + stats_serialized_.ReportInteresting().c_str()); + } + + num_message_++; + } + + private: + uint64_t num_message_ = 1; + + LogReaderList reader_list_; + LogTags tags_; + PruneList prune_list_; + + LogStatistics stats_simple_; + SimpleLogBuffer simple_log_buffer_{&reader_list_, &tags_, &stats_simple_}; + + LogStatistics stats_chatty_; + ChattyLogBuffer chatty_log_buffer_{&reader_list_, &tags_, &prune_list_, &stats_chatty_}; + + LogStatistics stats_serialized_; + SerializedLogBuffer serialized_log_buffer_{&reader_list_, &tags_, &stats_serialized_}; +}; + +class SingleBufferOperation : public Operation { + public: + SingleBufferOperation(log_time first_log_timestamp, const char* buffer) { + if (!strcmp(buffer, "simple")) { + stats_.reset(new LogStatistics{false, false, first_log_timestamp}); + log_buffer_.reset(new SimpleLogBuffer(&reader_list_, &tags_, stats_.get())); + } else if (!strcmp(buffer, "chatty")) { + stats_.reset(new LogStatistics{false, false, first_log_timestamp}); + log_buffer_.reset( + new ChattyLogBuffer(&reader_list_, &tags_, &prune_list_, stats_.get())); + } else if (!strcmp(buffer, "serialized")) { + stats_.reset(new LogStatistics{false, true, first_log_timestamp}); + log_buffer_.reset(new SerializedLogBuffer(&reader_list_, &tags_, stats_.get())); + } else { + fprintf(stderr, "invalid log buffer type '%s'\n", buffer); + abort(); + } + } + + void Log(const RecordedLogMessage& meta, const char* msg) override { + PreOperation(); + log_buffer_->Log(static_cast<log_id_t>(meta.log_id), meta.realtime, meta.uid, meta.pid, + meta.tid, msg, meta.msg_len); + + Operation(); + + num_message_++; + } + + virtual void PreOperation() {} + virtual void Operation() {} + + protected: + uint64_t num_message_ = 1; + + LogReaderList reader_list_; + LogTags tags_; + PruneList prune_list_; + + std::unique_ptr<LogStatistics> stats_; + std::unique_ptr<LogBuffer> log_buffer_; +}; + +class PrintMemory : public SingleBufferOperation { + public: + PrintMemory(log_time first_log_timestamp, const char* buffer) + : SingleBufferOperation(first_log_timestamp, buffer) {} + + void Operation() override { + if (num_message_ % 100000 == 0) { + printf("%" PRIu64 ",%s\n", num_message_, + std::to_string(GetPrivateDirty() - baseline_memory_).c_str()); + } + } + + private: + size_t baseline_memory_ = GetPrivateDirty(); +}; + +class PrintLogs : public SingleBufferOperation { + public: + PrintLogs(log_time first_log_timestamp, const char* buffer, const char* buffers, + const char* print_point) + : SingleBufferOperation(first_log_timestamp, buffer) { + mask_ = BuffersToLogMask(buffers); + if (print_point != nullptr) { + uint64_t result = 0; + if (!ParseUint(print_point, &result)) { + fprintf(stderr, "Could not parse print point '%s'\n", print_point); + exit(1); + } + print_point_ = result; + } + } + + void Operation() override { + if (print_point_ && num_message_ >= *print_point_) { + End(); + exit(0); + } + } + + void End() override { + std::unique_ptr<LogWriter> test_writer(new StdoutWriter()); + std::unique_ptr<FlushToState> flush_to_state = log_buffer_->CreateFlushToState(1, mask_); + log_buffer_->FlushTo(test_writer.get(), *flush_to_state, nullptr); + + auto stats_string = stats_->Format(0, 0, mask_); + printf("%s\n", stats_string.c_str()); + } + + private: + LogMask mask_ = kLogMaskAll; + std::optional<uint64_t> print_point_; +}; + +class PrintLatency : public SingleBufferOperation { + public: + PrintLatency(log_time first_log_timestamp, const char* buffer) + : SingleBufferOperation(first_log_timestamp, buffer) {} + + void PreOperation() override { operation_start_ = std::chrono::steady_clock::now(); } + + void Operation() override { + auto end = std::chrono::steady_clock::now(); + auto duration = (end - operation_start_).count(); + durations_.emplace_back(duration); + } + + void End() override { + std::sort(durations_.begin(), durations_.end()); + auto q1 = durations_.size() / 4; + auto q2 = durations_.size() / 2; + auto q3 = 3 * durations_.size() / 4; + + auto p95 = 95 * durations_.size() / 100; + auto p99 = 99 * durations_.size() / 100; + auto p9999 = 9999 * durations_.size() / 10000; + + printf("q1: %lld q2: %lld q3: %lld p95: %lld p99: %lld p99.99: %lld max: %lld\n", + durations_[q1], durations_[q2], durations_[q3], durations_[p95], durations_[p99], + durations_[p9999], durations_.back()); + } + + private: + std::chrono::steady_clock::time_point operation_start_; + std::vector<long long> durations_; +}; + +class PrintAllLogs : public SingleBufferOperation { + public: + PrintAllLogs(log_time first_log_timestamp, const char* buffer, const char* buffers) + : SingleBufferOperation(first_log_timestamp, buffer) { + LogMask mask = BuffersToLogMask(buffers); + auto lock = std::unique_lock{reader_list_.reader_threads_lock()}; + std::unique_ptr<LogWriter> stdout_writer(new StdoutWriter()); + std::unique_ptr<LogReaderThread> log_reader( + new LogReaderThread(log_buffer_.get(), &reader_list_, std::move(stdout_writer), + false, 0, mask, 0, {}, 1, {})); + reader_list_.reader_threads().emplace_back(std::move(log_reader)); + } + + void Operation() override { + // If the rate of reading logs is slower than the rate of incoming logs, then the reader + // thread is disconnected to not overflow log buffers, therefore we artificially slow down + // the incoming log rate. + usleep(100); + } +}; + +int main(int argc, char** argv) { + if (argc < 3) { + fprintf(stderr, "Usage: %s FILE OPERATION [BUFFER] [OPTIONS]\n", argv[0]); + return 1; + } + + if (strcmp(argv[2], "interesting") != 0 && argc < 4) { + fprintf(stderr, "Operations other than 'interesting' require a BUFFER argument\n"); + return 1; + } + + int recorded_messages_fd = open(argv[1], O_RDONLY); + if (recorded_messages_fd == -1) { + fprintf(stderr, "Couldn't open input file\n"); + return 1; + } + struct stat fd_stat; + if (fstat(recorded_messages_fd, &fd_stat) != 0) { + fprintf(stderr, "Couldn't fstat input file\n"); + return 1; + } + auto recorded_messages = MappedFile::FromFd(recorded_messages_fd, 0, + static_cast<size_t>(fd_stat.st_size), PROT_READ); + if (recorded_messages == nullptr) { + fprintf(stderr, "Couldn't mmap input file\n"); + return 1; + } + + // LogStatistics typically uses 'now()' to initialize its log range state, but this doesn't work + // when replaying older logs, so we instead give it the timestamp from the first log. + log_time first_log_timestamp = GetFirstTimeStamp(*recorded_messages); + + std::unique_ptr<Operation> operation; + if (!strcmp(argv[2], "interesting")) { + operation.reset(new PrintInteresting(first_log_timestamp)); + } else if (!strcmp(argv[2], "memory_usage")) { + operation.reset(new PrintMemory(first_log_timestamp, argv[3])); + } else if (!strcmp(argv[2], "latency")) { + operation.reset(new PrintLatency(first_log_timestamp, argv[3])); + } else if (!strcmp(argv[2], "print_logs")) { + operation.reset(new PrintLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr, + argc > 5 ? argv[5] : nullptr)); + } else if (!strcmp(argv[2], "print_all_logs")) { + operation.reset( + new PrintAllLogs(first_log_timestamp, argv[3], argc > 4 ? argv[4] : nullptr)); + } else if (!strcmp(argv[2], "nothing")) { + operation.reset(new SingleBufferOperation(first_log_timestamp, argv[3])); + } else { + fprintf(stderr, "unknown operation '%s'\n", argv[2]); + return 1; + } + + // LogBuffer::Log() won't log without this on host. + __android_log_set_minimum_priority(ANDROID_LOG_VERBOSE); + // But we still want to suppress messages <= error to not interrupt the rest of the output. + __android_log_set_logger([](const struct __android_log_message* log_message) { + if (log_message->priority < ANDROID_LOG_ERROR) { + return; + } + __android_log_stderr_logger(log_message); + }); + + operation->Begin(); + + uint64_t read_position = 0; + while (read_position + sizeof(RecordedLogMessage) < recorded_messages->size()) { + auto* meta = + reinterpret_cast<RecordedLogMessage*>(recorded_messages->data() + read_position); + if (read_position + sizeof(RecordedLogMessage) + meta->msg_len >= + recorded_messages->size()) { + break; + } + char* msg = recorded_messages->data() + read_position + sizeof(RecordedLogMessage); + read_position += sizeof(RecordedLogMessage) + meta->msg_len; + + operation->Log(*meta, msg); + } + + operation->End(); + + return 0; +} diff --git a/logd/SerializedFlushToState.cpp b/logd/SerializedFlushToState.cpp index 2633348cf0..b02ccc3494 100644 --- a/logd/SerializedFlushToState.cpp +++ b/logd/SerializedFlushToState.cpp @@ -31,7 +31,7 @@ SerializedFlushToState::SerializedFlushToState(uint64_t start, LogMask log_mask) SerializedFlushToState::~SerializedFlushToState() { log_id_for_each(i) { if (log_positions_[i]) { - log_positions_[i]->buffer_it->DecReaderRefCount(true); + log_positions_[i]->buffer_it->DecReaderRefCount(); } } } @@ -78,7 +78,7 @@ void SerializedFlushToState::AddMinHeapEntry(log_id_t log_id) { logs_needed_from_next_position_[log_id] = true; } else { // Otherwise, if there is another buffer piece, move to that and do the same check. - buffer_it->DecReaderRefCount(true); + buffer_it->DecReaderRefCount(); ++buffer_it; buffer_it->IncReaderRefCount(); log_positions_[log_id]->read_offset = 0; @@ -134,7 +134,7 @@ void SerializedFlushToState::Prune(log_id_t log_id, } // // Decrease the ref count since we're deleting our reference. - buffer_it->DecReaderRefCount(false); + buffer_it->DecReaderRefCount(); // Delete in the reference. log_positions_[log_id].reset(); diff --git a/logd/SerializedLogBuffer.cpp b/logd/SerializedLogBuffer.cpp index a626d30e83..972a3f3a97 100644 --- a/logd/SerializedLogBuffer.cpp +++ b/logd/SerializedLogBuffer.cpp @@ -123,7 +123,7 @@ void SerializedLogBuffer::RemoveChunkFromStats(log_id_t log_id, SerializedLogChu stats_->Subtract(entry->ToLogStatisticsElement(log_id)); read_offset += entry->total_len(); } - chunk.DecReaderRefCount(false); + chunk.DecReaderRefCount(); } void SerializedLogBuffer::NotifyReadersOfPrune( diff --git a/logd/SerializedLogChunk.cpp b/logd/SerializedLogChunk.cpp index e444856a40..de641d62a2 100644 --- a/logd/SerializedLogChunk.cpp +++ b/logd/SerializedLogChunk.cpp @@ -31,7 +31,6 @@ void SerializedLogChunk::Compress() { << " size used: " << write_offset_ << " compressed size: " << compressed_log_.size(); } - contents_.Resize(0); } // TODO: Develop a better reference counting strategy to guard against the case where the writer is @@ -44,13 +43,13 @@ void SerializedLogChunk::IncReaderRefCount() { CompressionEngine::GetInstance().Decompress(compressed_log_, contents_); } -void SerializedLogChunk::DecReaderRefCount(bool compress) { +void SerializedLogChunk::DecReaderRefCount() { CHECK_NE(reader_ref_count_, 0U); if (--reader_ref_count_ != 0) { return; } - if (compress && !writer_active_) { - Compress(); + if (!writer_active_) { + contents_.Resize(0); } } @@ -83,18 +82,19 @@ bool SerializedLogChunk::ClearUidLogs(uid_t uid, log_id_t log_id, LogStatistics* } if (new_write_offset == 0) { - DecReaderRefCount(false); + DecReaderRefCount(); return true; } - // Clear the old compressed logs and set write_offset_ appropriately for DecReaderRefCount() - // to compress the new partially cleared log. + // Clear the old compressed logs and set write_offset_ appropriately to compress the new + // partially cleared log. if (new_write_offset != write_offset_) { compressed_log_.Resize(0); write_offset_ = new_write_offset; + Compress(); } - DecReaderRefCount(true); + DecReaderRefCount(); return false; } diff --git a/logd/SerializedLogChunk.h b/logd/SerializedLogChunk.h index 50bae638c6..0991eacb6b 100644 --- a/logd/SerializedLogChunk.h +++ b/logd/SerializedLogChunk.h @@ -30,9 +30,7 @@ class SerializedLogChunk { void Compress(); void IncReaderRefCount(); - // Decrease the reader ref count and compress the log if appropriate. `compress` should only be - // set to false in the case that the log buffer will be deleted afterwards. - void DecReaderRefCount(bool compress); + void DecReaderRefCount(); // Must have no readers referencing this. Return true if there are no logs left in this chunk. bool ClearUidLogs(uid_t uid, log_id_t log_id, LogStatistics* stats); @@ -50,8 +48,9 @@ class SerializedLogChunk { void FinishWriting() { writer_active_ = false; + Compress(); if (reader_ref_count_ == 0) { - Compress(); + contents_.Resize(0); } } diff --git a/logd/SerializedLogChunkTest.cpp b/logd/SerializedLogChunkTest.cpp index 2b478a3fbb..f10b9c673b 100644 --- a/logd/SerializedLogChunkTest.cpp +++ b/logd/SerializedLogChunkTest.cpp @@ -113,8 +113,7 @@ TEST(SerializedLogChunk, three_logs) { TEST(SerializedLogChunk, catch_DecCompressedRef_CHECK) { size_t chunk_size = 10 * 4096; auto chunk = SerializedLogChunk{chunk_size}; - EXPECT_DEATH({ chunk.DecReaderRefCount(true); }, ""); - EXPECT_DEATH({ chunk.DecReaderRefCount(false); }, ""); + EXPECT_DEATH({ chunk.DecReaderRefCount(); }, ""); } // Check that the CHECK() in ClearUidLogs() if the ref count is greater than 0 is caught. @@ -123,7 +122,7 @@ TEST(SerializedLogChunk, catch_ClearUidLogs_CHECK) { auto chunk = SerializedLogChunk{chunk_size}; chunk.IncReaderRefCount(); EXPECT_DEATH({ chunk.ClearUidLogs(1000, LOG_ID_MAIN, nullptr); }, ""); - chunk.DecReaderRefCount(false); + chunk.DecReaderRefCount(); } class UidClearTest : public testing::TestWithParam<bool> { @@ -144,7 +143,7 @@ class UidClearTest : public testing::TestWithParam<bool> { check(chunk_); if (finish_writing) { - chunk_.DecReaderRefCount(false); + chunk_.DecReaderRefCount(); } } diff --git a/logd/fuzz/log_buffer_log_fuzzer.cpp b/logd/fuzz/log_buffer_log_fuzzer.cpp index 8309f95147..d71a2f91f0 100644 --- a/logd/fuzz/log_buffer_log_fuzzer.cpp +++ b/logd/fuzz/log_buffer_log_fuzzer.cpp @@ -30,16 +30,6 @@ #define MIN_TAG_ID 1000 #define TAG_MOD 10 -#ifndef __ANDROID__ -unsigned long __android_logger_get_buffer_size(log_id_t) { - return 1024 * 1024; -} - -bool __android_logger_valid_buffer_size(unsigned long) { - return true; -} -#endif - char* android::uidToName(uid_t) { return strdup("fake"); } diff --git a/logd/logd_test.cpp b/logd/logd_test.cpp index ed34ea413c..5a0585a735 100644 --- a/logd/logd_test.cpp +++ b/logd/logd_test.cpp @@ -162,6 +162,7 @@ static char* find_benchmark_spam(char* cp) { } #endif +#ifdef LOGD_ENABLE_FLAKY_TESTS TEST(logd, statistics) { #ifdef __ANDROID__ size_t len; @@ -237,6 +238,7 @@ TEST(logd, statistics) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } +#endif #ifdef __ANDROID__ static void caught_signal(int /* signum */) { @@ -720,6 +722,7 @@ TEST(logd, timeout) { } #endif +#ifdef LOGD_ENABLE_FLAKY_TESTS // b/27242723 confirmed fixed TEST(logd, SNDTIMEO) { #ifdef __ANDROID__ @@ -777,6 +780,7 @@ TEST(logd, SNDTIMEO) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } +#endif TEST(logd, getEventTag_list) { #ifdef __ANDROID__ @@ -832,127 +836,3 @@ TEST(logd, getEventTag_newentry) { GTEST_LOG_(INFO) << "This test does nothing.\n"; #endif } - -#ifdef __ANDROID__ -static inline uint32_t get4LE(const uint8_t* src) { - return src[0] | (src[1] << 8) | (src[2] << 16) | (src[3] << 24); -} - -static inline uint32_t get4LE(const char* src) { - return get4LE(reinterpret_cast<const uint8_t*>(src)); -} -#endif - -void __android_log_btwrite_multiple__helper(int count) { -#ifdef __ANDROID__ - log_time ts(CLOCK_MONOTONIC); - usleep(100); - log_time ts1(CLOCK_MONOTONIC); - - // We fork to create a unique pid for the submitted log messages - // so that we do not collide with the other _multiple_ tests. - - pid_t pid = fork(); - - if (pid == 0) { - // child - for (int i = count; i; --i) { - ASSERT_LT( - 0, __android_log_btwrite(0, EVENT_TYPE_LONG, &ts, sizeof(ts))); - usleep(100); - } - ASSERT_LT(0, - __android_log_btwrite(0, EVENT_TYPE_LONG, &ts1, sizeof(ts1))); - usleep(1000000); - - _exit(0); - } - - siginfo_t info = {}; - ASSERT_EQ(0, TEMP_FAILURE_RETRY(waitid(P_PID, pid, &info, WEXITED))); - ASSERT_EQ(0, info.si_status); - - struct logger_list* logger_list; - ASSERT_TRUE(nullptr != (logger_list = android_logger_list_open(LOG_ID_EVENTS, - ANDROID_LOG_NONBLOCK, 0, pid))); - - int expected_count = (count < 2) ? count : 2; - int expected_chatty_count = (count <= 2) ? 0 : 1; - int expected_identical_count = (count < 2) ? 0 : (count - 2); - static const int expected_expire_count = 0; - - count = 0; - int second_count = 0; - int chatty_count = 0; - int identical_count = 0; - int expire_count = 0; - - 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 ((eventData[4] == EVENT_TYPE_LONG) && - (log_msg.entry.len == (4 + 1 + 8))) { - if (tag != 0) continue; - - log_time* tx = reinterpret_cast<log_time*>(eventData + 4 + 1); - if (ts == *tx) { - ++count; - } else if (ts1 == *tx) { - ++second_count; - } - } else if (eventData[4] == EVENT_TYPE_STRING) { - if (tag != CHATTY_LOG_TAG) continue; - ++chatty_count; - // int len = get4LE(eventData + 4 + 1); - log_msg.buf[LOGGER_ENTRY_MAX_LEN] = '\0'; - const char* cp; - if ((cp = strstr(eventData + 4 + 1 + 4, " identical "))) { - unsigned val = 0; - sscanf(cp, " identical %u lines", &val); - identical_count += val; - } else if ((cp = strstr(eventData + 4 + 1 + 4, " expire "))) { - unsigned val = 0; - sscanf(cp, " expire %u lines", &val); - expire_count += val; - } - } - } - - android_logger_list_close(logger_list); - - EXPECT_EQ(expected_count, count); - EXPECT_EQ(1, second_count); - EXPECT_EQ(expected_chatty_count, chatty_count); - EXPECT_EQ(expected_identical_count, identical_count); - EXPECT_EQ(expected_expire_count, expire_count); -#else - count = 0; - GTEST_LOG_(INFO) << "This test does nothing.\n"; -#endif -} - -TEST(logd, multiple_test_1) { - __android_log_btwrite_multiple__helper(1); -} - -TEST(logd, multiple_test_2) { - __android_log_btwrite_multiple__helper(2); -} - -TEST(logd, multiple_test_3) { - __android_log_btwrite_multiple__helper(3); -} - -TEST(logd, multiple_test_10) { - __android_log_btwrite_multiple__helper(10); -} diff --git a/logd/main.cpp b/logd/main.cpp index 897e11e3a3..c92c5b7194 100644 --- a/logd/main.cpp +++ b/logd/main.cpp @@ -62,7 +62,9 @@ #include "SerializedLogBuffer.h" #include "SimpleLogBuffer.h" +using android::base::GetBoolProperty; using android::base::GetProperty; +using android::base::SetProperty; #define KMSG_PRIORITY(PRI) \ '<', '0' + LOG_MAKEPRI(LOG_DAEMON, LOG_PRI(PRI)) / 10, \ @@ -82,9 +84,10 @@ static void DropPrivs(bool klogd, bool auditd) { PLOG(FATAL) << "failed to set batch scheduler"; } - if (!__android_logger_property_get_bool("ro.debuggable", BOOL_DEFAULT_FALSE) && - prctl(PR_SET_DUMPABLE, 0) == -1) { - PLOG(FATAL) << "failed to clear PR_SET_DUMPABLE"; + if (!GetBoolProperty("ro.debuggable", false)) { + if (prctl(PR_SET_DUMPABLE, 0) == -1) { + PLOG(FATAL) << "failed to clear PR_SET_DUMPABLE"; + } } std::unique_ptr<struct _cap_struct, int (*)(void*)> caps(cap_init(), cap_free); @@ -110,6 +113,14 @@ static void DropPrivs(bool klogd, bool auditd) { } } +// GetBoolProperty that defaults to true if `ro.debuggable == true && ro.config.low_rawm == false`. +static bool GetBoolPropertyEngSvelteDefault(const std::string& name) { + bool default_value = + GetBoolProperty("ro.debuggable", false) && !GetBoolProperty("ro.config.low_ram", false); + + return GetBoolProperty(name, default_value); +} + char* android::uidToName(uid_t u) { struct Userdata { uid_t uid; @@ -207,6 +218,8 @@ static int issueReinit() { // logging plugins like auditd and restart control. Additional // transitory per-client threads are created for each reader. int main(int argc, char* argv[]) { + // We want EPIPE when a reader disconnects, not to terminate logd. + signal(SIGPIPE, SIG_IGN); // logd is written under the assumption that the timezone is UTC. // If TZ is not set, persist.sys.timezone is looked up in some time utility // libc functions, including mktime. It confuses the logd time handling, @@ -236,10 +249,9 @@ int main(int argc, char* argv[]) { } int fdPmesg = -1; - bool klogd = __android_logger_property_get_bool( - "ro.logd.kernel", - BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE); + bool klogd = GetBoolPropertyEngSvelteDefault("ro.logd.kernel"); if (klogd) { + SetProperty("ro.logd.kernel", "true"); static const char proc_kmsg[] = "/proc/kmsg"; fdPmesg = android_get_control_file(proc_kmsg); if (fdPmesg < 0) { @@ -249,7 +261,7 @@ int main(int argc, char* argv[]) { if (fdPmesg < 0) PLOG(ERROR) << "Failed to open " << proc_kmsg; } - bool auditd = __android_logger_property_get_bool("ro.logd.auditd", BOOL_DEFAULT_TRUE); + bool auditd = GetBoolProperty("ro.logd.auditd", true); DropPrivs(klogd, auditd); // A cache of event log tags @@ -258,13 +270,11 @@ int main(int argc, char* argv[]) { // Pruning configuration. PruneList prune_list; - std::string buffer_type = GetProperty("logd.buffer_type", "chatty"); + std::string buffer_type = GetProperty("logd.buffer_type", "serialized"); // Partial (required for chatty) or full logging statistics. - bool enable_full_log_statistics = __android_logger_property_get_bool( - "logd.statistics", BOOL_DEFAULT_TRUE | BOOL_DEFAULT_FLAG_PERSIST | - BOOL_DEFAULT_FLAG_ENG | BOOL_DEFAULT_FLAG_SVELTE); - LogStatistics log_statistics(enable_full_log_statistics, buffer_type == "serialized"); + LogStatistics log_statistics(GetBoolPropertyEngSvelteDefault("logd.statistics"), + buffer_type == "serialized"); // Serves the purpose of managing the last logs times read on a socket connection, and as a // reader lock on a range of log entries. @@ -309,9 +319,7 @@ int main(int argc, char* argv[]) { // and LogReader is notified to send updates to connected clients. LogAudit* al = nullptr; if (auditd) { - int dmesg_fd = __android_logger_property_get_bool("ro.logd.auditd.dmesg", BOOL_DEFAULT_TRUE) - ? fdDmesg - : -1; + int dmesg_fd = GetBoolProperty("ro.logd.auditd.dmesg", true) ? fdDmesg : -1; al = new LogAudit(log_buffer, dmesg_fd, &log_statistics); } diff --git a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp index a643062804..3907413cc8 100644 --- a/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp +++ b/property_service/libpropertyinfoserializer/property_info_serializer_test.cpp @@ -139,7 +139,7 @@ TEST(propertyinfoserializer, GetPropertyInfo) { auto property_info_area = reinterpret_cast<const PropertyInfoArea*>(serialized_trie.data()); - // Sanity check + // Smoke test auto root_node = property_info_area->root_node(); EXPECT_STREQ("root", root_node.name()); EXPECT_STREQ("default", property_info_area->context(root_node.context_index())); diff --git a/qemu_pipe/qemu_pipe.cpp b/qemu_pipe/qemu_pipe.cpp index beeccb07f2..03afb211e3 100644 --- a/qemu_pipe/qemu_pipe.cpp +++ b/qemu_pipe/qemu_pipe.cpp @@ -35,7 +35,6 @@ using android::base::WriteFully; #endif int qemu_pipe_open(const char* pipeName) { - // Sanity check. if (!pipeName) { errno = EINVAL; return -1; diff --git a/rootdir/Android.mk b/rootdir/Android.mk index ac8e8478a9..77fa94e739 100644 --- a/rootdir/Android.mk +++ b/rootdir/Android.mk @@ -131,6 +131,16 @@ LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/vendor_dlkm # via /vendor/lib/modules directly. LOCAL_POST_INSTALL_CMD += ; ln -sf /vendor/vendor_dlkm/etc $(TARGET_ROOT_OUT)/vendor_dlkm/etc +# For /odm_dlkm partition. +LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/odm_dlkm +# For Treble Generic System Image (GSI), system-as-root GSI needs to work on +# both devices with and without /odm_dlkm partition. Those symlinks are for +# devices without /odm_dlkm partition. For devices with /odm_dlkm +# partition, mount odm_dlkm.img under /odm_dlkm will hide those symlinks. +# Note that /odm_dlkm/lib is omitted because odm DLKMs should be accessed +# via /odm/lib/modules directly. +LOCAL_POST_INSTALL_CMD += ; ln -sf /odm/odm_dlkm/etc $(TARGET_ROOT_OUT)/odm_dlkm/etc + ifdef BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE LOCAL_POST_INSTALL_CMD += ; mkdir -p $(TARGET_ROOT_OUT)/cache else diff --git a/rootdir/init.rc b/rootdir/init.rc index fb6f1bea27..6ef3bdca69 100644 --- a/rootdir/init.rc +++ b/rootdir/init.rc @@ -81,6 +81,11 @@ on early-init # Mount tracefs mount tracefs tracefs /sys/kernel/tracing + # create sys dirctory + mkdir /dev/sys 0755 system system + mkdir /dev/sys/fs 0755 system system + mkdir /dev/sys/block 0755 system system + # Run boringssl self test for each ABI so that later processes can skip it. http://b/139348610 on early-init && property:ro.product.cpu.abilist32=* exec_start boringssl_self_test32 @@ -867,17 +872,26 @@ on boot chown root system /sys/block/zram0/writeback chmod 0664 /sys/block/zram0/writeback + # to access F2FS sysfs on dm-<num> directly + mkdir /dev/sys/fs/by-name 0755 system system + symlink /sys/fs/f2fs/${dev.mnt.blk.data} /dev/sys/fs/by-name/userdata + + # to access dm-<num> sysfs + mkdir /dev/sys/block/by-name 0755 system system + symlink /sys/devices/virtual/block/${dev.mnt.blk.data} /dev/sys/block/by-name/userdata + # F2FS tuning. Set cp_interval larger than dirty_expire_centisecs, 30 secs, # to avoid power consumption when system becomes mostly idle. Be careful # to make it too large, since it may bring userdata loss, if they # are not aware of using fsync()/sync() to prepare sudden power-cut. - write /sys/fs/f2fs/${dev.mnt.blk.data}/cp_interval 200 - write /sys/fs/f2fs/${dev.mnt.blk.data}/gc_urgent_sleep_time 50 + write /dev/sys/fs/by-name/userdata/cp_interval 200 + write /dev/sys/fs/by-name/userdata/gc_urgent_sleep_time 50 + write /dev/sys/fs/by-name/userdata/iostat_enable 1 # limit discard size to 128MB in order to avoid long IO latency # for filesystem tuning first (dm or sda) # Note that, if dm-<num> is used, sda/mmcblk0 should be tuned in vendor/init.rc - write /sys/devices/virtual/block/${dev.mnt.blk.data}/queue/discard_max_bytes 134217728 + write /dev/sys/block/by-name/userdata/queue/discard_max_bytes 134217728 # Permissions for System Server and daemons. chown system system /sys/power/autosleep diff --git a/trusty/confirmationui/NotSoSecureInput.cpp b/trusty/confirmationui/NotSoSecureInput.cpp index 3d9a2d6e50..18e45cd35b 100644 --- a/trusty/confirmationui/NotSoSecureInput.cpp +++ b/trusty/confirmationui/NotSoSecureInput.cpp @@ -82,7 +82,7 @@ Nonce generateNonce() { /** * This is an implementation of the SecureInput protocol in unserspace. This is - * just an example and should not be used as is. The protocol implemented her + * just an example and should not be used as is. The protocol implemented here * should be used by a trusted input device that can assert user events with * high assurance even if the HLOS kernel is compromised. A confirmationui HAL * that links directly against this implementation is not secure and shal not be diff --git a/trusty/gatekeeper/trusty_gatekeeper.cpp b/trusty/gatekeeper/trusty_gatekeeper.cpp index d149664605..e416fb2acc 100644 --- a/trusty/gatekeeper/trusty_gatekeeper.cpp +++ b/trusty/gatekeeper/trusty_gatekeeper.cpp @@ -56,9 +56,9 @@ TrustyGateKeeperDevice::~TrustyGateKeeperDevice() { SizedBuffer hidl_vec2sized_buffer(const hidl_vec<uint8_t>& vec) { if (vec.size() == 0 || vec.size() > std::numeric_limits<uint32_t>::max()) return {}; - auto dummy = new uint8_t[vec.size()]; - std::copy(vec.begin(), vec.end(), dummy); - return {dummy, static_cast<uint32_t>(vec.size())}; + auto buffer = new uint8_t[vec.size()]; + std::copy(vec.begin(), vec.end(), buffer); + return {buffer, static_cast<uint32_t>(vec.size())}; } Return<void> TrustyGateKeeperDevice::enroll(uint32_t uid, diff --git a/trusty/keymaster/TrustyKeymaster.cpp b/trusty/keymaster/TrustyKeymaster.cpp index f3ef747f69..750a9d71cf 100644 --- a/trusty/keymaster/TrustyKeymaster.cpp +++ b/trusty/keymaster/TrustyKeymaster.cpp @@ -173,7 +173,7 @@ void TrustyKeymaster::AbortOperation(const AbortOperationRequest& request, } GetHmacSharingParametersResponse TrustyKeymaster::GetHmacSharingParameters() { - // Dummy empty buffer to allow ForwardCommand to have something to serialize + // Empty buffer to allow ForwardCommand to have something to serialize Buffer request; GetHmacSharingParametersResponse response; ForwardCommand(KM_GET_HMAC_SHARING_PARAMETERS, request, &response); diff --git a/trusty/libtrusty/include/trusty/ipc.h b/trusty/libtrusty/include/trusty/ipc.h new file mode 100644 index 0000000000..1fa6fe4aaf --- /dev/null +++ b/trusty/libtrusty/include/trusty/ipc.h @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2020 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 _UAPI_LINUX_TRUSTY_IPC_H_ +#define _UAPI_LINUX_TRUSTY_IPC_H_ + +#include <linux/ioctl.h> +#include <linux/types.h> +#include <linux/uio.h> + +/** + * enum transfer_kind - How to send an fd to Trusty + * @TRUSTY_SHARE: Memory will be accessible by Linux and Trusty. On ARM it will + * be mapped as nonsecure. Suitable for shared memory. The paired + * fd must be a "memfd". + * @TRUSTY_LEND: Memory will be accessible only to Trusty. On ARM it will be + * transitioned to "Secure" memory if Trusty is in TrustZone. + * This transfer kind is suitable for donating video buffers or + * other similar resources. The paired fd may need to come from a + * platform-specific allocator for memory that may be + * transitioned to "Secure". + * + * Describes how the user would like the resource in question to be sent to + * Trusty. Options may be valid only for certain kinds of fds. + */ +enum transfer_kind { + TRUSTY_SHARE = 0, + TRUSTY_LEND = 1, +}; + +/** + * struct trusty_shm - Describes a transfer of memory to Trusty + * @fd: The fd to transfer + * @transfer: How to transfer it - see &enum transfer_kind + */ +struct trusty_shm { + __s32 fd; + __u32 transfer; +}; + +/** + * struct tipc_send_msg_req - Request struct for @TIPC_IOC_SEND_MSG + * @iov: Pointer to an array of &struct iovec describing data to be sent + * @shm: Pointer to an array of &struct trusty_shm describing any file + * descriptors to be transferred. + * @iov_cnt: Number of elements in the @iov array + * @shm_cnt: Number of elements in the @shm array + */ +struct tipc_send_msg_req { + __u64 iov; + __u64 shm; + __u64 iov_cnt; + __u64 shm_cnt; +}; + +#define TIPC_IOC_MAGIC 'r' +#define TIPC_IOC_CONNECT _IOW(TIPC_IOC_MAGIC, 0x80, char*) +#define TIPC_IOC_SEND_MSG _IOW(TIPC_IOC_MAGIC, 0x81, struct tipc_send_msg_req) + +#if defined(CONFIG_COMPAT) +#define TIPC_IOC_CONNECT_COMPAT _IOW(TIPC_IOC_MAGIC, 0x80, compat_uptr_t) +#endif + +#endif diff --git a/trusty/libtrusty/include/trusty/tipc.h b/trusty/libtrusty/include/trusty/tipc.h index a3f2a3f611..b44afd3379 100644 --- a/trusty/libtrusty/include/trusty/tipc.h +++ b/trusty/libtrusty/include/trusty/tipc.h @@ -21,7 +21,11 @@ extern "C" { #endif +#include <sys/uio.h> +#include <trusty/ipc.h> + int tipc_connect(const char *dev_name, const char *srv_name); +ssize_t tipc_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shm, int shmcnt); int tipc_close(int fd); #ifdef __cplusplus diff --git a/trusty/libtrusty/tipc-test/tipc_test.c b/trusty/libtrusty/tipc-test/tipc_test.c index d20d4eebfb..ca581dc2d6 100644 --- a/trusty/libtrusty/tipc-test/tipc_test.c +++ b/trusty/libtrusty/tipc-test/tipc_test.c @@ -21,6 +21,8 @@ #include <stdlib.h> #include <unistd.h> #include <getopt.h> +#define __USE_GNU +#include <sys/mman.h> #include <sys/uio.h> #include <trusty/tipc.h> @@ -39,6 +41,7 @@ static const char *closer1_name = "com.android.ipc-unittest.srv.closer1"; static const char *closer2_name = "com.android.ipc-unittest.srv.closer2"; static const char *closer3_name = "com.android.ipc-unittest.srv.closer3"; static const char *main_ctrl_name = "com.android.ipc-unittest.ctrl"; +static const char* receiver_name = "com.android.trusty.memref.receiver"; static const char *_sopts = "hsvD:t:r:m:b:"; static const struct option _lopts[] = { @@ -66,25 +69,25 @@ static const char *usage = "\n" ; -static const char *usage_long = -"\n" -"The following tests are available:\n" -" connect - connect to datasink service\n" -" connect_foo - connect to non existing service\n" -" burst_write - send messages to datasink service\n" -" echo - send/receive messages to echo service\n" -" select - test select call\n" -" blocked_read - test blocked read\n" -" closer1 - connection closed by remote (test1)\n" -" closer2 - connection closed by remote (test2)\n" -" closer3 - connection closed by remote (test3)\n" -" ta2ta-ipc - execute TA to TA unittest\n" -" dev-uuid - print device uuid\n" -" ta-access - test ta-access flags\n" -" writev - writev test\n" -" readv - readv test\n" -"\n" -; +static const char* usage_long = + "\n" + "The following tests are available:\n" + " connect - connect to datasink service\n" + " connect_foo - connect to non existing service\n" + " burst_write - send messages to datasink service\n" + " echo - send/receive messages to echo service\n" + " select - test select call\n" + " blocked_read - test blocked read\n" + " closer1 - connection closed by remote (test1)\n" + " closer2 - connection closed by remote (test2)\n" + " closer3 - connection closed by remote (test3)\n" + " ta2ta-ipc - execute TA to TA unittest\n" + " dev-uuid - print device uuid\n" + " ta-access - test ta-access flags\n" + " writev - writev test\n" + " readv - readv test\n" + " send-fd - transmit memfd to trusty, use as shm\n" + "\n"; static uint opt_repeat = 1; static uint opt_msgsize = 32; @@ -885,6 +888,66 @@ static int readv_test(uint repeat, uint msgsz, bool var) return 0; } +static int send_fd_test(void) { + int ret; + int memfd = -1; + int fd = -1; + volatile char* buf = MAP_FAILED; + + fd = tipc_connect(dev_name, receiver_name); + if (fd < 0) { + fprintf(stderr, "Failed to connect to test support TA - is it missing?\n"); + ret = -1; + goto cleanup; + } + + memfd = memfd_create("tipc-send-fd", 0); + if (memfd < 0) { + fprintf(stderr, "Failed to create memfd: %s\n", strerror(errno)); + ret = -1; + goto cleanup; + } + + if (ftruncate(memfd, PAGE_SIZE) < 0) { + fprintf(stderr, "Failed to resize memfd: %s\n", strerror(errno)); + ret = -1; + goto cleanup; + } + + buf = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_SHARED, memfd, 0); + if (buf == MAP_FAILED) { + fprintf(stderr, "Failed to map memfd: %s\n", strerror(errno)); + ret = -1; + goto cleanup; + } + + strcpy((char*)buf, "From NS"); + + struct trusty_shm shm = { + .fd = memfd, + .transfer = TRUSTY_SHARE, + }; + + ssize_t rc = tipc_send(fd, NULL, 0, &shm, 1); + if (rc < 0) { + fprintf(stderr, "tipc_send failed\n"); + ret = rc; + goto cleanup; + } + char c; + read(fd, &c, 1); + tipc_close(fd); + + ret = strcmp("Hello from Trusty!", (const char*)buf) ? (-1) : 0; + +cleanup: + if (buf != MAP_FAILED) { + munmap((char*)buf, PAGE_SIZE); + } + close(memfd); + tipc_close(fd); + return ret; +} int main(int argc, char **argv) { @@ -933,10 +996,12 @@ int main(int argc, char **argv) rc = writev_test(opt_repeat, opt_msgsize, opt_variable); } else if (strcmp(test_name, "readv") == 0) { rc = readv_test(opt_repeat, opt_msgsize, opt_variable); - } else { - fprintf(stderr, "Unrecognized test name '%s'\n", test_name); - print_usage_and_exit(argv[0], EXIT_FAILURE, true); - } - - return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; + } else if (strcmp(test_name, "send-fd") == 0) { + rc = send_fd_test(); + } else { + fprintf(stderr, "Unrecognized test name '%s'\n", test_name); + print_usage_and_exit(argv[0], EXIT_FAILURE, true); + } + + return rc == 0 ? EXIT_SUCCESS : EXIT_FAILURE; } diff --git a/trusty/libtrusty/trusty.c b/trusty/libtrusty/trusty.c index a6238af7d6..ad4d8cd546 100644 --- a/trusty/libtrusty/trusty.c +++ b/trusty/libtrusty/trusty.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2015 The Android Open Source Project + * Copyright (C) 2020 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. @@ -27,7 +27,7 @@ #include <log/log.h> -#include "tipc_ioctl.h" +#include <trusty/ipc.h> int tipc_connect(const char *dev_name, const char *srv_name) { @@ -55,6 +55,22 @@ int tipc_connect(const char *dev_name, const char *srv_name) return fd; } +ssize_t tipc_send(int fd, const struct iovec* iov, int iovcnt, struct trusty_shm* shms, + int shmcnt) { + struct tipc_send_msg_req req; + req.iov = (__u64)iov; + req.iov_cnt = (__u64)iovcnt; + req.shm = (__u64)shms; + req.shm_cnt = (__u64)shmcnt; + + int rc = ioctl(fd, TIPC_IOC_SEND_MSG, &req); + if (rc < 0) { + ALOGE("%s: failed to send message (err=%d)\n", __func__, rc); + } + + return rc; +} + void tipc_close(int fd) { close(fd); diff --git a/trusty/trusty-test.mk b/trusty/trusty-test.mk new file mode 100644 index 0000000000..fd353d12b6 --- /dev/null +++ b/trusty/trusty-test.mk @@ -0,0 +1,16 @@ +# Copyright (C) 2020 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. + +PRODUCT_PACKAGES += \ + spiproxyd \ diff --git a/trusty/utils/spiproxyd/Android.bp b/trusty/utils/spiproxyd/Android.bp new file mode 100644 index 0000000000..c1d0987a3e --- /dev/null +++ b/trusty/utils/spiproxyd/Android.bp @@ -0,0 +1,36 @@ +// Copyright (C) 2020 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_binary { + name: "spiproxyd", + vendor: true, + + srcs: [ + "main.c", + ], + + shared_libs: [ + "liblog", + "libtrusty", + ], + + init_rc: [ + "proxy.rc", + ], + + cflags: [ + "-Wall", + "-Werror", + ], +} diff --git a/trusty/utils/spiproxyd/main.c b/trusty/utils/spiproxyd/main.c new file mode 100644 index 0000000000..c10866b5fd --- /dev/null +++ b/trusty/utils/spiproxyd/main.c @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 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_TAG "spiproxyd" + +#include <assert.h> +#include <fcntl.h> +#include <getopt.h> +#include <log/log.h> +#include <stdlib.h> +#include <string.h> +#include <trusty/tipc.h> +#include <unistd.h> + +int handle_msg(int trusty_dev_fd, int spi_dev_fd) { + int rc; + uint8_t msg_buf[4096]; + size_t msg_len; + + /* read request from SPI Trusty app */ + rc = read(trusty_dev_fd, &msg_buf, sizeof(msg_buf)); + if (rc < 0) { + ALOGE("failed (%d) to read request from TA\n", rc); + return rc; + } + msg_len = rc; + + /* forward request to SPI host device */ + rc = write(spi_dev_fd, &msg_buf, msg_len); + if (rc < 0 || (size_t)rc != msg_len) { + ALOGE("failed (%d) to forward request to host\n", rc); + return rc < 0 ? rc : -1; + } + + /* read response from SPI host device */ + rc = read(spi_dev_fd, &msg_buf, sizeof(msg_buf)); + if (rc < 0) { + ALOGE("failed (%d) to read response from host\n", rc); + return rc; + } + msg_len = rc; + + /* forward response to SPI Trusty app */ + rc = write(trusty_dev_fd, &msg_buf, msg_len); + if (rc < 0 || (size_t)rc != msg_len) { + ALOGE("failed (%d) to forward response to TA\n", rc); + return rc < 0 ? rc : -1; + } + + return 0; +} + +int event_loop(int trusty_dev_fd, int spi_dev_fd) { + while (true) { + int rc = handle_msg(trusty_dev_fd, spi_dev_fd); + if (rc < 0) { + ALOGE("exiting event loop\n"); + return EXIT_FAILURE; + } + } +} + +static void show_usage() { + ALOGE("usage: spiproxyd -t TRUSTY_DEVICE -s SPI_DEVICE -p SPI_PROXY_PORT\n"); +} + +static void parse_args(int argc, char* argv[], const char** trusty_dev_name, + const char** spi_dev_name, const char** spi_proxy_port) { + int opt; + while ((opt = getopt(argc, argv, "ht:s:p:")) != -1) { + switch (opt) { + case 'h': + show_usage(); + exit(EXIT_SUCCESS); + break; + case 't': + *trusty_dev_name = strdup(optarg); + break; + case 's': + *spi_dev_name = strdup(optarg); + break; + case 'p': + *spi_proxy_port = strdup(optarg); + break; + default: + show_usage(); + exit(EXIT_FAILURE); + break; + } + } + + if (!*trusty_dev_name || !*spi_dev_name || !*spi_proxy_port) { + show_usage(); + exit(EXIT_FAILURE); + } +} + +int main(int argc, char* argv[]) { + int rc; + const char* trusty_dev_name = NULL; + const char* spi_dev_name = NULL; + const char* spi_proxy_port = NULL; + int trusty_dev_fd; + int spi_dev_fd; + + parse_args(argc, argv, &trusty_dev_name, &spi_dev_name, &spi_proxy_port); + + rc = tipc_connect(trusty_dev_name, spi_proxy_port); + if (rc < 0) { + ALOGE("failed (%d) to connect to SPI proxy port\n", rc); + return rc; + } + trusty_dev_fd = rc; + + rc = open(spi_dev_name, O_RDWR, 0); + if (rc < 0) { + ALOGE("failed (%d) to open SPI device\n", rc); + return rc; + } + spi_dev_fd = rc; + + return event_loop(trusty_dev_fd, spi_dev_fd); +} diff --git a/trusty/utils/spiproxyd/proxy.rc b/trusty/utils/spiproxyd/proxy.rc new file mode 100644 index 0000000000..7d63e6ab4b --- /dev/null +++ b/trusty/utils/spiproxyd/proxy.rc @@ -0,0 +1,20 @@ +# Copyright (C) 2020 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. + +service spiproxyd /vendor/bin/spiproxyd -t /dev/trusty-ipc-dev0 \ + -s /dev/vport3p2 -p com.android.trusty.spi.proxy + class main + user system + group system + oneshot |
