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 <fcntl.h> 20 #include <pthread.h> 21 #include <signal.h> 22 #include <stdlib.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 #if defined(ART_TARGET_ANDROID) 33 #include <tombstoned/tombstoned.h> 34 #endif 35 36 #include "arch/instruction_set.h" 37 #include "base/file_utils.h" 38 #include "base/logging.h" // For GetCmdLine. 39 #include "base/os.h" 40 #include "base/time_utils.h" 41 #include "base/unix_file/fd_file.h" 42 #include "base/utils.h" 43 #include "class_linker.h" 44 #include "gc/heap.h" 45 #include "jit/profile_saver.h" 46 #include "runtime.h" 47 #include "scoped_thread_state_change-inl.h" 48 #include "signal_set.h" 49 #include "thread.h" 50 #include "thread_list.h" 51 52 namespace art { 53 54 static void DumpCmdLine(std::ostream& os) { 55 #if defined(__linux__) 56 // Show the original command line, and the current command line too if it's changed. 57 // On Android, /proc/self/cmdline will have been rewritten to something like "system_server". 58 // Note: The string "Cmd line:" is chosen to match the format used by debuggerd. 59 std::string current_cmd_line; 60 if (ReadFileToString("/proc/self/cmdline", ¤t_cmd_line)) { 61 current_cmd_line.resize(current_cmd_line.find_last_not_of('\0') + 1); // trim trailing '\0's 62 std::replace(current_cmd_line.begin(), current_cmd_line.end(), '\0', ' '); 63 64 os << "Cmd line: " << current_cmd_line << "\n"; 65 const char* stashed_cmd_line = GetCmdLine(); 66 if (stashed_cmd_line != nullptr && current_cmd_line != stashed_cmd_line 67 && strcmp(stashed_cmd_line, "<unset>") != 0) { 68 os << "Original command line: " << stashed_cmd_line << "\n"; 69 } 70 } 71 #else 72 os << "Cmd line: " << GetCmdLine() << "\n"; 73 #endif 74 } 75 76 SignalCatcher::SignalCatcher(const std::string& stack_trace_file, 77 bool use_tombstoned_stack_trace_fd) 78 : stack_trace_file_(stack_trace_file), 79 use_tombstoned_stack_trace_fd_(use_tombstoned_stack_trace_fd), 80 lock_("SignalCatcher lock"), 81 cond_("SignalCatcher::cond_", lock_), 82 thread_(nullptr) { 83 #if !defined(ART_TARGET_ANDROID) 84 // We're not running on Android, so we can't communicate with tombstoned 85 // to ask for an open file. 86 CHECK(!use_tombstoned_stack_trace_fd_); 87 #endif 88 89 SetHaltFlag(false); 90 91 // Create a raw pthread; its start routine will attach to the runtime. 92 CHECK_PTHREAD_CALL(pthread_create, (&pthread_, nullptr, &Run, this), "signal catcher thread"); 93 94 Thread* self = Thread::Current(); 95 MutexLock mu(self, lock_); 96 while (thread_ == nullptr) { 97 cond_.Wait(self); 98 } 99 } 100 101 SignalCatcher::~SignalCatcher() { 102 // Since we know the thread is just sitting around waiting for signals 103 // to arrive, send it one. 104 SetHaltFlag(true); 105 CHECK_PTHREAD_CALL(pthread_kill, (pthread_, SIGQUIT), "signal catcher shutdown"); 106 CHECK_PTHREAD_CALL(pthread_join, (pthread_, nullptr), "signal catcher shutdown"); 107 } 108 109 void SignalCatcher::SetHaltFlag(bool new_value) { 110 MutexLock mu(Thread::Current(), lock_); 111 halt_ = new_value; 112 } 113 114 bool SignalCatcher::ShouldHalt() { 115 MutexLock mu(Thread::Current(), lock_); 116 return halt_; 117 } 118 119 bool SignalCatcher::OpenStackTraceFile(android::base::unique_fd* tombstone_fd, 120 android::base::unique_fd* output_fd) { 121 if (use_tombstoned_stack_trace_fd_) { 122 #if defined(ART_TARGET_ANDROID) 123 return tombstoned_connect(getpid(), tombstone_fd, output_fd, kDebuggerdJavaBacktrace); 124 #else 125 UNUSED(tombstone_fd); 126 UNUSED(output_fd); 127 #endif 128 } 129 130 // The runtime is not configured to dump traces to a file, will LOG(INFO) 131 // instead. 132 if (stack_trace_file_.empty()) { 133 return false; 134 } 135 136 int fd = open(stack_trace_file_.c_str(), O_APPEND | O_CREAT | O_WRONLY, 0666); 137 if (fd == -1) { 138 PLOG(ERROR) << "Unable to open stack trace file '" << stack_trace_file_ << "'"; 139 return false; 140 } 141 142 output_fd->reset(fd); 143 return true; 144 } 145 146 void SignalCatcher::Output(const std::string& s) { 147 android::base::unique_fd tombstone_fd; 148 android::base::unique_fd output_fd; 149 if (!OpenStackTraceFile(&tombstone_fd, &output_fd)) { 150 LOG(INFO) << s; 151 return; 152 } 153 154 ScopedThreadStateChange tsc(Thread::Current(), kWaitingForSignalCatcherOutput); 155 156 std::unique_ptr<File> file(new File(output_fd.release(), true /* check_usage */)); 157 bool success = file->WriteFully(s.data(), s.size()); 158 if (success) { 159 success = file->FlushCloseOrErase() == 0; 160 } else { 161 file->Erase(); 162 } 163 164 const std::string output_path_msg = (use_tombstoned_stack_trace_fd_) ? 165 "[tombstoned]" : stack_trace_file_; 166 167 if (success) { 168 LOG(INFO) << "Wrote stack traces to '" << output_path_msg << "'"; 169 } else { 170 PLOG(ERROR) << "Failed to write stack traces to '" << output_path_msg << "'"; 171 } 172 173 #if defined(ART_TARGET_ANDROID) 174 if (use_tombstoned_stack_trace_fd_ && !tombstoned_notify_completion(tombstone_fd)) { 175 PLOG(WARNING) << "Unable to notify tombstoned of dump completion"; 176 } 177 #endif 178 } 179 180 void SignalCatcher::HandleSigQuit() { 181 Runtime* runtime = Runtime::Current(); 182 std::ostringstream os; 183 os << "\n" 184 << "----- pid " << getpid() << " at " << GetIsoDate() << " -----\n"; 185 186 DumpCmdLine(os); 187 188 // Note: The strings "Build fingerprint:" and "ABI:" are chosen to match the format used by 189 // debuggerd. This allows, for example, the stack tool to work. 190 std::string fingerprint = runtime->GetFingerprint(); 191 os << "Build fingerprint: '" << (fingerprint.empty() ? "unknown" : fingerprint) << "'\n"; 192 os << "ABI: '" << GetInstructionSetString(runtime->GetInstructionSet()) << "'\n"; 193 194 os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "\n"; 195 196 runtime->DumpForSigQuit(os); 197 198 if ((false)) { 199 std::string maps; 200 if (ReadFileToString("/proc/self/maps", &maps)) { 201 os << "/proc/self/maps:\n" << maps; 202 } 203 } 204 os << "----- end " << getpid() << " -----\n"; 205 Output(os.str()); 206 } 207 208 void SignalCatcher::HandleSigUsr1() { 209 LOG(INFO) << "SIGUSR1 forcing GC (no HPROF) and profile save"; 210 Runtime::Current()->GetHeap()->CollectGarbage(/* clear_soft_references */ false); 211 ProfileSaver::ForceProcessProfiles(); 212 } 213 214 int SignalCatcher::WaitForSignal(Thread* self, SignalSet& signals) { 215 ScopedThreadStateChange tsc(self, kWaitingInMainSignalCatcherLoop); 216 217 // Signals for sigwait() must be blocked but not ignored. We 218 // block signals like SIGQUIT for all threads, so the condition 219 // is met. When the signal hits, we wake up, without any signal 220 // handlers being invoked. 221 int signal_number = signals.Wait(); 222 if (!ShouldHalt()) { 223 // Let the user know we got the signal, just in case the system's too screwed for us to 224 // actually do what they want us to do... 225 LOG(INFO) << *self << ": reacting to signal " << signal_number; 226 227 // If anyone's holding locks (which might prevent us from getting back into state Runnable), say so... 228 Runtime::Current()->DumpLockHolders(LOG_STREAM(INFO)); 229 } 230 231 return signal_number; 232 } 233 234 void* SignalCatcher::Run(void* arg) { 235 SignalCatcher* signal_catcher = reinterpret_cast<SignalCatcher*>(arg); 236 CHECK(signal_catcher != nullptr); 237 238 Runtime* runtime = Runtime::Current(); 239 CHECK(runtime->AttachCurrentThread("Signal Catcher", true, runtime->GetSystemThreadGroup(), 240 !runtime->IsAotCompiler())); 241 242 Thread* self = Thread::Current(); 243 DCHECK_NE(self->GetState(), kRunnable); 244 { 245 MutexLock mu(self, signal_catcher->lock_); 246 signal_catcher->thread_ = self; 247 signal_catcher->cond_.Broadcast(self); 248 } 249 250 // Set up mask with signals we want to handle. 251 SignalSet signals; 252 signals.Add(SIGQUIT); 253 signals.Add(SIGUSR1); 254 255 while (true) { 256 int signal_number = signal_catcher->WaitForSignal(self, signals); 257 if (signal_catcher->ShouldHalt()) { 258 runtime->DetachCurrentThread(); 259 return nullptr; 260 } 261 262 switch (signal_number) { 263 case SIGQUIT: 264 signal_catcher->HandleSigQuit(); 265 break; 266 case SIGUSR1: 267 signal_catcher->HandleSigUsr1(); 268 break; 269 default: 270 LOG(ERROR) << "Unexpected signal %d" << signal_number; 271 break; 272 } 273 } 274 } 275 276 } // namespace art 277