Proyectos de Subversion Iphone Microlearning

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
// Copyright 2020 Google LLC
2
//
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
6
//
7
//      http://www.apache.org/licenses/LICENSE-2.0
8
//
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
14
 
15
#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags.h"
16
#import "FirebasePerformance/Sources/Configurations/FPRConfigurations+Private.h"
17
#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h"
18
#import "FirebasePerformance/Sources/Configurations/FPRRemoteConfigFlags+Private.h"
19
 
20
#import "FirebasePerformance/Sources/FPRConsoleLogger.h"
21
 
22
#import "FirebaseCore/Sources/Private/FirebaseCoreInternal.h"
23
 
24
#define ONE_DAY_SECONDS 24 * 60 * 60
25
 
26
static NSDate *FPRAppStartTime = nil;
27
 
28
typedef NS_ENUM(NSInteger, FPRConfigValueType) {
29
  // Config value type String.
30
  FPRConfigValueTypeString,
31
  // Config value type Bool.
32
  FPRConfigValueTypeBool,
33
  // Config value type Integer.
34
  FPRConfigValueTypeInteger,
35
  // Config value type Float.
36
  FPRConfigValueTypeFloat,
37
};
38
 
39
@interface FPRRemoteConfigFlags ()
40
 
41
/** @brief Represents if a fetch is currently in progress. */
42
@property(atomic) BOOL fetchInProgress;
43
 
44
/** @brief Dictionary of different config keys and value types. */
45
@property(nonatomic) NSDictionary<NSString *, NSNumber *> *configKeys;
46
 
47
/** @brief Last time the configs were cached. */
48
@property(nonatomic) NSDate *lastCachedTime;
49
 
50
@end
51
 
52
@implementation FPRRemoteConfigFlags
53
 
54
+ (void)load {
55
  FPRAppStartTime = [NSDate date];
56
}
57
 
58
+ (nullable instancetype)sharedInstance {
59
  static FPRRemoteConfigFlags *instance = nil;
60
  static dispatch_once_t onceToken;
61
  dispatch_once(&onceToken, ^{
62
    FIRRemoteConfig *rc = [FIRRemoteConfig remoteConfigWithFIRNamespace:@"fireperf"
63
                                                                    app:[FIRApp defaultApp]];
64
    instance = [[FPRRemoteConfigFlags alloc] initWithRemoteConfig:rc];
65
  });
66
  return instance;
67
}
68
 
69
- (instancetype)initWithRemoteConfig:(FIRRemoteConfig *)config {
70
  self = [super init];
71
  if (self) {
72
    _fprRemoteConfig = config;
73
    _userDefaults = [FPRConfigurations sharedInstance].userDefaults;
74
    self.fetchInProgress = NO;
75
 
76
    // Set the overall delay to 5+random(25) making the config fetch delay at a max of 30 seconds
77
    self.applicationStartTime = FPRAppStartTime;
78
    self.appStartConfigFetchDelayInSeconds =
79
        kFPRMinAppStartConfigFetchDelayInSeconds + arc4random_uniform(25);
80
 
81
    NSMutableDictionary<NSString *, NSNumber *> *keysToCache =
82
        [[NSMutableDictionary<NSString *, NSNumber *> alloc] init];
83
    [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_log_source"];
84
    [keysToCache setObject:@(FPRConfigValueTypeBool) forKey:@"fpr_enabled"];
85
    [keysToCache setObject:@(FPRConfigValueTypeString) forKey:@"fpr_disabled_ios_versions"];
86
    [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_rl_time_limit_sec"];
87
    [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_rl_trace_event_count_fg"];
88
    [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_rl_trace_event_count_bg"];
89
    [keysToCache setObject:@(FPRConfigValueTypeInteger)
90
                    forKey:@"fpr_rl_network_request_event_count_fg"];
91
    [keysToCache setObject:@(FPRConfigValueTypeInteger)
92
                    forKey:@"fpr_rl_network_request_event_count_bg"];
93
    [keysToCache setObject:@(FPRConfigValueTypeFloat) forKey:@"fpr_vc_trace_sampling_rate"];
94
    [keysToCache setObject:@(FPRConfigValueTypeFloat)
95
                    forKey:@"fpr_vc_network_request_sampling_rate"];
96
    [keysToCache setObject:@(FPRConfigValueTypeFloat) forKey:@"fpr_vc_session_sampling_rate"];
97
    [keysToCache setObject:@(FPRConfigValueTypeInteger)
98
                    forKey:@"fpr_session_gauge_cpu_capture_frequency_fg_ms"];
99
    [keysToCache setObject:@(FPRConfigValueTypeInteger)
100
                    forKey:@"fpr_session_gauge_cpu_capture_frequency_bg_ms"];
101
    [keysToCache setObject:@(FPRConfigValueTypeInteger)
102
                    forKey:@"fpr_session_gauge_memory_capture_frequency_fg_ms"];
103
    [keysToCache setObject:@(FPRConfigValueTypeInteger)
104
                    forKey:@"fpr_session_gauge_memory_capture_frequency_bg_ms"];
105
    [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_session_max_duration_min"];
106
    [keysToCache setObject:@(FPRConfigValueTypeInteger) forKey:@"fpr_prewarm_detection"];
107
    self.configKeys = [keysToCache copy];
108
 
109
    [self update];
110
  }
111
  return self;
112
}
113
 
114
- (void)update {
115
  // If a fetch is already happening, do not attempt a fetch.
116
  if (self.fetchInProgress) {
117
    return;
118
  }
119
 
120
  NSTimeInterval timeIntervalSinceLastFetch =
121
      [self.fprRemoteConfig.lastFetchTime timeIntervalSinceNow];
122
  NSTimeInterval timeSinceAppStart = [self.applicationStartTime timeIntervalSinceNow];
123
  if ((ABS(timeSinceAppStart) > self.appStartConfigFetchDelayInSeconds) &&
124
      (!self.fprRemoteConfig.lastFetchTime ||
125
       ABS(timeIntervalSinceLastFetch) > kFPRConfigFetchIntervalInSeconds)) {
126
    self.fetchInProgress = YES;
127
    [self.fprRemoteConfig
128
        fetchAndActivateWithCompletionHandler:^(FIRRemoteConfigFetchAndActivateStatus status,
129
                                                NSError *_Nullable error) {
130
          self.lastFetchStatus = self.fprRemoteConfig.lastFetchStatus;
131
          if (status == FIRRemoteConfigFetchAndActivateStatusError) {
132
            FPRLogError(kFPRConfigurationFetchFailure, @"Unable to fetch configurations.");
133
          } else {
134
            self.lastFetchedTime = self.fprRemoteConfig.lastFetchTime;
135
            // If a fetch was successful,
136
            // 1. Clear the old cache
137
            [self resetCache];
138
            // 2. Cache the new config values
139
            [self cacheConfigValues];
140
          }
141
          self.fetchInProgress = NO;
142
        }];
143
  } else if (self.fprRemoteConfig.lastFetchTime) {
144
    // Update the last fetched time to know that remote config fetch has happened in the past.
145
    self.lastFetchedTime = self.fprRemoteConfig.lastFetchTime;
146
  }
147
}
148
 
149
#pragma mark - Util methods.
150
 
151
- (void)resetCache {
152
  [self.configKeys
153
      enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *valueType, BOOL *stop) {
154
        NSString *cacheKey = [NSString stringWithFormat:@"%@.%@", kFPRConfigPrefix, key];
155
        [self.userDefaults removeObjectForKey:cacheKey];
156
      }];
157
}
158
 
159
- (void)cacheConfigValues {
160
  [self.configKeys
161
      enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *valueType, BOOL *stop) {
162
        FIRRemoteConfigValue *rcValue = [self.fprRemoteConfig configValueForKey:key];
163
 
164
        // Cache only values that comes from remote.
165
        if (rcValue != nil && rcValue.source == FIRRemoteConfigSourceRemote) {
166
          FPRConfigValueType configValueType = [valueType integerValue];
167
          NSString *cacheKey = [NSString stringWithFormat:@"%@.%@", kFPRConfigPrefix, key];
168
 
169
          if (configValueType == FPRConfigValueTypeInteger) {
170
            NSInteger integerValue = [[rcValue numberValue] integerValue];
171
            [self.userDefaults setInteger:integerValue forKey:cacheKey];
172
          } else if (configValueType == FPRConfigValueTypeFloat) {
173
            float floatValue = [[rcValue numberValue] floatValue];
174
            [self.userDefaults setFloat:floatValue forKey:cacheKey];
175
          } else if (configValueType == FPRConfigValueTypeBool) {
176
            BOOL boolValue = [rcValue boolValue];
177
            [self.userDefaults setBool:boolValue forKey:cacheKey];
178
          } else if (configValueType == FPRConfigValueTypeString) {
179
            NSString *stringValue = [rcValue stringValue];
180
            [self.userDefaults setObject:stringValue forKey:cacheKey];
181
          }
182
 
183
          self.lastCachedTime = [NSDate date];
184
        }
185
      }];
186
}
187
 
188
- (id)cachedValueForConfigFlag:(NSString *)configFlag {
189
  // If the cached value is too old, return nil.
190
  if (ABS([self.lastFetchedTime timeIntervalSinceNow]) > 7 * ONE_DAY_SECONDS) {
191
    return nil;
192
  }
193
 
194
  NSString *cacheKey = [NSString stringWithFormat:@"%@.%@", kFPRConfigPrefix, configFlag];
195
  id cachedValueObject = [self.userDefaults objectForKey:cacheKey];
196
  return cachedValueObject;
197
}
198
 
199
#pragma mark - Config value fetch methods.
200
 
201
- (NSString *)getStringValueForFlag:(NSString *)flagName defaultValue:(NSString *)defaultValue {
202
  id cachedValueObject = [self cachedValueForConfigFlag:flagName];
203
  if ([cachedValueObject isKindOfClass:[NSString class]]) {
204
    return (NSString *)cachedValueObject;
205
  }
206
 
207
  return defaultValue;
208
}
209
 
210
- (int)getIntValueForFlag:(NSString *)flagName defaultValue:(int)defaultValue {
211
  id cachedValueObject = [self cachedValueForConfigFlag:flagName];
212
  if (cachedValueObject) {
213
    return [cachedValueObject intValue];
214
  }
215
 
216
  return defaultValue;
217
}
218
 
219
- (float)getFloatValueForFlag:(NSString *)flagName defaultValue:(float)defaultValue {
220
  id cachedValueObject = [self cachedValueForConfigFlag:flagName];
221
  if (cachedValueObject) {
222
    return [cachedValueObject floatValue];
223
  }
224
 
225
  return defaultValue;
226
}
227
 
228
- (BOOL)getBoolValueForFlag:(NSString *)flagName defaultValue:(BOOL)defaultValue {
229
  id cachedValueObject = [self cachedValueForConfigFlag:flagName];
230
  if (cachedValueObject) {
231
    return [cachedValueObject boolValue];
232
  }
233
 
234
  return defaultValue;
235
}
236
 
237
#pragma mark - Configuration methods.
238
 
239
- (int)logSourceWithDefaultValue:(int)logSource {
240
  return [self getIntValueForFlag:@"fpr_log_source" defaultValue:logSource];
241
}
242
 
243
- (BOOL)performanceSDKEnabledWithDefaultValue:(BOOL)sdkEnabled {
244
  /* Order of preference:
245
   * 1. If remote config fetch was a failure, return NO.
246
   * 2. If the fetch was successful, but RC does not have the value (not a remote value),
247
   *    return YES.
248
   * 3. Else, use the value from RC.
249
   */
250
 
251
  if (self.lastFetchStatus == FIRRemoteConfigFetchStatusFailure) {
252
    return NO;
253
  }
254
 
255
  return [self getBoolValueForFlag:@"fpr_enabled" defaultValue:sdkEnabled];
256
}
257
 
258
- (NSSet<NSString *> *)sdkDisabledVersionsWithDefaultValue:(NSSet<NSString *> *)sdkVersions {
259
  NSMutableSet<NSString *> *disabledVersions = [[NSMutableSet<NSString *> alloc] init];
260
 
261
  NSString *sdkVersionsString = [[self getStringValueForFlag:@"fpr_disabled_ios_versions"
262
                                                defaultValue:@""]
263
      stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
264
  if (sdkVersionsString.length > 0) {
265
    NSArray<NSString *> *sdkVersionStrings = [sdkVersionsString componentsSeparatedByString:@";"];
266
    for (NSString *sdkVersionString in sdkVersionStrings) {
267
      NSString *trimmedString = [sdkVersionString
268
          stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceCharacterSet]];
269
      if (trimmedString.length > 0) {
270
        [disabledVersions addObject:trimmedString];
271
      }
272
    }
273
  } else {
274
    return sdkVersions;
275
  }
276
 
277
  return [disabledVersions copy];
278
}
279
 
280
#pragma mark - Rate limiting flags
281
 
282
- (int)rateLimitTimeDurationWithDefaultValue:(int)durationInSeconds {
283
  return [self getIntValueForFlag:@"fpr_rl_time_limit_sec" defaultValue:durationInSeconds];
284
}
285
 
286
- (int)rateLimitTraceCountInForegroundWithDefaultValue:(int)eventCount {
287
  return [self getIntValueForFlag:@"fpr_rl_trace_event_count_fg" defaultValue:eventCount];
288
}
289
 
290
- (int)rateLimitTraceCountInBackgroundWithDefaultValue:(int)eventCount {
291
  return [self getIntValueForFlag:@"fpr_rl_trace_event_count_bg" defaultValue:eventCount];
292
}
293
 
294
- (int)rateLimitNetworkRequestCountInForegroundWithDefaultValue:(int)eventCount {
295
  return [self getIntValueForFlag:@"fpr_rl_network_request_event_count_fg" defaultValue:eventCount];
296
}
297
 
298
- (int)rateLimitNetworkRequestCountInBackgroundWithDefaultValue:(int)eventCount {
299
  return [self getIntValueForFlag:@"fpr_rl_network_request_event_count_bg" defaultValue:eventCount];
300
}
301
 
302
#pragma mark - Sampling flags
303
 
304
- (float)traceSamplingRateWithDefaultValue:(float)samplingRate {
305
  return [self getFloatValueForFlag:@"fpr_vc_trace_sampling_rate" defaultValue:samplingRate];
306
}
307
 
308
- (float)networkRequestSamplingRateWithDefaultValue:(float)samplingRate {
309
  return [self getFloatValueForFlag:@"fpr_vc_network_request_sampling_rate"
310
                       defaultValue:samplingRate];
311
}
312
 
313
#pragma mark - Session flags
314
 
315
- (float)sessionSamplingRateWithDefaultValue:(float)samplingRate {
316
  return [self getFloatValueForFlag:@"fpr_vc_session_sampling_rate" defaultValue:samplingRate];
317
}
318
 
319
- (int)sessionGaugeCPUCaptureFrequencyInForegroundWithDefaultValue:(int)defaultFrequency {
320
  return [self getIntValueForFlag:@"fpr_session_gauge_cpu_capture_frequency_fg_ms"
321
                     defaultValue:defaultFrequency];
322
}
323
 
324
- (int)sessionGaugeCPUCaptureFrequencyInBackgroundWithDefaultValue:(int)defaultFrequency {
325
  return [self getIntValueForFlag:@"fpr_session_gauge_cpu_capture_frequency_bg_ms"
326
                     defaultValue:defaultFrequency];
327
}
328
 
329
- (int)sessionGaugeMemoryCaptureFrequencyInForegroundWithDefaultValue:(int)defaultFrequency {
330
  return [self getIntValueForFlag:@"fpr_session_gauge_memory_capture_frequency_fg_ms"
331
                     defaultValue:defaultFrequency];
332
}
333
 
334
- (int)sessionGaugeMemoryCaptureFrequencyInBackgroundWithDefaultValue:(int)defaultFrequency {
335
  return [self getIntValueForFlag:@"fpr_session_gauge_memory_capture_frequency_bg_ms"
336
                     defaultValue:defaultFrequency];
337
}
338
 
339
- (int)sessionMaxDurationWithDefaultValue:(int)maxDurationInMinutes {
340
  return [self getIntValueForFlag:@"fpr_session_max_duration_min"
341
                     defaultValue:maxDurationInMinutes];
342
}
343
 
344
@end