Commit c4afc5c8 authored by Justin Cohen's avatar Justin Cohen Committed by Chromium LUCI CQ

ios: Attempt to reduce hangs that recover.

There's some speculation that MainThreadFreezeDetector is catching too
many hangs that eventually recover, especially on change from foreground
to background.  If a hang report is generated, but the app recovers,
return early before |reportGenerated| can be set.


Change-Id: Ib4a4f9b1db44eeb42ce15da7f312f4df0033e401
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2536386
Commit-Queue: Justin Cohen <justincohen@chromium.org>
Reviewed-by: default avatarMark Pearson <mpearson@chromium.org>
Reviewed-by: default avatarMichael Lippautz <mlippautz@chromium.org>
Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Reviewed-by: default avatarOlivier Robin <olivierrobin@chromium.org>
Auto-Submit: Justin Cohen <justincohen@chromium.org>
Cr-Commit-Position: refs/heads/master@{#833884}
parent e7192d4d
...@@ -62,13 +62,6 @@ void StartUploadingReportsInRecoveryMode(); ...@@ -62,13 +62,6 @@ void StartUploadingReportsInRecoveryMode();
// Resets the Breakpad configuration from the main bundle. // Resets the Breakpad configuration from the main bundle.
void RestoreDefaultConfiguration(); void RestoreDefaultConfiguration();
// Sets a key indicating that UI thread is frozen (if value is 'true'),
// otherwise remove the key.
// Setting the value is synchronous as it is expected to be set just before the
// report generation.
// Unsetting the value is asynchronous.
void SetHangReport(bool value);
} // namespace breakpad_helper } // namespace breakpad_helper
#endif // IOS_CHROME_BROWSER_CRASH_REPORT_BREAKPAD_HELPER_H_ #endif // IOS_CHROME_BROWSER_CRASH_REPORT_BREAKPAD_HELPER_H_
...@@ -46,8 +46,6 @@ NSString* const kCrashReportsUploadingEnabledKey = ...@@ -46,8 +46,6 @@ NSString* const kCrashReportsUploadingEnabledKey =
NSString* const kUptimeAtRestoreInMs = @"uptime_at_restore_in_ms"; NSString* const kUptimeAtRestoreInMs = @"uptime_at_restore_in_ms";
NSString* const kUploadedInRecoveryMode = @"uploaded_in_recovery_mode"; NSString* const kUploadedInRecoveryMode = @"uploaded_in_recovery_mode";
NSString* const kHangReport = @"hang-report";
void DeleteAllReportsInDirectory(base::FilePath directory) { void DeleteAllReportsInDirectory(base::FilePath directory) {
base::FileEnumerator enumerator(directory, false, base::FileEnumerator enumerator(directory, false,
base::FileEnumerator::FILES); base::FileEnumerator::FILES);
...@@ -284,11 +282,4 @@ void RestoreDefaultConfiguration() { ...@@ -284,11 +282,4 @@ void RestoreDefaultConfiguration() {
[[BreakpadController sharedInstance] setUploadingEnabled:NO]; [[BreakpadController sharedInstance] setUploadingEnabled:NO];
} }
void SetHangReport(bool value) {
if (value)
AddReportParameter(kHangReport, @"yes", false);
else
RemoveReportParameter(kHangReport);
}
} // namespace breakpad_helper } // namespace breakpad_helper
...@@ -63,7 +63,6 @@ TEST_F(BreakpadHelperTest, CrashReportUserApplicationStateAllKeys) { ...@@ -63,7 +63,6 @@ TEST_F(BreakpadHelperTest, CrashReportUserApplicationStateAllKeys) {
// single breakpad record. This test should include all keys for // single breakpad record. This test should include all keys for
// CrashReportUserApplicationState, since the whole dictionary is considered a // CrashReportUserApplicationState, since the whole dictionary is considered a
// single breakpad record. // single breakpad record.
breakpad_helper::SetHangReport(true);
crash_keys::SetCurrentlyInBackground(true); crash_keys::SetCurrentlyInBackground(true);
crash_keys::SetCurrentlySignedIn(true); crash_keys::SetCurrentlySignedIn(true);
crash_keys::SetMemoryWarningCount(2); crash_keys::SetMemoryWarningCount(2);
......
...@@ -26,7 +26,23 @@ void LogRecoveryTime(base::TimeDelta time) { ...@@ -26,7 +26,23 @@ void LogRecoveryTime(base::TimeDelta time) {
UMA_HISTOGRAM_TIMES("IOS.MainThreadFreezeDetection.RecoveredAfter", time); UMA_HISTOGRAM_TIMES("IOS.MainThreadFreezeDetection.RecoveredAfter", time);
} }
} // Key indicating that UI thread is frozen.
NSString* const kHangReportKey = @"hang-report";
// Key of the UMA Startup.MobileSessionStartAction histogram.
const char kUMAMainThreadFreezeDetectionNotRunningAfterReport[] =
"IOS.MainThreadFreezeDetection.NotRunningAfterReport";
// Enum actions for the IOS.MainThreadFreezeDetection.NotRunningAfterReport UMA
// metric. These values are persisted to logs. Entries should not be renumbered
// and numeric values should never be reused.
enum class IOSMainThreadFreezeDetectionNotRunningAfterReportBlock {
kAfterBreakpadRef = 0,
kAfterFileManagerUTEMove = 1,
kMaxValue = kAfterFileManagerUTEMove,
};
} // namespace
@interface MainThreadFreezeDetector () @interface MainThreadFreezeDetector ()
// The callback that is called regularly on main thread. // The callback that is called regularly on main thread.
...@@ -127,24 +143,23 @@ void LogRecoveryTime(base::TimeDelta time) { ...@@ -127,24 +143,23 @@ void LogRecoveryTime(base::TimeDelta time) {
} }
- (void)runInMainLoop { - (void)runInMainLoop {
NSDate* oldLastSeenMainThread = self.lastSeenMainThread;
self.lastSeenMainThread = [NSDate date];
if (self.reportGenerated) { if (self.reportGenerated) {
self.reportGenerated = NO; self.reportGenerated = NO;
// Remove information about the last session info. // Remove information about the last session info.
[[NSUserDefaults standardUserDefaults] [[NSUserDefaults standardUserDefaults]
removeObjectForKey:@(kNsUserDefaultKeyLastSessionInfo)]; removeObjectForKey:@(kNsUserDefaultKeyLastSessionInfo)];
LogRecoveryTime(base::TimeDelta::FromSecondsD( LogRecoveryTime(base::TimeDelta::FromSecondsD(
[[NSDate date] timeIntervalSinceDate:self.lastSeenMainThread])); [[NSDate date] timeIntervalSinceDate:oldLastSeenMainThread]));
// Restart the freeze detection. // Restart the freeze detection.
dispatch_after( dispatch_async(_freezeDetectionQueue, ^{
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)),
_freezeDetectionQueue, ^{
[self cleanAndRunInFreezeDetectionQueue]; [self cleanAndRunInFreezeDetectionQueue];
}); });
} }
if (!self.running) { if (!self.running) {
return; return;
} }
self.lastSeenMainThread = [NSDate date];
dispatch_after( dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)),
dispatch_get_main_queue(), ^{ dispatch_get_main_queue(), ^{
...@@ -168,14 +183,22 @@ void LogRecoveryTime(base::TimeDelta time) { ...@@ -168,14 +183,22 @@ void LogRecoveryTime(base::TimeDelta time) {
} }
if ([[NSDate date] timeIntervalSinceDate:self.lastSeenMainThread] > if ([[NSDate date] timeIntervalSinceDate:self.lastSeenMainThread] >
self.delay) { self.delay) {
breakpad_helper::SetHangReport(true);
[[BreakpadController sharedInstance] [[BreakpadController sharedInstance]
withBreakpadRef:^(BreakpadRef breakpadRef) { withBreakpadRef:^(BreakpadRef breakpadRef) {
if (!self.running) {
UMA_HISTOGRAM_ENUMERATION(
kUMAMainThreadFreezeDetectionNotRunningAfterReport,
IOSMainThreadFreezeDetectionNotRunningAfterReportBlock::
kAfterBreakpadRef);
return;
}
if (!breakpadRef) { if (!breakpadRef) {
return; return;
} }
BreakpadAddUploadParameter(breakpadRef, kHangReportKey, @"yes");
NSDictionary* breakpadReportInfo = NSDictionary* breakpadReportInfo =
BreakpadGenerateReport(breakpadRef, nil); BreakpadGenerateReport(breakpadRef, nil);
BreakpadRemoveUploadParameter(breakpadRef, kHangReportKey);
if (!breakpadReportInfo) { if (!breakpadReportInfo) {
return; return;
} }
...@@ -201,6 +224,13 @@ void LogRecoveryTime(base::TimeDelta time) { ...@@ -201,6 +224,13 @@ void LogRecoveryTime(base::TimeDelta time) {
toPath:UTEConfigFile toPath:UTEConfigFile
error:nil]; error:nil];
[fileManager moveItemAtPath:dumpFile toPath:UTEDumpFile error:nil]; [fileManager moveItemAtPath:dumpFile toPath:UTEDumpFile error:nil];
if (!self.running) {
UMA_HISTOGRAM_ENUMERATION(
kUMAMainThreadFreezeDetectionNotRunningAfterReport,
IOSMainThreadFreezeDetectionNotRunningAfterReportBlock::
kAfterFileManagerUTEMove);
return;
}
[[NSUserDefaults standardUserDefaults] [[NSUserDefaults standardUserDefaults]
setObject:@{ setObject:@{
@"dump" : [dumpFile lastPathComponent], @"dump" : [dumpFile lastPathComponent],
...@@ -209,11 +239,11 @@ void LogRecoveryTime(base::TimeDelta time) { ...@@ -209,11 +239,11 @@ void LogRecoveryTime(base::TimeDelta time) {
} }
forKey:@(kNsUserDefaultKeyLastSessionInfo)]; forKey:@(kNsUserDefaultKeyLastSessionInfo)];
self.reportGenerated = YES; self.reportGenerated = YES;
breakpad_helper::SetHangReport(false);
}]; }];
return; return;
} }
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1 * NSEC_PER_SEC)), dispatch_after(
dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)),
_freezeDetectionQueue, ^{ _freezeDetectionQueue, ^{
[self runInFreezeDetectionQueue]; [self runInFreezeDetectionQueue];
}); });
......
...@@ -39056,6 +39056,16 @@ Called by update_gpu_driver_bug_workaround_entries.py.--> ...@@ -39056,6 +39056,16 @@ Called by update_gpu_driver_bug_workaround_entries.py.-->
<int value="4" label="Authorized when Chrome is in use"/> <int value="4" label="Authorized when Chrome is in use"/>
</enum> </enum>
<enum name="IOSMainThreadFreezeDetectionNotRunningAfterReportBlock">
<int value="0" label="After Breakpad Ref">
Freeze detection stopped after obtaining the breakpad lock.
</int>
<int value="1" label="After FileManager UTE move">
Freeze detection stopped after moving the hang report out of the Breakpad
directory and into the |UTE| directory.
</int>
</enum>
<enum name="IOSMenuAction"> <enum name="IOSMenuAction">
<int value="0" label="Open in New Tab"/> <int value="0" label="Open in New Tab"/>
<int value="1" label="Open in New Incognito Tab"/> <int value="1" label="Open in New Incognito Tab"/>
...@@ -423,6 +423,17 @@ reviews. Googlers can read more about this at go/gwsq-gerrit. ...@@ -423,6 +423,17 @@ reviews. Googlers can read more about this at go/gwsq-gerrit.
</summary> </summary>
</histogram> </histogram>
<histogram name="IOS.MainThreadFreezeDetection.NotRunningAfterReport"
enum="IOSMainThreadFreezeDetectionNotRunningAfterReportBlock"
expires_after="2021-07-01">
<owner>justincohen@chromium.org</owner>
<owner>olivierrobin@chromium.org</owner>
<summary>
Recorded when the main thread recovers immediately after a freeze report was
generated.
</summary>
</histogram>
<histogram name="IOS.MainThreadFreezeDetection.RecoveredAfter" units="ms" <histogram name="IOS.MainThreadFreezeDetection.RecoveredAfter" units="ms"
expires_after="2021-11-12"> expires_after="2021-11-12">
<owner>eugenebut@chromium.org</owner> <owner>eugenebut@chromium.org</owner>
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment