Commit 0692640e authored by Olivier Robin's avatar Olivier Robin Committed by Commit Bot

Pause PreviousSessionInfo when protected data is unavailable.

When Protected data is not available, access NSUserDefault can freeze
the application.
Pause all the data collection based on notifications on that period.

Bug: 1129779
Change-Id: I2d304e410b2e2068b71ab3363e548e43e66b973c
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2454088Reviewed-by: default avatarEugene But <eugenebut@chromium.org>
Commit-Queue: Olivier Robin <olivierrobin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#815161}
parent c3740b5c
......@@ -12,6 +12,8 @@
#include "url/gurl.h"
namespace previous_session_info_constants {
// - The (Integer) representing UIApplicationState.
extern NSString* const kPreviousSessionInfoApplicationState;
// Key in the UserDefaults for a boolean value keeping track of memory warnings.
extern NSString* const kDidSeeMemoryWarningShortlyBeforeTerminating;
// Key in the UserDefaults for a double value which stores OS start time.
......
......@@ -66,9 +66,6 @@ DeviceThermalState GetThermalStateFromNSProcessInfoThermalState(
NSString* const kLastRanVersion = @"LastRanVersion";
// - The (string) device language.
NSString* const kLastRanLanguage = @"LastRanLanguage";
// - The (Integer) representing UIApplicationState.
NSString* const kPreviousSessionInfoApplicationState =
@"PreviousSessionInfoApplicationState";
// - The (integer) available device storage, in kilobytes.
NSString* const kPreviousSessionInfoAvailableDeviceStorage =
@"PreviousSessionInfoAvailableDeviceStorage";
......@@ -97,6 +94,8 @@ NSString* const kPreviousSessionInfoMultiWindowEnabled =
} // namespace
namespace previous_session_info_constants {
NSString* const kPreviousSessionInfoApplicationState =
@"PreviousSessionInfoApplicationState";
NSString* const kDidSeeMemoryWarningShortlyBeforeTerminating =
@"DidSeeMemoryWarning";
NSString* const kOSStartTime = @"OSStartTime";
......@@ -112,6 +111,9 @@ NSString* const kPreviousSessionInfoURLs = @"PreviousSessionInfoURLs";
// Whether beginRecordingCurrentSession was called.
@property(nonatomic, assign) BOOL didBeginRecordingCurrentSession;
// Whether recording data is in progress.
@property(nonatomic, assign) BOOL recordingCurrentSession;
// Used for setting and resetting kPreviousSessionInfoRestoringSession flag.
// Can be greater than one if multiple sessions are being restored in parallel.
@property(atomic, assign) int numberOfSessionsBeingRestored;
......@@ -151,10 +153,12 @@ static PreviousSessionInfo* gSharedInstance = nil;
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
gSharedInstance->_applicationState.reset();
if ([defaults objectForKey:kPreviousSessionInfoApplicationState]) {
gSharedInstance->_applicationState =
std::make_unique<UIApplicationState>(static_cast<UIApplicationState>(
[defaults integerForKey:kPreviousSessionInfoApplicationState]));
if ([defaults objectForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]) {
gSharedInstance->_applicationState = std::make_unique<UIApplicationState>(
static_cast<UIApplicationState>([defaults
integerForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]));
}
gSharedInstance.availableDeviceStorage = -1;
......@@ -231,7 +235,6 @@ static PreviousSessionInfo* gSharedInstance = nil;
if (self.didBeginRecordingCurrentSession)
return;
self.didBeginRecordingCurrentSession = YES;
NSUserDefaults* defaults = [NSUserDefaults standardUserDefaults];
// Set the current Chrome version.
......@@ -263,7 +266,6 @@ static PreviousSessionInfo* gSharedInstance = nil;
removeObjectForKey:previous_session_info_constants::
kDidSeeMemoryWarningShortlyBeforeTerminating];
[self updateApplicationState];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateApplicationState)
......@@ -274,6 +276,16 @@ static PreviousSessionInfo* gSharedInstance = nil;
selector:@selector(updateApplicationState)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(protectedDataWillBecomeUnavailable)
name:UIApplicationProtectedDataWillBecomeUnavailable
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(protectedDataDidBecomeAvailable)
name:UIApplicationProtectedDataWillBecomeUnavailable
object:nil];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateApplicationState)
......@@ -286,36 +298,57 @@ static PreviousSessionInfo* gSharedInstance = nil;
object:nil];
[UIDevice currentDevice].batteryMonitoringEnabled = YES;
[self updateStoredBatteryLevel];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateStoredBatteryLevel)
name:UIDeviceBatteryLevelDidChangeNotification
object:nil];
[self updateStoredBatteryState];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateStoredBatteryState)
name:UIDeviceBatteryStateDidChangeNotification
object:nil];
[self updateStoredLowPowerMode];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateStoredLowPowerMode)
name:NSProcessInfoPowerStateDidChangeNotification
object:nil];
[self updateStoredThermalState];
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:@selector(updateStoredThermalState)
name:NSProcessInfoThermalStateDidChangeNotification
object:nil];
[self resumeRecordingCurrentSession];
}
- (void)resumeRecordingCurrentSession {
if (self.recordingCurrentSession)
return;
self.recordingCurrentSession = YES;
[self updateApplicationState];
[self updateStoredBatteryLevel];
[self updateStoredBatteryState];
[self updateStoredLowPowerMode];
[self updateStoredThermalState];
// Save critical state information for crash detection.
[defaults synchronize];
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)pauseRecordingCurrentSession {
self.recordingCurrentSession = NO;
}
- (void)protectedDataWillBecomeUnavailable {
[self pauseRecordingCurrentSession];
}
- (void)protectedDataDidBecomeAvailable {
[self resumeRecordingCurrentSession];
}
- (UIApplicationState*)applicationState {
......@@ -323,7 +356,7 @@ static PreviousSessionInfo* gSharedInstance = nil;
}
- (void)updateAvailableDeviceStorage:(NSInteger)availableStorage {
if (!self.didBeginRecordingCurrentSession)
if (!self.recordingCurrentSession)
return;
[[NSUserDefaults standardUserDefaults]
......@@ -334,11 +367,15 @@ static PreviousSessionInfo* gSharedInstance = nil;
}
- (void)updateSessionEndTime {
if (!self.recordingCurrentSession)
return;
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date]
forKey:kPreviousSessionInfoEndTime];
}
- (void)updateStoredBatteryLevel {
if (!self.recordingCurrentSession)
return;
[[NSUserDefaults standardUserDefaults]
setFloat:[UIDevice currentDevice].batteryLevel
forKey:kPreviousSessionInfoBatteryLevel];
......@@ -346,14 +383,19 @@ static PreviousSessionInfo* gSharedInstance = nil;
}
- (void)updateApplicationState {
if (!self.recordingCurrentSession)
return;
[[NSUserDefaults standardUserDefaults]
setInteger:UIApplication.sharedApplication.applicationState
forKey:kPreviousSessionInfoApplicationState];
forKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState];
[self updateSessionEndTime];
}
- (void)updateStoredBatteryState {
if (!self.recordingCurrentSession)
return;
UIDevice* device = [UIDevice currentDevice];
// Translate value to an app defined enum as the system could change the
// underlying values of UIDeviceBatteryState between OS versions.
......@@ -370,6 +412,8 @@ static PreviousSessionInfo* gSharedInstance = nil;
}
- (void)updateStoredLowPowerMode {
if (!self.recordingCurrentSession)
return;
BOOL isLowPoweredModeEnabled =
[[NSProcessInfo processInfo] isLowPowerModeEnabled];
[[NSUserDefaults standardUserDefaults]
......@@ -380,6 +424,8 @@ static PreviousSessionInfo* gSharedInstance = nil;
}
- (void)updateStoredThermalState {
if (!self.recordingCurrentSession)
return;
NSProcessInfo* processInfo = [NSProcessInfo processInfo];
// Translate value to an app defined enum as the system could change the
// underlying values of NSProcessInfoThermalState between OS versions.
......
......@@ -25,6 +25,10 @@
+ (void)resetSharedInstanceForTesting;
- (void)pauseRecordingCurrentSession;
- (void)resumeRecordingCurrentSession;
- (void)updateApplicationState;
@end
#endif // IOS_CHROME_BROWSER_METRICS_PREVIOUS_SESSION_INFO_PRIVATE_H_
......@@ -552,4 +552,78 @@ TEST_F(PreviousSessionInfoTest, ReportParameterURLs) {
[PreviousSessionInfo resetSharedInstanceForTesting];
}
// Tests data collection pausing.
TEST_F(PreviousSessionInfoTest, PausePreviousSessionInfoCollection) {
// Default state.
[NSUserDefaults.standardUserDefaults
removeObjectForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState];
[PreviousSessionInfo resetSharedInstanceForTesting];
EXPECT_FALSE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Start recording. This should update the state.
[[PreviousSessionInfo sharedInstance] beginRecordingCurrentSession];
EXPECT_TRUE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Cleanup.
[NSUserDefaults.standardUserDefaults
removeObjectForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState];
EXPECT_FALSE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Updating state should work when recording is enabled.
[[PreviousSessionInfo sharedInstance] updateApplicationState];
EXPECT_TRUE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Cleanup.
[NSUserDefaults.standardUserDefaults
removeObjectForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState];
EXPECT_FALSE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Updating state should be noop when recording is paused.
[[PreviousSessionInfo sharedInstance] pauseRecordingCurrentSession];
[[PreviousSessionInfo sharedInstance] updateApplicationState];
EXPECT_FALSE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Resume recording should update the state.
[[PreviousSessionInfo sharedInstance] resumeRecordingCurrentSession];
EXPECT_TRUE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Cleanup
[NSUserDefaults.standardUserDefaults
removeObjectForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState];
EXPECT_FALSE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Updating state should work when recording is enabled.
[[PreviousSessionInfo sharedInstance] updateApplicationState];
EXPECT_TRUE([NSUserDefaults.standardUserDefaults
valueForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState]);
// Cleanup.
[NSUserDefaults.standardUserDefaults
removeObjectForKey:previous_session_info_constants::
kPreviousSessionInfoApplicationState];
[PreviousSessionInfo resetSharedInstanceForTesting];
}
} // namespace
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