Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -209,11 +209,6 @@ public class URLSessionInstrumentation {
}
}
self.setIdKey(value: sessionTaskId, for: task)

// We want to identify background tasks
if session.configuration.identifier == nil {
objc_setAssociatedObject(task, "IsBackground", true, .OBJC_ASSOCIATION_RETAIN_NONATOMIC)
}
return task
}
let swizzledIMP = imp_implementationWithBlock(
Expand Down Expand Up @@ -743,15 +738,12 @@ public class URLSessionInstrumentation {
return
}

// We cannot instrument async background tasks because they crash if you assign a delegate
if #available(OSX 13.0, iOS 16.0, watchOS 9.0, tvOS 16.0, *) {
if objc_getAssociatedObject(task, "IsBackground") is Bool {
guard Task.basePriority == nil else {
return
}
}
// Background tasks cannot be instrumented because they crash if you assign a delegate
// They require the delegate to be set when creating the session
guard !task.isBackground else {
return
}

let taskId = idKeyForTask(task)
if let request = task.currentRequest {
queue.sync {
Expand Down Expand Up @@ -878,3 +870,18 @@ class AsyncTaskDelegate: NSObject, URLSessionTaskDelegate {
}
}
}

extension URLSessionTask {
var isBackground: Bool {
[
"__NSCFBackgroundAVAggregateAssetDownloadTask",
"__NSCFBackgroundAVAggregateAssetDownloadTaskNoChildTask",
"__NSCFBackgroundAVAssetDownloadTask",
"__NSCFBackgroundDataTask",
"__NSCFBackgroundDownloadTask",
"__NSCFBackgroundSessionTask",
"__NSCFBackgroundUploadTask"
]
.contains(String(describing: type(of: self)))
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -1057,4 +1057,28 @@ class URLSessionInstrumentationTests: XCTestCase {
XCTAssertEqual(attributes["server.port"]?.description, "8080")
XCTAssertEqual(attributes["url.scheme"]?.description, "http")
}

// MARK: - Background session tests
@available(macOS 10.15, iOS 15.0, tvOS 15.0, watchOS 8.0, *)
public func testBackgroundSession_ShouldNotCrashWhenAssigningDelegate() async throws {
let request = URLRequest(url: URL(string: "http://localhost:33333/success")!)

// Background sessions require a delegate to be set when creating the session.
// However, for this test, we set to nil so it tries to do it on resume (where the crash happens)
let session = URLSession(
configuration: URLSessionConfiguration.background(
withIdentifier: UUID().uuidString
),
delegate: nil,
delegateQueue: .main
)

// Background sessions cannot use async/await or completion handlers
// Must use dataTask(with:) and call resume()
let task = session.dataTask(with: request)
task.resume()

// The test passes if tasks completes without crashing.
wait { task.state == .completed }
}
}
24 changes: 24 additions & 0 deletions Tests/Shared/TestUtils/XCTestCase+Wait.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//
// Copyright The OpenTelemetry Authors
// SPDX-License-Identifier: Apache-2.0
//

import XCTest

extension XCTestCase {
public func wait(timeout: TimeInterval = 3, interval: TimeInterval = 0.1, until block: @escaping () throws -> Bool) {
let expectation = expectation(description: "wait for block to pass")
let timer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { _ in
do {
if try block() {
expectation.fulfill()
}
} catch {
fatalError("Waiting for operation that threw an error: \(error)")
}
}

wait(for: [expectation], timeout: timeout)
timer.invalidate()
}
}
Loading