Skip to content

Commit 03ecafd

Browse files
authored
Refactor GDT Backgrounding (#3896)
* Fix missing `runningInBackground` flags. * Attempt at fixing background issues with GDT. * Add missing deprecated implementation. * Transfer extra call to background call. * Style * Further review comments. * Fix testing. * Refactored FLLIntegrationTest. This does a few things - split the tests into a specific multithreaded test and a recursive run without crashing. It also adds a notification for the upload to post how many events were uploaded. This should be a bit more reliable and helps the overall validation during the "run without crashing" test. * Removed extra log. * Fix flag for Catalyst. * Disable currently non-functional test. * Further review comments. * Migrate CCT tests to match FLL. * Revert accidental partial change. * Clarify comment for starting the background tasks. * Review feedback, changelog additions and bug numbers.
1 parent dbca369 commit 03ecafd

19 files changed

+308
-279
lines changed

GoogleDataTransport.podspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
Pod::Spec.new do |s|
22
s.name = 'GoogleDataTransport'
3-
s.version = '2.0.0'
3+
s.version = '3.0.0'
44
s.summary = 'Google iOS SDK data transport.'
55

66
s.description = <<-DESC

GoogleDataTransport/CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
1+
# v3.0.0
2+
- Changes backgrounding logic to reduce background usage and properly complete
3+
all tasks. (#3893)
4+
- Fix Catalyst define checks. (#3695)
5+
- Fix ubsan issues in GDT (#3910)
6+
- Add support for FLL. (#3867)
7+
18
# v2.0.0
29
- Change/rename all classes and references from GDT to GDTCOR. (#3729)
310

GoogleDataTransport/GDTCORLibrary/GDTCORPlatform.m

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,10 @@ - (instancetype)init {
102102
return self;
103103
}
104104

105-
- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithExpirationHandler:(void (^)(void))handler {
106-
return
107-
[[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithExpirationHandler:handler];
105+
- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name
106+
expirationHandler:(void (^)(void))handler {
107+
return [[self sharedApplicationForBackgroundTask] beginBackgroundTaskWithName:name
108+
expirationHandler:handler];
108109
}
109110

110111
- (void)endBackgroundTask:(GDTCORBackgroundIdentifier)bgID {
@@ -124,6 +125,16 @@ - (BOOL)isAppExtension {
124125
#endif
125126
}
126127

128+
- (BOOL)isRunningInBackground {
129+
#if TARGET_OS_IOS || TARGET_OS_TV
130+
BOOL runningInBackground =
131+
[[self sharedApplicationForBackgroundTask] applicationState] == UIApplicationStateBackground;
132+
return runningInBackground;
133+
#else // For macoS and Catalyst apps.
134+
return NO;
135+
#endif
136+
}
137+
127138
/** Returns a UIApplication instance if on the appropriate platform.
128139
*
129140
* @return The shared UIApplication if on the appropriate platform.

GoogleDataTransport/GDTCORLibrary/GDTCORStorage.m

Lines changed: 24 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,13 @@ - (void)storeEvent:(GDTCOREvent *)event {
8181
[self createEventDirectoryIfNotExists];
8282

8383
__block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid;
84-
if (_runningInBackground) {
85-
bgID = [[GDTCORApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
86-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
87-
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
88-
bgID = GDTCORBackgroundIdentifierInvalid;
89-
}
90-
}];
91-
}
84+
bgID = [[GDTCORApplication sharedApplication]
85+
beginBackgroundTaskWithName:@"GDTStorage"
86+
expirationHandler:^{
87+
// End the background task if it's still valid.
88+
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
89+
bgID = GDTCORBackgroundIdentifierInvalid;
90+
}];
9291

9392
dispatch_async(_storageQueue, ^{
9493
// Check that a backend implementation is available for this target.
@@ -117,8 +116,8 @@ - (void)storeEvent:(GDTCOREvent *)event {
117116
[self.uploadCoordinator forceUploadForTarget:target];
118117
}
119118

120-
// Write state to disk.
121-
if (self->_runningInBackground) {
119+
// Write state to disk if we're in the background.
120+
if ([[GDTCORApplication sharedApplication] isRunningInBackground]) {
122121
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
123122
NSError *error;
124123
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self
@@ -132,11 +131,9 @@ - (void)storeEvent:(GDTCOREvent *)event {
132131
}
133132
}
134133

135-
// If running in the background, save state to disk and end the associated background task.
136-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
137-
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
138-
bgID = GDTCORBackgroundIdentifierInvalid;
139-
}
134+
// Cancel or end the associated background task if it's still valid.
135+
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
136+
bgID = GDTCORBackgroundIdentifierInvalid;
140137
});
141138
}
142139

@@ -229,8 +226,16 @@ - (void)appWillForeground:(GDTCORApplication *)app {
229226
}
230227

231228
- (void)appWillBackground:(GDTCORApplication *)app {
232-
self->_runningInBackground = YES;
233229
dispatch_async(_storageQueue, ^{
230+
// Immediately request a background task to run until the end of the current queue of work, and
231+
// cancel it once the work is done.
232+
__block GDTCORBackgroundIdentifier bgID =
233+
[app beginBackgroundTaskWithName:@"GDTStorage"
234+
expirationHandler:^{
235+
[app endBackgroundTask:bgID];
236+
bgID = GDTCORBackgroundIdentifierInvalid;
237+
}];
238+
234239
if (@available(macOS 10.13, iOS 11.0, tvOS 11.0, *)) {
235240
NSError *error;
236241
NSData *data = [NSKeyedArchiver archivedDataWithRootObject:self
@@ -242,20 +247,10 @@ - (void)appWillBackground:(GDTCORApplication *)app {
242247
[NSKeyedArchiver archiveRootObject:self toFile:[GDTCORStorage archivePath]];
243248
#endif
244249
}
245-
});
246250

247-
// Create an immediate background task to run until the end of the current queue of work.
248-
__block GDTCORBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
249-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
250-
[app endBackgroundTask:bgID];
251-
bgID = GDTCORBackgroundIdentifierInvalid;
252-
}
253-
}];
254-
dispatch_async(_storageQueue, ^{
255-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
256-
[app endBackgroundTask:bgID];
257-
bgID = GDTCORBackgroundIdentifierInvalid;
258-
}
251+
// End the background task if it's still valid.
252+
[app endBackgroundTask:bgID];
253+
bgID = GDTCORBackgroundIdentifierInvalid;
259254
});
260255
}
261256

GoogleDataTransport/GDTCORLibrary/GDTCORTransformer.m

Lines changed: 10 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -50,14 +50,12 @@ - (void)transformEvent:(GDTCOREvent *)event
5050
GDTCORAssert(event, @"You can't write a nil event");
5151

5252
__block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid;
53-
if (_runningInBackground) {
54-
bgID = [[GDTCORApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
55-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
56-
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
57-
bgID = GDTCORBackgroundIdentifierInvalid;
58-
}
59-
}];
60-
}
53+
bgID = [[GDTCORApplication sharedApplication]
54+
beginBackgroundTaskWithName:@"GDTTransformer"
55+
expirationHandler:^{
56+
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
57+
bgID = GDTCORBackgroundIdentifierInvalid;
58+
}];
6159
dispatch_async(_eventWritingQueue, ^{
6260
GDTCOREvent *transformedEvent = event;
6361
for (id<GDTCOREventTransformer> transformer in transformers) {
@@ -73,36 +71,14 @@ - (void)transformEvent:(GDTCOREvent *)event
7371
}
7472
}
7573
[self.storageInstance storeEvent:transformedEvent];
76-
if (self->_runningInBackground) {
77-
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
78-
bgID = GDTCORBackgroundIdentifierInvalid;
79-
}
80-
});
81-
}
82-
83-
#pragma mark - GDTCORLifecycleProtocol
8474

85-
- (void)appWillForeground:(GDTCORApplication *)app {
86-
dispatch_async(_eventWritingQueue, ^{
87-
self->_runningInBackground = NO;
75+
// The work is done, cancel the background task if it's valid.
76+
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
77+
bgID = GDTCORBackgroundIdentifierInvalid;
8878
});
8979
}
9080

91-
- (void)appWillBackground:(GDTCORApplication *)app {
92-
// Create an immediate background task to run until the end of the current queue of work.
93-
__block GDTCORBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
94-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
95-
[app endBackgroundTask:bgID];
96-
bgID = GDTCORBackgroundIdentifierInvalid;
97-
}
98-
}];
99-
dispatch_async(_eventWritingQueue, ^{
100-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
101-
[app endBackgroundTask:bgID];
102-
bgID = GDTCORBackgroundIdentifierInvalid;
103-
}
104-
});
105-
}
81+
#pragma mark - GDTCORLifecycleProtocol
10682

10783
- (void)appWillTerminate:(GDTCORApplication *)application {
10884
// Flush the queue immediately.

GoogleDataTransport/GDTCORLibrary/GDTCORUploadCoordinator.m

Lines changed: 1 addition & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ - (void)startTimer {
8080
dispatch_source_set_timer(self->_timer, DISPATCH_TIME_NOW, self->_timerInterval,
8181
self->_timerLeeway);
8282
dispatch_source_set_event_handler(self->_timer, ^{
83-
if (!self->_runningInBackground) {
83+
if (![[GDTCORApplication sharedApplication] isRunningInBackground]) {
8484
GDTCORUploadConditions conditions = [self uploadConditions];
8585
[self uploadTargets:[self.registrar.targetToUploader allKeys] conditions:conditions];
8686
}
@@ -186,30 +186,12 @@ - (void)encodeWithCoder:(NSCoder *)aCoder {
186186

187187
- (void)appWillForeground:(GDTCORApplication *)app {
188188
// Not entirely thread-safe, but it should be fine.
189-
self->_runningInBackground = NO;
190189
[self startTimer];
191190
}
192191

193192
- (void)appWillBackground:(GDTCORApplication *)app {
194-
// Not entirely thread-safe, but it should be fine.
195-
self->_runningInBackground = YES;
196-
197193
// Should be thread-safe. If it ends up not being, put this in a dispatch_sync.
198194
[self stopTimer];
199-
200-
// Create an immediate background task to run until the end of the current queue of work.
201-
__block GDTCORBackgroundIdentifier bgID = [app beginBackgroundTaskWithExpirationHandler:^{
202-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
203-
[app endBackgroundTask:bgID];
204-
bgID = GDTCORBackgroundIdentifierInvalid;
205-
}
206-
}];
207-
dispatch_async(_coordinationQueue, ^{
208-
if (bgID != GDTCORBackgroundIdentifierInvalid) {
209-
[app endBackgroundTask:bgID];
210-
bgID = GDTCORBackgroundIdentifierInvalid;
211-
}
212-
});
213195
}
214196

215197
- (void)appWillTerminate:(GDTCORApplication *)application {

GoogleDataTransport/GDTCORLibrary/Private/GDTCORStorage_Private.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,6 @@ NS_ASSUME_NONNULL_BEGIN
3535
/** The upload coordinator instance used by this storage instance. */
3636
@property(nonatomic) GDTCORUploadCoordinator *uploadCoordinator;
3737

38-
/** If YES, every call to -storeLog results in background task and serializes the singleton to disk.
39-
*/
40-
@property(nonatomic) BOOL runningInBackground;
41-
4238
/** Returns the path to the keyed archive of the singleton. This is where the singleton is saved
4339
* to disk during certain app lifecycle events.
4440
*

GoogleDataTransport/GDTCORLibrary/Private/GDTCORTransformer_Private.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ NS_ASSUME_NONNULL_BEGIN
2828
/** The storage instance used to store events. Should only be used to inject a testing fake. */
2929
@property(nonatomic) GDTCORStorage *storageInstance;
3030

31-
/** If YES, every call to -transformEvent will result in a background task. */
32-
@property(nonatomic, readonly) BOOL runningInBackground;
33-
3431
@end
3532

3633
NS_ASSUME_NONNULL_END

GoogleDataTransport/GDTCORLibrary/Private/GDTCORUploadCoordinator.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,6 @@ NS_ASSUME_NONNULL_BEGIN
5959
/** The registrar object the coordinator will use. Generally used for testing. */
6060
@property(nonatomic) GDTCORRegistrar *registrar;
6161

62-
/** If YES, completion and other operations will result in serializing the singleton to disk. */
63-
@property(nonatomic, readonly) BOOL runningInBackground;
64-
6562
/** Forces the backend specified by the target to upload the provided set of events. This should
6663
* only ever happen when the QoS tier of an event requires it.
6764
*

GoogleDataTransport/GDTCORLibrary/Public/GDTCORPlatform.h

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,21 @@ FOUNDATION_EXPORT const GDTCORBackgroundIdentifier GDTCORBackgroundIdentifierInv
6767
*/
6868
+ (nullable GDTCORApplication *)sharedApplication;
6969

70+
/** Flag to determine if the application is running in the background.
71+
*
72+
* @return YES if the app is running in the background, otherwise NO.
73+
*/
74+
- (BOOL)isRunningInBackground;
75+
7076
/** Creates a background task with the returned identifier if on a suitable platform.
7177
*
78+
* @name name The name of the task, useful for debugging which background tasks are running.
7279
* @param handler The handler block that is called if the background task expires.
7380
* @return An identifier for the background task, or GDTCORBackgroundIdentifierInvalid if one
7481
* couldn't be created.
7582
*/
76-
- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithExpirationHandler:
77-
(void (^__nullable)(void))handler;
83+
- (GDTCORBackgroundIdentifier)beginBackgroundTaskWithName:(NSString *)name
84+
expirationHandler:(void (^__nullable)(void))handler;
7885

7986
/** Ends the background task if the identifier is valid.
8087
*

0 commit comments

Comments
 (0)