John Reck | dc87c52 | 2016-02-29 13:31:18 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2016 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | #include "gtest/gtest.h" |
| 18 | |
| 19 | #include "Caches.h" |
| 20 | #include "thread/TaskManager.h" |
| 21 | #include "tests/common/TestUtils.h" |
| 22 | |
| 23 | #include <memunreachable/memunreachable.h> |
| 24 | |
| 25 | #include <cstdio> |
| 26 | #include <iostream> |
| 27 | #include <map> |
| 28 | #include <unordered_set> |
| 29 | #include <signal.h> |
| 30 | #include <unistd.h> |
| 31 | |
| 32 | using namespace std; |
| 33 | using namespace android; |
| 34 | using namespace android::uirenderer; |
| 35 | |
| 36 | static auto CRASH_SIGNALS = { |
| 37 | SIGABRT, |
| 38 | SIGSEGV, |
| 39 | SIGBUS, |
| 40 | }; |
| 41 | |
| 42 | static map<int, struct sigaction> gSigChain; |
| 43 | |
| 44 | static void gtestSigHandler(int sig, siginfo_t* siginfo, void* context) { |
| 45 | auto testinfo = ::testing::UnitTest::GetInstance()->current_test_info(); |
| 46 | printf("[ FAILED ] %s.%s\n", testinfo->test_case_name(), |
| 47 | testinfo->name()); |
| 48 | printf("[ FATAL! ] Process crashed, aborting tests!\n"); |
| 49 | fflush(stdout); |
| 50 | |
| 51 | // restore the default sighandler and re-raise |
| 52 | struct sigaction sa = gSigChain[sig]; |
| 53 | sigaction(sig, &sa, nullptr); |
| 54 | raise(sig); |
| 55 | } |
| 56 | |
| 57 | static void logUnreachable(initializer_list<UnreachableMemoryInfo> infolist) { |
| 58 | // merge them all |
| 59 | UnreachableMemoryInfo merged; |
| 60 | unordered_set<uintptr_t> addrs; |
| 61 | merged.allocation_bytes = 0; |
| 62 | merged.leak_bytes = 0; |
| 63 | merged.num_allocations = 0; |
| 64 | merged.num_leaks = 0; |
| 65 | for (auto& info : infolist) { |
| 66 | // We'll be a little hazzy about these ones and just hope the biggest |
| 67 | // is the most accurate |
| 68 | merged.allocation_bytes = max(merged.allocation_bytes, info.allocation_bytes); |
| 69 | merged.num_allocations = max(merged.num_allocations, info.num_allocations); |
| 70 | for (auto& leak : info.leaks) { |
| 71 | if (addrs.find(leak.begin) == addrs.end()) { |
| 72 | merged.leaks.push_back(leak); |
| 73 | merged.num_leaks++; |
| 74 | merged.leak_bytes += leak.size; |
| 75 | addrs.insert(leak.begin); |
| 76 | } |
| 77 | } |
| 78 | } |
| 79 | |
| 80 | // Now log the result |
| 81 | if (merged.num_leaks) { |
| 82 | cout << endl << "Leaked memory!" << endl; |
John Reck | 88737a0 | 2016-03-08 11:03:35 -0800 | [diff] [blame] | 83 | if (!merged.leaks[0].backtrace.num_frames) { |
John Reck | dc87c52 | 2016-02-29 13:31:18 -0800 | [diff] [blame] | 84 | cout << "Re-run with 'setprop libc.debug.malloc.program hwui_unit_test'" |
| 85 | << endl << "and 'setprop libc.debug.malloc.options backtrace=8'" |
| 86 | << " to get backtraces" << endl; |
| 87 | } |
| 88 | cout << merged.ToString(false); |
| 89 | } |
| 90 | } |
| 91 | |
| 92 | static void checkForLeaks() { |
| 93 | // TODO: Until we can shutdown the RT thread we need to do this in |
| 94 | // two passes as GetUnreachableMemory has limited insight into |
| 95 | // thread-local caches so some leaks will not be properly tagged as leaks |
| 96 | nsecs_t before = systemTime(); |
| 97 | UnreachableMemoryInfo rtMemInfo; |
| 98 | TestUtils::runOnRenderThread([&rtMemInfo](renderthread::RenderThread& thread) { |
| 99 | if (Caches::hasInstance()) { |
| 100 | Caches::getInstance().tasks.stop(); |
| 101 | } |
| 102 | // Check for leaks |
| 103 | if (!GetUnreachableMemory(rtMemInfo)) { |
| 104 | cerr << "Failed to get unreachable memory!" << endl; |
| 105 | return; |
| 106 | } |
| 107 | }); |
| 108 | UnreachableMemoryInfo uiMemInfo; |
| 109 | if (!GetUnreachableMemory(uiMemInfo)) { |
| 110 | cerr << "Failed to get unreachable memory!" << endl; |
| 111 | return; |
| 112 | } |
| 113 | logUnreachable({rtMemInfo, uiMemInfo}); |
| 114 | nsecs_t after = systemTime(); |
| 115 | cout << "Leak check took " << ns2ms(after - before) << "ms" << endl; |
| 116 | } |
| 117 | |
| 118 | int main(int argc, char* argv[]) { |
| 119 | // Register a crash handler |
| 120 | struct sigaction sa; |
| 121 | memset(&sa, 0, sizeof(sa)); |
| 122 | sa.sa_sigaction = >estSigHandler; |
| 123 | sa.sa_flags = SA_SIGINFO; |
| 124 | for (auto sig : CRASH_SIGNALS) { |
| 125 | struct sigaction old_sa; |
| 126 | sigaction(sig, &sa, &old_sa); |
| 127 | gSigChain.insert(pair<int, struct sigaction>(sig, old_sa)); |
| 128 | } |
| 129 | |
| 130 | // Run the tests |
| 131 | testing::InitGoogleTest(&argc, argv); |
| 132 | int ret = RUN_ALL_TESTS(); |
| 133 | checkForLeaks(); |
| 134 | return ret; |
| 135 | } |
| 136 | |