Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixed session creation failing due to no background task #1317

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions SmartDeviceLink-iOS.xcodeproj/project.pbxproj
Expand Up @@ -1238,6 +1238,8 @@
756C62772289F11F008B57A2 /* SDLDynamicMenuUpdateRunScore.m in Sources */ = {isa = PBXBuildFile; fileRef = 756C62752289F11F008B57A2 /* SDLDynamicMenuUpdateRunScore.m */; };
880245A420F79C3400ED195B /* SDLFileManagerConfiguration.h in Headers */ = {isa = PBXBuildFile; fileRef = 880245A220F79C3400ED195B /* SDLFileManagerConfiguration.h */; settings = {ATTRIBUTES = (Public, ); }; };
880245A520F79C3400ED195B /* SDLFileManagerConfiguration.m in Sources */ = {isa = PBXBuildFile; fileRef = 880245A320F79C3400ED195B /* SDLFileManagerConfiguration.m */; };
8803DCEF22C2B84B00FBB7CE /* SDLBackgroundTaskManager.h in Headers */ = {isa = PBXBuildFile; fileRef = 8803DCED22C2B84B00FBB7CE /* SDLBackgroundTaskManager.h */; };
8803DCF022C2B84B00FBB7CE /* SDLBackgroundTaskManager.m in Sources */ = {isa = PBXBuildFile; fileRef = 8803DCEE22C2B84B00FBB7CE /* SDLBackgroundTaskManager.m */; };
880D267A220DDD1000B3F496 /* SDLWeatherServiceDataSpec.m in Sources */ = {isa = PBXBuildFile; fileRef = 880D2679220DDD1000B3F496 /* SDLWeatherServiceDataSpec.m */; };
880D267D220DE5DF00B3F496 /* SDLWeatherServiceManifest.h in Headers */ = {isa = PBXBuildFile; fileRef = 880D267B220DE5DF00B3F496 /* SDLWeatherServiceManifest.h */; settings = {ATTRIBUTES = (Public, ); }; };
880D267E220DE5DF00B3F496 /* SDLWeatherServiceManifest.m in Sources */ = {isa = PBXBuildFile; fileRef = 880D267C220DE5DF00B3F496 /* SDLWeatherServiceManifest.m */; };
Expand Down Expand Up @@ -2892,6 +2894,8 @@
756C62752289F11F008B57A2 /* SDLDynamicMenuUpdateRunScore.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLDynamicMenuUpdateRunScore.m; sourceTree = "<group>"; };
880245A220F79C3400ED195B /* SDLFileManagerConfiguration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLFileManagerConfiguration.h; sourceTree = "<group>"; };
880245A320F79C3400ED195B /* SDLFileManagerConfiguration.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLFileManagerConfiguration.m; sourceTree = "<group>"; };
8803DCED22C2B84B00FBB7CE /* SDLBackgroundTaskManager.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLBackgroundTaskManager.h; sourceTree = "<group>"; };
8803DCEE22C2B84B00FBB7CE /* SDLBackgroundTaskManager.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLBackgroundTaskManager.m; sourceTree = "<group>"; };
880D2679220DDD1000B3F496 /* SDLWeatherServiceDataSpec.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLWeatherServiceDataSpec.m; sourceTree = "<group>"; };
880D267B220DE5DF00B3F496 /* SDLWeatherServiceManifest.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SDLWeatherServiceManifest.h; sourceTree = "<group>"; };
880D267C220DE5DF00B3F496 /* SDLWeatherServiceManifest.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SDLWeatherServiceManifest.m; sourceTree = "<group>"; };
Expand Down Expand Up @@ -4791,6 +4795,8 @@
5D5934F61A85189500687FB9 /* Utilities */ = {
isa = PBXGroup;
children = (
8803DCED22C2B84B00FBB7CE /* SDLBackgroundTaskManager.h */,
8803DCEE22C2B84B00FBB7CE /* SDLBackgroundTaskManager.m */,
97E26DEA1E807AD70074A3C7 /* SDLMutableDataQueue.h */,
97E26DEB1E807AD70074A3C7 /* SDLMutableDataQueue.m */,
E9C32B831AB20B2900F283AF /* @categories */,
Expand Down Expand Up @@ -6426,6 +6432,7 @@
5D61FC511A84238C00846EE7 /* SDLButtonCapabilities.h in Headers */,
5D61FDE91A84238C00846EE7 /* SDLUnsubscribeButtonResponse.h in Headers */,
5D61FCD51A84238C00846EE7 /* SDLImageType.h in Headers */,
8803DCEF22C2B84B00FBB7CE /* SDLBackgroundTaskManager.h in Headers */,
5D61FC2F1A84238C00846EE7 /* SDLAddCommandResponse.h in Headers */,
5D0C2A0020D9479B008B56CD /* SDLStreamingVideoLifecycleManager.h in Headers */,
5D61FD631A84238C00846EE7 /* SDLResetGlobalProperties.h in Headers */,
Expand Down Expand Up @@ -7204,6 +7211,7 @@
5D61FC5E1A84238C00846EE7 /* SDLChangeRegistrationResponse.m in Sources */,
5D8204231BCEA89A00D0A41B /* SDLFileManager.m in Sources */,
1EB59CC0202DA26000343A61 /* SDLSeatControlData.m in Sources */,
8803DCF022C2B84B00FBB7CE /* SDLBackgroundTaskManager.m in Sources */,
5D61FC7D1A84238C00846EE7 /* SDLDeleteInteractionChoiceSetResponse.m in Sources */,
DAC572661D10C5640004288B /* CGPoint_Util.m in Sources */,
5D00AC681F140F0A004000D9 /* SDLSystemCapabilityType.m in Sources */,
Expand Down
44 changes: 44 additions & 0 deletions SmartDeviceLink/SDLBackgroundTaskManager.h
@@ -0,0 +1,44 @@
//
// SDLBackgroundTaskManager.h
// SmartDeviceLink
//
// Created by Nicole on 6/25/19.
// Copyright © 2019 smartdevicelink. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>

NS_ASSUME_NONNULL_BEGIN

/**
* Class for managing a background task.
*/
@interface SDLBackgroundTaskManager : NSObject

- (instancetype)init NS_UNAVAILABLE;

/**
* Convenience init for starting a background task with a specific name.
*
* @param backgroundTaskName The name for the background task
* @return A SDLBackgroundTaskManager object
*/
- (instancetype)initWithBackgroundTaskName:(NSString *)backgroundTaskName;

/**
* Starts a background task that allows the app to establish a session while app is backgrounded. If the app is not currently backgrounded, the background task will remain dormant until the app moves to the background.
*/
- (void)startBackgroundTask;

/**
* Cleans up a background task when it is stopped. This should be called when:
*
* 1. The app has established a session.
* 2. The system has called the `expirationHandler` for the background task. The system may kill the app if the background task is not ended when `expirationHandler` is called.
*/
- (void)endBackgroundTask;

@end

NS_ASSUME_NONNULL_END
68 changes: 68 additions & 0 deletions SmartDeviceLink/SDLBackgroundTaskManager.m
@@ -0,0 +1,68 @@
//
// SDLBackgroundTaskManager.m
// SmartDeviceLink
//
// Created by Nicole on 6/25/19.
// Copyright © 2019 smartdevicelink. All rights reserved.
//

#import "SDLBackgroundTaskManager.h"

#import "SDLLogMacros.h"


NS_ASSUME_NONNULL_BEGIN

@interface SDLBackgroundTaskManager ()
@property (copy, nonatomic) NSString *backgroundTaskName;
@property (assign, nonatomic) UIBackgroundTaskIdentifier currentBackgroundTaskId;

@end

@implementation SDLBackgroundTaskManager

- (instancetype)initWithBackgroundTaskName:(NSString *)backgroundTaskName {
SDLLogV(@"SDLBackgroundTaskManager init with name %@", backgroundTaskName);
self = [super init];
if (!self) {
return nil;
}

_backgroundTaskName = backgroundTaskName;

return self;
}

- (void)startBackgroundTask {
if (self.currentBackgroundTaskId != UIBackgroundTaskInvalid) {
SDLLogV(@"The %@ background task is already running.", self.backgroundTaskName);
return;
}

__weak typeof(self) weakself = self;
self.currentBackgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:self.backgroundTaskName expirationHandler:^{
SDLLogD(@"The %@ background task expired", self.backgroundTaskName);
[weakself endBackgroundTask];
}];

SDLLogD(@"The %@ background task started with id: %lu", self.backgroundTaskName, (unsigned long)self.currentBackgroundTaskId);
}

- (void)endBackgroundTask {
if (self.currentBackgroundTaskId == UIBackgroundTaskInvalid) {
SDLLogV(@"Background task already ended. Returning...");
return;
}

SDLLogD(@"Ending background task with id: %lu", (unsigned long)self.currentBackgroundTaskId);
[[UIApplication sharedApplication] endBackgroundTask:self.currentBackgroundTaskId];
self.currentBackgroundTaskId = UIBackgroundTaskInvalid;
}

- (void)dealloc {
[self endBackgroundTask];
}

@end

NS_ASSUME_NONNULL_END
87 changes: 2 additions & 85 deletions SmartDeviceLink/SDLIAPTransport.m
Expand Up @@ -15,12 +15,10 @@
#import "SDLIAPDataSession.h"
#import "SDLIAPDataSessionDelegate.h"
#import "SDLLogMacros.h"
#import "SDLTimer.h"
#import <CommonCrypto/CommonDigest.h>

NS_ASSUME_NONNULL_BEGIN

NSString *const BackgroundTaskName = @"com.sdl.transport.iap.backgroundTask";
int const CreateSessionRetries = 3;

@interface SDLIAPTransport () <SDLIAPControlSessionDelegate, SDLIAPDataSessionDelegate>
Expand All @@ -30,7 +28,6 @@ @interface SDLIAPTransport () <SDLIAPControlSessionDelegate, SDLIAPDataSessionDe
@property (assign, nonatomic) int retryCounter;
@property (assign, nonatomic) BOOL sessionSetupInProgress;
@property (assign, nonatomic) BOOL transportDestroyed;
@property (nonatomic, assign) UIBackgroundTaskIdentifier backgroundTaskId;
@property (assign, nonatomic) BOOL accessoryConnectDuringActiveSession;

@end
Expand Down Expand Up @@ -60,39 +57,6 @@ - (instancetype)init {
return self;
}

#pragma mark - Background Task

/**
* Starts a background task that allows the app to search for accessories and while the app is in the background.
*/
- (void)sdl_backgroundTaskStart {
if (self.backgroundTaskId != UIBackgroundTaskInvalid) {
SDLLogV(@"A background task is already running. No need to start a background task.");
return;
}

self.backgroundTaskId = [[UIApplication sharedApplication] beginBackgroundTaskWithName:BackgroundTaskName expirationHandler:^{
SDLLogD(@"Background task expired");
[self sdl_backgroundTaskEnd];
}];

SDLLogD(@"Started a background task with id: %lu", (unsigned long)self.backgroundTaskId);
}

/**
* Cleans up a background task when it is stopped.
*/
- (void)sdl_backgroundTaskEnd {
if (self.backgroundTaskId == UIBackgroundTaskInvalid) {
SDLLogV(@"No background task running. No need to stop the background task. Returning...");
return;
}

SDLLogD(@"Ending background task with id: %lu", (unsigned long)self.backgroundTaskId);
[[UIApplication sharedApplication] endBackgroundTask:self.backgroundTaskId];
self.backgroundTaskId = UIBackgroundTaskInvalid;
}

#pragma mark - Notifications

/**
Expand All @@ -108,14 +72,6 @@ - (void)sdl_startEventListening {
selector:@selector(sdl_accessoryDisconnected:)
name:EAAccessoryDidDisconnectNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sdl_applicationWillEnterForeground:)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(sdl_applicationDidEnterBackground:)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[EAAccessoryManager sharedAccessoryManager] registerForLocalNotifications];
}

Expand All @@ -125,7 +81,6 @@ - (void)sdl_startEventListening {
- (void)sdl_stopEventListening {
SDLLogV(@"SDLIAPTransport stopped listening for events");
[[EAAccessoryManager sharedAccessoryManager] unregisterForLocalNotifications];
[[NSNotificationCenter defaultCenter] removeObserver:self];
}

#pragma mark EAAccessory Notifications
Expand All @@ -145,11 +100,6 @@ - (void)sdl_accessoryConnected:(NSNotification *)notification {

double retryDelay = self.sdl_retryDelay;
SDLLogD(@"Accessory Connected (%@), Opening in %0.03fs", notification.userInfo[EAAccessoryKey], retryDelay);

if ([[UIApplication sharedApplication] applicationState] != UIApplicationStateActive) {
SDLLogD(@"Accessory connected while app is in background. Starting background task.");
[self sdl_backgroundTaskStart];
}

self.retryCounter = 0;
[self performSelector:@selector(sdl_connect:) withObject:nil afterDelay:retryDelay];
Expand Down Expand Up @@ -182,7 +132,7 @@ - (BOOL)sdl_isDataSessionActive:(nullable SDLIAPDataSession *)dataSession newAcc
*/
- (void)sdl_accessoryDisconnected:(NSNotification *)notification {
EAAccessory *accessory = [notification.userInfo objectForKey:EAAccessoryKey];
SDLLogD(@"Accessory with serial number %@ and connectionID %lu disconnecting.", accessory.serialNumber, (unsigned long)accessory.connectionID);
SDLLogD(@"Accessory with serial number: %@, and connectionID: %lu disconnecting.", accessory.serialNumber, (unsigned long)accessory.connectionID);

if (self.accessoryConnectDuringActiveSession == YES) {
SDLLogD(@"Switching transports from Bluetooth to USB. Will reconnect over Bluetooth after disconnecting the USB session.");
Expand Down Expand Up @@ -227,31 +177,6 @@ - (void)sdl_destroyTransport {
[self.delegate onTransportDisconnected];
}

#pragma mark App Lifecycle Notifications

/**
* Handles a notification sent by the system when the app enters the foreground.
*
* If the app is still searching for an accessory, a background task will be started so the app can still search for and/or connect with an accessory while it is in the background.
*
* @param notification Notification
*/
- (void)sdl_applicationWillEnterForeground:(NSNotification *)notification {
SDLLogV(@"App foregrounded, attempting connection");
[self sdl_backgroundTaskEnd];
[self connect];
}

/**
* Handles a notification sent by the system when the app enters the background.
*
* @param notification Notification
*/
- (void)sdl_applicationDidEnterBackground:(NSNotification *)notification {
SDLLogV(@"App backgrounded, starting background task");
[self sdl_backgroundTaskStart];
}

#pragma mark - Stream Lifecycle

#pragma mark SDLTransportTypeProtocol
Expand All @@ -273,12 +198,6 @@ - (void)sendData:(NSData *)data {
* Attempts to connect to an accessory.
*/
- (void)connect {
UIApplicationState state = [UIApplication sharedApplication].applicationState;
if (state != UIApplicationStateActive) {
SDLLogV(@"App inactive on connect, starting background task");
[self sdl_backgroundTaskStart];
}

[self sdl_connect:nil];
}

Expand Down Expand Up @@ -329,7 +248,7 @@ - (void)sdl_connect:(nullable EAAccessory *)accessory {
* @param accessory The accessory to try to establish a session with, or nil to scan all connected accessories.
*/
- (void)sdl_establishSessionWithAccessory:(nullable EAAccessory *)accessory {
SDLLogD(@"Attempting to connect accessory: %@", accessory.name);
SDLLogD(@"Attempting to connect accessory named: %@, with connectionID: %lu", accessory.name, (unsigned long)accessory.connectionID);
if (self.retryCounter < CreateSessionRetries) {
self.retryCounter++;

Expand Down Expand Up @@ -399,7 +318,6 @@ - (void)controlSession:(nonnull SDLIAPControlSession *)controlSession didReceive
*/
- (void)dataSessionDidReceiveData:(nonnull NSData *)data {
[self.delegate onDataReceived:data];
[self sdl_backgroundTaskStart];
}

/**
Expand Down Expand Up @@ -598,7 +516,6 @@ - (BOOL)createSessionWithAccessory:(EAAccessory *)accessory protocolString:(NSSt
- (void)dealloc {
SDLLogV(@"SDLIAPTransport dealloc");
[self disconnect];
[self sdl_backgroundTaskEnd];
self.controlSession = nil;
self.dataSession = nil;
self.delegate = nil;
Expand Down