Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Side by Side Diff: ios/chrome/browser/crash_report/crash_report_helper.mm

Issue 2580363002: Upstream Chrome on iOS source code [1/11]. (Closed)
Patch Set: Created 4 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "ios/chrome/browser/crash_report/crash_report_helper.h"
6
7 #include <Foundation/Foundation.h>
8
9 #include "base/auto_reset.h"
10 #include "base/bind.h"
11 #include "base/debug/crash_logging.h"
12 #include "base/files/file_enumerator.h"
13 #include "base/files/file_path.h"
14 #include "base/files/file_util.h"
15 #include "base/location.h"
16 #include "base/mac/scoped_nsobject.h"
17 #include "base/path_service.h"
18 #include "base/strings/sys_string_conversions.h"
19 #include "base/time/time.h"
20 #include "components/upload_list/crash_upload_list.h"
21 #include "ios/chrome/browser/chrome_paths.h"
22 #include "ios/chrome/browser/crash_report/breakpad_helper.h"
23 #import "ios/chrome/browser/crash_report/crash_report_user_application_state.h"
24 #import "ios/chrome/browser/tabs/tab.h"
25 #import "ios/chrome/browser/tabs/tab_model.h"
26 #import "ios/chrome/browser/tabs/tab_model_observer.h"
27 #include "ios/web/public/browser_state.h"
28 #include "ios/web/public/web_state/web_state.h"
29 #include "ios/web/public/web_thread.h"
30 #import "net/base/mac/url_conversions.h"
31
32 // TabModelObserver that allows loaded urls to be sent to the crash server.
33 @interface CrashReporterURLObserver : NSObject<TabModelObserver> {
34 @private
35 // Map associating the tab id to the breakpad key used to keep track of the
36 // loaded URL.
37 base::scoped_nsobject<NSMutableDictionary> breakpadKeyByTabId_;
38 // List of keys to use for recording URLs. This list is sorted such that a new
39 // tab must use the first key in this list to record its URLs.
40 base::scoped_nsobject<NSMutableArray> breakpadKeys_;
41 }
42 + (CrashReporterURLObserver*)uniqueInstance;
43 // Removes the URL for the tab with the given id from the URLs sent to the crash
44 // server.
45 - (void)removeTabId:(NSString*)tabId;
46 // Records the given URL associated to the given id to the list of URLs to send
47 // to the crash server. If |pending| is true, the URL is one that is
48 // expected to start loading, but hasn't actually been seen yet.
49 - (void)recordURL:(NSString*)url
50 forTabId:(NSString*)tabId
51 pending:(BOOL)pending;
52 // Callback for the kTabUrlStartedLoadingNotificationForCrashReporting
53 // notification. Extracts the parameter from the notification and calls
54 // |recordURL:forTabId:pending:|.
55 - (void)urlChanged:(NSNotification*)notification;
56 // Callback for the kTabUrlMayStartLoadingNotificationForCrashReporting
57 // notification. Extracts the parameter from the notification and calls
58 // |recordURL:forTabId:pending:|.
59 - (void)urlChangeExpected:(NSNotification*)notification;
60 @end
61
62 // TabModelObserver that some tabs stats to be sent to the crash server.
63 @interface CrashReporterTabStateObserver : NSObject<TabModelObserver> {
64 @private
65 // Map associating the tab id to an object describing the current state of the
66 // tab.
67 base::scoped_nsobject<NSMutableDictionary> tabCurrentStateByTabId_;
68 }
69 + (CrashReporterURLObserver*)uniqueInstance;
70 // Removes the stats for the tab tabId
71 - (void)removeTabId:(NSString*)tabId;
72 // Callback for the kTabClosingCurrentDocumentNotificationForCrashReporting
73 // notification. Removes document related information from
74 // tabCurrentStateByTabId_ by calling closingDocumentInTab:tabId.
75 - (void)closingDocument:(NSNotification*)notification;
76 // Removes document related information from tabCurrentStateByTabId_.
77 - (void)closingDocumentInTab:(NSString*)tabId;
78 // Callback for the kTabIsShowingExportableNotificationForCrashReporting
79 // notification. Sets the mimeType in tabCurrentStateByTabId_.
80 - (void)showingExportableDocument:(NSNotification*)notification;
81
82 // Sets a tab |tabId| specific information with key |key| and value |value| in
83 // tabCurrentStateByTabId_.
84 - (void)setTabInfo:(NSString*)key
85 withValue:(NSString*)value
86 forTab:(NSString*)tabId;
87 // Retrieves the |key| information for tab |tabId|.
88 - (id)getTabInfo:(NSString*)key forTab:(NSString*)tabId;
89 // Removes the |key| information for tab |tabId|
90 - (void)removeTabInfo:(NSString*)key forTab:(NSString*)tabId;
91 @end
92
93 namespace {
94
95 // Returns the breakpad key to use for a pending URL corresponding to the
96 // same tab that is using |key|.
97 NSString* PendingURLKeyForKey(NSString* key) {
98 return [key stringByAppendingString:@"-pending"];
99 }
100
101 // Max number of urls to send. This must be kept low for privacy issue as well
102 // as because breakpad does limit the total number of parameters to 64.
103 const int kNumberOfURLsToSend = 1;
104 }
105
106 @implementation CrashReporterURLObserver
107
108 + (CrashReporterURLObserver*)uniqueInstance {
109 static CrashReporterURLObserver* instance =
110 [[CrashReporterURLObserver alloc] init];
111 return instance;
112 }
113
114 - (id)init {
115 if ((self = [super init])) {
116 breakpadKeyByTabId_.reset(
117 [[NSMutableDictionary alloc] initWithCapacity:kNumberOfURLsToSend]);
118 breakpadKeys_.reset(
119 [[NSMutableArray alloc] initWithCapacity:kNumberOfURLsToSend]);
120 for (int i = 0; i < kNumberOfURLsToSend; ++i)
121 [breakpadKeys_ addObject:[NSString stringWithFormat:@"url%d", i]];
122 // Register for url changed notifications.
123 [[NSNotificationCenter defaultCenter]
124 addObserver:self
125 selector:@selector(urlChanged:)
126 name:kTabUrlStartedLoadingNotificationForCrashReporting
127 object:nil];
128 [[NSNotificationCenter defaultCenter]
129 addObserver:self
130 selector:@selector(urlChangeExpected:)
131 name:kTabUrlMayStartLoadingNotificationForCrashReporting
132 object:nil];
133 }
134 return self;
135 }
136
137 - (void)urlChanged:(NSNotification*)notification {
138 Tab* tab = notification.object;
139 DCHECK(tab);
140 if (tab.webState->GetBrowserState()->IsOffTheRecord())
141 return;
142 NSString* url = [notification.userInfo objectForKey:kTabUrlKey];
143 DCHECK(url);
144 [self recordURL:url forTabId:tab.tabId pending:NO];
145 }
146
147 - (void)urlChangeExpected:(NSNotification*)notification {
148 Tab* tab = notification.object;
149 DCHECK(tab);
150 if (tab.webState->GetBrowserState()->IsOffTheRecord())
151 return;
152 NSString* url = [notification.userInfo objectForKey:kTabUrlKey];
153 DCHECK(url);
154 [self recordURL:url forTabId:tab.tabId pending:YES];
155 }
156
157 - (void)removeTabId:(NSString*)tabId {
158 NSString* key = [breakpadKeyByTabId_ objectForKey:tabId];
159 if (!key)
160 return;
161 base::scoped_nsobject<NSString> alive([key retain]);
162 breakpad_helper::RemoveReportParameter(key);
163 breakpad_helper::RemoveReportParameter(PendingURLKeyForKey(key));
164 [breakpadKeyByTabId_ removeObjectForKey:tabId];
165 [breakpadKeys_ removeObject:key];
166 [breakpadKeys_ insertObject:key atIndex:0];
167 }
168
169 - (void)recordURL:(NSString*)url
170 forTabId:(NSString*)tabId
171 pending:(BOOL)pending {
172 NSString* breakpadKey = [breakpadKeyByTabId_ objectForKey:tabId];
173 BOOL reusingKey = NO;
174 if (!breakpadKey) {
175 // Get the first breakpad key and push it back at the end of the keys.
176 base::scoped_nsobject<NSString> alive(
177 [[breakpadKeys_ objectAtIndex:0] retain]);
178 breakpadKey = alive.get();
179 [breakpadKeys_ removeObject:breakpadKey];
180 [breakpadKeys_ addObject:breakpadKey];
181 // Remove the current mapping to the breakpad key.
182 for (NSString* tabId in
183 [breakpadKeyByTabId_ allKeysForObject:breakpadKey]) {
184 reusingKey = YES;
185 [breakpadKeyByTabId_ removeObjectForKey:tabId];
186 }
187 // Associate the breakpad key to the tab id.
188 [breakpadKeyByTabId_ setObject:breakpadKey forKey:tabId];
189 }
190 NSString* pendingKey = PendingURLKeyForKey(breakpadKey);
191 if (pending) {
192 if (reusingKey)
193 breakpad_helper::RemoveReportParameter(breakpadKey);
194 breakpad_helper::AddReportParameter(pendingKey, url, true);
195 } else {
196 breakpad_helper::AddReportParameter(breakpadKey, url, true);
197 breakpad_helper::RemoveReportParameter(pendingKey);
198 }
199 }
200
201 - (void)tabModel:(TabModel*)model
202 didRemoveTab:(Tab*)tab
203 atIndex:(NSUInteger)index {
204 [self removeTabId:tab.tabId];
205 }
206
207 - (void)tabModel:(TabModel*)model
208 didReplaceTab:(Tab*)oldTab
209 withTab:(Tab*)newTab
210 atIndex:(NSUInteger)index {
211 [self removeTabId:oldTab.tabId];
212 }
213
214 - (void)tabModel:(TabModel*)model
215 didChangeActiveTab:(Tab*)newTab
216 previousTab:(Tab*)previousTab
217 atIndex:(NSUInteger)modelIndex {
218 [self recordURL:base::SysUTF8ToNSString(newTab.url.spec())
219 forTabId:newTab.tabId
220 pending:NO];
221 }
222
223 // Empty method left in place in case jailbreakers are swizzling this.
224 - (void)detectJailbrokenDevice {
225 // This method has been intentionally left blank.
226 }
227
228 @end
229
230 @implementation CrashReporterTabStateObserver
231
232 + (CrashReporterTabStateObserver*)uniqueInstance {
233 static CrashReporterTabStateObserver* instance =
234 [[CrashReporterTabStateObserver alloc] init];
235 return instance;
236 }
237
238 - (id)init {
239 if ((self = [super init])) {
240 tabCurrentStateByTabId_.reset([[NSMutableDictionary alloc] init]);
241 // Register for url changed notifications.
242 [[NSNotificationCenter defaultCenter]
243 addObserver:self
244 selector:@selector(closingDocument:)
245 name:kTabClosingCurrentDocumentNotificationForCrashReporting
246 object:nil];
247 [[NSNotificationCenter defaultCenter]
248 addObserver:self
249 selector:@selector(showingExportableDocument:)
250 name:kTabIsShowingExportableNotificationForCrashReporting
251 object:nil];
252 }
253 return self;
254 }
255
256 - (void)closingDocument:(NSNotification*)notification {
257 Tab* tab = notification.object;
258 [self closingDocumentInTab:[tab tabId]];
259 }
260
261 - (void)closingDocumentInTab:(NSString*)tabId {
262 NSString* mime = (NSString*)[self getTabInfo:@"mime" forTab:tabId];
263 if ([mime isEqualToString:@"application/pdf"])
264 breakpad_helper::SetCurrentTabIsPDF(false);
265 [self removeTabInfo:@"mime" forTab:tabId];
266 }
267
268 - (void)setTabInfo:(NSString*)key
269 withValue:(NSString*)value
270 forTab:(NSString*)tabId {
271 NSMutableDictionary* tabCurrentState =
272 [tabCurrentStateByTabId_ objectForKey:tabId];
273 if (tabCurrentState == nil) {
274 base::scoped_nsobject<NSMutableDictionary> currentStateOfNewTab(
275 [[NSMutableDictionary alloc] init]);
276 [tabCurrentStateByTabId_ setObject:currentStateOfNewTab.get() forKey:tabId];
277 tabCurrentState = [tabCurrentStateByTabId_ objectForKey:tabId];
278 }
279 [tabCurrentState setObject:value forKey:key];
280 }
281
282 - (id)getTabInfo:(NSString*)key forTab:(NSString*)tabId {
283 NSMutableDictionary* tabValues = [tabCurrentStateByTabId_ objectForKey:tabId];
284 return [tabValues objectForKey:key];
285 }
286
287 - (void)removeTabInfo:(NSString*)key forTab:(NSString*)tabId {
288 [[tabCurrentStateByTabId_ objectForKey:tabId] removeObjectForKey:key];
289 }
290
291 - (void)showingExportableDocument:(NSNotification*)notification {
292 Tab* tab = notification.object;
293 NSString* oldMime = (NSString*)[self getTabInfo:@"mime" forTab:[tab tabId]];
294 if ([oldMime isEqualToString:@"application/pdf"])
295 return;
296
297 std::string mime = [tab webState]->GetContentsMimeType();
298 NSString* nsMime = base::SysUTF8ToNSString(mime);
299 [self setTabInfo:@"mime" withValue:nsMime forTab:[tab tabId]];
300 breakpad_helper::SetCurrentTabIsPDF(true);
301 }
302
303 - (void)removeTabId:(NSString*)tabId {
304 [self closingDocumentInTab:tabId];
305 [tabCurrentStateByTabId_ removeObjectForKey:tabId];
306 }
307
308 - (void)tabModel:(TabModel*)model
309 didRemoveTab:(Tab*)tab
310 atIndex:(NSUInteger)index {
311 [self removeTabId:tab.tabId];
312 }
313
314 - (void)tabModel:(TabModel*)model
315 didReplaceTab:(Tab*)oldTab
316 withTab:(Tab*)newTab
317 atIndex:(NSUInteger)index {
318 [self removeTabId:oldTab.tabId];
319 }
320
321 @end
322
323 namespace ios_internal {
324 namespace breakpad {
325
326 void MonitorURLsForTabModel(TabModel* tab_model) {
327 DCHECK(!tab_model.isOffTheRecord);
328 [tab_model addObserver:[CrashReporterURLObserver uniqueInstance]];
329 }
330
331 void StopMonitoringURLsForTabModel(TabModel* tab_model) {
332 [tab_model removeObserver:[CrashReporterURLObserver uniqueInstance]];
333 }
334
335 void MonitorTabStateForTabModel(TabModel* tab_model) {
336 [tab_model addObserver:[CrashReporterTabStateObserver uniqueInstance]];
337 }
338
339 void StopMonitoringTabStateForTabModel(TabModel* tab_model) {
340 [tab_model removeObserver:[CrashReporterTabStateObserver uniqueInstance]];
341 }
342
343 void ClearStateForTabModel(TabModel* tab_model) {
344 CrashReporterURLObserver* observer =
345 [CrashReporterURLObserver uniqueInstance];
346 for (Tab* tab in tab_model) {
347 [observer removeTabId:tab.tabId];
348 }
349 }
350
351 } // namespace breakpad
352 } // namespace ios_internal
OLDNEW
« no previous file with comments | « ios/chrome/browser/crash_report/crash_report_helper.h ('k') | ios/chrome/browser/crash_report/crash_restore_helper.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698