AutorÃa | Ultima modificación | Ver Log |
// 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.#include <stdatomic.h>#if __has_include(<FBLPromises/FBLPromises.h>)#import <FBLPromises/FBLPromises.h>#else#import "FBLPromises.h"#endif#include "Crashlytics/Crashlytics/Components/FIRCLSCrashedMarkerFile.h"#include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"#import "Crashlytics/Crashlytics/Components/FIRCLSHost.h"#include "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionArbiter.h"#import "Crashlytics/Crashlytics/DataCollection/FIRCLSDataCollectionToken.h"#import "Crashlytics/Crashlytics/FIRCLSUserDefaults/FIRCLSUserDefaults.h"#include "Crashlytics/Crashlytics/Handlers/FIRCLSException.h"#import "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"#include "Crashlytics/Crashlytics/Helpers/FIRCLSProfiling.h"#include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"#import "Crashlytics/Crashlytics/Models/FIRCLSFileManager.h"#import "Crashlytics/Crashlytics/Models/FIRCLSSettings.h"#import "Crashlytics/Crashlytics/Settings/Models/FIRCLSApplicationIdentifierModel.h"#import "Crashlytics/Crashlytics/Helpers/FIRCLSLogger.h"#import "Crashlytics/Shared/FIRCLSByteUtility.h"#import "Crashlytics/Shared/FIRCLSConstants.h"#import "Crashlytics/Shared/FIRCLSFABHost.h"#import "Crashlytics/Crashlytics/Controllers/FIRCLSAnalyticsManager.h"#import "Crashlytics/Crashlytics/Controllers/FIRCLSExistingReportManager.h"#import "Crashlytics/Crashlytics/Controllers/FIRCLSManagerData.h"#import "Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.h"#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportManager.h"#import "Crashlytics/Crashlytics/Controllers/FIRCLSReportUploader.h"#import "Crashlytics/Crashlytics/Private/FIRCLSExistingReportManager_Private.h"#import "Crashlytics/Crashlytics/Private/FIRCLSOnDemandModel_Private.h"#import "Crashlytics/Crashlytics/Private/FIRExceptionModel_Private.h"#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"#import "FirebaseInstallations/Source/Library/Private/FirebaseInstallationsInternal.h"#import "Interop/Analytics/Public/FIRAnalyticsInterop.h"#import <GoogleDataTransport/GoogleDataTransport.h>#if TARGET_OS_IPHONE#import <UIKit/UIKit.h>#endifFIRCLSContext _firclsContext;dispatch_queue_t _firclsLoggingQueue;dispatch_queue_t _firclsBinaryImageQueue;dispatch_queue_t _firclsExceptionQueue;static atomic_bool _hasInitializedInstance;NSString *const FIRCLSGoogleTransportMappingID = @"1206";/// Empty protocol to register with FirebaseCore's component system.@protocol FIRCrashlyticsInstanceProvider <NSObject>@end@interface FIRCrashlytics () <FIRLibrary, FIRCrashlyticsInstanceProvider>@property(nonatomic) BOOL didPreviouslyCrash;@property(nonatomic, copy) NSString *googleAppID;@property(nonatomic) FIRCLSDataCollectionArbiter *dataArbiter;@property(nonatomic) FIRCLSFileManager *fileManager;@property(nonatomic) FIRCLSReportManager *reportManager;@property(nonatomic) FIRCLSReportUploader *reportUploader;@property(nonatomic, strong) FIRCLSExistingReportManager *existingReportManager;@property(nonatomic, strong) FIRCLSAnalyticsManager *analyticsManager;// Dependencies common to each of the Controllers@property(nonatomic, strong) FIRCLSManagerData *managerData;@end@implementation FIRCrashlytics#pragma mark - Singleton Support- (instancetype)initWithApp:(FIRApp *)appappInfo:(NSDictionary *)appInfoinstallations:(FIRInstallations *)installationsanalytics:(id<FIRAnalyticsInterop>)analytics {self = [super init];if (self) {bool expectedCalled = NO;if (!atomic_compare_exchange_strong(&_hasInitializedInstance, &expectedCalled, YES)) {FIRCLSErrorLog(@"Cannot instantiate more than one instance of Crashlytics.");return nil;}FIRCLSProfileMark mark = FIRCLSProfilingStart();NSLog(@"[Firebase/Crashlytics] Version %@", FIRCLSSDKVersion());FIRCLSDeveloperLog("Crashlytics", @"Running on %@, %@ (%@)", FIRCLSHostModelInfo(),FIRCLSHostOSDisplayVersion(), FIRCLSHostOSBuildVersion());GDTCORTransport *googleTransport =[[GDTCORTransport alloc] initWithMappingID:FIRCLSGoogleTransportMappingIDtransformers:niltarget:kGDTCORTargetCSH];_fileManager = [[FIRCLSFileManager alloc] init];_googleAppID = app.options.googleAppID;_dataArbiter = [[FIRCLSDataCollectionArbiter alloc] initWithApp:app withAppInfo:appInfo];FIRCLSApplicationIdentifierModel *appModel = [[FIRCLSApplicationIdentifierModel alloc] init];FIRCLSSettings *settings = [[FIRCLSSettings alloc] initWithFileManager:_fileManagerappIDModel:appModel];FIRCLSOnDemandModel *onDemandModel =[[FIRCLSOnDemandModel alloc] initWithFIRCLSSettings:settings];_managerData = [[FIRCLSManagerData alloc] initWithGoogleAppID:_googleAppIDgoogleTransport:googleTransportinstallations:installationsanalytics:analyticsfileManager:_fileManagerdataArbiter:_dataArbitersettings:settingsonDemandModel:onDemandModel];_reportUploader = [[FIRCLSReportUploader alloc] initWithManagerData:_managerData];_existingReportManager =[[FIRCLSExistingReportManager alloc] initWithManagerData:_managerDatareportUploader:_reportUploader];_analyticsManager = [[FIRCLSAnalyticsManager alloc] initWithAnalytics:analytics];_reportManager = [[FIRCLSReportManager alloc] initWithManagerData:_managerDataexistingReportManager:_existingReportManageranalyticsManager:_analyticsManager];_didPreviouslyCrash = [_fileManager didCrashOnPreviousExecution];// Process did crash during previous executionif (_didPreviouslyCrash) {// Delete the crash file marker in the background ensure start up is as fast as possibledispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{NSString *crashedMarkerFileFullPath = [[self.fileManager rootPath]stringByAppendingPathComponent:[NSStringstringWithUTF8String:FIRCLSCrashedMarkerFileName]];[self.fileManager removeItemAtPath:crashedMarkerFileFullPath];});}[[[_reportManager startWithProfilingMark:mark] then:^id _Nullable(NSNumber *_Nullable value) {if (![value boolValue]) {FIRCLSErrorLog(@"Crash reporting could not be initialized");}return value;}] catch:^void(NSError *error) {FIRCLSErrorLog(@"Crash reporting failed to initialize with error: %@", error);}];}return self;}+ (void)load {[FIRApp registerInternalLibrary:(Class<FIRLibrary>)self withName:@"firebase-crashlytics"];}+ (NSArray<FIRComponent *> *)componentsToRegister {FIRDependency *analyticsDep =[FIRDependency dependencyWithProtocol:@protocol(FIRAnalyticsInterop)];FIRComponentCreationBlock creationBlock =^id _Nullable(FIRComponentContainer *container, BOOL *isCacheable) {if (!container.app.isDefaultApp) {FIRCLSErrorLog(@"Crashlytics must be used with the default Firebase app.");return nil;}id<FIRAnalyticsInterop> analytics = FIR_COMPONENT(FIRAnalyticsInterop, container);FIRInstallations *installations = [FIRInstallations installationsWithApp:container.app];*isCacheable = YES;return [[FIRCrashlytics alloc] initWithApp:container.appappInfo:NSBundle.mainBundle.infoDictionaryinstallations:installationsanalytics:analytics];};FIRComponent *component =[FIRComponent componentWithProtocol:@protocol(FIRCrashlyticsInstanceProvider)instantiationTiming:FIRInstantiationTimingEagerInDefaultAppdependencies:@[ analyticsDep ]creationBlock:creationBlock];return @[ component ];}+ (instancetype)crashlytics {// The container will return the same instance since isCacheable is setFIRApp *defaultApp = [FIRApp defaultApp]; // Missing configure will be logged here.// Get the instance from the `FIRApp`'s container. This will create a new instance the// first time it is called, and since `isCacheable` is set in the component creation// block, it will return the existing instance on subsequent calls.id<FIRCrashlyticsInstanceProvider> instance =FIR_COMPONENT(FIRCrashlyticsInstanceProvider, defaultApp.container);// In the component creation block, we return an instance of `FIRCrashlytics`. Cast it and// return it.return (FIRCrashlytics *)instance;}- (void)setCrashlyticsCollectionEnabled:(BOOL)enabled {[self.dataArbiter setCrashlyticsCollectionEnabled:enabled];}- (BOOL)isCrashlyticsCollectionEnabled {return [self.dataArbiter isCrashlyticsCollectionEnabled];}#pragma mark - API: didCrashDuringPreviousExecution- (BOOL)didCrashDuringPreviousExecution {return self.didPreviouslyCrash;}- (void)processDidCrashDuringPreviousExecution {NSString *crashedMarkerFileName = [NSString stringWithUTF8String:FIRCLSCrashedMarkerFileName];NSString *crashedMarkerFileFullPath =[[self.fileManager rootPath] stringByAppendingPathComponent:crashedMarkerFileName];self.didPreviouslyCrash = [self.fileManager fileExistsAtPath:crashedMarkerFileFullPath];if (self.didPreviouslyCrash) {// Delete the crash file marker in the background ensure start up is as fast as possibledispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{[self.fileManager removeItemAtPath:crashedMarkerFileFullPath];});}}#pragma mark - API: Logging- (void)log:(NSString *)msg {FIRCLSLog(@"%@", msg);}- (void)logWithFormat:(NSString *)format, ... {va_list args;va_start(args, format);[self logWithFormat:format arguments:args];va_end(args);}- (void)logWithFormat:(NSString *)format arguments:(va_list)args {[self log:[[NSString alloc] initWithFormat:format arguments:args]];}#pragma mark - API: Accessors- (void)checkForUnsentReportsWithCompletion:(void (^)(BOOL))completion {[[self.reportManager checkForUnsentReports]then:^id _Nullable(FIRCrashlyticsReport *_Nullable value) {completion(value ? true : false);return nil;}];}- (void)checkAndUpdateUnsentReportsWithCompletion:(void (^)(FIRCrashlyticsReport *_Nonnull))completion {[[self.reportManager checkForUnsentReports]then:^id _Nullable(FIRCrashlyticsReport *_Nullable value) {completion(value);return nil;}];}- (void)sendUnsentReports {[self.reportManager sendUnsentReports];}- (void)deleteUnsentReports {[self.reportManager deleteUnsentReports];}#pragma mark - API: setUserID- (void)setUserID:(nullable NSString *)userID {FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSUserIdentifierKey, userID);}#pragma mark - API: setCustomValue- (void)setCustomValue:(nullable id)value forKey:(NSString *)key {FIRCLSUserLoggingRecordUserKeyValue(key, value);}- (void)setCustomKeysAndValues:(NSDictionary *)keysAndValues {FIRCLSUserLoggingRecordUserKeysAndValues(keysAndValues);}#pragma mark - API: Development Platform// These two methods are depercated by our own API, so// its ok to implement them#pragma clang diagnostic push#pragma clang diagnostic ignored "-Wdeprecated-implementations"+ (void)setDevelopmentPlatformName:(NSString *)name {[[self crashlytics] setDevelopmentPlatformName:name];}+ (void)setDevelopmentPlatformVersion:(NSString *)version {[[self crashlytics] setDevelopmentPlatformVersion:version];}#pragma clang diagnostic pop- (NSString *)developmentPlatformName {FIRCLSErrorLog(@"developmentPlatformName is write-only");return nil;}- (void)setDevelopmentPlatformName:(NSString *)developmentPlatformName {FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSDevelopmentPlatformNameKey,developmentPlatformName);}- (NSString *)developmentPlatformVersion {FIRCLSErrorLog(@"developmentPlatformVersion is write-only");return nil;}- (void)setDevelopmentPlatformVersion:(NSString *)developmentPlatformVersion {FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSDevelopmentPlatformVersionKey,developmentPlatformVersion);}#pragma mark - API: Errors and Exceptions- (void)recordError:(NSError *)error {FIRCLSUserLoggingRecordError(error, nil);}- (void)recordExceptionModel:(FIRExceptionModel *)exceptionModel {FIRCLSExceptionRecordModel(exceptionModel);}- (void)recordOnDemandExceptionModel:(FIRExceptionModel *)exceptionModel {[self.managerData.onDemandModelrecordOnDemandExceptionIfQuota:exceptionModelwithDataCollectionEnabled:[self.dataArbiter isCrashlyticsCollectionEnabled]usingExistingReportManager:self.existingReportManager];}@end