Skip to content

[Performance] Fix missing network traces for Swift async/await URLSession requests on iOS 16+ (#11861)#15982

Open
JesusRojass wants to merge 15 commits intofirebase:mainfrom
JesusRojass:JesusRojass/#11861
Open

[Performance] Fix missing network traces for Swift async/await URLSession requests on iOS 16+ (#11861)#15982
JesusRojass wants to merge 15 commits intofirebase:mainfrom
JesusRojass:JesusRojass/#11861

Conversation

@JesusRojass
Copy link
Copy Markdown
Collaborator

@JesusRojass JesusRojass commented Mar 26, 2026

Discussion

Fixes #11861

Firebase Performance instruments NSURLSession by swizzling ObjC methods on session delegate
classes and task creation methods. This works well for traditional ObjC style request patterns
(completion handlers, delegate callbacks), but Swift async/await URLSession methods like
data(for:), download(for:), bytes(for:) are pure Swift extensions on URLSession with
no ObjC selector, so they are invisible to method swizzling and not traced on iOS 16+.

Changes

Two NSURLSessionTaskDelegate callbacks are now instrumented for both ObjC and async/await
created tasks:

  • URLSession:didCreateTask: (iOS 16+): entry point to attach a FPRNetworkTrace to the
    task. Skips if the ObjC task creation swizzle already attached one.

  • URLSession:task:didFinishCollectingMetrics: (iOS 10+): exit point to complete and
    remove the trace. Uses NSURLSessionTaskTransactionMetrics for accurate byte counts. The
    traceCompleted guard in FPRNetworkTrace makes this safe to call more than once: for
    completion handler tasks the trace is already gone (early return); for delegate based tasks
    this fires first and didCompleteWithError: becomes a no op.

Both hooks are wired into FPRNSURLSessionDelegate (no user delegate) and
FPRNSURLSessionDelegateInstrument (user delegate present, via class level swizzle and
CopySelector).

Testing

All existing tests pass.

New tests (FPRNSURLSessionInstrumentTest)

  • testDelegateURLSessionTaskDidFinishCollectingMetrics: real HTTP request against the
    hermetic test server, verifies the delegate flag is set and the trace removed after response.

  • testDelegateURLSessionTaskDidFinishCollectingMetricsCopiedForNonImplementingDelegate:
    verifies CopySelector installs didFinishCollectingMetrics: on delegates that do not
    implement it, ensuring async/await tasks are traced even for sparse delegate implementations.

  • testDidCreateTaskDoesNotDoubleTraceObjCCreatedTask: verifies that when didCreateTask:
    fires for an ObjC created task the existing trace is preserved and no duplicate is created.

  • testDelegateURLSessionDidCreateTaskCalledOnIOS16: verifies the didCreateTask: hook
    is wired through the class level swizzle and reaches the user delegate on iOS 16+.

Pre-existing test fixes

  • testDelegateURLSessionTaskDidCompleteWithError (FPRNSURLSessionInstrumentTest):
    replaced http://nonurl + 5 second DNS spin with stopped local server for a deterministic
    "connection refused" failure.

  • testConnectionDidFailWithError (FPRNSURLConnectionInstrumentTest): same fix. The
    new didFinishCollectingMetrics: instrumentation added enough overhead to the shared
    delegate queue to push the DNS timeout past the 2 second window.

API Changes

  • No API Changes.

@gemini-code-assist
Copy link
Copy Markdown
Contributor

Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

@JesusRojass
Copy link
Copy Markdown
Collaborator Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Swift async/await network tasks by implementing and instrumenting URLSession:didCreateTask: and URLSession:task:didFinishCollectingMetrics: delegate methods. The changes also include updates to unit tests for more deterministic failure scenarios and new tests for the async/await functionality. Feedback suggests refactoring duplicated logic in the instrumentation methods into common helper functions for improved maintainability. Additionally, it's recommended to remove > 0 checks when assigning responseSize and requestSize from NSURLSessionTaskTransactionMetrics to ensure accuracy and consistency, as these metrics are considered reliable.

@JesusRojass
Copy link
Copy Markdown
Collaborator Author

/gemini review

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces support for Swift async/await network instrumentation in Firebase Performance. It adds handling for URLSession:didCreateTask: (iOS 16+) and URLSession:task:didFinishCollectingMetrics: (iOS 10+) to capture network traces for tasks where traditional delegate callbacks might be suppressed. The changes include new helper functions, updated instrumentation logic in FPRNSURLSessionDelegateInstrument, and comprehensive unit tests to verify the new behavior and ensure no duplicate traces are created. I have no feedback to provide.

@JesusRojass
Copy link
Copy Markdown
Collaborator Author

The machine is pleased and so am I

Ready for review @visumickey

@JesusRojass
Copy link
Copy Markdown
Collaborator Author

@visumickey All CI/CD check should hopefully pass now!

@JesusRojass
Copy link
Copy Markdown
Collaborator Author

Hello there @tejasd

Wondering if you could help me review this one too please!

@JesusRojass
Copy link
Copy Markdown
Collaborator Author

@tejasd @mghaznav Tagging for review!

@JesusRojass JesusRojass requested review from mghaznav and tejasd April 21, 2026 15:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Swift Concurrency] Performance Monitoring does not collect network traces when using URLSession's async methods

2 participants