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 "FirebasePerformance/Sources/Gauges/FPRGaugeManager.h"#import "FirebasePerformance/Sources/Gauges/FPRGaugeManager+Private.h"#import "FirebasePerformance/Sources/Common/FPRDiagnostics.h"#import "FirebasePerformance/Sources/Configurations/FPRConfigurations.h"#import "FirebasePerformance/Sources/FPRClient.h"#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeCollector.h"#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeCollector.h"#import <UIKit/UIKit.h>// Number of gauge data information after which that gets flushed to Google Data Transport.NSInteger const kGaugeDataBatchSize = 25;NS_EXTENSION_UNAVAILABLE("Firebase Performance is not supported for extensions.")@interface FPRGaugeManager () <FPRCPUGaugeCollectorDelegate, FPRMemoryGaugeCollectorDelegate>/** @brief List of gauges that are currently being actively captured. */@property(nonatomic, readwrite) FPRGauges activeGauges;/** @brief List of gauge information collected. Intentionally this is not a typed collection. Gauge* data could be CPU Gauge data or Memory gauge data.*/@property(nonatomic) NSMutableArray *gaugeData;/** @brief Currently active sessionID. */@property(nonatomic, readwrite, copy) NSString *currentSessionId;@end@implementation FPRGaugeManager+ (instancetype)sharedInstance {static FPRGaugeManager *instance = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{instance = [[FPRGaugeManager alloc] initWithGauges:FPRGaugeNone];});return instance;}- (instancetype)initWithGauges:(FPRGauges)gauges {self = [super init];if (self) {_activeGauges = FPRGaugeNone;_gaugeData = [[NSMutableArray alloc] init];_gaugeDataProtectionQueue =dispatch_queue_create("com.google.perf.gaugeManager.gaugeData", DISPATCH_QUEUE_SERIAL);_isColdStart = YES;[self startAppActivityTracking];}return self;}- (void)dealloc {[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIApplicationDidBecomeActiveNotificationobject:[UIApplication sharedApplication]];[[NSNotificationCenter defaultCenter] removeObserver:selfname:UIApplicationWillResignActiveNotificationobject:[UIApplication sharedApplication]];}/*** Starts tracking the application state changes.*/- (void)startAppActivityTracking {[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(appStateChanged:)name:UIApplicationDidBecomeActiveNotificationobject:[UIApplication sharedApplication]];[[NSNotificationCenter defaultCenter] addObserver:selfselector:@selector(appStateChanged:)name:UIApplicationWillResignActiveNotificationobject:[UIApplication sharedApplication]];}- (void)appStateChanged:(NSNotification *)notification {FPRApplicationState applicationState = [FPRAppActivityTracker sharedInstance].applicationState;[self.cpuGaugeCollector updateSamplingFrequencyForApplicationState:applicationState];[self.memoryGaugeCollector updateSamplingFrequencyForApplicationState:applicationState];self.isColdStart = NO;}#pragma mark - Implementation methods- (BOOL)gaugeCollectionEnabled {// Allow gauge collection to happen during cold start. During dispatch time, we do another check// to make sure if gauge collection is enabled. This is to accomodate gauge metric collection// during app_start scenario.if (self.isColdStart) {return YES;}// Check if the SDK is enabled to collect gauge data.BOOL sdkEnabled = [[FPRConfigurations sharedInstance] sdkEnabled];if (!sdkEnabled) {return NO;}return [FPRConfigurations sharedInstance].isDataCollectionEnabled;}- (void)startCollectingGauges:(FPRGauges)gauges forSessionId:(NSString *)sessionId {// Dispatch the already available gauge data with old sessionId.[self prepareAndDispatchCollectedGaugeDataWithSessionId:self.currentSessionId];self.currentSessionId = sessionId;if (self.gaugeCollectionEnabled) {if ((gauges & FPRGaugeCPU) == FPRGaugeCPU) {self.cpuGaugeCollector = [[FPRCPUGaugeCollector alloc] initWithDelegate:self];}if ((gauges & FPRGaugeMemory) == FPRGaugeMemory) {self.memoryGaugeCollector = [[FPRMemoryGaugeCollector alloc] initWithDelegate:self];}self.activeGauges = self.activeGauges | gauges;}}- (void)stopCollectingGauges:(FPRGauges)gauges {if ((gauges & FPRGaugeCPU) == FPRGaugeCPU) {self.cpuGaugeCollector = nil;}if ((gauges & FPRGaugeMemory) == FPRGaugeMemory) {self.memoryGaugeCollector = nil;}self.activeGauges = self.activeGauges & ~(gauges);// Flush out all the already collected gauge metrics[self prepareAndDispatchCollectedGaugeDataWithSessionId:self.currentSessionId];}- (void)collectAllGauges {if (self.cpuGaugeCollector) {[self.cpuGaugeCollector collectMetric];}if (self.memoryGaugeCollector) {[self.memoryGaugeCollector collectMetric];}}- (void)dispatchMetric:(id)gaugeMetric {// If the gauge metric is of type CPU, then dispatch only if CPU collection is enabled.if ([gaugeMetric isKindOfClass:[FPRCPUGaugeData class]] &&((self.activeGauges & FPRGaugeCPU) == FPRGaugeCPU)) {[self addGaugeData:gaugeMetric];}// If the gauge metric is of type memory, then dispatch only if memory collection is enabled.if ([gaugeMetric isKindOfClass:[FPRMemoryGaugeData class]] &&((self.activeGauges & FPRGaugeMemory) == FPRGaugeMemory)) {[self addGaugeData:gaugeMetric];}}#pragma mark - Utils- (void)prepareAndDispatchCollectedGaugeDataWithSessionId:(nullable NSString *)sessionId {dispatch_async(self.gaugeDataProtectionQueue, ^{NSArray *dispatchGauges = [self.gaugeData copy];self.gaugeData = [[NSMutableArray alloc] init];dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{if (dispatchGauges.count > 0 && sessionId != nil) {[[FPRClient sharedInstance] logGaugeMetric:dispatchGauges forSessionId:sessionId];FPRLogInfo(kFPRGaugeManagerDataCollected, @"Logging %lu gauge metrics.",(unsigned long)dispatchGauges.count);}});});}/*** Adds the gauge to the batch and decide on when to dispatch the events to Google Data Transport.** @param gauge Gauge data received from the collectors.*/- (void)addGaugeData:(id)gauge {dispatch_async(self.gaugeDataProtectionQueue, ^{if (gauge) {[self.gaugeData addObject:gauge];if (self.gaugeData.count >= kGaugeDataBatchSize) {[self prepareAndDispatchCollectedGaugeDataWithSessionId:self.currentSessionId];}}});}#pragma mark - FPRCPUGaugeCollectorDelegate methods- (void)cpuGaugeCollector:(FPRCPUGaugeCollector *)collector gaugeData:(FPRCPUGaugeData *)gaugeData {[self addGaugeData:gaugeData];}#pragma mark - FPRMemoryGaugeCollectorDelegate methods- (void)memoryGaugeCollector:(FPRMemoryGaugeCollector *)collectorgaugeData:(FPRMemoryGaugeData *)gaugeData {[self addGaugeData:gaugeData];}@end