瀏覽代碼

[Crashlytics] update deprecated kernel api for visionPro (#11515)

* [Crashlytics] Fix build issues on visionOS

Fixed Firebase Crashlytics SDK build issues for visionOS, along with
corresponding unit test changes. This also resolves build issues with
the underlying Firebase Sessions SDK.

* Allow pod-lib-lint warnings for Firebase Sessions

* VisionOS deprecated kernel api update

* Moved `swift(>=5.9)` check to separate `#if` statement

* Move swift(>=5.9) check in SessionStartEventTests

* adding comment, declear and use internal macro

---------

Co-authored-by: Andrew Heard <andrewheard@google.com>
themiswang 2 年之前
父節點
當前提交
97e7b25be1

+ 2 - 1
.github/workflows/sessions.yml

@@ -33,7 +33,8 @@ jobs:
       run: scripts/setup_bundler.sh
     - name: Build and test
       run: |
-        scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSessions.podspec --platforms=${{ matrix.target }}
+        scripts/third_party/travis/retry.sh scripts/pod_lib_lint.rb FirebaseSessions.podspec \
+            --platforms=${{ matrix.target }} \
 
   spm:
     # Don't run on private repo unless it is a PR.

+ 21 - 1
Crashlytics/Crashlytics/Components/FIRCLSBinaryImage.m

@@ -23,6 +23,7 @@
 
 #include "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
 #include "Crashlytics/Crashlytics/Components/FIRCLSHost.h"
+#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
 #include "Crashlytics/Crashlytics/Helpers/FIRCLSFeatures.h"
 #include "Crashlytics/Crashlytics/Helpers/FIRCLSFile.h"
 #include "Crashlytics/Crashlytics/Helpers/FIRCLSUtility.h"
@@ -241,7 +242,7 @@ static FIRCLSMachOSegmentCommand FIRCLSBinaryImageMachOGetSegmentCommand(
 
   return segmentCommand;
 }
-
+#if !CLS_TARGET_OS_XR
 static bool FIRCLSBinaryImageMachOSliceInitSectionByName(FIRCLSMachOSliceRef slice,
                                                          const char* segName,
                                                          const char* sectionName,
@@ -279,6 +280,7 @@ static bool FIRCLSBinaryImageMachOSliceInitSectionByName(FIRCLSMachOSliceRef sli
 
   return true;
 }
+#endif
 
 static void FIRCLSPopulateImageDetailWithLoadCommand(uint32_t type,
                                                      uint32_t size,
@@ -343,23 +345,41 @@ static bool FIRCLSBinaryImageFillInImageDetails(FIRCLSBinaryImageDetails* detail
   FIRCLSMachOSection section;
 
 #if CLS_COMPACT_UNWINDING_SUPPORTED
+#if !CLS_TARGET_OS_XR
   if (FIRCLSBinaryImageMachOSliceInitSectionByName(&details->slice, SEG_TEXT, "__unwind_info",
                                                    &section)) {
     details->node.unwindInfo = (void*)(section.addr + details->vmaddr_slide);
   }
+#else
+  unsigned long unwindInfoSize;
+  details->node.unwindInfo = (void*)getsectiondata(details->slice.startAddress, "__TEXT",
+                                                   "__unwind_info", &unwindInfoSize);
+#endif
 #endif
 
 #if CLS_DWARF_UNWINDING_SUPPORTED
+#if !CLS_TARGET_OS_XR
   if (FIRCLSBinaryImageMachOSliceInitSectionByName(&details->slice, SEG_TEXT, "__eh_frame",
                                                    &section)) {
     details->node.ehFrame = (void*)(section.addr + details->vmaddr_slide);
   }
+#else
+  unsigned long ehFrameSize;
+  details->node.ehFrame =
+      (void*)getsectiondata(details->slice.startAddress, "__TEXT", "__eh_frame", &ehFrameSize);
+#endif
 #endif
 
+#if !CLS_TARGET_OS_XR
   if (FIRCLSBinaryImageMachOSliceInitSectionByName(&details->slice, SEG_DATA, "__crash_info",
                                                    &section)) {
     details->node.crashInfo = (void*)(section.addr + details->vmaddr_slide);
   }
+#else
+  unsigned long crashInfoSize;
+  details->node.crashInfo =
+      (void*)getsectiondata(details->slice.startAddress, "__TEXT", "__crash_info", &crashInfoSize);
+#endif
 
   return true;
 }

+ 9 - 6
Crashlytics/Crashlytics/Controllers/FIRCLSNotificationManager.m

@@ -17,6 +17,7 @@
 #import "Crashlytics/Crashlytics/Components/FIRCLSApplication.h"
 #import "Crashlytics/Crashlytics/Components/FIRCLSGlobals.h"
 #import "Crashlytics/Crashlytics/Components/FIRCLSUserLogging.h"
+#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
 
 #if TARGET_OS_IPHONE
 #import <UIKit/UIKit.h>
@@ -38,6 +39,7 @@
                                            selector:@selector(didBecomeInactive:)
                                                name:UIApplicationDidEnterBackgroundNotification
                                              object:nil];
+#if !CLS_TARGET_OS_XR
   [[NSNotificationCenter defaultCenter] addObserver:self
                                            selector:@selector(didChangeOrientation:)
                                                name:UIDeviceOrientationDidChangeNotification
@@ -51,6 +53,7 @@
              name:UIApplicationDidChangeStatusBarOrientationNotification
            object:nil];
 #pragma clang diagnostic pop
+#endif  // !CLS_TARGET_OS_XR
 
 #elif CLS_TARGET_OS_OSX
   [[NSNotificationCenter defaultCenter] addObserver:self
@@ -65,22 +68,22 @@
 }
 
 - (void)captureInitialNotificationStates {
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS && (!CLS_TARGET_OS_XR)
   UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
   UIInterfaceOrientation statusBarOrientation =
       [FIRCLSApplicationSharedInstance() statusBarOrientation];
-#endif
+#endif  // TARGET_OS_IOS && (!CLS_TARGET_OS_XR)
 
   // It's nice to do this async, so we don't hold up the main thread while doing three
   // consecutive IOs here.
   dispatch_async(FIRCLSGetLoggingQueue(), ^{
     FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSInBackgroundKey, @"0");
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS && (!CLS_TARGET_OS_XR)
     FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSDeviceOrientationKey,
                                            [@(orientation) description]);
     FIRCLSUserLoggingWriteInternalKeyValue(FIRCLSUIOrientationKey,
                                            [@(statusBarOrientation) description]);
-#endif
+#endif  // TARGET_OS_IOS && (!CLS_TARGET_OS_XR)
   });
 }
 
@@ -92,7 +95,7 @@
   FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSInBackgroundKey, @YES);
 }
 
-#if TARGET_OS_IOS
+#if TARGET_OS_IOS && (!CLS_TARGET_OS_XR)
 - (void)didChangeOrientation:(NSNotification *)notification {
   UIDeviceOrientation orientation = [[UIDevice currentDevice] orientation];
 
@@ -105,6 +108,6 @@
 
   FIRCLSUserLoggingRecordInternalKeyValue(FIRCLSUIOrientationKey, @(statusBarOrientation));
 }
-#endif
+#endif  // TARGET_OS_IOS && (!CLS_TARGET_OS_XR)
 
 @end

+ 7 - 0
Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h

@@ -57,6 +57,13 @@
 #include <arm/arch.h>
 #endif
 
+// VisionOS support
+#if defined(TARGET_OS_XR) && TARGET_OS_XR
+#define CLS_TARGET_OS_XR 1
+#else
+#define CLS_TARGET_OS_XR 0
+#endif
+
 #if defined(__arm__)
 #define CLS_CPU_ARM 1
 #endif

+ 31 - 4
Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.m

@@ -13,6 +13,7 @@
 // limitations under the License.
 
 #include "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
+#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
 
 #include <Foundation/Foundation.h>
 
@@ -20,6 +21,7 @@
 #include <mach-o/fat.h>
 #include <mach-o/getsect.h>
 #include <mach-o/ldsyms.h>
+#include <mach-o/utils.h>
 
 #include <sys/mman.h>
 #include <sys/stat.h>
@@ -261,16 +263,28 @@ void FIRCLSMachOSliceEnumerateLoadCommands(FIRCLSMachOSliceRef slice,
 }
 
 struct FIRCLSMachOSlice FIRCLSMachOSliceGetCurrent(void) {
-  const NXArchInfo* archInfo;
   struct FIRCLSMachOSlice slice;
   void* executableSymbol;
   Dl_info dlinfo;
 
+#if !CLS_TARGET_OS_XR
+  const NXArchInfo* archInfo;
   archInfo = NXGetLocalArchInfo();
+
   if (archInfo) {
     slice.cputype = archInfo->cputype;
     slice.cpusubtype = archInfo->cpusubtype;
   }
+#else
+  cpu_type_t cputype;
+  cpu_subtype_t cpusubtype;
+  const char* archname = macho_arch_name_for_mach_header(NULL);
+  bool hasArchInfo = macho_cpu_type_for_arch_name(archname, &cputype, &cpusubtype);
+  if (hasArchInfo) {
+    slice.cputype = cputype;
+    slice.cpusubtype = cpusubtype;
+  }
+#endif
 
   slice.startAddress = NULL;
 
@@ -311,8 +325,6 @@ const char* FIRCLSMachOSliceGetExecutablePath(FIRCLSMachOSliceRef slice) {
 }
 
 const char* FIRCLSMachOSliceGetArchitectureName(FIRCLSMachOSliceRef slice) {
-  const NXArchInfo* archInfo;
-
   // there are some special cases here for types not handled by earlier OSes
   if (slice->cputype == CPU_TYPE_ARM && slice->cpusubtype == CPU_SUBTYPE_ARM_V7S) {
     return "armv7s";
@@ -330,12 +342,23 @@ const char* FIRCLSMachOSliceGetArchitectureName(FIRCLSMachOSliceRef slice) {
     return "armv7k";
   }
 
+#if !CLS_TARGET_OS_XR
+  const NXArchInfo* archInfo;
+
   archInfo = NXGetArchInfoFromCpuType(slice->cputype, slice->cpusubtype);
   if (!archInfo) {
     return "unknown";
   }
 
   return archInfo->name;
+#else
+  const char* archname = macho_arch_name_for_mach_header(NULL);
+
+  if (!archname) {
+    return "unknown";
+  }
+  return archname;
+#endif
 }
 
 bool FIRCLSMachOSliceIs64Bit(FIRCLSMachOSliceRef slice) {
@@ -343,6 +366,7 @@ bool FIRCLSMachOSliceIs64Bit(FIRCLSMachOSliceRef slice) {
   return (slice->cputype & CPU_ARCH_ABI64) == CPU_ARCH_ABI64;
 }
 
+// deprecated
 bool FIRCLSMachOSliceGetSectionByName(FIRCLSMachOSliceRef slice,
                                       const char* segName,
                                       const char* sectionName,
@@ -381,6 +405,9 @@ bool FIRCLSMachOSliceInitSectionByName(FIRCLSMachOSliceRef slice,
 
   memset(section, 0, sizeof(FIRCLSMachOSection));
 
+// Deprecated code for vision OS, entire function is not used anywhere
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
   if (FIRCLSMachOSliceIs64Bit(slice)) {
     const struct section_64* sect =
         getsectbynamefromheader_64(slice->startAddress, segName, sectionName);
@@ -401,7 +428,7 @@ bool FIRCLSMachOSliceInitSectionByName(FIRCLSMachOSliceRef slice,
     section->size = sect->size;
     section->offset = sect->offset;
   }
-
+#pragma clang diagnostic pop
   return true;
 }
 

+ 18 - 1
Crashlytics/UnitTests/FIRCLSMachO/FIRCLSMachOTests.m

@@ -13,9 +13,13 @@
 // limitations under the License.
 
 #import "Crashlytics/UnitTests/FIRCLSMachO/FIRCLSMachOTests.h"
+#include <mach-o/dyld.h>
+#include <mach-o/getsect.h>
+#include <mach-o/utils.h>
 
-#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
+#include "Crashlytics/Crashlytics/Helpers/FIRCLSDefines.h"
 
+#import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachO.h"
 #import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOBinary.h"
 #import "Crashlytics/Shared/FIRCLSMachO/FIRCLSMachOSlice.h"
 #import "Crashlytics/Shared/FIRCLSMachO/FIRCLSdSYM.h"
@@ -313,6 +317,7 @@
   XCTAssert(ptr != NULL);
 }
 
+#if !CLS_TARGET_OS_XR
 - (void)testReadArm64Section {
   NSString* path = [[self resourcePath] stringByAppendingPathComponent:@"armv7-armv7s-arm64.dylib"];
   struct FIRCLSMachOFile file;
@@ -333,5 +338,17 @@
   XCTAssert(FIRCLSMachOSliceGetSectionByName(&slice, SEG_TEXT, "__unwind_info", &ptr));
   XCTAssert(ptr != NULL);
 }
+#endif
+
+#if CLS_TARGET_OS_XR
+
+- (void)testVisionProGetSlice {
+  struct FIRCLSMachOSlice slice = FIRCLSMachOSliceGetCurrent();
+  XCTAssertEqual(slice.cputype, CPU_TYPE_ARM64);
+
+  const char* archname = macho_arch_name_for_mach_header(NULL);
+  XCTAssertEqualObjects(@(archname), @"arm64");
+}
+#endif
 
 @end

+ 78 - 34
FirebaseSessions/Sources/SessionStartEvent.swift

@@ -256,44 +256,88 @@ class SessionStartEvent: NSObject, GDTCOREventDataObject {
     -> firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype {
     var subtype: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
 
-    #if os(iOS) && !targetEnvironment(macCatalyst)
-      switch mobileSubtype {
-      case CTRadioAccessTechnologyGPRS:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
-      case CTRadioAccessTechnologyEdge:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
-      case CTRadioAccessTechnologyWCDMA:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
-      case CTRadioAccessTechnologyCDMA1x:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
-      case CTRadioAccessTechnologyHSDPA:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
-      case CTRadioAccessTechnologyHSUPA:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
-      case CTRadioAccessTechnologyCDMAEVDORev0:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
-      case CTRadioAccessTechnologyCDMAEVDORevA:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
-      case CTRadioAccessTechnologyCDMAEVDORevB:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
-      case CTRadioAccessTechnologyeHRPD:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
-      case CTRadioAccessTechnologyLTE:
-        subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
-      default:
+    // swift(>=5.9) implies Xcode 15+
+    // Need to have this swift version check to use os(xrOS) macro, VisionOS support.
+    #if swift(>=5.9)
+      #if os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+        switch mobileSubtype {
+        case CTRadioAccessTechnologyGPRS:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
+        case CTRadioAccessTechnologyEdge:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
+        case CTRadioAccessTechnologyWCDMA:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+        case CTRadioAccessTechnologyCDMA1x:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+        case CTRadioAccessTechnologyHSDPA:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
+        case CTRadioAccessTechnologyHSUPA:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
+        case CTRadioAccessTechnologyCDMAEVDORev0:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
+        case CTRadioAccessTechnologyCDMAEVDORevA:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
+        case CTRadioAccessTechnologyCDMAEVDORevB:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
+        case CTRadioAccessTechnologyeHRPD:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
+        case CTRadioAccessTechnologyLTE:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
+        default:
+          subtype =
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+        }
+
+        if #available(iOS 14.1, *) {
+          if mobileSubtype == CTRadioAccessTechnologyNRNSA || mobileSubtype ==
+            CTRadioAccessTechnologyNR {
+            subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
+          }
+        }
+      #else // os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
         subtype =
           firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
-      }
+      #endif // os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+    #else // swift(>=5.9)
+      #if os(iOS) && !targetEnvironment(macCatalyst)
+        switch mobileSubtype {
+        case CTRadioAccessTechnologyGPRS:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
+        case CTRadioAccessTechnologyEdge:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
+        case CTRadioAccessTechnologyWCDMA:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+        case CTRadioAccessTechnologyCDMA1x:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+        case CTRadioAccessTechnologyHSDPA:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
+        case CTRadioAccessTechnologyHSUPA:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
+        case CTRadioAccessTechnologyCDMAEVDORev0:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
+        case CTRadioAccessTechnologyCDMAEVDORevA:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
+        case CTRadioAccessTechnologyCDMAEVDORevB:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
+        case CTRadioAccessTechnologyeHRPD:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
+        case CTRadioAccessTechnologyLTE:
+          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
+        default:
+          subtype =
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+        }
 
-      if #available(iOS 14.1, *) {
-        if mobileSubtype == CTRadioAccessTechnologyNRNSA || mobileSubtype ==
-          CTRadioAccessTechnologyNR {
-          subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
+        if #available(iOS 14.1, *) {
+          if mobileSubtype == CTRadioAccessTechnologyNRNSA || mobileSubtype ==
+            CTRadioAccessTechnologyNR {
+            subtype = firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
+          }
         }
-      }
-    #else
-      subtype =
-        firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+      #else // os(iOS) && !targetEnvironment(macCatalyst)
+        subtype =
+          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+      #endif // os(iOS) && !targetEnvironment(macCatalyst)
     #endif
 
     return subtype

+ 383 - 180
FirebaseSessions/Tests/Unit/SessionStartEventTests.swift

@@ -222,11 +222,19 @@ class SessionStartEventTests: XCTestCase {
     mockNetworkInfo.networkType = .mobile
     // Mobile Subtypes are always empty on non-iOS platforms, and
     // Performance doesn't support those platforms anyways
-    #if os(iOS) && !targetEnvironment(macCatalyst)
-      mockNetworkInfo.mobileSubtype = CTRadioAccessTechnologyHSUPA
-    #else
-      mockNetworkInfo.mobileSubtype = ""
-    #endif
+    #if swift(>=5.9)
+      #if os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+        mockNetworkInfo.mobileSubtype = CTRadioAccessTechnologyHSUPA
+      #else // os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+        mockNetworkInfo.mobileSubtype = ""
+      #endif // os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+    #else // swift(>=5.9)
+      #if os(iOS) && !targetEnvironment(macCatalyst)
+        mockNetworkInfo.mobileSubtype = CTRadioAccessTechnologyHSUPA
+      #else // os(iOS) && !targetEnvironment(macCatalyst)
+        mockNetworkInfo.mobileSubtype = ""
+      #endif // os(iOS) && !targetEnvironment(macCatalyst)
+    #endif // os(iOS) && !targetEnvironment(macCatalyst)
     appInfo.networkInfo = mockNetworkInfo
 
     let event = SessionStartEvent(sessionInfo: defaultSessionInfo, appInfo: appInfo, time: time)
@@ -265,17 +273,31 @@ class SessionStartEventTests: XCTestCase {
       )
       // Mobile Subtypes are always empty on non-iOS platforms, and
       // Performance doesn't support those platforms anyways
-      #if os(iOS) && !targetEnvironment(macCatalyst)
-        XCTAssertEqual(
-          event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
-        )
-      #else
-        XCTAssertEqual(
-          event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
-        )
-      #endif
+      #if swift(>=5.9)
+        #if os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+          XCTAssertEqual(
+            event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
+          )
+        #else // os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+          XCTAssertEqual(
+            event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+          )
+        #endif // os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+      #else // swift(>=5.9)
+        #if os(iOS) && !targetEnvironment(macCatalyst)
+          XCTAssertEqual(
+            event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
+          )
+        #else // os(iOS) && !targetEnvironment(macCatalyst)
+          XCTAssertEqual(
+            event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+          )
+        #endif // os(iOS) && !targetEnvironment(macCatalyst)
+      #endif // swift(>=5.9)
       assertEqualProtoString(
         proto.application_info.apple_app_info.mcc_mnc,
         expected: "",
@@ -330,180 +352,361 @@ class SessionStartEventTests: XCTestCase {
   }
 
   /// Following tests can be run only in iOS environment
-  #if os(iOS) && !targetEnvironment(macCatalyst)
-    func test_convertMobileSubtype_convertsCorrectlyPreOS14() {
-      let expectations: [(
-        given: String,
-        expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
-      )] = [
-        (
-          CTRadioAccessTechnologyGPRS,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
-        ),
-        (
-          CTRadioAccessTechnologyEdge,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
-        ),
-        (
-          CTRadioAccessTechnologyWCDMA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
-        ),
-        (
-          CTRadioAccessTechnologyCDMA1x,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
-        ),
-        (
-          CTRadioAccessTechnologyHSDPA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
-        ),
-        (
-          CTRadioAccessTechnologyHSUPA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
-        ),
-        (
-          CTRadioAccessTechnologyCDMAEVDORev0,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
-        ),
-        (
-          CTRadioAccessTechnologyCDMAEVDORevA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
-        ),
-        (
-          CTRadioAccessTechnologyCDMAEVDORevB,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
-        ),
-        (
-          CTRadioAccessTechnologyeHRPD,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
-        ),
-        (
-          CTRadioAccessTechnologyLTE,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
-        ),
-        (
-          "random",
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
-        ),
-      ]
-
-      expectations
-        .forEach { (
+  #if swift(>=5.9)
+    #if os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+      func test_convertMobileSubtype_convertsCorrectlyPreOS14() {
+        let expectations: [(
           given: String,
           expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
-        ) in
-          let mockNetworkInfo = MockNetworkInfo()
-          mockNetworkInfo.mobileSubtype = given
-          appInfo.networkInfo = mockNetworkInfo
-
-          let event = SessionStartEvent(
-            sessionInfo: self.defaultSessionInfo,
-            appInfo: appInfo,
-            time: time
-          )
+        )] = [
+          (
+            CTRadioAccessTechnologyGPRS,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
+          ),
+          (
+            CTRadioAccessTechnologyEdge,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
+          ),
+          (
+            CTRadioAccessTechnologyWCDMA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+          ),
+          (
+            CTRadioAccessTechnologyCDMA1x,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+          ),
+          (
+            CTRadioAccessTechnologyHSDPA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
+          ),
+          (
+            CTRadioAccessTechnologyHSUPA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORev0,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORevA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORevB,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
+          ),
+          (
+            CTRadioAccessTechnologyeHRPD,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
+          ),
+          (
+            CTRadioAccessTechnologyLTE,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
+          ),
+          (
+            "random",
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+          ),
+        ]
+
+        expectations
+          .forEach { (
+            given: String,
+            expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
+          ) in
+            let mockNetworkInfo = MockNetworkInfo()
+            mockNetworkInfo.mobileSubtype = given
+            appInfo.networkInfo = mockNetworkInfo
+
+            let event = SessionStartEvent(
+              sessionInfo: self.defaultSessionInfo,
+              appInfo: appInfo,
+              time: time
+            )
 
-          // These fields will only be filled in when the Perf SDK is installed
-          event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
+            // These fields will only be filled in when the Perf SDK is installed
+            event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
 
-          testProtoAndDecodedProto(sessionEvent: event) { proto in
-            XCTAssertEqual(
-              event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
-              expected
+            testProtoAndDecodedProto(sessionEvent: event) { proto in
+              XCTAssertEqual(
+                event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
+                expected
+              )
+            }
+          }
+      }
+    #endif // os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+  #else // swift(>=5.9)
+    #if os(iOS) && !targetEnvironment(macCatalyst)
+      func test_convertMobileSubtype_convertsCorrectlyPreOS14() {
+        let expectations: [(
+          given: String,
+          expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
+        )] = [
+          (
+            CTRadioAccessTechnologyGPRS,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
+          ),
+          (
+            CTRadioAccessTechnologyEdge,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
+          ),
+          (
+            CTRadioAccessTechnologyWCDMA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+          ),
+          (
+            CTRadioAccessTechnologyCDMA1x,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+          ),
+          (
+            CTRadioAccessTechnologyHSDPA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
+          ),
+          (
+            CTRadioAccessTechnologyHSUPA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORev0,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORevA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORevB,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
+          ),
+          (
+            CTRadioAccessTechnologyeHRPD,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
+          ),
+          (
+            CTRadioAccessTechnologyLTE,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
+          ),
+          (
+            "random",
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+          ),
+        ]
+
+        expectations
+          .forEach { (
+            given: String,
+            expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
+          ) in
+            let mockNetworkInfo = MockNetworkInfo()
+            mockNetworkInfo.mobileSubtype = given
+            appInfo.networkInfo = mockNetworkInfo
+
+            let event = SessionStartEvent(
+              sessionInfo: self.defaultSessionInfo,
+              appInfo: appInfo,
+              time: time
             )
+
+            // These fields will only be filled in when the Perf SDK is installed
+            event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
+
+            testProtoAndDecodedProto(sessionEvent: event) { proto in
+              XCTAssertEqual(
+                event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
+                expected
+              )
+            }
           }
-        }
-    }
-  #endif
-
-  #if os(iOS) && !targetEnvironment(macCatalyst)
-    @available(iOS 14.1, *)
-    func test_convertMobileSubtype_convertsCorrectlyPostOS14() {
-      let expectations: [(
-        given: String,
-        expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
-      )] = [
-        (
-          CTRadioAccessTechnologyGPRS,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
-        ),
-        (
-          CTRadioAccessTechnologyEdge,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
-        ),
-        (
-          CTRadioAccessTechnologyWCDMA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
-        ),
-        (
-          CTRadioAccessTechnologyCDMA1x,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
-        ),
-        (
-          CTRadioAccessTechnologyHSDPA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
-        ),
-        (
-          CTRadioAccessTechnologyHSUPA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
-        ),
-        (
-          CTRadioAccessTechnologyCDMAEVDORev0,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
-        ),
-        (
-          CTRadioAccessTechnologyCDMAEVDORevA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
-        ),
-        (
-          CTRadioAccessTechnologyCDMAEVDORevB,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
-        ),
-        (
-          CTRadioAccessTechnologyeHRPD,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
-        ),
-        (
-          CTRadioAccessTechnologyLTE,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
-        ),
-        (
-          CTRadioAccessTechnologyNRNSA,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
-        ),
-        (
-          CTRadioAccessTechnologyNR,
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
-        ),
-        (
-          "random",
-          firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
-        ),
-      ]
-
-      expectations
-        .forEach { (
+      }
+    #endif // os(iOS) && !targetEnvironment(macCatalyst)
+  #endif // swift(>=5.9)
+
+  #if swift(>=5.9)
+    #if os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+      @available(iOS 14.1, *)
+      func test_convertMobileSubtype_convertsCorrectlyPostOS14() {
+        let expectations: [(
           given: String,
           expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
-        ) in
-          let mockNetworkInfo = MockNetworkInfo()
-          mockNetworkInfo.mobileSubtype = given
-          appInfo.networkInfo = mockNetworkInfo
-
-          let event = SessionStartEvent(
-            sessionInfo: self.defaultSessionInfo,
-            appInfo: appInfo,
-            time: time
-          )
+        )] = [
+          (
+            CTRadioAccessTechnologyGPRS,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
+          ),
+          (
+            CTRadioAccessTechnologyEdge,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
+          ),
+          (
+            CTRadioAccessTechnologyWCDMA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+          ),
+          (
+            CTRadioAccessTechnologyCDMA1x,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+          ),
+          (
+            CTRadioAccessTechnologyHSDPA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
+          ),
+          (
+            CTRadioAccessTechnologyHSUPA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORev0,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORevA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORevB,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
+          ),
+          (
+            CTRadioAccessTechnologyeHRPD,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
+          ),
+          (
+            CTRadioAccessTechnologyLTE,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
+          ),
+          (
+            CTRadioAccessTechnologyNRNSA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
+          ),
+          (
+            CTRadioAccessTechnologyNR,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
+          ),
+          (
+            "random",
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+          ),
+        ]
+
+        expectations
+          .forEach { (
+            given: String,
+            expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
+          ) in
+            let mockNetworkInfo = MockNetworkInfo()
+            mockNetworkInfo.mobileSubtype = given
+            appInfo.networkInfo = mockNetworkInfo
+
+            let event = SessionStartEvent(
+              sessionInfo: self.defaultSessionInfo,
+              appInfo: appInfo,
+              time: time
+            )
 
-          // These fields will only be filled in when the Perf SDK is installed
-          event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
+            // These fields will only be filled in when the Perf SDK is installed
+            event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
 
-          testProtoAndDecodedProto(sessionEvent: event) { proto in
-            XCTAssertEqual(
-              event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
-              expected
+            testProtoAndDecodedProto(sessionEvent: event) { proto in
+              XCTAssertEqual(
+                event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
+                expected
+              )
+            }
+          }
+      }
+    #endif // os(iOS) && !targetEnvironment(macCatalyst) && !os(xrOS)
+  #else // swift(>=5.9)
+    #if os(iOS) && !targetEnvironment(macCatalyst)
+      @available(iOS 14.1, *)
+      func test_convertMobileSubtype_convertsCorrectlyPostOS14() {
+        let expectations: [(
+          given: String,
+          expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
+        )] = [
+          (
+            CTRadioAccessTechnologyGPRS,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_GPRS
+          ),
+          (
+            CTRadioAccessTechnologyEdge,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EDGE
+          ),
+          (
+            CTRadioAccessTechnologyWCDMA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+          ),
+          (
+            CTRadioAccessTechnologyCDMA1x,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_CDMA
+          ),
+          (
+            CTRadioAccessTechnologyHSDPA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSDPA
+          ),
+          (
+            CTRadioAccessTechnologyHSUPA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_HSUPA
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORev0,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_0
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORevA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_A
+          ),
+          (
+            CTRadioAccessTechnologyCDMAEVDORevB,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EVDO_B
+          ),
+          (
+            CTRadioAccessTechnologyeHRPD,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_EHRPD
+          ),
+          (
+            CTRadioAccessTechnologyLTE,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_LTE
+          ),
+          (
+            CTRadioAccessTechnologyNRNSA,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
+          ),
+          (
+            CTRadioAccessTechnologyNR,
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_NR
+          ),
+          (
+            "random",
+            firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype_UNKNOWN_MOBILE_SUBTYPE
+          ),
+        ]
+
+        expectations
+          .forEach { (
+            given: String,
+            expected: firebase_appquality_sessions_NetworkConnectionInfo_MobileSubtype
+          ) in
+            let mockNetworkInfo = MockNetworkInfo()
+            mockNetworkInfo.mobileSubtype = given
+            appInfo.networkInfo = mockNetworkInfo
+
+            let event = SessionStartEvent(
+              sessionInfo: self.defaultSessionInfo,
+              appInfo: appInfo,
+              time: time
             )
+
+            // These fields will only be filled in when the Perf SDK is installed
+            event.set(subscriber: .Performance, isDataCollectionEnabled: true, appInfo: appInfo)
+
+            testProtoAndDecodedProto(sessionEvent: event) { proto in
+              XCTAssertEqual(
+                event.proto.application_info.apple_app_info.network_connection_info.mobile_subtype,
+                expected
+              )
+            }
           }
-        }
-    }
-  #endif
+      }
+    #endif // os(iOS) && !targetEnvironment(macCatalyst)
+  #endif // swift(>=5.9)
 }