OLD | NEW |
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "chrome/browser/android/crash_dump_manager.h" | 5 #include "chrome/browser/android/crash_dump_manager.h" |
6 | 6 |
7 #include "base/bind.h" | 7 #include "base/bind.h" |
8 #include "base/file_util.h" | 8 #include "base/file_util.h" |
9 #include "base/format_macros.h" | 9 #include "base/format_macros.h" |
10 #include "base/logging.h" | 10 #include "base/logging.h" |
(...skipping 27 matching lines...) Expand all Loading... |
38 DCHECK(!instance_); | 38 DCHECK(!instance_); |
39 | 39 |
40 instance_ = this; | 40 instance_ = this; |
41 | 41 |
42 notification_registrar_.Add(this, | 42 notification_registrar_.Add(this, |
43 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, | 43 content::NOTIFICATION_RENDERER_PROCESS_TERMINATED, |
44 content::NotificationService::AllSources()); | 44 content::NotificationService::AllSources()); |
45 notification_registrar_.Add(this, | 45 notification_registrar_.Add(this, |
46 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | 46 content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
47 content::NotificationService::AllSources()); | 47 content::NotificationService::AllSources()); |
48 notification_registrar_.Add(this, | 48 |
49 content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED, | 49 StartObservingBrowserChildProcesses(); |
50 content::NotificationService::AllSources()); | |
51 notification_registrar_.Add(this, | |
52 content::NOTIFICATION_CHILD_PROCESS_CRASHED, | |
53 content::NotificationService::AllSources()); | |
54 } | 50 } |
55 | 51 |
56 CrashDumpManager::~CrashDumpManager() { | 52 CrashDumpManager::~CrashDumpManager() { |
57 instance_ = NULL; | 53 instance_ = NULL; |
| 54 |
| 55 StopObservingBrowserChildProcesses(); |
58 } | 56 } |
59 | 57 |
60 int CrashDumpManager::CreateMinidumpFile(int child_process_id) { | 58 int CrashDumpManager::CreateMinidumpFile(int child_process_id) { |
61 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)); | 59 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::PROCESS_LAUNCHER)); |
62 base::FilePath minidump_path; | 60 base::FilePath minidump_path; |
63 if (!file_util::CreateTemporaryFile(&minidump_path)) | 61 if (!file_util::CreateTemporaryFile(&minidump_path)) |
64 return base::kInvalidPlatformFileValue; | 62 return base::kInvalidPlatformFileValue; |
65 | 63 |
66 base::PlatformFileError error; | 64 base::PlatformFileError error; |
67 // We need read permission as the minidump is generated in several phases | 65 // We need read permission as the minidump is generated in several phases |
68 // and needs to be read at some point. | 66 // and needs to be read at some point. |
69 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ | | 67 int flags = base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ | |
70 base::PLATFORM_FILE_WRITE; | 68 base::PLATFORM_FILE_WRITE; |
71 base::PlatformFile minidump_file = | 69 base::PlatformFile minidump_file = |
72 base::CreatePlatformFile(minidump_path, flags, NULL, &error); | 70 base::CreatePlatformFile(minidump_path, flags, NULL, &error); |
73 if (minidump_file == base::kInvalidPlatformFileValue) { | 71 if (minidump_file == base::kInvalidPlatformFileValue) { |
74 LOG(ERROR) << "Failed to create temporary file, crash won't be reported."; | 72 LOG(ERROR) << "Failed to create temporary file, crash won't be reported."; |
75 return base::kInvalidPlatformFileValue; | 73 return base::kInvalidPlatformFileValue; |
76 } | 74 } |
77 | 75 |
78 { | 76 { |
79 base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_); | 77 base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_); |
80 DCHECK(!ContainsKey(child_process_id_to_minidump_path_, child_process_id)); | 78 DCHECK(!ContainsKey(child_process_id_to_minidump_path_, child_process_id)); |
81 child_process_id_to_minidump_path_[child_process_id] = minidump_path; | 79 child_process_id_to_minidump_path_[child_process_id] = minidump_path; |
82 } | 80 } |
83 return minidump_file; | 81 return minidump_file; |
84 } | 82 } |
85 | 83 |
| 84 void CrashDumpManager::BrowserChildProcessHostDisconnected( |
| 85 const content::ChildProcessData& data) { |
| 86 OnChildExit(data.id, data.handle); |
| 87 } |
| 88 |
| 89 void CrashDumpManager::BrowserChildProcessCrashed( |
| 90 const content::ChildProcessData& data) { |
| 91 OnChildExit(data.id, data.handle); |
| 92 } |
| 93 |
86 void CrashDumpManager::ProcessMinidump(const base::FilePath& minidump_path, | 94 void CrashDumpManager::ProcessMinidump(const base::FilePath& minidump_path, |
87 base::ProcessHandle pid) { | 95 base::ProcessHandle pid) { |
88 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | 96 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); |
89 int64 file_size = 0; | 97 int64 file_size = 0; |
90 int r = file_util::GetFileSize(minidump_path, &file_size); | 98 int r = file_util::GetFileSize(minidump_path, &file_size); |
91 DCHECK(r) << "Failed to retrieve size for minidump " | 99 DCHECK(r) << "Failed to retrieve size for minidump " |
92 << minidump_path.value(); | 100 << minidump_path.value(); |
93 | 101 |
94 if (file_size == 0) { | 102 if (file_size == 0) { |
95 // Empty minidump, this process did not crash. Just remove the file. | 103 // Empty minidump, this process did not crash. Just remove the file. |
(...skipping 24 matching lines...) Expand all Loading... |
120 file_util::Delete(minidump_path, false); | 128 file_util::Delete(minidump_path, false); |
121 return; | 129 return; |
122 } | 130 } |
123 LOG(INFO) << "Crash minidump successfully generated: " << | 131 LOG(INFO) << "Crash minidump successfully generated: " << |
124 crash_dump_dir.Append(filename).value(); | 132 crash_dump_dir.Append(filename).value(); |
125 } | 133 } |
126 | 134 |
127 void CrashDumpManager::Observe(int type, | 135 void CrashDumpManager::Observe(int type, |
128 const content::NotificationSource& source, | 136 const content::NotificationSource& source, |
129 const content::NotificationDetails& details) { | 137 const content::NotificationDetails& details) { |
130 int child_process_id; | |
131 base::ProcessHandle pid; | |
132 switch (type) { | 138 switch (type) { |
133 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: | 139 case content::NOTIFICATION_RENDERER_PROCESS_TERMINATED: |
134 // NOTIFICATION_RENDERER_PROCESS_TERMINATED is sent when the renderer | 140 // NOTIFICATION_RENDERER_PROCESS_TERMINATED is sent when the renderer |
135 // process is cleanly shutdown. However, we need to fallthrough so that | 141 // process is cleanly shutdown. However, we need to fallthrough so that |
136 // we close the minidump_fd we kept open. | 142 // we close the minidump_fd we kept open. |
137 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { | 143 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: { |
138 content::RenderProcessHost* rph = | 144 content::RenderProcessHost* rph = |
139 content::Source<content::RenderProcessHost>(source).ptr(); | 145 content::Source<content::RenderProcessHost>(source).ptr(); |
140 child_process_id = rph->GetID(); | 146 OnChildExit(rph->GetID(), rph->GetHandle()); |
141 pid = rph->GetHandle(); | |
142 break; | |
143 } | |
144 case content::NOTIFICATION_CHILD_PROCESS_CRASHED: | |
145 case content::NOTIFICATION_CHILD_PROCESS_HOST_DISCONNECTED: { | |
146 content::ChildProcessData* child_process_data = | |
147 content::Details<content::ChildProcessData>(details).ptr(); | |
148 child_process_id = child_process_data->id; | |
149 pid = child_process_data->handle; | |
150 break; | 147 break; |
151 } | 148 } |
152 default: | 149 default: |
153 NOTREACHED(); | 150 NOTREACHED(); |
154 return; | 151 return; |
155 } | 152 } |
| 153 } |
| 154 |
| 155 void CrashDumpManager::OnChildExit(int child_process_id, |
| 156 base::ProcessHandle pid) { |
156 base::FilePath minidump_path; | 157 base::FilePath minidump_path; |
157 { | 158 { |
158 base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_); | 159 base::AutoLock auto_lock(child_process_id_to_minidump_path_lock_); |
159 ChildProcessIDToMinidumpPath::iterator iter = | 160 ChildProcessIDToMinidumpPath::iterator iter = |
160 child_process_id_to_minidump_path_.find(child_process_id); | 161 child_process_id_to_minidump_path_.find(child_process_id); |
161 if (iter == child_process_id_to_minidump_path_.end()) { | 162 if (iter == child_process_id_to_minidump_path_.end()) { |
162 // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a | 163 // We might get a NOTIFICATION_RENDERER_PROCESS_TERMINATED and a |
163 // NOTIFICATION_RENDERER_PROCESS_CLOSED. | 164 // NOTIFICATION_RENDERER_PROCESS_CLOSED. |
164 return; | 165 return; |
165 } | 166 } |
166 minidump_path = iter->second; | 167 minidump_path = iter->second; |
167 child_process_id_to_minidump_path_.erase(iter); | 168 child_process_id_to_minidump_path_.erase(iter); |
168 } | 169 } |
169 BrowserThread::PostTask( | 170 BrowserThread::PostTask( |
170 BrowserThread::FILE, FROM_HERE, | 171 BrowserThread::FILE, FROM_HERE, |
171 base::Bind(&CrashDumpManager::ProcessMinidump, minidump_path, pid)); | 172 base::Bind(&CrashDumpManager::ProcessMinidump, minidump_path, pid)); |
172 } | 173 } |
OLD | NEW |