AutorÃa | Ultima modificación | Ver Log |
// Copyright 2020 Google LLC//// 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 <UIKit/UIKit.h>#import "FirebasePerformance/Sources/Common/FPRConstants.h"#import "FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h"#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h"#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags+Private.h"#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h"#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"FPRConfigName kFPRConfigDataCollectionEnabled = @"dataCollectionEnabled";FPRConfigName kFPRConfigInstrumentationEnabled = @"instrumentationEnabled";NSString *const kFPRConfigInstrumentationUserPreference =@"com.firebase.performanceInsrumentationEnabled";NSString *const kFPRConfigInstrumentationPlistKey = @"firebase_performance_instrumentation_enabled";NSString *const kFPRConfigCollectionUserPreference = @"com.firebase.performanceCollectionEnabled";NSString *const kFPRConfigCollectionPlistKey = @"firebase_performance_collection_enabled";NSString *const kFPRDiagnosticsUserPreference = @"FPRDiagnosticsLocal";NSString *const kFPRDiagnosticsEnabledPlistKey = @"FPRDiagnosticsLocal";NSString *const kFPRConfigCollectionDeactivationPlistKey =@"firebase_performance_collection_deactivated";NSString *const kFPRConfigLogSource = @"com.firebase.performanceLogSource";@implementation FPRConfigurationsstatic dispatch_once_t gSharedInstanceToken;+ (instancetype)sharedInstance {static FPRConfigurations *instance = nil;dispatch_once(&gSharedInstanceToken, ^{FPRConfigurationSource sources = FPRConfigurationSourceRemoteConfig;instance = [[FPRConfigurations alloc] initWithSources:sources];});return instance;}+ (void)reset {// TODO(b/120032990): Reset the singletons that this singleton uses.gSharedInstanceToken = 0;[[NSUserDefaults standardUserDefaults]removeObjectForKey:kFPRConfigInstrumentationUserPreference];[[NSUserDefaults standardUserDefaults] removeObjectForKey:kFPRConfigCollectionUserPreference];}- (instancetype)initWithSources:(FPRConfigurationSource)source {self = [super init];if (self) {_sources = source;[self setupRemoteConfigFlags];// Register for notifications to update configs.[self registerForNotifications];self.FIRAppClass = [FIRApp class];self.userDefaults = [NSUserDefaults standardUserDefaults];self.infoDictionary = [NSBundle mainBundle].infoDictionary;self.mainBundleIdentifier = [NSBundle mainBundle].bundleIdentifier;self.updateQueue = dispatch_queue_create("com.google.perf.configUpdate", DISPATCH_QUEUE_SERIAL);}return self;}- (void)registerForNotifications {[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(update)name:UIApplicationDidBecomeActiveNotificationobject:nil];}/** Searches the main bundle and the bundle from bundleForClass: info dictionaries for the key and* returns the first result.** @param key The key to search the info dictionaries for.* @return The first object found in the info dictionary of the main bundle and bundleForClass:.*/- (nullable id)objectForInfoDictionaryKey:(NSString *)key {// If the config infoDictionary has been set to a new dictionary, only use the original dictionary// instead of the new dictionary.if (self.infoDictionary != [NSBundle mainBundle].infoDictionary) {return self.infoDictionary[key]; // nullable.}NSArray<NSBundle *> *bundles = @[ [NSBundle mainBundle], [NSBundle bundleForClass:[self class]] ];for (NSBundle *bundle in bundles) {id object = [bundle objectForInfoDictionaryKey:key];if (object) {return object; // nonnull.}}return nil;}- (void)update {dispatch_async(self.updateQueue, ^{if (!self.remoteConfigFlags) {[self setupRemoteConfigFlags];}[self.remoteConfigFlags update];});}/*** Sets up the remote config flags instance based on 3 different factors:* 1. Is the firebase app configured?* 2. Is the remote config source enabled?* 3. If the Remote Config flags instance exists already?*/- (void)setupRemoteConfigFlags {if (!self.remoteConfigFlags && [self.FIRAppClass isDefaultAppConfigured] &&(self.sources & FPRConfigurationSourceRemoteConfig) == FPRConfigurationSourceRemoteConfig) {self.remoteConfigFlags = [FPRRemoteConfigFlags sharedInstance];}}#pragma mark - Overridden Properties- (void)setDataCollectionEnabled:(BOOL)dataCollectionEnabled {[self.userDefaults setBool:dataCollectionEnabled forKey:kFPRConfigCollectionUserPreference];}// The data collection flag is determined by this order:// 1. A plist flag for permanently disabling data collection// 2. The runtime flag (NSUserDefaults)// 3. A plist flag for enabling/disabling (overrideable)// 4. The global data collection switch from Core.- (BOOL)isDataCollectionEnabled {/*** Perf only works with the default app, so validate it exists then use the value from the global* data collection from the default app as the base value if no other values are set.*/if (![self.FIRAppClass isDefaultAppConfigured]) {return NO;}BOOL dataCollectionPreference = [self.FIRAppClass defaultApp].isDataCollectionDefaultEnabled;// Check if data collection is permanently disabled by plist. If so, disable data collection.id dataCollectionDeactivationObject =[self objectForInfoDictionaryKey:kFPRConfigCollectionDeactivationPlistKey];if (dataCollectionDeactivationObject) {BOOL dataCollectionDeactivated = [dataCollectionDeactivationObject boolValue];if (dataCollectionDeactivated) {return NO;}}/*** Check if the performance collection preference key is available in NSUserDefaults.* If it exists - Just honor that and return that value.* If it does not exist - Check if firebase_performance_collection_enabled exists in Info.plist.* If it exists - honor that and return that value.* If not - return YES stating performance collection is enabled.*/id dataCollectionPreferenceObject =[self.userDefaults objectForKey:kFPRConfigCollectionUserPreference];if (dataCollectionPreferenceObject) {dataCollectionPreference = [dataCollectionPreferenceObject boolValue];} else {dataCollectionPreferenceObject = [self objectForInfoDictionaryKey:kFPRConfigCollectionPlistKey];if (dataCollectionPreferenceObject) {dataCollectionPreference = [dataCollectionPreferenceObject boolValue];}}return dataCollectionPreference;}- (void)setInstrumentationEnabled:(BOOL)instrumentationEnabled {[self.userDefaults setBool:instrumentationEnabled forKey:kFPRConfigInstrumentationUserPreference];}- (BOOL)isInstrumentationEnabled {BOOL instrumentationPreference = YES;id instrumentationPreferenceObject =[self.userDefaults objectForKey:kFPRConfigInstrumentationUserPreference];/*** Check if the performance instrumentation preference key is available in NSUserDefaults.* If it exists - Just honor that and return that value.* If not - Check if firebase_performance_instrumentation_enabled exists in Info.plist.* If it exists - honor that and return that value.* If not - return YES stating performance instrumentation is enabled.*/if (instrumentationPreferenceObject) {instrumentationPreference = [instrumentationPreferenceObject boolValue];} else {instrumentationPreferenceObject =[self objectForInfoDictionaryKey:kFPRConfigInstrumentationPlistKey];if (instrumentationPreferenceObject) {instrumentationPreference = [instrumentationPreferenceObject boolValue];}}return instrumentationPreference;}#pragma mark - Fireperf SDK configurations.- (BOOL)sdkEnabled {BOOL enabled = YES;if (self.remoteConfigFlags) {enabled = [self.remoteConfigFlags performanceSDKEnabledWithDefaultValue:enabled];}// Check if the current version is one of the disabled versions.if ([[self sdkDisabledVersions] containsObject:[NSString stringWithUTF8String:kFPRSDKVersion]]) {enabled = NO;}// If there is a plist override, honor that value.// NOTE: PList override should ideally be used only for tests and not for production.id plistObject = [self objectForInfoDictionaryKey:@"firebase_performance_sdk_enabled"];if (plistObject) {enabled = [plistObject boolValue];}return enabled;}- (BOOL)diagnosticsEnabled {BOOL enabled = NO;/*** Check if the diagnostics preference key is available in NSUserDefaults.* If it exists - Just honor that and return that value.* If not - Check if firebase_performance_instrumentation_enabled exists in Info.plist.* If it exists - honor that and return that value.* If not - return NO stating diagnostics is disabled.*/id diagnosticsEnabledPreferenceObject =[self.userDefaults objectForKey:kFPRDiagnosticsUserPreference];if (diagnosticsEnabledPreferenceObject) {enabled = [diagnosticsEnabledPreferenceObject boolValue];} else {id diagnosticsEnabledObject = [self objectForInfoDictionaryKey:kFPRDiagnosticsEnabledPlistKey];if (diagnosticsEnabledObject) {enabled = [diagnosticsEnabledObject boolValue];}}return enabled;}- (NSSet<NSString *> *)sdkDisabledVersions {NSMutableSet<NSString *> *disabledVersions = [[NSMutableSet<NSString *> alloc] init];if (self.remoteConfigFlags) {NSSet<NSString *> *sdkDisabledVersions =[self.remoteConfigFlags sdkDisabledVersionsWithDefaultValue:[disabledVersions copy]];if (sdkDisabledVersions.count > 0) {[disabledVersions addObjectsFromArray:[sdkDisabledVersions allObjects]];}}return [disabledVersions copy];}- (int)logSource {/*** Order of preference of returning the log source.* If it is an autopush build (based on environment variable), always return* LogRequest_LogSource_FireperfAutopush (461). If there is a recent value of remote config fetch,* honor that value. If logSource cached value (NSUserDefaults value) exists, honor that. Fallback* to the default value LogRequest_LogSource_Fireperf (462).*/int logSource = 462;NSDictionary<NSString *, NSString *> *environment = [NSProcessInfo processInfo].environment;if (environment[@"FPR_AUTOPUSH_ENV"] != nil &&[environment[@"FPR_AUTOPUSH_ENV"] isEqualToString:@"1"]) {logSource = 461;} else {if (self.remoteConfigFlags) {logSource = [self.remoteConfigFlags logSourceWithDefaultValue:462];}}return logSource;}- (PrewarmDetectionMode)prewarmDetectionMode {PrewarmDetectionMode mode = PrewarmDetectionModeActivePrewarm;if (self.remoteConfigFlags) {mode = [self.remoteConfigFlags getIntValueForFlag:@"fpr_prewarm_detection"defaultValue:(int)mode];}return mode;}#pragma mark - Log sampling configurations.- (float)logTraceSamplingRate {float samplingRate = 1.0f;if (self.remoteConfigFlags) {float rcSamplingRate = [self.remoteConfigFlags traceSamplingRateWithDefaultValue:samplingRate];if (rcSamplingRate >= 0) {samplingRate = rcSamplingRate;}}return samplingRate;}- (float)logNetworkSamplingRate {float samplingRate = 1.0f;if (self.remoteConfigFlags) {float rcSamplingRate =[self.remoteConfigFlags networkRequestSamplingRateWithDefaultValue:samplingRate];if (rcSamplingRate >= 0) {samplingRate = rcSamplingRate;}}return samplingRate;}#pragma mark - Traces rate limiting configurations.- (uint32_t)foregroundEventCount {uint32_t eventCount = 300;if (self.remoteConfigFlags) {eventCount =[self.remoteConfigFlags rateLimitTraceCountInForegroundWithDefaultValue:eventCount];}return eventCount;}- (uint32_t)foregroundEventTimeLimit {uint32_t timeLimit = 600;if (self.remoteConfigFlags) {timeLimit = [self.remoteConfigFlags rateLimitTimeDurationWithDefaultValue:timeLimit];}uint32_t timeLimitInMinutes = timeLimit / 60;return timeLimitInMinutes;}- (uint32_t)backgroundEventCount {uint32_t eventCount = 30;if (self.remoteConfigFlags) {eventCount =[self.remoteConfigFlags rateLimitTraceCountInBackgroundWithDefaultValue:eventCount];}return eventCount;}- (uint32_t)backgroundEventTimeLimit {uint32_t timeLimit = 600;if (self.remoteConfigFlags) {timeLimit = [self.remoteConfigFlags rateLimitTimeDurationWithDefaultValue:timeLimit];}uint32_t timeLimitInMinutes = timeLimit / 60;return timeLimitInMinutes;}#pragma mark - Network requests rate limiting configurations.- (uint32_t)foregroundNetworkEventCount {uint32_t eventCount = 700;if (self.remoteConfigFlags) {eventCount = [self.remoteConfigFlagsrateLimitNetworkRequestCountInForegroundWithDefaultValue:eventCount];}return eventCount;}- (uint32_t)foregroundNetworkEventTimeLimit {uint32_t timeLimit = 600;if (self.remoteConfigFlags) {timeLimit = [self.remoteConfigFlags rateLimitTimeDurationWithDefaultValue:timeLimit];}uint32_t timeLimitInMinutes = timeLimit / 60;return timeLimitInMinutes;}- (uint32_t)backgroundNetworkEventCount {uint32_t eventCount = 70;if (self.remoteConfigFlags) {eventCount = [self.remoteConfigFlagsrateLimitNetworkRequestCountInBackgroundWithDefaultValue:eventCount];}return eventCount;}- (uint32_t)backgroundNetworkEventTimeLimit {uint32_t timeLimit = 600;if (self.remoteConfigFlags) {timeLimit = [self.remoteConfigFlags rateLimitTimeDurationWithDefaultValue:timeLimit];}uint32_t timeLimitInMinutes = timeLimit / 60;return timeLimitInMinutes;}#pragma mark - Sessions feature related configurations.- (float_t)sessionsSamplingPercentage {float samplingPercentage = 1.0f; // One Percent.if (self.remoteConfigFlags) {float rcSamplingRate =[self.remoteConfigFlags sessionSamplingRateWithDefaultValue:(samplingPercentage / 100)];if (rcSamplingRate >= 0) {samplingPercentage = rcSamplingRate * 100;}}id plistObject = [self objectForInfoDictionaryKey:@"sessionsSamplingPercentage"];if (plistObject) {samplingPercentage = [plistObject floatValue];}return samplingPercentage;}- (uint32_t)maxSessionLengthInMinutes {uint32_t sessionLengthInMinutes = 240;if (self.remoteConfigFlags) {sessionLengthInMinutes =[self.remoteConfigFlags sessionMaxDurationWithDefaultValue:sessionLengthInMinutes];}// If the session max length gets set to 0, default it to 240 minutes.if (sessionLengthInMinutes == 0) {return 240;}return sessionLengthInMinutes;}- (uint32_t)cpuSamplingFrequencyInForegroundInMS {uint32_t samplingFrequency = 100;if (self.remoteConfigFlags) {samplingFrequency = [self.remoteConfigFlagssessionGaugeCPUCaptureFrequencyInForegroundWithDefaultValue:samplingFrequency];}return samplingFrequency;}- (uint32_t)cpuSamplingFrequencyInBackgroundInMS {uint32_t samplingFrequency = 0;if (self.remoteConfigFlags) {samplingFrequency = [self.remoteConfigFlagssessionGaugeCPUCaptureFrequencyInBackgroundWithDefaultValue:samplingFrequency];}return samplingFrequency;}- (uint32_t)memorySamplingFrequencyInForegroundInMS {uint32_t samplingFrequency = 100;if (self.remoteConfigFlags) {samplingFrequency = [self.remoteConfigFlagssessionGaugeMemoryCaptureFrequencyInForegroundWithDefaultValue:samplingFrequency];}return samplingFrequency;}- (uint32_t)memorySamplingFrequencyInBackgroundInMS {uint32_t samplingFrequency = 0;if (self.remoteConfigFlags) {samplingFrequency = [self.remoteConfigFlagssessionGaugeMemoryCaptureFrequencyInBackgroundWithDefaultValue:samplingFrequency];}return samplingFrequency;}@end