blob: 3c608c5a6e7027a4ea8cd9dae7bf48b0cbb59de4 [file] [log] [blame]
// Copyright 2013 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#import "ios/chrome/browser/signin/signin_util_internal.h"
#import <UIKit/UIKit.h>
#import "base/files/file_util.h"
#import "base/logging.h"
#import "base/metrics/histogram_functions.h"
#import "base/path_service.h"
#import "base/strings/sys_string_conversions.h"
#import "components/signin/public/identity_manager/tribool.h"
#import "ios/chrome/browser/shared/model/paths/paths.h"
#if !defined(__has_feature) || !__has_feature(objc_arc)
#error "This file requires ARC support."
#endif
namespace {
// Enum values for Signin.IOSDeviceRestoreSentinelError histograms.
// Entries should not be renumbered and numeric values should never be reused.
enum class SigninIOSDeviceRestoreSentinelError : int {
// No error to create the sentinel file.
kNoError = 0,
// Failed to create the sentinel file.
kSentinelFileCreationFailed = 1,
// Failed to set ExcludeFromBackupFlag to sentinel file.
kExcludedFromBackupFlagFailed = 2,
kMaxValue = kExcludedFromBackupFlagFailed,
};
// Records Signin.IOSDeviceRestoreSentinelError histogram.
void RecordSentinelErrorHistogram(SigninIOSDeviceRestoreSentinelError error) {
base::UmaHistogramEnumeration("Signin.IOSDeviceRestoreSentinelError", error);
}
// Creates a sentinel file asynchronously, and set ExcludeFromBackupFlag
// according to `exclude_from_backup`.
void CreateSentinelFileAsync(const base::FilePath sentinel_path,
bool exclude_from_backup) {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
NSFileManager* file_manager = [NSFileManager defaultManager];
NSString* path_string = base::SysUTF8ToNSString(sentinel_path.value());
BOOL create_success = [file_manager createFileAtPath:path_string
contents:nil
attributes:nil];
if (!create_success) {
RecordSentinelErrorHistogram(
SigninIOSDeviceRestoreSentinelError::kSentinelFileCreationFailed);
return;
}
if (!exclude_from_backup) {
RecordSentinelErrorHistogram(
SigninIOSDeviceRestoreSentinelError::kNoError);
return;
}
NSURL* url = [NSURL fileURLWithPath:path_string];
NSError* error = nil;
[url setResourceValue:@YES
forKey:NSURLIsExcludedFromBackupKey
error:&error];
DLOG_IF(ERROR, error != nil) << "Error setting excluded backup key, error: "
<< base::SysNSStringToUTF8(error.description);
RecordSentinelErrorHistogram(
(error == nil) ? SigninIOSDeviceRestoreSentinelError::kNoError
: SigninIOSDeviceRestoreSentinelError::
kExcludedFromBackupFlagFailed);
});
}
} // namespace
// File name for sentinel to backup in iOS backup device.
const base::FilePath::CharType kSentinelThatIsBackedUp[] =
FILE_PATH_LITERAL("BackedUpSentinel");
// File name for sentinel to not backup in iOS backup device.
const base::FilePath::CharType kSentinelThatIsNotBackedUp[] =
FILE_PATH_LITERAL("NotBackedUpSentinel");
// Computes the full path for a sentinel file with name `sentinel_name`.
// This method can return an emtpy string if failed.
base::FilePath PathForSentinel(const base::FilePath::CharType* sentinel_name) {
base::FilePath user_data_path;
if (!base::PathService::Get(ios::DIR_USER_DATA, &user_data_path)) {
return base::FilePath();
}
return user_data_path.Append(sentinel_name);
}
signin::Tribool IsFirstSessionAfterDeviceRestoreInternal() {
const base::FilePath backed_up_sentinel_path =
PathForSentinel(kSentinelThatIsBackedUp);
const base::FilePath not_backed_up_sentinel_path =
PathForSentinel(kSentinelThatIsNotBackedUp);
bool path_successfully_generated =
!backed_up_sentinel_path.empty() && !not_backed_up_sentinel_path.empty();
base::UmaHistogramBoolean("Signin.IOSDeviceRestoreSentinelPathGenerated",
path_successfully_generated);
if (!path_successfully_generated) {
return signin::Tribool::kUnknown;
}
bool does_backed_up_sentinel_file_exist =
base::PathExists(backed_up_sentinel_path);
bool does_not_backed_up_sentinel_file_exist =
base::PathExists(not_backed_up_sentinel_path);
if (!does_backed_up_sentinel_file_exist) {
CreateSentinelFileAsync(backed_up_sentinel_path,
/* exclude_from_backup */ false);
}
if (!does_not_backed_up_sentinel_file_exist) {
CreateSentinelFileAsync(not_backed_up_sentinel_path,
/* exclude_from_backup */ true);
}
if (does_backed_up_sentinel_file_exist) {
return does_not_backed_up_sentinel_file_exist ? signin::Tribool::kFalse
: signin::Tribool::kTrue;
}
return signin::Tribool::kUnknown;
}