mirror of
https://github.com/firebase/firebase-ios-sdk
synced 2026-11-09 22:36:01 +05:45
* Create NanoPb code generation scripts (#8336) * Create NanoPb code generation scripts * Fix style and add README * Fix copyright * Update proto_generator.py * Update README.md * Create nanopb options file. (#8371) * Create NanoPb code generation scripts * Fix style and add README * Fix copyright * Update perf_metrics.options * Update options with map * Add generated proto files. * Update imports. * Convert Objective-C Classes to Nanopb (#8387) * Convert all traces to nanopb * Refactor for loop. * Add set has_application_info to true. * Incorporated comments. * Fix style * Create NanoPb code generation scripts (#8336) * Create NanoPb code generation scripts * Fix style and add README * Fix copyright * Update proto_generator.py * Update README.md * Create nanopb options file. (#8371) * Create NanoPb code generation scripts * Fix style and add README * Fix copyright * Update perf_metrics.options * Update options with map * Add generated proto files. * Update imports. * Convert Objective-C Classes to Nanopb (#8387) * Convert all traces to nanopb * Refactor for loop. * Add set has_application_info to true. * Incorporated comments. * Fix style * Fix style * Convert nanopb struct to GDTCOREventDataObject and update the source code to use nanopb struct. (#8439) * Convert all traces to nanopb * Refactor for loop. * WIP: nanopb conversion in FPRClient and FPREvent * Update FPRClientTest.m * Update FPRClient.m * Update FPRClientTest.m * Add set has_application_info to true. * Remove proto imports. * Set has_fields to be true in FPRTestUtils.m * Completed GDTEvent conversion. * Fix sampler tests. * Fix style * Refactor nanopb struct setter * Fix style * Fix pod-lib-lint failures. * Update FPRClient with decoded string * Set some "_has" fields to true. * Add prefix to extern methods. * Fix style. * Update FPRClient to use trace.name without FPRDecodeString * Fix style * Incorporate comments. * Integrate Performance with SPM (#8476) * Convert all traces to nanopb * Refactor for loop. * WIP: nanopb conversion in FPRClient and FPREvent * Update FPRClientTest.m * Update FPRClient.m * Update FPRClientTest.m * Add set has_application_info to true. * Remove proto imports. * Set has_fields to be true in FPRTestUtils.m * Completed GDTEvent conversion. * Fix sampler tests. * Fix style * Refactor nanopb struct setter * Fix style * Fix pod-lib-lint failures. * Update FPRClient with decoded string * Set some "_has" fields to true. * Add prefix to extern methods. * Fix style. * Update FPRClient to use trace.name without FPRDecodeString * Fix style * Update Package.swift * Update Package.swift * Update Package.swift * Made SDK and unit tests buildable. * Made all unit tests passing. * Update keyWindow style. * Add Performance to workflow. * Update FPRUIViewControllerInstrument.h * Incorporate comments. * Add Performance to SwiftPMTests. * Update style. * Fix Unit tests and update workflow. * Add FirebasePerformance wrapper * Update import statement. * Update style. * Update performance.yml * Create PerformanceUnit.xcscheme * Update objc-module.m * Update objc-module.m * Updae objc-header.m * Update objc-header.m * Incorporate feedback. * Update objc-header.m * Organize folder structure to fix the spm tests. * Update public import path * Delete xcodebuild.log * Update workflow files * Fix failing swift-test for Perf SPM (#8507) * Fix UIKit import * Update FPRNetworkTraceTest.m * Exclude TARGET_OS_MACCATALYST from objc header test * Update main.swift * Update main.swift Co-authored-by: Paul Beusterien <paulbeusterien@google.com> * Remove Protobuf dependency (#8511) * Remove protobuf dependency * Update FirebasePerformance.podspec * Incorporate comments. * Update UIKit import Co-authored-by: Paul Beusterien <paulbeusterien@google.com>
536 lines
23 KiB
Objective-C
536 lines
23 KiB
Objective-C
// Copyright 2021 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/FPRNanoPbUtils.h"
|
|
|
|
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
#import <CoreTelephony/CTCarrier.h>
|
|
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
|
|
#endif
|
|
#import <SystemConfiguration/SystemConfiguration.h>
|
|
|
|
#import "FirebasePerformance/Sources/Common/FPRConstants.h"
|
|
#import "FirebasePerformance/Sources/FIRPerformance+Internal.h"
|
|
#import "FirebasePerformance/Sources/FPRDataUtils.h"
|
|
#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h"
|
|
#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h"
|
|
#import "FirebasePerformance/Sources/Timer/FIRTrace+Private.h"
|
|
|
|
#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.h"
|
|
#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h"
|
|
|
|
#define BYTES_TO_KB(x) (x / 1024)
|
|
|
|
static firebase_perf_v1_NetworkRequestMetric_HttpMethod FPRHTTPMethodForString(
|
|
NSString *methodString);
|
|
static firebase_perf_v1_NetworkConnectionInfo_NetworkType FPRNetworkConnectionInfoNetworkType(void);
|
|
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
static firebase_perf_v1_NetworkConnectionInfo_MobileSubtype FPRCellularNetworkType(void);
|
|
#endif
|
|
NSArray<FPRSessionDetails *> *FPRMakeFirstSessionVerbose(NSArray<FPRSessionDetails *> *sessions);
|
|
|
|
#pragma mark - Nanopb creation utilities
|
|
|
|
/** Converts the network method string to a value defined in the enum
|
|
* firebase_perf_v1_NetworkRequestMetric_HttpMethod.
|
|
* @return Enum value of the method string. If there is no mapping value defined for the method
|
|
* firebase_perf_v1_NetworkRequestMetric_HttpMethod_HTTP_METHOD_UNKNOWN is returned.
|
|
*/
|
|
static firebase_perf_v1_NetworkRequestMetric_HttpMethod FPRHTTPMethodForString(
|
|
NSString *methodString) {
|
|
static NSDictionary<NSString *, NSNumber *> *HTTPToFPRNetworkTraceMethod;
|
|
static dispatch_once_t onceToken = 0;
|
|
dispatch_once(&onceToken, ^{
|
|
HTTPToFPRNetworkTraceMethod = @{
|
|
@"GET" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_GET),
|
|
@"POST" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_POST),
|
|
@"PUT" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_PUT),
|
|
@"DELETE" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_DELETE),
|
|
@"HEAD" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_HEAD),
|
|
@"PATCH" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_PATCH),
|
|
@"OPTIONS" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_OPTIONS),
|
|
@"TRACE" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_TRACE),
|
|
@"CONNECT" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_CONNECT),
|
|
};
|
|
});
|
|
|
|
NSNumber *HTTPMethod = HTTPToFPRNetworkTraceMethod[methodString];
|
|
if (HTTPMethod == nil) {
|
|
return firebase_perf_v1_NetworkRequestMetric_HttpMethod_HTTP_METHOD_UNKNOWN;
|
|
}
|
|
return HTTPMethod.intValue;
|
|
}
|
|
|
|
/** Get the current network connection type in firebase_perf_v1_NetworkConnectionInfo_NetworkType
|
|
* format.
|
|
* @return Current network connection type.
|
|
*/
|
|
static firebase_perf_v1_NetworkConnectionInfo_NetworkType FPRNetworkConnectionInfoNetworkType() {
|
|
firebase_perf_v1_NetworkConnectionInfo_NetworkType networkType =
|
|
firebase_perf_v1_NetworkConnectionInfo_NetworkType_NONE;
|
|
|
|
static SCNetworkReachabilityRef reachabilityRef = 0;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorSystemDefault, "google.com");
|
|
});
|
|
|
|
SCNetworkReachabilityFlags reachabilityFlags = 0;
|
|
SCNetworkReachabilityGetFlags(reachabilityRef, &reachabilityFlags);
|
|
|
|
// Parse the network flags to set the network type.
|
|
if (reachabilityFlags & kSCNetworkReachabilityFlagsReachable) {
|
|
if (reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN) {
|
|
networkType = firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE;
|
|
} else {
|
|
networkType = firebase_perf_v1_NetworkConnectionInfo_NetworkType_WIFI;
|
|
}
|
|
}
|
|
|
|
return networkType;
|
|
}
|
|
|
|
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
/** Get the current cellular network connection type in
|
|
* firebase_perf_v1_NetworkConnectionInfo_MobileSubtype format.
|
|
* @return Current cellular network connection type.
|
|
*/
|
|
static firebase_perf_v1_NetworkConnectionInfo_MobileSubtype FPRCellularNetworkType() {
|
|
static NSDictionary<NSString *, NSNumber *> *cellularNetworkToMobileSubtype;
|
|
static dispatch_once_t onceToken = 0;
|
|
dispatch_once(&onceToken, ^{
|
|
cellularNetworkToMobileSubtype = @{
|
|
CTRadioAccessTechnologyGPRS : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_GPRS),
|
|
CTRadioAccessTechnologyEdge : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EDGE),
|
|
CTRadioAccessTechnologyWCDMA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_CDMA),
|
|
CTRadioAccessTechnologyHSDPA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSDPA),
|
|
CTRadioAccessTechnologyHSUPA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSUPA),
|
|
CTRadioAccessTechnologyCDMA1x : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_CDMA),
|
|
CTRadioAccessTechnologyCDMAEVDORev0 :
|
|
@(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_0),
|
|
CTRadioAccessTechnologyCDMAEVDORevA :
|
|
@(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_A),
|
|
CTRadioAccessTechnologyCDMAEVDORevB :
|
|
@(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_B),
|
|
CTRadioAccessTechnologyeHRPD : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EHRPD),
|
|
CTRadioAccessTechnologyLTE : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_LTE)
|
|
};
|
|
});
|
|
|
|
NSString *networkString = FPRNetworkInfo().currentRadioAccessTechnology;
|
|
NSNumber *cellularNetworkType = cellularNetworkToMobileSubtype[networkString];
|
|
return cellularNetworkType.intValue;
|
|
}
|
|
#endif
|
|
|
|
#pragma mark - Nanopb decode and encode helper methods
|
|
|
|
pb_bytes_array_t *FPREncodeData(NSData *data) {
|
|
pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length));
|
|
if (pbBytesArray != NULL) {
|
|
[data getBytes:pbBytesArray->bytes length:data.length];
|
|
pbBytesArray->size = (pb_size_t)data.length;
|
|
}
|
|
return pbBytesArray;
|
|
}
|
|
|
|
pb_bytes_array_t *FPREncodeString(NSString *string) {
|
|
NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding];
|
|
return FPREncodeData(stringBytes);
|
|
}
|
|
|
|
NSData *FPRDecodeData(pb_bytes_array_t *pbData) {
|
|
NSData *data = [NSData dataWithBytes:&(pbData->bytes) length:pbData->size];
|
|
return data;
|
|
}
|
|
|
|
NSString *FPRDecodeString(pb_bytes_array_t *pbData) {
|
|
NSData *data = FPRDecodeData(pbData);
|
|
return [NSString stringWithCString:[data bytes] encoding:NSUTF8StringEncoding];
|
|
}
|
|
|
|
StringToStringMap *_Nullable FPREncodeStringToStringMap(NSDictionary *_Nullable dict) {
|
|
StringToStringMap *map = calloc(dict.count, sizeof(StringToStringMap));
|
|
__block NSUInteger index = 0;
|
|
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
|
|
map[index].key = FPREncodeString(key);
|
|
map[index].value = FPREncodeString(value);
|
|
index++;
|
|
}];
|
|
return map;
|
|
}
|
|
|
|
NSDictionary<NSString *, NSString *> *FPRDecodeStringToStringMap(StringToStringMap *map,
|
|
NSInteger count) {
|
|
NSMutableDictionary<NSString *, NSString *> *dict = [[NSMutableDictionary alloc] init];
|
|
for (int i = 0; i < count; i++) {
|
|
NSString *key = FPRDecodeString(map[i].key);
|
|
NSString *value = FPRDecodeString(map[i].value);
|
|
dict[key] = value;
|
|
}
|
|
return [dict copy];
|
|
}
|
|
|
|
StringToNumberMap *_Nullable FPREncodeStringToNumberMap(NSDictionary *_Nullable dict) {
|
|
StringToNumberMap *map = calloc(dict.count, sizeof(StringToNumberMap));
|
|
__block NSUInteger index = 0;
|
|
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *value, BOOL *stop) {
|
|
map[index].key = FPREncodeString(key);
|
|
map[index].value = [value longLongValue];
|
|
map[index].has_value = true;
|
|
index++;
|
|
}];
|
|
return map;
|
|
}
|
|
|
|
NSDictionary<NSString *, NSNumber *> *_Nullable FPRDecodeStringToNumberMap(
|
|
StringToNumberMap *_Nullable map, NSInteger count) {
|
|
NSMutableDictionary<NSString *, NSNumber *> *dict = [[NSMutableDictionary alloc] init];
|
|
for (int i = 0; i < count; i++) {
|
|
if (map[i].has_value) {
|
|
NSString *key = FPRDecodeString(map[i].key);
|
|
NSNumber *value = [NSNumber numberWithLongLong:map[i].value];
|
|
dict[key] = value;
|
|
}
|
|
}
|
|
return [dict copy];
|
|
}
|
|
|
|
firebase_perf_v1_PerfSession *FPREncodePerfSessions(NSArray<FPRSessionDetails *> *sessions,
|
|
NSInteger count) {
|
|
firebase_perf_v1_PerfSession *perfSessions = calloc(count, sizeof(firebase_perf_v1_PerfSession));
|
|
__block NSUInteger perfSessionIndex = 0;
|
|
|
|
[sessions enumerateObjectsUsingBlock:^(FPRSessionDetails *_Nonnull session, NSUInteger index,
|
|
BOOL *_Nonnull stop) {
|
|
perfSessions[perfSessionIndex].session_id = FPREncodeString(session.sessionId);
|
|
perfSessions[perfSessionIndex].session_verbosity_count = 0;
|
|
if ((session.options & FPRSessionOptionsEvents) ||
|
|
(session.options & FPRSessionOptionsGauges)) {
|
|
perfSessions[perfSessionIndex].session_verbosity =
|
|
calloc(perfSessions[perfSessionIndex].session_verbosity_count,
|
|
sizeof(firebase_perf_v1_SessionVerbosity));
|
|
perfSessions[perfSessionIndex].session_verbosity[0] =
|
|
firebase_perf_v1_SessionVerbosity_GAUGES_AND_SYSTEM_EVENTS;
|
|
perfSessions[perfSessionIndex].session_verbosity_count = 1;
|
|
}
|
|
perfSessionIndex++;
|
|
}];
|
|
return perfSessions;
|
|
}
|
|
|
|
#pragma mark - Public methods
|
|
|
|
firebase_perf_v1_PerfMetric FPRGetPerfMetricMessage(NSString *appID) {
|
|
firebase_perf_v1_PerfMetric perfMetricMessage = firebase_perf_v1_PerfMetric_init_default;
|
|
FPRSetApplicationInfo(&perfMetricMessage, FPRGetApplicationInfoMessage());
|
|
perfMetricMessage.application_info.google_app_id = FPREncodeString(appID);
|
|
|
|
return perfMetricMessage;
|
|
}
|
|
|
|
firebase_perf_v1_ApplicationInfo FPRGetApplicationInfoMessage() {
|
|
firebase_perf_v1_ApplicationInfo appInfoMessage = firebase_perf_v1_ApplicationInfo_init_default;
|
|
firebase_perf_v1_IosApplicationInfo iosAppInfo = firebase_perf_v1_IosApplicationInfo_init_default;
|
|
NSBundle *mainBundle = [NSBundle mainBundle];
|
|
iosAppInfo.bundle_short_version =
|
|
FPREncodeString([mainBundle infoDictionary][@"CFBundleShortVersionString"]);
|
|
iosAppInfo.sdk_version = FPREncodeString([NSString stringWithUTF8String:kFPRSDKVersion]);
|
|
iosAppInfo.network_connection_info.network_type = FPRNetworkConnectionInfoNetworkType();
|
|
iosAppInfo.has_network_connection_info = true;
|
|
iosAppInfo.network_connection_info.has_network_type = true;
|
|
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
CTTelephonyNetworkInfo *networkInfo = FPRNetworkInfo();
|
|
CTCarrier *provider = networkInfo.subscriberCellularProvider;
|
|
NSString *mccMnc = FPRValidatedMccMnc(provider.mobileCountryCode, provider.mobileNetworkCode);
|
|
if (mccMnc) {
|
|
iosAppInfo.mcc_mnc = FPREncodeString(mccMnc);
|
|
}
|
|
if (iosAppInfo.network_connection_info.network_type ==
|
|
firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE) {
|
|
iosAppInfo.network_connection_info.mobile_subtype = FPRCellularNetworkType();
|
|
iosAppInfo.network_connection_info.has_mobile_subtype = true;
|
|
}
|
|
#endif
|
|
appInfoMessage.ios_app_info = iosAppInfo;
|
|
appInfoMessage.has_ios_app_info = true;
|
|
|
|
NSDictionary<NSString *, NSString *> *attributes =
|
|
[[FIRPerformance sharedInstance].attributes mutableCopy];
|
|
appInfoMessage.custom_attributes_count = (pb_size_t)attributes.count;
|
|
appInfoMessage.custom_attributes =
|
|
(firebase_perf_v1_ApplicationInfo_CustomAttributesEntry *)FPREncodeStringToStringMap(
|
|
attributes);
|
|
|
|
return appInfoMessage;
|
|
}
|
|
|
|
firebase_perf_v1_TraceMetric FPRGetTraceMetric(FIRTrace *trace) {
|
|
firebase_perf_v1_TraceMetric traceMetric = firebase_perf_v1_TraceMetric_init_default;
|
|
traceMetric.name = FPREncodeString(trace.name);
|
|
|
|
// Set if the trace is an internally created trace.
|
|
traceMetric.is_auto = trace.isInternal;
|
|
traceMetric.has_is_auto = true;
|
|
|
|
// Convert the trace duration from seconds to microseconds.
|
|
traceMetric.duration_us = trace.totalTraceTimeInterval * USEC_PER_SEC;
|
|
traceMetric.has_duration_us = true;
|
|
|
|
// Convert the start time from seconds to microseconds.
|
|
traceMetric.client_start_time_us = trace.startTimeSinceEpoch * USEC_PER_SEC;
|
|
traceMetric.has_client_start_time_us = true;
|
|
|
|
// Filling counters
|
|
NSDictionary<NSString *, NSNumber *> *counters = trace.counters;
|
|
traceMetric.counters_count = (pb_size_t)counters.count;
|
|
traceMetric.counters =
|
|
(firebase_perf_v1_TraceMetric_CountersEntry *)FPREncodeStringToNumberMap(counters);
|
|
|
|
// Filling subtraces
|
|
traceMetric.subtraces_count = (pb_size_t)[trace.stages count];
|
|
firebase_perf_v1_TraceMetric *subtraces =
|
|
calloc(traceMetric.subtraces_count, sizeof(firebase_perf_v1_TraceMetric));
|
|
__block NSUInteger subtraceIndex = 0;
|
|
[trace.stages
|
|
enumerateObjectsUsingBlock:^(FIRTrace *_Nonnull stage, NSUInteger idx, BOOL *_Nonnull stop) {
|
|
subtraces[subtraceIndex] = FPRGetTraceMetric(stage);
|
|
subtraceIndex++;
|
|
}];
|
|
traceMetric.subtraces = subtraces;
|
|
|
|
// Filling custom attributes
|
|
NSDictionary<NSString *, NSString *> *attributes = [trace.attributes mutableCopy];
|
|
traceMetric.custom_attributes_count = (pb_size_t)attributes.count;
|
|
traceMetric.custom_attributes =
|
|
(firebase_perf_v1_TraceMetric_CustomAttributesEntry *)FPREncodeStringToStringMap(attributes);
|
|
|
|
// Filling session details
|
|
NSArray<FPRSessionDetails *> *orderedSessions = FPRMakeFirstSessionVerbose(trace.sessions);
|
|
traceMetric.perf_sessions_count = (pb_size_t)[orderedSessions count];
|
|
traceMetric.perf_sessions =
|
|
FPREncodePerfSessions(orderedSessions, traceMetric.perf_sessions_count);
|
|
|
|
return traceMetric;
|
|
}
|
|
|
|
firebase_perf_v1_NetworkRequestMetric FPRGetNetworkRequestMetric(FPRNetworkTrace *trace) {
|
|
firebase_perf_v1_NetworkRequestMetric networkMetric =
|
|
firebase_perf_v1_NetworkRequestMetric_init_default;
|
|
networkMetric.url = FPREncodeString(trace.trimmedURLString);
|
|
networkMetric.http_method = FPRHTTPMethodForString(trace.URLRequest.HTTPMethod);
|
|
networkMetric.has_http_method = true;
|
|
|
|
// Convert the start time from seconds to microseconds.
|
|
networkMetric.client_start_time_us = trace.startTimeSinceEpoch * USEC_PER_SEC;
|
|
networkMetric.has_client_start_time_us = true;
|
|
|
|
networkMetric.request_payload_bytes = trace.requestSize;
|
|
networkMetric.has_request_payload_bytes = true;
|
|
networkMetric.response_payload_bytes = trace.responseSize;
|
|
networkMetric.has_response_payload_bytes = true;
|
|
|
|
networkMetric.http_response_code = trace.responseCode;
|
|
networkMetric.has_http_response_code = true;
|
|
networkMetric.response_content_type = FPREncodeString(trace.responseContentType);
|
|
|
|
if (trace.responseError) {
|
|
networkMetric.network_client_error_reason =
|
|
firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_GENERIC_CLIENT_ERROR;
|
|
networkMetric.has_network_client_error_reason = true;
|
|
}
|
|
|
|
NSTimeInterval requestTimeUs =
|
|
USEC_PER_SEC *
|
|
[trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
|
|
andState:FPRNetworkTraceCheckpointStateRequestCompleted];
|
|
if (requestTimeUs > 0) {
|
|
networkMetric.time_to_request_completed_us = requestTimeUs;
|
|
networkMetric.has_time_to_request_completed_us = true;
|
|
}
|
|
|
|
NSTimeInterval responseIntiationTimeUs =
|
|
USEC_PER_SEC *
|
|
[trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
|
|
andState:FPRNetworkTraceCheckpointStateResponseReceived];
|
|
if (responseIntiationTimeUs > 0) {
|
|
networkMetric.time_to_response_initiated_us = responseIntiationTimeUs;
|
|
networkMetric.has_time_to_response_initiated_us = true;
|
|
}
|
|
|
|
NSTimeInterval responseCompletedUs =
|
|
USEC_PER_SEC *
|
|
[trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
|
|
andState:FPRNetworkTraceCheckpointStateResponseCompleted];
|
|
if (responseCompletedUs > 0) {
|
|
networkMetric.time_to_response_completed_us = responseCompletedUs;
|
|
networkMetric.has_time_to_response_completed_us = true;
|
|
}
|
|
|
|
// Filling custom attributes
|
|
NSDictionary<NSString *, NSString *> *attributes = [trace.attributes mutableCopy];
|
|
networkMetric.custom_attributes_count = (pb_size_t)attributes.count;
|
|
networkMetric.custom_attributes =
|
|
(firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry *)FPREncodeStringToStringMap(
|
|
attributes);
|
|
|
|
// Filling session details
|
|
NSArray<FPRSessionDetails *> *orderedSessions = FPRMakeFirstSessionVerbose(trace.sessions);
|
|
networkMetric.perf_sessions_count = (pb_size_t)[orderedSessions count];
|
|
networkMetric.perf_sessions =
|
|
FPREncodePerfSessions(orderedSessions, networkMetric.perf_sessions_count);
|
|
|
|
return networkMetric;
|
|
}
|
|
|
|
firebase_perf_v1_GaugeMetric FPRGetGaugeMetric(NSArray *gaugeData, NSString *sessionId) {
|
|
firebase_perf_v1_GaugeMetric gaugeMetric = firebase_perf_v1_GaugeMetric_init_default;
|
|
gaugeMetric.session_id = FPREncodeString(sessionId);
|
|
|
|
__block NSInteger cpuReadingsCount = 0;
|
|
__block NSInteger memoryReadingsCount = 0;
|
|
|
|
firebase_perf_v1_CpuMetricReading *cpuReadings =
|
|
calloc([gaugeData count], sizeof(firebase_perf_v1_CpuMetricReading));
|
|
firebase_perf_v1_IosMemoryReading *memoryReadings =
|
|
calloc([gaugeData count], sizeof(firebase_perf_v1_IosMemoryReading));
|
|
[gaugeData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
|
if ([obj isKindOfClass:[FPRCPUGaugeData class]]) {
|
|
FPRCPUGaugeData *gaugeData = (FPRCPUGaugeData *)obj;
|
|
cpuReadings[cpuReadingsCount].client_time_us =
|
|
gaugeData.collectionTime.timeIntervalSince1970 * USEC_PER_SEC;
|
|
cpuReadings[cpuReadingsCount].has_client_time_us = true;
|
|
cpuReadings[cpuReadingsCount].system_time_us = gaugeData.systemTime;
|
|
cpuReadings[cpuReadingsCount].has_system_time_us = true;
|
|
cpuReadings[cpuReadingsCount].user_time_us = gaugeData.userTime;
|
|
cpuReadings[cpuReadingsCount].has_user_time_us = true;
|
|
cpuReadingsCount++;
|
|
}
|
|
|
|
if ([obj isKindOfClass:[FPRMemoryGaugeData class]]) {
|
|
FPRMemoryGaugeData *gaugeData = (FPRMemoryGaugeData *)obj;
|
|
memoryReadings[memoryReadingsCount].client_time_us =
|
|
gaugeData.collectionTime.timeIntervalSince1970 * USEC_PER_SEC;
|
|
memoryReadings[memoryReadingsCount].has_client_time_us = true;
|
|
memoryReadings[memoryReadingsCount].used_app_heap_memory_kb =
|
|
(int32_t)BYTES_TO_KB(gaugeData.heapUsed);
|
|
memoryReadings[memoryReadingsCount].has_used_app_heap_memory_kb = true;
|
|
memoryReadings[memoryReadingsCount].free_app_heap_memory_kb =
|
|
(int32_t)BYTES_TO_KB(gaugeData.heapAvailable);
|
|
memoryReadings[memoryReadingsCount].has_free_app_heap_memory_kb = true;
|
|
memoryReadingsCount++;
|
|
}
|
|
}];
|
|
cpuReadings = realloc(cpuReadings, cpuReadingsCount * sizeof(firebase_perf_v1_CpuMetricReading));
|
|
memoryReadings =
|
|
realloc(memoryReadings, memoryReadingsCount * sizeof(firebase_perf_v1_IosMemoryReading));
|
|
|
|
gaugeMetric.cpu_metric_readings = cpuReadings;
|
|
gaugeMetric.cpu_metric_readings_count = (pb_size_t)cpuReadingsCount;
|
|
gaugeMetric.ios_memory_readings = memoryReadings;
|
|
gaugeMetric.ios_memory_readings_count = (pb_size_t)memoryReadingsCount;
|
|
return gaugeMetric;
|
|
}
|
|
|
|
firebase_perf_v1_ApplicationProcessState FPRApplicationProcessState(FPRTraceState state) {
|
|
firebase_perf_v1_ApplicationProcessState processState =
|
|
firebase_perf_v1_ApplicationProcessState_APPLICATION_PROCESS_STATE_UNKNOWN;
|
|
switch (state) {
|
|
case FPRTraceStateForegroundOnly:
|
|
processState = firebase_perf_v1_ApplicationProcessState_FOREGROUND;
|
|
break;
|
|
|
|
case FPRTraceStateBackgroundOnly:
|
|
processState = firebase_perf_v1_ApplicationProcessState_BACKGROUND;
|
|
break;
|
|
|
|
case FPRTraceStateBackgroundAndForeground:
|
|
processState = firebase_perf_v1_ApplicationProcessState_FOREGROUND_BACKGROUND;
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
|
|
return processState;
|
|
}
|
|
|
|
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
CTTelephonyNetworkInfo *FPRNetworkInfo() {
|
|
static CTTelephonyNetworkInfo *networkInfo;
|
|
static dispatch_once_t onceToken;
|
|
dispatch_once(&onceToken, ^{
|
|
networkInfo = [[CTTelephonyNetworkInfo alloc] init];
|
|
});
|
|
return networkInfo;
|
|
}
|
|
#endif
|
|
|
|
/** Reorders the list of sessions to make sure the first session is verbose if at least one session
|
|
* in the list is verbose.
|
|
* @return Ordered list of sessions.
|
|
*/
|
|
NSArray<FPRSessionDetails *> *FPRMakeFirstSessionVerbose(NSArray<FPRSessionDetails *> *sessions) {
|
|
NSMutableArray<FPRSessionDetails *> *orderedSessions =
|
|
[[NSMutableArray<FPRSessionDetails *> alloc] initWithArray:sessions];
|
|
|
|
NSInteger firstVerboseSessionIndex = -1;
|
|
for (int i = 0; i < [sessions count]; i++) {
|
|
if ([sessions[i] isVerbose]) {
|
|
firstVerboseSessionIndex = i;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (firstVerboseSessionIndex > 0) {
|
|
FPRSessionDetails *verboseSession = orderedSessions[firstVerboseSessionIndex];
|
|
[orderedSessions removeObjectAtIndex:firstVerboseSessionIndex];
|
|
[orderedSessions insertObject:verboseSession atIndex:0];
|
|
}
|
|
|
|
return [orderedSessions copy];
|
|
}
|
|
|
|
#pragma mark - Nanopb struct fields populating helper methods
|
|
|
|
void FPRSetApplicationInfo(firebase_perf_v1_PerfMetric *perfMetric,
|
|
firebase_perf_v1_ApplicationInfo appInfo) {
|
|
perfMetric->application_info = appInfo;
|
|
perfMetric->has_application_info = true;
|
|
}
|
|
|
|
void FPRSetTraceMetric(firebase_perf_v1_PerfMetric *perfMetric,
|
|
firebase_perf_v1_TraceMetric traceMetric) {
|
|
perfMetric->trace_metric = traceMetric;
|
|
perfMetric->has_trace_metric = true;
|
|
}
|
|
|
|
void FPRSetNetworkRequestMetric(firebase_perf_v1_PerfMetric *perfMetric,
|
|
firebase_perf_v1_NetworkRequestMetric networkMetric) {
|
|
perfMetric->network_request_metric = networkMetric;
|
|
perfMetric->has_network_request_metric = true;
|
|
}
|
|
|
|
void FPRSetGaugeMetric(firebase_perf_v1_PerfMetric *perfMetric,
|
|
firebase_perf_v1_GaugeMetric gaugeMetric) {
|
|
perfMetric->gauge_metric = gaugeMetric;
|
|
perfMetric->has_gauge_metric = true;
|
|
}
|
|
|
|
void FPRSetApplicationProcessState(firebase_perf_v1_PerfMetric *perfMetric,
|
|
firebase_perf_v1_ApplicationProcessState state) {
|
|
perfMetric->application_info.application_process_state = state;
|
|
perfMetric->application_info.has_application_process_state = true;
|
|
}
|