5.1
3.4のコードがピックアップされた後、解析は下の行に進み、レスポンスを受信した後、レスポンスからRegisteredかどうかを判断し、send_signal()メソッドを呼び出してSIGQUITシグナルを送信し、anrが発生したpidに対応するログのダンプを開始します。
bool debuggerd_trigger_dump(pid_t tid, DebuggerdDumpType dump_type, unsigned int timeout_ms,
unique_fd output_fd) {
// Check to make sure we've successfully registered.
InterceptResponse response;
// .4レスポンスで、対応するkRegistered判定を行う。
rc = TEMP_FAILURE_RETRY(recv(set_timeout(sockfd.get()), &response, sizeof(response), MSG_TRUNC));
if (response.status != InterceptStatus::kRegistered) {
LOG(ERROR) << "libdebuggerd_client: unexpected registration response: "
<< static_cast(response.status);
return false;
}
//でSIGQUITシグナルを送信する。/Q_Mainline/art/runtime/runtime.ccシグナルは
if (!send_signal(tid, dump_type)) {
return false;
}
}
初期化メソッドInit()では、init時にSIGQUITが登録され、Signals.Add(SIGQUIT)を通してBlockSignals()で登録されます。
bool Runtime::Init(RuntimeArgumentMap&& runtime_options_in) {
//BlockSignals() で、SIGQUIT シグナルを登録する。
BlockSignals();
// Look for a native bridge.
//
// The intended flow here is, in the case of a running system:
//
// Runtime::Init() (zygote):
// LoadNativeBridge -> dlopen from cmd line parameter.
// |
// V
// Runtime::Start() (zygote):
// No-op wrt native bridge.
// |
// | start app
// V
// DidForkFromZygote(action)
// action = kUnload -> dlclose native bridge.
// action = kInitialize -> initialize library
//
//
// The intended flow here is, in the case of a simple dalvikvm call:
//
// Runtime::Init():
// LoadNativeBridge -> dlopen from cmd line parameter.
// |
// V
// Runtime::Start():
// DidForkFromZygote(kInitialize) -> try to initialize any native bridge given.
// No-op wrt native bridge.
{
//コメントから、LoadNativeBridge()は結局、Runtimeを呼び出している。::Start()
std::string native_bridge_file_name = runtime_options.ReleaseOrDefault(Opt::NativeBridge);
is_native_bridge_loaded_ = LoadNativeBridge(native_bridge_file_name);
}
}
void Runtime::BlockSignals() {
SignalSet signals;
signals.Add(SIGPIPE);
// SIGQUIT is used to dump the runtime's state (including stack traces).
signals.Add(SIGQUIT);
// SIGUSR1 is used to initiate a GC.
signals.Add(SIGUSR1);
signals.Block();
}
5.3
InitNonZygoteOrPostFork()を呼び出したRuntime::Start()
bool Runtime::Start() {
if (!is_zygote_) {
InitNonZygoteOrPostFork(self->GetJniEnv(), /* is_system_server= */ false, action, GetInstructionSetString(kRuntimeISA));
}
5.4
Runtime::InitNonZygoteOrPostFork()、StartSignalCatcher()と呼ばれます。
void Runtime::InitNonZygoteOrPostFork(JNIEnv* env, bool is_system_server, NativeBridgeAction action, const char* isa, bool profile_system_server) {
StartSignalCatcher();
}
5.5
void Runtime::StartSignalCatcher() {
if (!is_zygote_) {
signal_catcher_ = new SignalCatcher();
}
}
5.6art/runtime/signal_catcher.cc
SignalCatcher::SignalCatcher()は、コンストラクタ・メソッドを通じてSignalCatcher:オブジェクトを生成し、コンストラクタ・メソッドでは、コメントから分かるように、Run()が実行されます。
SignalCatcher::SignalCatcher(): lock_("SignalCatcher lock"),cond_("SignalCatcher::cond_", lock_),thread_(nullptr) {
SetHaltFlag(false);
// Create a raw pthread; its start routine will attach to the runtime.
CHECK_PTHREAD_CALL(pthread_create, (&pthread_, nullptr, &Run, this), "signal catcher thread");
}
5.7
void* SignalCatcher::Run(void* arg) {
while (true) {
int signal_number = signal_catcher->WaitForSignal(self, signals);
if (signal_catcher->ShouldHalt()) {
runtime->DetachCurrentThread();
return nullptr;
}
switch (signal_number) {
case SIGQUIT:
signal_catcher->HandleSigQuit();
break;
}
}
}
5.8
SignalCatcher::HandleSigQuit()では、このメソッドはosstringstream型のosストリームを作成し、出力が必要なすべてのログをそこに格納します。
void SignalCatcher::HandleSigQuit() {
Runtime* runtime = Runtime::Current();
std::ostringstream os;
os << "
"
<< "----- pid " << getpid() << " at " << GetIsoDate() << " -----
";
DumpCmdLine(os);
// Note: The strings "Build fingerprint:" and "ABI:" are chosen to match the format used by
// debuggerd. This allows, for example, the stack tool to work.
std::string fingerprint = runtime->GetFingerprint();
os << "Build fingerprint: '" << (fingerprint.empty() ? "unknown" : fingerprint) << "'
";
os << "ABI: '" << GetInstructionSetString(runtime->GetInstructionSet()) << "'
";
os << "Build type: " << (kIsDebugBuild ? "debug" : "optimized") << "
";
runtime->DumpForSigQuit(os);
os << "----- end " << getpid() << " -----
";
Output(os.str());
}
5.9
Runtime::DumpForSigQuit()は、c++のポリモーフィックな性質によって、対応するDumpForSigQuit()を通じて対応するログを収集します。
void Runtime::DumpForSigQuit(std::ostream& os) {
GetClassLinker()->DumpForSigQuit(os);
GetInternTable()->DumpForSigQuit(os);
//jvmlogを収集する
GetJavaVM()->DumpForSigQuit(os);
//総割り当て数などのメモリ使用ログを収集する。
GetHeap()->DumpForSigQuit(os);
oat_file_manager_->DumpForSigQuit(os);
if (GetJit() != nullptr) {
GetJit()->DumpForSigQuit(os);
} else {
os << "Running non JIT
";
}
DumpDeoptimizations(os);
TrackedAllocators::Dump(os);
os << "
";
thread_list_->DumpForSigQuit(os);
BaseMutex::DumpAll(os);
}
5.10
void SignalCatcher::Output(const std::string& s) {
ScopedThreadStateChange tsc(Thread::Current(), kWaitingForSignalCatcherOutput);
PaletteStatus status = PaletteWriteCrashThreadStacks(s.data(), s.size());
if (status == PaletteStatus::kOkay) {
LOG(INFO) << "Wrote stack traces to tombstoned";
} else {
CHECK(status == PaletteStatus::kFailedCheckLog);
LOG(ERROR) << "Failed to write stack traces to tombstoned";
}
}
5.11
PaletteStatus PaletteWriteCrashThreadStacks()は、ここで2つのユニーク_fd(スマートファイル記述子、および自動回復に似たスマートポインタとみなすことができる)を作成し、tombstoned_connect()を介してソケットサーバーに接続します。データ通信は、output_fdを取得し、ログ内のosストリームにWriteFully()メソッドを介して、output_fdに書き込み、最初にtombstoned_connectこのメソッドを分析し、それがより重要です!
パラメータ: stacks = os.data(), stacks_len = os.size()
enum PaletteStatus PaletteWriteCrashThreadStacks(/*in*/const char* stacks, size_t stacks_len) {
android::base::unique_fd tombstone_fd;
android::base::unique_fd output_fd;
//output_fd = pipe_write.get()
if (!tombstoned_connect(getpid(), &tombstone_fd, &output_fd, kDebuggerdJavaBacktrace)) {
// Failure here could be due to file descriptor resource exhaustion
// so write the stack trace message to the log in case it helps
// debug that.
LOG(INFO) << std::string_view(stacks, stacks_len);
// tombstoned_connect() logs failure reason.
return PaletteStatus::kFailedCheckLog;
}
PaletteStatus status = PaletteStatus::kOkay;
//スタックを出力に書き出す_fd = pipe_write.get()そして/Q_Mainline/system/core/debuggerd/client/debuggerd_client.cppデバッガーd_trigger_dump()パイプによるメソッドでは_read.get()読み出す
if (!android::base::WriteFully(output_fd, stacks, stacks_len)) {
PLOG(ERROR) << "Failed to write tombstoned output";
TEMP_FAILURE_RETRY(ftruncate(output_fd, 0));
status = PaletteStatus::kFailedCheckLog;
}
}
5.12
tombstoned_connect()、このメソッドはsystem/core/debuggerd/tombstoned/tombstoned_client.cppに実装されています。
bool tombstoned_connect(pid_t pid, unique_fd* tombstoned_socket, unique_fd* output_fd,
DebuggerdDumpType dump_type) {
unique_fd sockfd(
socket_local_client((dump_type != kDebuggerdJavaBacktrace ? kTombstonedCrashSocketName
: kTombstonedJavaTraceSocketName),
ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_SEQPACKET));
TombstonedCrashPacket packet = {};
packet.packet_type = CrashPacketType::kDumpRequest;
packet.packet.dump_request.pid = pid;
packet.packet.dump_request.dump_type = dump_type;
if (TEMP_FAILURE_RETRY(write(sockfd, &packet, sizeof(packet))) != sizeof(packet)) {
async_safe_format_log(ANDROID_LOG_ERROR, "libc", "failed to write DumpRequest packet: %s",
strerror(errno));
return false;
}
unique_fd tmp_output_fd;
// .4SendFileDescriptorsを送信することで
//packet = response = {.packet_type = CrashPacketType::kPerformDump}
//tmp_output_fd = output_fd = pipe_write.get()
ssize_t rc = ReceiveFileDescriptors(sockfd, &packet, sizeof(packet), &tmp_output_fd);
*tombstoned_socket = std::move(sockfd);
//output_fd = tmp_output_fd = output_fd = pipe_write.get()
*output_fd = std::move(tmp_output_fd);
return true;
}