FPRNanoPbUtils.m 23 KB

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