File: child_exit_observer_android.cc

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (199 lines) | stat: -rw-r--r-- 7,410 bytes parent folder | download | duplicates (5)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "components/crash/content/browser/child_exit_observer_android.h"

#include <unistd.h>

#include "base/check_op.h"
#include "base/containers/contains.h"
#include "base/functional/bind.h"
#include "components/crash/content/browser/crash_memory_metrics_collector_android.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/child_process_data.h"
#include "content/public/browser/child_process_termination_info.h"

using content::BrowserThread;

namespace crash_reporter {

namespace {

void PopulateTerminationInfo(
    const content::ChildProcessTerminationInfo& content_info,
    ChildExitObserver::TerminationInfo* info) {
  info->binding_state = content_info.binding_state;
  info->threw_exception_during_init = content_info.threw_exception_during_init;
  info->was_killed_intentionally_by_browser =
      content_info.was_killed_intentionally_by_browser;
  info->renderer_has_visible_clients =
      content_info.renderer_has_visible_clients;
  info->renderer_was_subframe = content_info.renderer_was_subframe;
  info->is_spare_renderer = content_info.is_spare_renderer;
  info->has_spare_renderer = content_info.has_spare_renderer;
}

}  // namespace

ChildExitObserver::TerminationInfo::TerminationInfo() = default;
ChildExitObserver::TerminationInfo::TerminationInfo(
    const TerminationInfo& other) = default;
ChildExitObserver::TerminationInfo& ChildExitObserver::TerminationInfo::
operator=(const TerminationInfo& other) = default;

ChildExitObserver::ChildExitObserver() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  BrowserChildProcessObserver::Add(this);
  scoped_crash_handler_host_observation_.Observe(
      crashpad::CrashHandlerHost::Get());
}

ChildExitObserver::~ChildExitObserver() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  BrowserChildProcessObserver::Remove(this);
}

void ChildExitObserver::RegisterClient(std::unique_ptr<Client> client) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  base::AutoLock auto_lock(registered_clients_lock_);
  registered_clients_.push_back(std::move(client));
}

void ChildExitObserver::ChildReceivedCrashSignal(base::ProcessId pid,
                                                 int signo) {
  base::AutoLock lock(crash_signals_lock_);
  bool result =
      child_pid_to_crash_signal_.insert(std::make_pair(pid, signo)).second;
  DCHECK(result);
}

void ChildExitObserver::OnRenderProcessHostCreated(
    content::RenderProcessHost* host) {
  // The child process pid isn't available when process is gone, keep a mapping
  // between process_host_id and pid, so we can find it later.
  process_host_id_to_pid_[host->GetDeprecatedID()] =
      host->GetProcess().Handle();
  if (!render_process_host_observation_.IsObservingSource(host)) {
    render_process_host_observation_.AddObservation(host);
  }
}

void ChildExitObserver::OnChildExit(TerminationInfo* info) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  {
    base::AutoLock lock(crash_signals_lock_);
    auto pid_and_signal = child_pid_to_crash_signal_.find(info->pid);
    if (pid_and_signal != child_pid_to_crash_signal_.end()) {
      info->crash_signo = pid_and_signal->second;
      child_pid_to_crash_signal_.erase(pid_and_signal);
    }
  }

  std::vector<Client*> registered_clients_copy;
  {
    base::AutoLock auto_lock(registered_clients_lock_);
    for (auto& client : registered_clients_)
      registered_clients_copy.push_back(client.get());
  }
  for (auto* client : registered_clients_copy) {
    client->OnChildExit(*info);
  }
}

void ChildExitObserver::BrowserChildProcessHostDisconnected(
    const content::ChildProcessData& data) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  TerminationInfo info;
  auto it = browser_child_process_info_.find(data.id);
  if (it != browser_child_process_info_.end()) {
    info = it->second;
    browser_child_process_info_.erase(it);
  } else {
    info.process_host_id = data.id;
    if (data.GetProcess().IsValid())
      info.pid = data.GetProcess().Pid();
    info.process_type = static_cast<content::ProcessType>(data.process_type);
    info.app_state = base::android::ApplicationStatusListener::GetState();
    info.normal_termination = true;
  }
  OnChildExit(&info);
}

void ChildExitObserver::BrowserChildProcessKilled(
    const content::ChildProcessData& data,
    const content::ChildProcessTerminationInfo& content_info) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DCHECK(!base::Contains(browser_child_process_info_, data.id));
  TerminationInfo info;
  info.process_host_id = data.id;
  info.pid = data.GetProcess().Pid();
  info.process_type = static_cast<content::ProcessType>(data.process_type);
  info.app_state = base::android::ApplicationStatusListener::GetState();
  info.normal_termination = content_info.clean_exit;
  PopulateTerminationInfo(content_info, &info);
  browser_child_process_info_.emplace(data.id, info);
  // Subsequent BrowserChildProcessHostDisconnected will call OnChildExit.
}

void ChildExitObserver::RenderProcessExited(
    content::RenderProcessHost* host,
    const content::ChildProcessTerminationInfo& info) {
  ProcessRenderProcessHostLifetimeEndEvent(host, &info);
}

void ChildExitObserver::RenderProcessHostDestroyed(
    content::RenderProcessHost* host) {
  ProcessRenderProcessHostLifetimeEndEvent(host, nullptr);
  render_process_host_observation_.RemoveObservation(host);
}

void ChildExitObserver::ProcessRenderProcessHostLifetimeEndEvent(
    content::RenderProcessHost* rph,
    const content::ChildProcessTerminationInfo* content_info) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  TerminationInfo info;
  info.process_host_id = rph->GetDeprecatedID();
  info.pid = rph->GetProcess().Handle();
  info.process_type = content::PROCESS_TYPE_RENDERER;
  info.app_state = base::android::APPLICATION_STATE_UNKNOWN;
  info.renderer_has_visible_clients = rph->VisibleClientCount() > 0;
  info.renderer_was_subframe = rph->GetFrameDepth() > 0u;
  CrashMemoryMetricsCollector* collector =
      CrashMemoryMetricsCollector::GetFromRenderProcessHost(rph);

  // CrashMemoryMetircsCollector is created in chrome_content_browser_client,
  // and does not exist in non-chrome platforms such as android webview /
  // chromecast.
  if (collector) {
    // SharedMemory creation / Map() might fail.
    info.blink_oom_metrics = collector->MemoryMetrics();
  }

  if (content_info) {
    // We do not care about android fast shutdowns as it is a known case where
    // the renderer is intentionally killed when we are done with it.
    info.normal_termination = rph->FastShutdownStarted();
    info.renderer_shutdown_requested = rph->ShutdownRequested();
    info.app_state = base::android::ApplicationStatusListener::GetState();
    PopulateTerminationInfo(*content_info, &info);
  } else {
    // No |content_info| is provided when the renderer process is cleanly
    // shutdown.
    info.normal_termination = true;
    info.renderer_shutdown_requested = rph->ShutdownRequested();
  }

  const auto& iter = process_host_id_to_pid_.find(rph->GetDeprecatedID());
  if (iter == process_host_id_to_pid_.end()) {
    return;
  }
  if (info.pid == base::kNullProcessHandle) {
    info.pid = iter->second;
  }
  process_host_id_to_pid_.erase(iter);
  OnChildExit(&info);
}

}  // namespace crash_reporter