-
Notifications
You must be signed in to change notification settings - Fork 1.6k
GDTCCTUploader.m line 331 crash #5449
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
Comments
This comment has been minimized.
This comment has been minimized.
Hey @Coloretta, please fill out the issue template. It will help us debug your issue. Most importantly, we'll need to know the versions of GoogleDataTransport you're using, since this looks like a bug that was recently fixed in the latest version. |
This is happening to me too.
|
@fbarraganef What does your Podfile.lock look like? |
@mikehaney24 here is:
|
com.enviaflores.ios_issue_crash_b34dca04e0b046dbac68c793010ec882_DNE_0_v2.txt Here is the crash files received using crashlytics. |
Looks like this may be a bug in GDT-latest based on @fbarraganef's stack trace and Podfile.lock. |
I'm not sure that this crash is in GDT 6.0. The line numbers correspond to the previous crash, and the line numbers are different because of the change to fix it. @fbarraganef Are you sure the version of the app for the issue you're reporting shipped with the GDT changes? Line 331 isn't a line of code in the most recent version. |
@mikehaney24 yes, It's the same framework version shipped to the production app. A few days ago I updated the production app and I also update the pods, after that i started to receive such error reports. The Podfile.lock from previous version app in production is: PODS:
DEPENDENCIES:
SPEC REPOS: SPEC CHECKSUMS: PODFILE CHECKSUM: e99048d7338aafd749dad0d6d3823283368baffa COCOAPODS: 1.9.1 |
How many instances of this crash are you seeing? Is it possible that the app version was incremented and a build created (maybe to QA folks) while still on the old cocoapods? |
+1 App update released yesterday with Firebase updated and seeing thousands of crashes in production. No further details other than a stack trace. |
Pod installations are as follows:
|
How are y'all integrating with Firebase? Is anyone building Firebase as dynamic frameworks? |
@mikehaney24 We integrate through Cocoapods. |
@mikehaney24 no, I'm integrating with Cocoapods. |
@fbarraganef Can you copy and paste your copy of the file |
@awojnowski The updated pods should have fixed that issue (#5312). This issue is for those experiencing identical crashes after having upgraded to GoogleDataTransport >= 6.0.0 and GoogleDataTransportCCTSupport >= 3.0.0 |
/*
* Copyright 2019 Google
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#import "GDTCCTLibrary/Private/GDTCCTUploader.h"
#import <GoogleDataTransport/GDTCORConsoleLogger.h>
#import <GoogleDataTransport/GDTCORPlatform.h>
#import <GoogleDataTransport/GDTCORRegistrar.h>
#import <nanopb/pb.h>
#import <nanopb/pb_decode.h>
#import <nanopb/pb_encode.h>
#import "GDTCCTLibrary/Private/GDTCCTCompressionHelper.h"
#import "GDTCCTLibrary/Private/GDTCCTNanopbHelpers.h"
#import "GDTCCTLibrary/Private/GDTCCTPrioritizer.h"
#import "GDTCCTLibrary/Protogen/nanopb/cct.nanopb.h"
#ifdef GDTCCTSUPPORT_VERSION
#define STR(x) STR_EXPAND(x)
#define STR_EXPAND(x) #x
static NSString *const kGDTCCTSupportSDKVersion = @STR(GDTCCTSUPPORT_VERSION);
#else
static NSString *const kGDTCCTSupportSDKVersion = @"UNKNOWN";
#endif // GDTCCTSUPPORT_VERSION
#if !NDEBUG
NSNotificationName const GDTCCTUploadCompleteNotification = @"com.GDTCCTUploader.UploadComplete";
#endif // #if !NDEBUG
@interface GDTCCTUploader () <NSURLSessionDelegate>
// Redeclared as readwrite.
@property(nullable, nonatomic, readwrite) NSURLSessionUploadTask *currentTask;
@end
@implementation GDTCCTUploader
+ (void)load {
GDTCCTUploader *uploader = [GDTCCTUploader sharedInstance];
[[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetCCT];
[[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetFLL];
[[GDTCORRegistrar sharedInstance] registerUploader:uploader target:kGDTCORTargetCSH];
}
+ (instancetype)sharedInstance {
static GDTCCTUploader *sharedInstance;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
sharedInstance = [[GDTCCTUploader alloc] init];
});
return sharedInstance;
}
- (instancetype)init {
self = [super init];
if (self) {
_uploaderQueue = dispatch_queue_create("com.google.GDTCCTUploader", DISPATCH_QUEUE_SERIAL);
NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
_uploaderSession = [NSURLSession sessionWithConfiguration:config
delegate:self
delegateQueue:nil];
}
return self;
}
/**
*
*/
- (nullable NSURL *)serverURLForTarget:(GDTCORTarget)target {
// These strings should be interleaved to construct the real URL. This is just to (hopefully)
// fool github URL scanning bots.
static NSURL *CCTServerURL;
static dispatch_once_t CCTOnceToken;
dispatch_once(&CCTOnceToken, ^{
const char *p1 = "hts/frbslgiggolai.o/0clgbth";
const char *p2 = "tp:/ieaeogn.ogepscmvc/o/ac";
const char URL[54] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4],
p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8],
p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13],
p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17],
p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22],
p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], '\0'};
CCTServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]];
});
static NSURL *FLLServerURL;
static dispatch_once_t FLLOnceToken;
dispatch_once(&FLLOnceToken, ^{
const char *p1 = "hts/frbslgigp.ogepscmv/ieo/eaybtho";
const char *p2 = "tp:/ieaeogn-agolai.o/1frlglgc/aclg";
const char URL[69] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4],
p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8],
p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13],
p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17],
p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22],
p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], p2[26],
p1[27], p2[27], p1[28], p2[28], p1[29], p2[29], p1[30], p2[30], p1[31],
p2[31], p1[32], p2[32], p1[33], p2[33], '\0'};
FLLServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]];
});
static NSURL *CSHServerURL;
static dispatch_once_t CSHOnceToken;
dispatch_once(&CSHOnceToken, ^{
// These strings should be interleaved to construct the real URL. This is just to (hopefully)
// fool github URL scanning bots.
const char *p1 = "hts/cahyiseot-agolai.o/1frlglgc/aclg";
const char *p2 = "tp:/rsltcrprsp.ogepscmv/ieo/eaybtho";
const char URL[72] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3], p1[4],
p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7], p1[8], p2[8],
p1[9], p2[9], p1[10], p2[10], p1[11], p2[11], p1[12], p2[12], p1[13],
p2[13], p1[14], p2[14], p1[15], p2[15], p1[16], p2[16], p1[17], p2[17],
p1[18], p2[18], p1[19], p2[19], p1[20], p2[20], p1[21], p2[21], p1[22],
p2[22], p1[23], p2[23], p1[24], p2[24], p1[25], p2[25], p1[26], p2[26],
p1[27], p2[27], p1[28], p2[28], p1[29], p2[29], p1[30], p2[30], p1[31],
p2[31], p1[32], p2[32], p1[33], p2[33], p1[34], p2[34], p1[35], '\0'};
CSHServerURL = [NSURL URLWithString:[NSString stringWithUTF8String:URL]];
});
#if !NDEBUG
if (_testServerURL) {
return _testServerURL;
}
#endif // !NDEBUG
switch (target) {
case kGDTCORTargetCCT:
return CCTServerURL;
case kGDTCORTargetFLL:
return FLLServerURL;
case kGDTCORTargetCSH:
return CSHServerURL;
default:
GDTCORLogDebug(@"GDTCCTUploader doesn't support target %ld", (long)target);
return nil;
break;
}
}
- (NSString *)FLLAndCSHAPIKey {
static NSString *defaultServerKey;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
// These strings should be interleaved to construct the real key.
const char *p1 = "AzSBG0honD6A-PxV5nBc";
const char *p2 = "Iay44Iwtu2vV0AOrz1C";
const char defaultKey[40] = {p1[0], p2[0], p1[1], p2[1], p1[2], p2[2], p1[3], p2[3],
p1[4], p2[4], p1[5], p2[5], p1[6], p2[6], p1[7], p2[7],
p1[8], p2[8], p1[9], p2[9], p1[10], p2[10], p1[11], p2[11],
p1[12], p2[12], p1[13], p2[13], p1[14], p2[14], p1[15], p2[15],
p1[16], p2[16], p1[17], p2[17], p1[18], p2[18], p1[19], '\0'};
defaultServerKey = [NSString stringWithUTF8String:defaultKey];
});
return defaultServerKey;
}
- (void)uploadPackage:(GDTCORUploadPackage *)package {
__block GDTCORBackgroundIdentifier bgID = GDTCORBackgroundIdentifierInvalid;
bgID = [[GDTCORApplication sharedApplication]
beginBackgroundTaskWithName:@"GDTCCTUploader-upload"
expirationHandler:^{
if (bgID != GDTCORBackgroundIdentifierInvalid) {
// Cancel the upload and complete delivery.
[self.currentTask cancel];
[self.currentUploadPackage completeDelivery];
// End the background task.
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
}
}];
dispatch_async(_uploaderQueue, ^{
if (self->_currentTask || self->_currentUploadPackage) {
GDTCORLogWarning(GDTCORMCWUploadFailed, @"%@",
@"An upload shouldn't be initiated with another in progress.");
return;
}
GDTCORTarget target = package.target;
id completionHandler = ^(NSData *_Nullable data, NSURLResponse *_Nullable response,
NSError *_Nullable error) {
GDTCORLogDebug(@"%@", @"CCT: request completed");
if (error) {
GDTCORLogWarning(GDTCORMCWUploadFailed, @"There was an error uploading events: %@", error);
}
NSError *decodingError;
GDTCORClock *futureUploadTime;
if (data) {
gdt_cct_LogResponse logResponse = GDTCCTDecodeLogResponse(data, &decodingError);
if (!decodingError && logResponse.has_next_request_wait_millis) {
GDTCORLogDebug(
@"CCT: The backend responded asking to not upload for %lld millis from now.",
logResponse.next_request_wait_millis);
futureUploadTime =
[GDTCORClock clockSnapshotInTheFuture:logResponse.next_request_wait_millis];
} else if (decodingError) {
GDTCORLogDebug(@"There was a response decoding error: %@", decodingError);
}
pb_release(gdt_cct_LogResponse_fields, &logResponse);
}
if (!futureUploadTime) {
GDTCORLogDebug(@"%@", @"CCT: The backend response failed to parse, so the next request "
@"won't occur until 15 minutes from now");
// 15 minutes from now.
futureUploadTime = [GDTCORClock clockSnapshotInTheFuture:15 * 60 * 1000];
}
switch (target) {
case kGDTCORTargetCCT:
self->_CCTNextUploadTime = futureUploadTime;
break;
case kGDTCORTargetFLL:
// Falls through.
case kGDTCORTargetCSH:
self->_FLLNextUploadTime = futureUploadTime;
default:
break;
}
// Only retry if one of these codes is returned, or there was an error.
if (error || ((NSHTTPURLResponse *)response).statusCode == 429 ||
((NSHTTPURLResponse *)response).statusCode == 503) {
[package retryDeliveryInTheFuture];
} else {
#if !NDEBUG
// Post a notification when in DEBUG mode to state how many packages were uploaded. Useful
// for validation during tests.
[[NSNotificationCenter defaultCenter] postNotificationName:GDTCCTUploadCompleteNotification
object:@(package.events.count)];
#endif // #if !NDEBUG
GDTCORLogDebug(@"%@", @"CCT: package delivered");
[package completeDelivery];
}
// End the background task if there was one.
if (bgID != GDTCORBackgroundIdentifierInvalid) {
[[GDTCORApplication sharedApplication] endBackgroundTask:bgID];
bgID = GDTCORBackgroundIdentifierInvalid;
}
self.currentTask = nil;
self.currentUploadPackage = nil;
};
self->_currentUploadPackage = package;
NSData *requestProtoData =
[self constructRequestProtoFromPackage:(GDTCORUploadPackage *)package];
NSData *gzippedData = [GDTCCTCompressionHelper gzippedData:requestProtoData];
BOOL usingGzipData = gzippedData != nil && gzippedData.length < requestProtoData.length;
NSData *dataToSend = usingGzipData ? gzippedData : requestProtoData;
NSURLRequest *request = [self constructRequestForTarget:target data:dataToSend];
GDTCORLogDebug(@"CTT: request created: %@", request);
self.currentTask = [self.uploaderSession uploadTaskWithRequest:request
fromData:dataToSend
completionHandler:completionHandler];
GDTCORLogDebug(@"%@", @"CCT: The upload task is about to begin.");
[self.currentTask resume];
});
}
- (BOOL)readyToUploadTarget:(GDTCORTarget)target conditions:(GDTCORUploadConditions)conditions {
__block BOOL result = NO;
NSSet *CSHEvents = [[GDTCCTPrioritizer sharedInstance] eventsForTarget:kGDTCORTargetCSH];
dispatch_sync(_uploaderQueue, ^{
if (target == kGDTCORTargetCSH) {
result = CSHEvents.count > 0;
return;
}
if (self->_currentUploadPackage) {
result = NO;
GDTCORLogDebug(@"%@", @"CCT: can't upload because a package is in flight");
return;
}
if (self->_currentTask) {
result = NO;
GDTCORLogDebug(@"%@", @"CCT: can't upload because a task is in progress");
return;
}
if ((conditions & GDTCORUploadConditionHighPriority) == GDTCORUploadConditionHighPriority) {
result = YES;
GDTCORLogDebug(@"%@", @"CCT: a high priority event is allowing an upload");
return;
}
switch (target) {
case kGDTCORTargetCCT:
if (self->_CCTNextUploadTime) {
result = [[GDTCORClock snapshot] isAfter:self->_CCTNextUploadTime];
}
break;
case kGDTCORTargetFLL:
if (self->_FLLNextUploadTime) {
result = [[GDTCORClock snapshot] isAfter:self->_FLLNextUploadTime];
}
break;
default:
// The CSH backend should be handled above.
break;
}
if (result) {
GDTCORLogDebug(@"CCT: can upload to target %ld because the request wait time has transpired",
(long)target);
} else {
GDTCORLogDebug(@"CCT: can't upload to target %ld because the backend asked to wait",
(long)target);
}
result = YES;
GDTCORLogDebug(@"CCT: can upload to target %ld because nothing is preventing it", (long)target);
});
return result;
}
#pragma mark - Private helper methods
/** Constructs data given an upload package.
*
* @param package The upload package used to construct the request proto bytes.
* @return Proto bytes representing a gdt_cct_LogRequest object.
*/
- (nonnull NSData *)constructRequestProtoFromPackage:(GDTCORUploadPackage *)package {
// Segment the log events by log type.
NSMutableDictionary<NSString *, NSMutableSet<GDTCOREvent *> *> *logMappingIDToLogSet =
[[NSMutableDictionary alloc] init];
[package.events enumerateObjectsUsingBlock:^(GDTCOREvent *_Nonnull event, BOOL *_Nonnull stop) {
NSMutableSet *logSet = logMappingIDToLogSet[event.mappingID];
logSet = logSet ? logSet : [[NSMutableSet alloc] init];
[logSet addObject:event];
logMappingIDToLogSet[event.mappingID] = logSet;
}];
gdt_cct_BatchedLogRequest batchedLogRequest =
GDTCCTConstructBatchedLogRequest(logMappingIDToLogSet);
NSData *data = GDTCCTEncodeBatchedLogRequest(&batchedLogRequest);
pb_release(gdt_cct_BatchedLogRequest_fields, &batchedLogRequest);
return data ? data : [[NSData alloc] init];
}
/** Constructs a request to FLL given a URL and request body data.
*
* @param target The target backend to send the request to.
* @param data The request body data.
* @return A new NSURLRequest ready to be sent to FLL.
*/
- (NSURLRequest *)constructRequestForTarget:(GDTCORTarget)target data:(NSData *)data {
NSURL *URL = [self serverURLForTarget:target];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:URL];
NSString *targetString;
switch (target) {
case kGDTCORTargetCCT:
targetString = @"cct";
break;
case kGDTCORTargetFLL:
targetString = @"fll";
break;
case kGDTCORTargetCSH:
targetString = @"csh";
break;
default:
targetString = @"unknown";
break;
}
NSString *userAgent =
[NSString stringWithFormat:@"datatransport/%@ %@support/%@ apple/", kGDTCORVersion,
targetString, kGDTCCTSupportSDKVersion];
if (target == kGDTCORTargetFLL || target == kGDTCORTargetCSH) {
[request setValue:[self FLLAndCSHAPIKey] forHTTPHeaderField:@"X-Goog-Api-Key"];
}
if ([GDTCCTCompressionHelper isGzipped:data]) {
[request setValue:@"gzip" forHTTPHeaderField:@"Content-Encoding"];
}
[request setValue:@"application/x-protobuf" forHTTPHeaderField:@"Content-Type"];
[request setValue:@"gzip" forHTTPHeaderField:@"Accept-Encoding"];
[request setValue:userAgent forHTTPHeaderField:@"User-Agent"];
request.HTTPMethod = @"POST";
[request setHTTPBody:data];
return request;
}
#pragma mark - GDTCORUploadPackageProtocol
- (void)packageExpired:(GDTCORUploadPackage *)package {
dispatch_async(_uploaderQueue, ^{
[self.currentTask cancel];
self.currentTask = nil;
self.currentUploadPackage = nil;
});
}
#pragma mark - GDTCORLifecycleProtocol
- (void)appWillTerminate:(GDTCORApplication *)application {
dispatch_sync(_uploaderQueue, ^{
[self.currentTask cancel];
[self.currentUploadPackage completeDelivery];
});
}
#pragma mark - NSURLSessionDelegate
- (void)URLSession:(NSURLSession *)session
task:(NSURLSessionTask *)task
willPerformHTTPRedirection:(NSHTTPURLResponse *)response
newRequest:(NSURLRequest *)request
completionHandler:(void (^)(NSURLRequest *_Nullable))completionHandler {
if (!completionHandler) {
return;
}
if (response.statusCode == 302 || response.statusCode == 301) {
if ([request.URL isEqual:[self serverURLForTarget:kGDTCORTargetFLL]]) {
NSURLRequest *newRequest = [self constructRequestForTarget:kGDTCORTargetCCT
data:task.originalRequest.HTTPBody];
completionHandler(newRequest);
}
} else {
completionHandler(request);
}
}
@end |
@mikehaney24 When |
Yes, that issue is already fixed, as I said above, in #5312 |
@mikehaney24 I'am sorry that I have misunderstood your meaning.Now I have both update to new version.Thanks very much. |
No problem! This is a confusing issue. |
@fbarraganef Your file looks correct, so it doesn't really make sense that you're seeing a crash at the given lines. Unfortunately, the only recommendation I have is to |
@mikehaney24 Not the OP but just want to jump in and note that updating fixed this crash for us. Thank you for your quick reply and apologies for the confusion. |
Always getting crash in firebase sdk:
The text was updated successfully, but these errors were encountered: