Let users submit debug logs if app launch fails.
This commit is contained in:
parent
4aaae856d0
commit
98843cd45c
|
@ -61,6 +61,7 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
@property (nonatomic) UIWindow *screenProtectionWindow;
|
||||
@property (nonatomic) BOOL hasInitialRootViewController;
|
||||
@property (nonatomic) BOOL areVersionMigrationsComplete;
|
||||
@property (nonatomic) BOOL didAppLaunchFail;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -130,7 +131,15 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
|
||||
// We need to do this _after_ we set up logging, when the keychain is unlocked,
|
||||
// but before we access YapDatabase, files on disk, or NSUserDefaults
|
||||
[self ensureIsReadyForAppExtensions];
|
||||
if (![self ensureIsReadyForAppExtensions]) {
|
||||
// If this method has failed; do nothing.
|
||||
//
|
||||
// ensureIsReadyForAppExtensions will show a failure mode UI that
|
||||
// lets users report this error.
|
||||
DDLogInfo(@"%@ application: didFinishLaunchingWithOptions failed.", self.logTag);
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
[AppVersion instance];
|
||||
|
||||
|
@ -219,10 +228,10 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
}
|
||||
}
|
||||
|
||||
- (void)ensureIsReadyForAppExtensions
|
||||
- (BOOL)ensureIsReadyForAppExtensions
|
||||
{
|
||||
if ([OWSPreferences isReadyForAppExtensions]) {
|
||||
return;
|
||||
return YES;
|
||||
}
|
||||
|
||||
if ([NSFileManager.defaultManager fileExistsAtPath:TSStorageManager.legacyDatabaseFilePath]) {
|
||||
|
@ -238,14 +247,56 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
}
|
||||
|
||||
NSError *_Nullable error = [self convertDatabaseIfNecessary];
|
||||
// TODO: Handle this error.
|
||||
OWSAssert(!error);
|
||||
if (error) {
|
||||
OWSFail(@"%@ database conversion failed: %@", self.logTag, error);
|
||||
[self showLaunchFailureUI:error];
|
||||
return NO;
|
||||
}
|
||||
|
||||
[NSUserDefaults migrateToSharedUserDefaults];
|
||||
|
||||
[TSStorageManager migrateToSharedData];
|
||||
[OWSProfileManager migrateToSharedData];
|
||||
[TSAttachmentStream migrateToSharedData];
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)showLaunchFailureUI:(NSError *)error
|
||||
{
|
||||
// Disable normal functioning of app.
|
||||
self.didAppLaunchFail = YES;
|
||||
|
||||
// We perform a subset of the [application:didFinishLaunchingWithOptions:].
|
||||
[AppVersion instance];
|
||||
[self startupLogging];
|
||||
|
||||
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
|
||||
|
||||
// Show the launch screen until the async database view registrations are complete.
|
||||
self.window.rootViewController = [self loadingRootViewController];
|
||||
|
||||
[self.window makeKeyAndVisible];
|
||||
|
||||
UIAlertController *controller =
|
||||
[UIAlertController alertControllerWithTitle:NSLocalizedString(@"APP_LAUNCH_FAILURE_ALERT_TITLE",
|
||||
@"Title for the 'app launch failed' alert.")
|
||||
message:NSLocalizedString(@"APP_LAUNCH_FAILURE_ALERT_MESSAGE",
|
||||
@"Message for the 'app launch failed' alert.")
|
||||
preferredStyle:UIAlertControllerStyleAlert];
|
||||
|
||||
[controller addAction:[UIAlertAction actionWithTitle:NSLocalizedString(@"SETTINGS_ADVANCED_SUBMIT_DEBUGLOG", nil)
|
||||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[Pastelog submitLogsWithShareCompletion:^{
|
||||
DDLogInfo(
|
||||
@"%@ exiting after sharing debug logs.", self.logTag);
|
||||
[DDLog flushLog];
|
||||
exit(0);
|
||||
}];
|
||||
}]];
|
||||
UIViewController *fromViewController = [[UIApplication sharedApplication] frontmostViewController];
|
||||
[fromViewController presentViewController:controller animated:YES completion:nil];
|
||||
}
|
||||
|
||||
- (nullable NSError *)convertDatabaseIfNecessary
|
||||
|
@ -368,6 +419,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
OWSFail(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogInfo(@"%@ registered vanilla push token: %@", self.logTag, deviceToken);
|
||||
[PushRegistrationManager.sharedManager didReceiveVanillaPushToken:deviceToken];
|
||||
}
|
||||
|
@ -376,6 +432,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
OWSFail(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogError(@"%@ failed to register vanilla push token with error: %@", self.logTag, error);
|
||||
#ifdef DEBUG
|
||||
DDLogWarn(
|
||||
|
@ -392,6 +453,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
OWSFail(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogInfo(@"%@ registered user notification settings", self.logTag);
|
||||
[PushRegistrationManager.sharedManager didRegisterUserNotificationSettings];
|
||||
}
|
||||
|
@ -403,6 +469,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!AppReadiness.isAppReady) {
|
||||
DDLogWarn(@"%@ Ignoring openURL: app not ready.", self.logTag);
|
||||
// TODO: Consider using [AppReadiness runNowOrWhenAppIsReady:].
|
||||
|
@ -437,6 +508,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
- (void)applicationDidBecomeActive:(UIApplication *)application {
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogWarn(@"%@ applicationDidBecomeActive.", self.logTag);
|
||||
if (CurrentAppContext().isRunningTests) {
|
||||
return;
|
||||
|
@ -536,6 +612,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
- (void)applicationWillResignActive:(UIApplication *)application {
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogWarn(@"%@ applicationWillResignActive.", self.logTag);
|
||||
|
||||
__block OWSBackgroundTask *backgroundTask = [OWSBackgroundTask backgroundTaskWithLabelStr:__PRETTY_FUNCTION__];
|
||||
|
@ -564,6 +645,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
completionHandler:(void (^)(BOOL succeeded))completionHandler {
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AppReadiness.isAppReady) {
|
||||
DDLogWarn(@"%@ Ignoring performActionForShortcutItem: app not ready.", self.logTag);
|
||||
// TODO: Consider using [AppReadiness runNowOrWhenAppIsReady:].
|
||||
|
@ -602,6 +688,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return NO;
|
||||
}
|
||||
|
||||
if (!AppReadiness.isAppReady) {
|
||||
DDLogWarn(@"%@ Ignoring continueUserActivity: app not ready.", self.logTag);
|
||||
// TODO: Consider using [AppReadiness runNowOrWhenAppIsReady:].
|
||||
|
@ -772,6 +863,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo {
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
// It is safe to continue even if the app isn't ready.
|
||||
[[PushManager sharedManager] application:application didReceiveRemoteNotification:userInfo];
|
||||
}
|
||||
|
@ -781,6 +877,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
// It is safe to continue even if the app isn't ready.
|
||||
[[PushManager sharedManager] application:application
|
||||
didReceiveRemoteNotification:userInfo
|
||||
|
@ -790,6 +891,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification {
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
DDLogInfo(@"%@ %s %@", self.logTag, __PRETTY_FUNCTION__, notification);
|
||||
|
||||
[AppStoreRating preventPromptAtNextTest];
|
||||
|
@ -805,6 +911,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AppReadiness.isAppReady) {
|
||||
DDLogWarn(@"%@ Ignoring handleActionWithIdentifier: app not ready.", self.logTag);
|
||||
// TODO: Consider using [AppReadiness runNowOrWhenAppIsReady:].
|
||||
|
@ -825,6 +936,11 @@ static NSString *const kURLHostVerifyPrefix = @"verify";
|
|||
{
|
||||
OWSAssertIsOnMainThread();
|
||||
|
||||
if (self.didAppLaunchFail) {
|
||||
DDLogInfo(@"%@ %s", self.logTag, __PRETTY_FUNCTION__);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!AppReadiness.isAppReady) {
|
||||
DDLogWarn(@"%@ Ignoring handleActionWithIdentifier: app not ready.", self.logTag);
|
||||
// TODO: Consider using [AppReadiness runNowOrWhenAppIsReady:].
|
||||
|
|
|
@ -1,13 +1,15 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
@interface Pastelog : NSObject
|
||||
|
||||
typedef void (^successBlock)(NSError *error, NSString *urlString);
|
||||
typedef void (^DebugLogsUploadedBlock)(NSError *error, NSString *urlString);
|
||||
typedef void (^DebugLogsSharedBlock)(void);
|
||||
|
||||
+(void)submitLogs;
|
||||
+(void)submitLogsWithCompletion:(successBlock)block;
|
||||
+(void)submitLogsWithCompletion:(successBlock)block forFileLogger:(DDFileLogger*)fileLogger;
|
||||
+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)block;
|
||||
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block;
|
||||
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger;
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
//
|
||||
// Copyright (c) 2017 Open Whisper Systems. All rights reserved.
|
||||
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
||||
//
|
||||
|
||||
#import "Pastelog.h"
|
||||
|
@ -18,7 +18,7 @@
|
|||
|
||||
@property (nonatomic) UIAlertController *loadingAlert;
|
||||
@property (nonatomic) NSMutableData *responseData;
|
||||
@property (nonatomic) successBlock block;
|
||||
@property (nonatomic) DebugLogsUploadedBlock block;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -27,7 +27,20 @@
|
|||
@implementation Pastelog
|
||||
|
||||
+(void)submitLogs {
|
||||
[self submitLogsWithCompletion:^(NSError *error, NSString *urlString) {
|
||||
[self submitLogsWithShareCompletion:nil];
|
||||
}
|
||||
|
||||
+ (void)submitLogsWithShareCompletion:(nullable DebugLogsSharedBlock)shareCompletionParam
|
||||
{
|
||||
DebugLogsSharedBlock shareCompletion = ^{
|
||||
if (shareCompletionParam) {
|
||||
// Wait a moment. If PasteLog opens a URL, it needs a moment to complete.
|
||||
dispatch_after(
|
||||
dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC), dispatch_get_main_queue(), shareCompletionParam);
|
||||
}
|
||||
};
|
||||
|
||||
[self submitLogsWithUploadCompletion:^(NSError *error, NSString *urlString) {
|
||||
if (!error) {
|
||||
UIAlertController *alert = [UIAlertController
|
||||
alertControllerWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_TITLE", @"Title of the debug log alert.")
|
||||
|
@ -41,6 +54,8 @@
|
|||
style:UIAlertActionStyleDefault
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[Pastelog.sharedManager submitEmail:urlString];
|
||||
|
||||
shareCompletion();
|
||||
}]];
|
||||
[alert addAction:[UIAlertAction
|
||||
actionWithTitle:NSLocalizedString(@"DEBUG_LOG_ALERT_OPTION_COPY_LINK",
|
||||
|
@ -49,6 +64,8 @@
|
|||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
UIPasteboard *pb = [UIPasteboard generalPasteboard];
|
||||
[pb setString:urlString];
|
||||
|
||||
shareCompletion();
|
||||
}]];
|
||||
#ifdef DEBUG
|
||||
[alert addAction:[UIAlertAction
|
||||
|
@ -73,7 +90,8 @@
|
|||
@"Label for the 'Open a Bug Report' option of the the debug log alert.")
|
||||
style:UIAlertActionStyleCancel
|
||||
handler:^(UIAlertAction *_Nonnull action) {
|
||||
[Pastelog.sharedManager prepareRedirection:urlString];
|
||||
[Pastelog.sharedManager prepareRedirection:urlString
|
||||
shareCompletion:shareCompletion];
|
||||
}]];
|
||||
UIViewController *presentingViewController
|
||||
= UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
|
||||
|
@ -91,11 +109,13 @@
|
|||
}];
|
||||
}
|
||||
|
||||
+(void)submitLogsWithCompletion:(successBlock)block {
|
||||
[self submitLogsWithCompletion:(successBlock)block forFileLogger:[[DDFileLogger alloc] init]];
|
||||
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block
|
||||
{
|
||||
[self submitLogsWithUploadCompletion:block forFileLogger:[[DDFileLogger alloc] init]];
|
||||
}
|
||||
|
||||
+(void)submitLogsWithCompletion:(successBlock)block forFileLogger:(DDFileLogger*)fileLogger {
|
||||
+ (void)submitLogsWithUploadCompletion:(DebugLogsUploadedBlock)block forFileLogger:(DDFileLogger *)fileLogger
|
||||
{
|
||||
|
||||
[self sharedManager].block = block;
|
||||
|
||||
|
@ -231,7 +251,10 @@
|
|||
[UIApplication.sharedApplication openURL: [NSURL URLWithString: urlString]];
|
||||
}
|
||||
|
||||
- (void)prepareRedirection:(NSString*)url {
|
||||
- (void)prepareRedirection:(NSString *)url shareCompletion:(DebugLogsSharedBlock)shareCompletion
|
||||
{
|
||||
OWSAssert(shareCompletion);
|
||||
|
||||
UIPasteboard *pb = [UIPasteboard generalPasteboard];
|
||||
[pb setString:url];
|
||||
|
||||
|
@ -248,6 +271,8 @@
|
|||
[UIApplication.sharedApplication
|
||||
openURL:[NSURL URLWithString:[[NSBundle mainBundle]
|
||||
objectForInfoDictionaryKey:@"LOGS_URL"]]];
|
||||
|
||||
shareCompletion();
|
||||
}]];
|
||||
UIViewController *presentingViewController = UIApplication.sharedApplication.frontmostViewControllerIgnoringAlerts;
|
||||
[presentingViewController presentViewController:alert animated:NO completion:nil];
|
||||
|
|
|
@ -52,6 +52,12 @@
|
|||
/* No comment provided by engineer. */
|
||||
"APN_MESSAGE_IN_GROUP_DETAILED" = "%@ in group %@: %@";
|
||||
|
||||
/* Message for the 'app launch failed' alert. */
|
||||
"APP_LAUNCH_FAILURE_ALERT_MESSAGE" = "Signal can't launch. Please send your debug logs to our team so that we can try to resolve this issue.";
|
||||
|
||||
/* Title for the 'app launch failed' alert. */
|
||||
"APP_LAUNCH_FAILURE_ALERT_TITLE" = "Error";
|
||||
|
||||
/* Text prompting user to edit their profile name. */
|
||||
"APP_SETTINGS_EDIT_PROFILE_NAME_PROMPT" = "Enter your name";
|
||||
|
||||
|
|
Loading…
Reference in New Issue