1 |
efrain |
1 |
// Copyright 2021 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/FPRNanoPbUtils.h"
|
|
|
16 |
|
|
|
17 |
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
|
18 |
#import <CoreTelephony/CTCarrier.h>
|
|
|
19 |
#import <CoreTelephony/CTTelephonyNetworkInfo.h>
|
|
|
20 |
#endif
|
|
|
21 |
#import <SystemConfiguration/SystemConfiguration.h>
|
|
|
22 |
|
|
|
23 |
#import "FirebasePerformance/Sources/Common/FPRConstants.h"
|
|
|
24 |
#import "FirebasePerformance/Sources/FIRPerformance+Internal.h"
|
|
|
25 |
#import "FirebasePerformance/Sources/FPRDataUtils.h"
|
|
|
26 |
#import "FirebasePerformance/Sources/Public/FirebasePerformance/FIRPerformance.h"
|
|
|
27 |
#import "FirebasePerformance/Sources/Timer/FIRTrace+Internal.h"
|
|
|
28 |
#import "FirebasePerformance/Sources/Timer/FIRTrace+Private.h"
|
|
|
29 |
|
|
|
30 |
#import "FirebasePerformance/Sources/Gauges/CPU/FPRCPUGaugeData.h"
|
|
|
31 |
#import "FirebasePerformance/Sources/Gauges/Memory/FPRMemoryGaugeData.h"
|
|
|
32 |
|
|
|
33 |
#define BYTES_TO_KB(x) (x / 1024)
|
|
|
34 |
|
|
|
35 |
static firebase_perf_v1_NetworkRequestMetric_HttpMethod FPRHTTPMethodForString(
|
|
|
36 |
NSString *methodString);
|
|
|
37 |
static firebase_perf_v1_NetworkConnectionInfo_NetworkType FPRNetworkConnectionInfoNetworkType(void);
|
|
|
38 |
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
|
39 |
static firebase_perf_v1_NetworkConnectionInfo_MobileSubtype FPRCellularNetworkType(void);
|
|
|
40 |
#endif
|
|
|
41 |
NSArray<FPRSessionDetails *> *FPRMakeFirstSessionVerbose(NSArray<FPRSessionDetails *> *sessions);
|
|
|
42 |
|
|
|
43 |
#pragma mark - Nanopb creation utilities
|
|
|
44 |
|
|
|
45 |
/** Converts the network method string to a value defined in the enum
|
|
|
46 |
* firebase_perf_v1_NetworkRequestMetric_HttpMethod.
|
|
|
47 |
* @return Enum value of the method string. If there is no mapping value defined for the method
|
|
|
48 |
* firebase_perf_v1_NetworkRequestMetric_HttpMethod_HTTP_METHOD_UNKNOWN is returned.
|
|
|
49 |
*/
|
|
|
50 |
static firebase_perf_v1_NetworkRequestMetric_HttpMethod FPRHTTPMethodForString(
|
|
|
51 |
NSString *methodString) {
|
|
|
52 |
static NSDictionary<NSString *, NSNumber *> *HTTPToFPRNetworkTraceMethod;
|
|
|
53 |
static dispatch_once_t onceToken = 0;
|
|
|
54 |
dispatch_once(&onceToken, ^{
|
|
|
55 |
HTTPToFPRNetworkTraceMethod = @{
|
|
|
56 |
@"GET" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_GET),
|
|
|
57 |
@"POST" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_POST),
|
|
|
58 |
@"PUT" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_PUT),
|
|
|
59 |
@"DELETE" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_DELETE),
|
|
|
60 |
@"HEAD" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_HEAD),
|
|
|
61 |
@"PATCH" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_PATCH),
|
|
|
62 |
@"OPTIONS" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_OPTIONS),
|
|
|
63 |
@"TRACE" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_TRACE),
|
|
|
64 |
@"CONNECT" : @(firebase_perf_v1_NetworkRequestMetric_HttpMethod_CONNECT),
|
|
|
65 |
};
|
|
|
66 |
});
|
|
|
67 |
|
|
|
68 |
NSNumber *HTTPMethod = HTTPToFPRNetworkTraceMethod[methodString];
|
|
|
69 |
if (HTTPMethod == nil) {
|
|
|
70 |
return firebase_perf_v1_NetworkRequestMetric_HttpMethod_HTTP_METHOD_UNKNOWN;
|
|
|
71 |
}
|
|
|
72 |
return HTTPMethod.intValue;
|
|
|
73 |
}
|
|
|
74 |
|
|
|
75 |
/** Get the current network connection type in firebase_perf_v1_NetworkConnectionInfo_NetworkType
|
|
|
76 |
* format.
|
|
|
77 |
* @return Current network connection type.
|
|
|
78 |
*/
|
|
|
79 |
static firebase_perf_v1_NetworkConnectionInfo_NetworkType FPRNetworkConnectionInfoNetworkType() {
|
|
|
80 |
firebase_perf_v1_NetworkConnectionInfo_NetworkType networkType =
|
|
|
81 |
firebase_perf_v1_NetworkConnectionInfo_NetworkType_NONE;
|
|
|
82 |
|
|
|
83 |
static SCNetworkReachabilityRef reachabilityRef = 0;
|
|
|
84 |
static dispatch_once_t onceToken;
|
|
|
85 |
dispatch_once(&onceToken, ^{
|
|
|
86 |
reachabilityRef = SCNetworkReachabilityCreateWithName(kCFAllocatorSystemDefault, "google.com");
|
|
|
87 |
});
|
|
|
88 |
|
|
|
89 |
SCNetworkReachabilityFlags reachabilityFlags = 0;
|
|
|
90 |
SCNetworkReachabilityGetFlags(reachabilityRef, &reachabilityFlags);
|
|
|
91 |
|
|
|
92 |
// Parse the network flags to set the network type.
|
|
|
93 |
if (reachabilityFlags & kSCNetworkReachabilityFlagsReachable) {
|
|
|
94 |
if (reachabilityFlags & kSCNetworkReachabilityFlagsIsWWAN) {
|
|
|
95 |
networkType = firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE;
|
|
|
96 |
} else {
|
|
|
97 |
networkType = firebase_perf_v1_NetworkConnectionInfo_NetworkType_WIFI;
|
|
|
98 |
}
|
|
|
99 |
}
|
|
|
100 |
|
|
|
101 |
return networkType;
|
|
|
102 |
}
|
|
|
103 |
|
|
|
104 |
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
|
105 |
/** Get the current cellular network connection type in
|
|
|
106 |
* firebase_perf_v1_NetworkConnectionInfo_MobileSubtype format.
|
|
|
107 |
* @return Current cellular network connection type.
|
|
|
108 |
*/
|
|
|
109 |
static firebase_perf_v1_NetworkConnectionInfo_MobileSubtype FPRCellularNetworkType() {
|
|
|
110 |
static NSDictionary<NSString *, NSNumber *> *cellularNetworkToMobileSubtype;
|
|
|
111 |
static dispatch_once_t onceToken = 0;
|
|
|
112 |
dispatch_once(&onceToken, ^{
|
|
|
113 |
cellularNetworkToMobileSubtype = @{
|
|
|
114 |
CTRadioAccessTechnologyGPRS : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_GPRS),
|
|
|
115 |
CTRadioAccessTechnologyEdge : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EDGE),
|
|
|
116 |
CTRadioAccessTechnologyWCDMA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_CDMA),
|
|
|
117 |
CTRadioAccessTechnologyHSDPA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSDPA),
|
|
|
118 |
CTRadioAccessTechnologyHSUPA : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_HSUPA),
|
|
|
119 |
CTRadioAccessTechnologyCDMA1x : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_CDMA),
|
|
|
120 |
CTRadioAccessTechnologyCDMAEVDORev0 :
|
|
|
121 |
@(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_0),
|
|
|
122 |
CTRadioAccessTechnologyCDMAEVDORevA :
|
|
|
123 |
@(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_A),
|
|
|
124 |
CTRadioAccessTechnologyCDMAEVDORevB :
|
|
|
125 |
@(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EVDO_B),
|
|
|
126 |
CTRadioAccessTechnologyeHRPD : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_EHRPD),
|
|
|
127 |
CTRadioAccessTechnologyLTE : @(firebase_perf_v1_NetworkConnectionInfo_MobileSubtype_LTE)
|
|
|
128 |
};
|
|
|
129 |
});
|
|
|
130 |
|
|
|
131 |
NSString *networkString = FPRNetworkInfo().currentRadioAccessTechnology;
|
|
|
132 |
NSNumber *cellularNetworkType = cellularNetworkToMobileSubtype[networkString];
|
|
|
133 |
return cellularNetworkType.intValue;
|
|
|
134 |
}
|
|
|
135 |
#endif
|
|
|
136 |
|
|
|
137 |
#pragma mark - Nanopb decode and encode helper methods
|
|
|
138 |
|
|
|
139 |
pb_bytes_array_t *FPREncodeData(NSData *data) {
|
|
|
140 |
pb_bytes_array_t *pbBytesArray = calloc(1, PB_BYTES_ARRAY_T_ALLOCSIZE(data.length));
|
|
|
141 |
if (pbBytesArray != NULL) {
|
|
|
142 |
[data getBytes:pbBytesArray->bytes length:data.length];
|
|
|
143 |
pbBytesArray->size = (pb_size_t)data.length;
|
|
|
144 |
}
|
|
|
145 |
return pbBytesArray;
|
|
|
146 |
}
|
|
|
147 |
|
|
|
148 |
pb_bytes_array_t *FPREncodeString(NSString *string) {
|
|
|
149 |
NSData *stringBytes = [string dataUsingEncoding:NSUTF8StringEncoding];
|
|
|
150 |
return FPREncodeData(stringBytes);
|
|
|
151 |
}
|
|
|
152 |
|
|
|
153 |
StringToStringMap *_Nullable FPREncodeStringToStringMap(NSDictionary *_Nullable dict) {
|
|
|
154 |
StringToStringMap *map = calloc(dict.count, sizeof(StringToStringMap));
|
|
|
155 |
__block NSUInteger index = 0;
|
|
|
156 |
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSString *value, BOOL *stop) {
|
|
|
157 |
map[index].key = FPREncodeString(key);
|
|
|
158 |
map[index].value = FPREncodeString(value);
|
|
|
159 |
index++;
|
|
|
160 |
}];
|
|
|
161 |
return map;
|
|
|
162 |
}
|
|
|
163 |
|
|
|
164 |
StringToNumberMap *_Nullable FPREncodeStringToNumberMap(NSDictionary *_Nullable dict) {
|
|
|
165 |
StringToNumberMap *map = calloc(dict.count, sizeof(StringToNumberMap));
|
|
|
166 |
__block NSUInteger index = 0;
|
|
|
167 |
[dict enumerateKeysAndObjectsUsingBlock:^(NSString *key, NSNumber *value, BOOL *stop) {
|
|
|
168 |
map[index].key = FPREncodeString(key);
|
|
|
169 |
map[index].value = [value longLongValue];
|
|
|
170 |
map[index].has_value = true;
|
|
|
171 |
index++;
|
|
|
172 |
}];
|
|
|
173 |
return map;
|
|
|
174 |
}
|
|
|
175 |
|
|
|
176 |
firebase_perf_v1_PerfSession *FPREncodePerfSessions(NSArray<FPRSessionDetails *> *sessions,
|
|
|
177 |
NSInteger count) {
|
|
|
178 |
firebase_perf_v1_PerfSession *perfSessions = calloc(count, sizeof(firebase_perf_v1_PerfSession));
|
|
|
179 |
__block NSUInteger perfSessionIndex = 0;
|
|
|
180 |
|
|
|
181 |
[sessions enumerateObjectsUsingBlock:^(FPRSessionDetails *_Nonnull session, NSUInteger index,
|
|
|
182 |
BOOL *_Nonnull stop) {
|
|
|
183 |
perfSessions[perfSessionIndex].session_id = FPREncodeString(session.sessionId);
|
|
|
184 |
perfSessions[perfSessionIndex].session_verbosity_count = 0;
|
|
|
185 |
if ((session.options & FPRSessionOptionsEvents) ||
|
|
|
186 |
(session.options & FPRSessionOptionsGauges)) {
|
|
|
187 |
perfSessions[perfSessionIndex].session_verbosity_count = 1;
|
|
|
188 |
perfSessions[perfSessionIndex].session_verbosity =
|
|
|
189 |
calloc(perfSessions[perfSessionIndex].session_verbosity_count,
|
|
|
190 |
sizeof(firebase_perf_v1_SessionVerbosity));
|
|
|
191 |
perfSessions[perfSessionIndex].session_verbosity[0] =
|
|
|
192 |
firebase_perf_v1_SessionVerbosity_GAUGES_AND_SYSTEM_EVENTS;
|
|
|
193 |
}
|
|
|
194 |
perfSessionIndex++;
|
|
|
195 |
}];
|
|
|
196 |
return perfSessions;
|
|
|
197 |
}
|
|
|
198 |
|
|
|
199 |
#pragma mark - Public methods
|
|
|
200 |
|
|
|
201 |
firebase_perf_v1_PerfMetric FPRGetPerfMetricMessage(NSString *appID) {
|
|
|
202 |
firebase_perf_v1_PerfMetric perfMetricMessage = firebase_perf_v1_PerfMetric_init_default;
|
|
|
203 |
FPRSetApplicationInfo(&perfMetricMessage, FPRGetApplicationInfoMessage());
|
|
|
204 |
perfMetricMessage.application_info.google_app_id = FPREncodeString(appID);
|
|
|
205 |
|
|
|
206 |
return perfMetricMessage;
|
|
|
207 |
}
|
|
|
208 |
|
|
|
209 |
firebase_perf_v1_ApplicationInfo FPRGetApplicationInfoMessage() {
|
|
|
210 |
firebase_perf_v1_ApplicationInfo appInfoMessage = firebase_perf_v1_ApplicationInfo_init_default;
|
|
|
211 |
firebase_perf_v1_IosApplicationInfo iosAppInfo = firebase_perf_v1_IosApplicationInfo_init_default;
|
|
|
212 |
NSBundle *mainBundle = [NSBundle mainBundle];
|
|
|
213 |
iosAppInfo.bundle_short_version =
|
|
|
214 |
FPREncodeString([mainBundle infoDictionary][@"CFBundleShortVersionString"]);
|
|
|
215 |
iosAppInfo.sdk_version = FPREncodeString([NSString stringWithUTF8String:kFPRSDKVersion]);
|
|
|
216 |
iosAppInfo.network_connection_info.network_type = FPRNetworkConnectionInfoNetworkType();
|
|
|
217 |
iosAppInfo.has_network_connection_info = true;
|
|
|
218 |
iosAppInfo.network_connection_info.has_network_type = true;
|
|
|
219 |
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
|
220 |
CTTelephonyNetworkInfo *networkInfo = FPRNetworkInfo();
|
|
|
221 |
CTCarrier *provider = networkInfo.subscriberCellularProvider;
|
|
|
222 |
NSString *mccMnc = FPRValidatedMccMnc(provider.mobileCountryCode, provider.mobileNetworkCode);
|
|
|
223 |
if (mccMnc) {
|
|
|
224 |
iosAppInfo.mcc_mnc = FPREncodeString(mccMnc);
|
|
|
225 |
}
|
|
|
226 |
if (iosAppInfo.network_connection_info.network_type ==
|
|
|
227 |
firebase_perf_v1_NetworkConnectionInfo_NetworkType_MOBILE) {
|
|
|
228 |
iosAppInfo.network_connection_info.mobile_subtype = FPRCellularNetworkType();
|
|
|
229 |
iosAppInfo.network_connection_info.has_mobile_subtype = true;
|
|
|
230 |
}
|
|
|
231 |
#endif
|
|
|
232 |
appInfoMessage.ios_app_info = iosAppInfo;
|
|
|
233 |
appInfoMessage.has_ios_app_info = true;
|
|
|
234 |
|
|
|
235 |
NSDictionary<NSString *, NSString *> *attributes =
|
|
|
236 |
[[FIRPerformance sharedInstance].attributes mutableCopy];
|
|
|
237 |
appInfoMessage.custom_attributes_count = (pb_size_t)attributes.count;
|
|
|
238 |
appInfoMessage.custom_attributes =
|
|
|
239 |
(firebase_perf_v1_ApplicationInfo_CustomAttributesEntry *)FPREncodeStringToStringMap(
|
|
|
240 |
attributes);
|
|
|
241 |
|
|
|
242 |
return appInfoMessage;
|
|
|
243 |
}
|
|
|
244 |
|
|
|
245 |
firebase_perf_v1_TraceMetric FPRGetTraceMetric(FIRTrace *trace) {
|
|
|
246 |
firebase_perf_v1_TraceMetric traceMetric = firebase_perf_v1_TraceMetric_init_default;
|
|
|
247 |
traceMetric.name = FPREncodeString(trace.name);
|
|
|
248 |
|
|
|
249 |
// Set if the trace is an internally created trace.
|
|
|
250 |
traceMetric.is_auto = trace.isInternal;
|
|
|
251 |
traceMetric.has_is_auto = true;
|
|
|
252 |
|
|
|
253 |
// Convert the trace duration from seconds to microseconds.
|
|
|
254 |
traceMetric.duration_us = trace.totalTraceTimeInterval * USEC_PER_SEC;
|
|
|
255 |
traceMetric.has_duration_us = true;
|
|
|
256 |
|
|
|
257 |
// Convert the start time from seconds to microseconds.
|
|
|
258 |
traceMetric.client_start_time_us = trace.startTimeSinceEpoch * USEC_PER_SEC;
|
|
|
259 |
traceMetric.has_client_start_time_us = true;
|
|
|
260 |
|
|
|
261 |
// Filling counters
|
|
|
262 |
NSDictionary<NSString *, NSNumber *> *counters = trace.counters;
|
|
|
263 |
traceMetric.counters_count = (pb_size_t)counters.count;
|
|
|
264 |
traceMetric.counters =
|
|
|
265 |
(firebase_perf_v1_TraceMetric_CountersEntry *)FPREncodeStringToNumberMap(counters);
|
|
|
266 |
|
|
|
267 |
// Filling subtraces
|
|
|
268 |
traceMetric.subtraces_count = (pb_size_t)[trace.stages count];
|
|
|
269 |
firebase_perf_v1_TraceMetric *subtraces =
|
|
|
270 |
calloc(traceMetric.subtraces_count, sizeof(firebase_perf_v1_TraceMetric));
|
|
|
271 |
__block NSUInteger subtraceIndex = 0;
|
|
|
272 |
[trace.stages
|
|
|
273 |
enumerateObjectsUsingBlock:^(FIRTrace *_Nonnull stage, NSUInteger idx, BOOL *_Nonnull stop) {
|
|
|
274 |
subtraces[subtraceIndex] = FPRGetTraceMetric(stage);
|
|
|
275 |
subtraceIndex++;
|
|
|
276 |
}];
|
|
|
277 |
traceMetric.subtraces = subtraces;
|
|
|
278 |
|
|
|
279 |
// Filling custom attributes
|
|
|
280 |
NSDictionary<NSString *, NSString *> *attributes = [trace.attributes mutableCopy];
|
|
|
281 |
traceMetric.custom_attributes_count = (pb_size_t)attributes.count;
|
|
|
282 |
traceMetric.custom_attributes =
|
|
|
283 |
(firebase_perf_v1_TraceMetric_CustomAttributesEntry *)FPREncodeStringToStringMap(attributes);
|
|
|
284 |
|
|
|
285 |
// Filling session details
|
|
|
286 |
NSArray<FPRSessionDetails *> *orderedSessions = FPRMakeFirstSessionVerbose(trace.sessions);
|
|
|
287 |
traceMetric.perf_sessions_count = (pb_size_t)[orderedSessions count];
|
|
|
288 |
traceMetric.perf_sessions =
|
|
|
289 |
FPREncodePerfSessions(orderedSessions, traceMetric.perf_sessions_count);
|
|
|
290 |
|
|
|
291 |
return traceMetric;
|
|
|
292 |
}
|
|
|
293 |
|
|
|
294 |
firebase_perf_v1_NetworkRequestMetric FPRGetNetworkRequestMetric(FPRNetworkTrace *trace) {
|
|
|
295 |
firebase_perf_v1_NetworkRequestMetric networkMetric =
|
|
|
296 |
firebase_perf_v1_NetworkRequestMetric_init_default;
|
|
|
297 |
networkMetric.url = FPREncodeString(trace.trimmedURLString);
|
|
|
298 |
networkMetric.http_method = FPRHTTPMethodForString(trace.URLRequest.HTTPMethod);
|
|
|
299 |
networkMetric.has_http_method = true;
|
|
|
300 |
|
|
|
301 |
// Convert the start time from seconds to microseconds.
|
|
|
302 |
networkMetric.client_start_time_us = trace.startTimeSinceEpoch * USEC_PER_SEC;
|
|
|
303 |
networkMetric.has_client_start_time_us = true;
|
|
|
304 |
|
|
|
305 |
networkMetric.request_payload_bytes = trace.requestSize;
|
|
|
306 |
networkMetric.has_request_payload_bytes = true;
|
|
|
307 |
networkMetric.response_payload_bytes = trace.responseSize;
|
|
|
308 |
networkMetric.has_response_payload_bytes = true;
|
|
|
309 |
|
|
|
310 |
networkMetric.http_response_code = trace.responseCode;
|
|
|
311 |
networkMetric.has_http_response_code = true;
|
|
|
312 |
networkMetric.response_content_type = FPREncodeString(trace.responseContentType);
|
|
|
313 |
|
|
|
314 |
if (trace.responseError) {
|
|
|
315 |
networkMetric.network_client_error_reason =
|
|
|
316 |
firebase_perf_v1_NetworkRequestMetric_NetworkClientErrorReason_GENERIC_CLIENT_ERROR;
|
|
|
317 |
networkMetric.has_network_client_error_reason = true;
|
|
|
318 |
}
|
|
|
319 |
|
|
|
320 |
NSTimeInterval requestTimeUs =
|
|
|
321 |
USEC_PER_SEC *
|
|
|
322 |
[trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
|
|
|
323 |
andState:FPRNetworkTraceCheckpointStateRequestCompleted];
|
|
|
324 |
if (requestTimeUs > 0) {
|
|
|
325 |
networkMetric.time_to_request_completed_us = requestTimeUs;
|
|
|
326 |
networkMetric.has_time_to_request_completed_us = true;
|
|
|
327 |
}
|
|
|
328 |
|
|
|
329 |
NSTimeInterval responseIntiationTimeUs =
|
|
|
330 |
USEC_PER_SEC *
|
|
|
331 |
[trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
|
|
|
332 |
andState:FPRNetworkTraceCheckpointStateResponseReceived];
|
|
|
333 |
if (responseIntiationTimeUs > 0) {
|
|
|
334 |
networkMetric.time_to_response_initiated_us = responseIntiationTimeUs;
|
|
|
335 |
networkMetric.has_time_to_response_initiated_us = true;
|
|
|
336 |
}
|
|
|
337 |
|
|
|
338 |
NSTimeInterval responseCompletedUs =
|
|
|
339 |
USEC_PER_SEC *
|
|
|
340 |
[trace timeIntervalBetweenCheckpointState:FPRNetworkTraceCheckpointStateInitiated
|
|
|
341 |
andState:FPRNetworkTraceCheckpointStateResponseCompleted];
|
|
|
342 |
if (responseCompletedUs > 0) {
|
|
|
343 |
networkMetric.time_to_response_completed_us = responseCompletedUs;
|
|
|
344 |
networkMetric.has_time_to_response_completed_us = true;
|
|
|
345 |
}
|
|
|
346 |
|
|
|
347 |
// Filling custom attributes
|
|
|
348 |
NSDictionary<NSString *, NSString *> *attributes = [trace.attributes mutableCopy];
|
|
|
349 |
networkMetric.custom_attributes_count = (pb_size_t)attributes.count;
|
|
|
350 |
networkMetric.custom_attributes =
|
|
|
351 |
(firebase_perf_v1_NetworkRequestMetric_CustomAttributesEntry *)FPREncodeStringToStringMap(
|
|
|
352 |
attributes);
|
|
|
353 |
|
|
|
354 |
// Filling session details
|
|
|
355 |
NSArray<FPRSessionDetails *> *orderedSessions = FPRMakeFirstSessionVerbose(trace.sessions);
|
|
|
356 |
networkMetric.perf_sessions_count = (pb_size_t)[orderedSessions count];
|
|
|
357 |
networkMetric.perf_sessions =
|
|
|
358 |
FPREncodePerfSessions(orderedSessions, networkMetric.perf_sessions_count);
|
|
|
359 |
|
|
|
360 |
return networkMetric;
|
|
|
361 |
}
|
|
|
362 |
|
|
|
363 |
firebase_perf_v1_GaugeMetric FPRGetGaugeMetric(NSArray *gaugeData, NSString *sessionId) {
|
|
|
364 |
firebase_perf_v1_GaugeMetric gaugeMetric = firebase_perf_v1_GaugeMetric_init_default;
|
|
|
365 |
gaugeMetric.session_id = FPREncodeString(sessionId);
|
|
|
366 |
|
|
|
367 |
__block NSInteger cpuReadingsCount = 0;
|
|
|
368 |
__block NSInteger memoryReadingsCount = 0;
|
|
|
369 |
|
|
|
370 |
firebase_perf_v1_CpuMetricReading *cpuReadings =
|
|
|
371 |
calloc([gaugeData count], sizeof(firebase_perf_v1_CpuMetricReading));
|
|
|
372 |
firebase_perf_v1_IosMemoryReading *memoryReadings =
|
|
|
373 |
calloc([gaugeData count], sizeof(firebase_perf_v1_IosMemoryReading));
|
|
|
374 |
[gaugeData enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
|
|
|
375 |
if ([obj isKindOfClass:[FPRCPUGaugeData class]]) {
|
|
|
376 |
FPRCPUGaugeData *gaugeData = (FPRCPUGaugeData *)obj;
|
|
|
377 |
cpuReadings[cpuReadingsCount].client_time_us =
|
|
|
378 |
gaugeData.collectionTime.timeIntervalSince1970 * USEC_PER_SEC;
|
|
|
379 |
cpuReadings[cpuReadingsCount].has_client_time_us = true;
|
|
|
380 |
cpuReadings[cpuReadingsCount].system_time_us = gaugeData.systemTime;
|
|
|
381 |
cpuReadings[cpuReadingsCount].has_system_time_us = true;
|
|
|
382 |
cpuReadings[cpuReadingsCount].user_time_us = gaugeData.userTime;
|
|
|
383 |
cpuReadings[cpuReadingsCount].has_user_time_us = true;
|
|
|
384 |
cpuReadingsCount++;
|
|
|
385 |
}
|
|
|
386 |
|
|
|
387 |
if ([obj isKindOfClass:[FPRMemoryGaugeData class]]) {
|
|
|
388 |
FPRMemoryGaugeData *gaugeData = (FPRMemoryGaugeData *)obj;
|
|
|
389 |
memoryReadings[memoryReadingsCount].client_time_us =
|
|
|
390 |
gaugeData.collectionTime.timeIntervalSince1970 * USEC_PER_SEC;
|
|
|
391 |
memoryReadings[memoryReadingsCount].has_client_time_us = true;
|
|
|
392 |
memoryReadings[memoryReadingsCount].used_app_heap_memory_kb =
|
|
|
393 |
(int32_t)BYTES_TO_KB(gaugeData.heapUsed);
|
|
|
394 |
memoryReadings[memoryReadingsCount].has_used_app_heap_memory_kb = true;
|
|
|
395 |
memoryReadings[memoryReadingsCount].free_app_heap_memory_kb =
|
|
|
396 |
(int32_t)BYTES_TO_KB(gaugeData.heapAvailable);
|
|
|
397 |
memoryReadings[memoryReadingsCount].has_free_app_heap_memory_kb = true;
|
|
|
398 |
memoryReadingsCount++;
|
|
|
399 |
}
|
|
|
400 |
}];
|
|
|
401 |
cpuReadings = realloc(cpuReadings, cpuReadingsCount * sizeof(firebase_perf_v1_CpuMetricReading));
|
|
|
402 |
memoryReadings =
|
|
|
403 |
realloc(memoryReadings, memoryReadingsCount * sizeof(firebase_perf_v1_IosMemoryReading));
|
|
|
404 |
|
|
|
405 |
gaugeMetric.cpu_metric_readings = cpuReadings;
|
|
|
406 |
gaugeMetric.cpu_metric_readings_count = (pb_size_t)cpuReadingsCount;
|
|
|
407 |
gaugeMetric.ios_memory_readings = memoryReadings;
|
|
|
408 |
gaugeMetric.ios_memory_readings_count = (pb_size_t)memoryReadingsCount;
|
|
|
409 |
return gaugeMetric;
|
|
|
410 |
}
|
|
|
411 |
|
|
|
412 |
firebase_perf_v1_ApplicationProcessState FPRApplicationProcessState(FPRTraceState state) {
|
|
|
413 |
firebase_perf_v1_ApplicationProcessState processState =
|
|
|
414 |
firebase_perf_v1_ApplicationProcessState_APPLICATION_PROCESS_STATE_UNKNOWN;
|
|
|
415 |
switch (state) {
|
|
|
416 |
case FPRTraceStateForegroundOnly:
|
|
|
417 |
processState = firebase_perf_v1_ApplicationProcessState_FOREGROUND;
|
|
|
418 |
break;
|
|
|
419 |
|
|
|
420 |
case FPRTraceStateBackgroundOnly:
|
|
|
421 |
processState = firebase_perf_v1_ApplicationProcessState_BACKGROUND;
|
|
|
422 |
break;
|
|
|
423 |
|
|
|
424 |
case FPRTraceStateBackgroundAndForeground:
|
|
|
425 |
processState = firebase_perf_v1_ApplicationProcessState_FOREGROUND_BACKGROUND;
|
|
|
426 |
break;
|
|
|
427 |
|
|
|
428 |
default:
|
|
|
429 |
break;
|
|
|
430 |
}
|
|
|
431 |
|
|
|
432 |
return processState;
|
|
|
433 |
}
|
|
|
434 |
|
|
|
435 |
#ifdef TARGET_HAS_MOBILE_CONNECTIVITY
|
|
|
436 |
CTTelephonyNetworkInfo *FPRNetworkInfo() {
|
|
|
437 |
static CTTelephonyNetworkInfo *networkInfo;
|
|
|
438 |
static dispatch_once_t onceToken;
|
|
|
439 |
dispatch_once(&onceToken, ^{
|
|
|
440 |
networkInfo = [[CTTelephonyNetworkInfo alloc] init];
|
|
|
441 |
});
|
|
|
442 |
return networkInfo;
|
|
|
443 |
}
|
|
|
444 |
#endif
|
|
|
445 |
|
|
|
446 |
/** Reorders the list of sessions to make sure the first session is verbose if at least one session
|
|
|
447 |
* in the list is verbose.
|
|
|
448 |
* @return Ordered list of sessions.
|
|
|
449 |
*/
|
|
|
450 |
NSArray<FPRSessionDetails *> *FPRMakeFirstSessionVerbose(NSArray<FPRSessionDetails *> *sessions) {
|
|
|
451 |
NSMutableArray<FPRSessionDetails *> *orderedSessions =
|
|
|
452 |
[[NSMutableArray<FPRSessionDetails *> alloc] initWithArray:sessions];
|
|
|
453 |
|
|
|
454 |
NSInteger firstVerboseSessionIndex = -1;
|
|
|
455 |
for (int i = 0; i < [sessions count]; i++) {
|
|
|
456 |
if ([sessions[i] isVerbose]) {
|
|
|
457 |
firstVerboseSessionIndex = i;
|
|
|
458 |
break;
|
|
|
459 |
}
|
|
|
460 |
}
|
|
|
461 |
|
|
|
462 |
if (firstVerboseSessionIndex > 0) {
|
|
|
463 |
FPRSessionDetails *verboseSession = orderedSessions[firstVerboseSessionIndex];
|
|
|
464 |
[orderedSessions removeObjectAtIndex:firstVerboseSessionIndex];
|
|
|
465 |
[orderedSessions insertObject:verboseSession atIndex:0];
|
|
|
466 |
}
|
|
|
467 |
|
|
|
468 |
return [orderedSessions copy];
|
|
|
469 |
}
|
|
|
470 |
|
|
|
471 |
#pragma mark - Nanopb struct fields populating helper methods
|
|
|
472 |
|
|
|
473 |
void FPRSetApplicationInfo(firebase_perf_v1_PerfMetric *perfMetric,
|
|
|
474 |
firebase_perf_v1_ApplicationInfo appInfo) {
|
|
|
475 |
perfMetric->application_info = appInfo;
|
|
|
476 |
perfMetric->has_application_info = true;
|
|
|
477 |
}
|
|
|
478 |
|
|
|
479 |
void FPRSetTraceMetric(firebase_perf_v1_PerfMetric *perfMetric,
|
|
|
480 |
firebase_perf_v1_TraceMetric traceMetric) {
|
|
|
481 |
perfMetric->trace_metric = traceMetric;
|
|
|
482 |
perfMetric->has_trace_metric = true;
|
|
|
483 |
}
|
|
|
484 |
|
|
|
485 |
void FPRSetNetworkRequestMetric(firebase_perf_v1_PerfMetric *perfMetric,
|
|
|
486 |
firebase_perf_v1_NetworkRequestMetric networkMetric) {
|
|
|
487 |
perfMetric->network_request_metric = networkMetric;
|
|
|
488 |
perfMetric->has_network_request_metric = true;
|
|
|
489 |
}
|
|
|
490 |
|
|
|
491 |
void FPRSetGaugeMetric(firebase_perf_v1_PerfMetric *perfMetric,
|
|
|
492 |
firebase_perf_v1_GaugeMetric gaugeMetric) {
|
|
|
493 |
perfMetric->gauge_metric = gaugeMetric;
|
|
|
494 |
perfMetric->has_gauge_metric = true;
|
|
|
495 |
}
|
|
|
496 |
|
|
|
497 |
void FPRSetApplicationProcessState(firebase_perf_v1_PerfMetric *perfMetric,
|
|
|
498 |
firebase_perf_v1_ApplicationProcessState state) {
|
|
|
499 |
perfMetric->application_info.application_process_state = state;
|
|
|
500 |
perfMetric->application_info.has_application_process_state = true;
|
|
|
501 |
}
|