1 /* 2 * Copyright (C) 2008 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 "signal_catcher.h" 18 19 #include <csignal> 20 #include <cstdlib> 21 #include <fcntl.h> 22 #include <pthread.h> 23 #include <sys/stat.h> 24 #include <sys/time.h> 25 #include <sys/types.h> 26 #include <unistd.h> 27 28 #include <sstream> 29 30 #include <android-base/stringprintf.h> 31 32 #include "arch/instruction_set.h" 33 #include "base/logging.h" // For GetCmdLine. 34 #include "base/os.h" 35 #include "base/time_utils.h" 36 #include "base/utils.h" 37 #include "class_linker.h" 38 #include "gc/heap.h" 39 #include "jit/profile_saver.h" 40 #include "palette/palette.h" 41 #include "runtime.h" 42 #include "scoped_thread_state_change-inl.h" 43 #include "signal_set.h" 44 #include "thread.h" 45 #include "thread_list.h" 46 47 namespace art { 48 49 static void DumpCmdLine(std::ostream& os) { 50 #if defined(__linux__) 51 // Show the original command line, and the current command line too if it's changed. 52 // On Android, /proc/self/cmdline will have been rewritten to something like "system_server". 53 // Note: The string "Cmd line:" is chosen to match the format used by debuggerd. 54 std::string current_cmd_line; 55 if (ReadFileToString("/proc/self/cmdline", ¤t_cmd_line)) { 56 current_cmd_line.resize(current_cmd_line.find_last_not_of('\0') + 1); // trim trailing '\0's 57 std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' '); 58 59 os << "Cmd line: " << current_cmd_line << "\n"; 60 const char* stashed_cmd_line = GetCmdLine(); 61 if (stashed_cmd_line != nullptr && current_cmd_line != stashed_cmd_line 62 && strcmp(stashed_cmd_line, "<unset>") != 0) { 63 os << "Original command line: " << stashed_cmd_line << "\n"; 64 } 65 } 66 #else 67 os << "Cmd line: " << GetCmdLine() << "\n"; 68 #endif 69 } 70 71 SignalCatcher::SignalCatcher() 72 : lock_("SignalCatcher lock"), 73 cond_("SignalCatcher::cond_", lock_), 74 thread_(nullptr) { 75 SetHaltFlag(false); 76 77 // Create a raw pthread; its start routine will attach to the runtime. 78 CHECK_PTHREAD_CALL(pthread_create, (&pthread_, nullptr, &Run, this), "signal catcher thread"); 79 80 Thread* self = Thread::Current(); 81 MutexLock mu(self, lock_); 82 while (thread_ == nullptr) { 83 cond_.Wait(self); 84 } 85 } 86 87 SignalCatcher::~SignalCatcher() { 88 // Since we know the thread is just sitting around waiting for signals 89 // to arrive, send it one. 90 SetHaltFlag(true); 91 CHECK_PTHREAD_CALL(pthread_kill, (pthread_, SIGQUIT), "signal catcher shutdown"); 92 CHECK_PTHREAD_CALL(pthread_join, (pthread_, nullptr), "signal catcher shutdown"); 93 } 94 95 void SignalCatcher::SetHaltFlag(bool new_value) { 96 MutexLock mu(Thread::Current(), lock_); 97 halt_ = new_value; 98 } 99 100 bool SignalCatcher::ShouldHalt() { 101 MutexLock mu(Thread::Current(), lock_); 102 return halt_; 103 } 104 105 void SignalCatcher::Output(const std::string& s) { 106 ScopedThreadStateChange tsc(Thread::Current(), kWaitingForSignalCatcherOutput); 107 PaletteStatus status = PaletteWriteCrashThreadStacks(s.data(), s.size()); 108 if (status == PaletteStatus::kOkay) { 109 LOG(INFO) << "Wrote stack traces to tombstoned"; 110 } else { 111 CHECK(status == PaletteStatus::kFailedCheckLog); 112 LOG(ERROR) << "Failed to write stack traces to tombstoned"; 113 } 114 } 115 116 void SignalCatcher::HandleSigQuit() { 117 Runtime* runtime = Runtime::Current(); 118 std::ostringstream os; 119 os << "\n" 120 << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n"; 121 122 DumpCmdLine(os); 123 124 // Note: The strings "Build fingerprint:" and "ABI:" are chosen to match the format used by 125 // debuggerd. This allows, for example, the stack tool to work. 126 std::string fingerprint = runtime->GetFingerprint(); 127 os << "Build fingerprint: '" << (fingerprint.empty() ? "unknown" : fingerprint) << "'\n"; 128 os << "ABI: '" << GetInstructionSetString(runtime->GetInstructionSet()) << "'\n"; 129 130 os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n"; 131 132 runtime->DumpForSigQuit(os); 133 134 if ((false)) { 135 std::string maps; 136 if (ReadFileToString("/proc/self/maps", &maps)) { 137 os << "/proc/self/maps:\n" << maps; 138 } 139 } 140 os << "----- end " << getpid() << " -----\n"; 141 Output(os.str()); 142 } 143 144 void SignalCatcher::HandleSigUsr1() { 145 LOG(INFO) << "SIGUSR1 forcing GC (no HPROF) and profile save"; 146 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references= */ false); 147 ProfileSaver::ForceProcessProfiles(); 148 } 149 150 int SignalCatcher::WaitForSignal(Thread* self, SignalSet& signals) { 151 ScopedThreadStateChange tsc(self, kWaitingInMainSignalCatcherLoop); 152 153 // Signals for sigwait() must be blocked but not ignored. We 154 // block signals like SIGQUIT for all threads, so the condition 155 // is met. When the signal hits, we wake up, without any signal 156 // handlers being invoked. 157 int signal_number = signals.Wait(); 158 if (!ShouldHalt()) { 159 // Let the user know we got the signal, just in case the system's too screwed for us to 160 // actually do what they want us to do... 161 LOG(INFO) << *self << ": reacting to signal " << signal_number; 162 163 // If anyone's holding locks (which might prevent us from getting back into state Runnable), say so... 164 Runtime::Current()->DumpLockHolders(LOG_STREAM(INFO)); 165 } 166 167 return signal_number; 168 } 169 170 void* SignalCatcher::Run(void* arg) { 171 SignalCatcher* signal_catcher = reinterpret_cast<SignalCatcher*>(arg); 172 CHECK(signal_catcher != nullptr); 173 174 Runtime* runtime = Runtime::Current(); 175 CHECK(runtime->AttachCurrentThread("Signal Catcher", true, runtime->GetSystemThreadGroup(), 176 !runtime->IsAotCompiler())); 177 178 Thread* self = Thread::Current(); 179 DCHECK_NE(self->GetState(), kRunnable); 180 { 181 MutexLock mu(self, signal_catcher->lock_); 182 signal_catcher->thread_ = self; 183 signal_catcher->cond_.Broadcast(self); 184 } 185 186 // Set up mask with signals we want to handle. 187 SignalSet signals; 188 signals.Add(SIGQUIT); 189 signals.Add(SIGUSR1); 190 191 while (true) { 192 int signal_number = signal_catcher->WaitForSignal(self, signals); 193 if (signal_catcher->ShouldHalt()) { 194 runtime->DetachCurrentThread(); 195 return nullptr; 196 } 197 198 switch (signal_number) { 199 case SIGQUIT: 200 signal_catcher->HandleSigQuit(); 201 break; 202 case SIGUSR1: 203 signal_catcher->HandleSigUsr1(); 204 break; 205 default: 206 LOG(ERROR) << "Unexpected signal %d" << signal_number; 207 break; 208 } 209 } 210 } 211 212 } // namespace art 213