fix: prevent main app from blocking notification extension (take 4) - WPB-23511 🍒#4928
fix: prevent main app from blocking notification extension (take 4) - WPB-23511 🍒#4928samwyndham wants to merge 1 commit into
Conversation
zenkins
left a comment
There was a problem hiding this comment.
✅ Auto-approved cherry-pick PR 🍒.
There was a problem hiding this comment.
Pull request overview
This PR replaces the prior withExpiringActivity approach with a background-task “executer” abstraction so the main app can use UIApplication.beginBackgroundTask(...) while app extensions can use a no-op passthrough, reducing the chance that the main app blocks the Notification Service Extension (NSE) and causes it to expire.
Changes:
- Introduces
BackgroundTaskExecuter+withBackgroundTask+PassthroughTaskExecuter(WireSystem) and migrates sync/message-sending work from expiring-activity wrapping to background-task wrapping. - Adds
AppBackgroundTaskExecuterfor the main app and threads abackgroundTaskExecuterdependency through session/sync components; introducesSafeCoreCryptoto run CoreCrypto transactions under the executer. - Updates NSE and share extension cancellation flows to attempt “extra time” cancellation via
ProcessInfo.performExpiringActivity(...), and removes the oldExpiringActivityimplementation/tests.
Reviewed changes
Copilot reviewed 64 out of 66 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| WireDomain/Tests/WireDomainTests/Synchronization/PullPendingUpdateEventsSyncV2Tests.swift | Updates test CoreCrypto provider setup to use SafeCoreCrypto. |
| WireDomain/Tests/WireDomainTests/Synchronization/IncrementalSyncV2Tests.swift | Updates test setup to inject SafeCoreCrypto and PassthroughTaskExecuter. |
| WireDomain/Tests/WireDomainTests/Synchronization/IncrementalSyncTests.swift | Injects PassthroughTaskExecuter into IncrementalSync under test. |
| WireDomain/Sources/WireDomain/Synchronization/IncrementalSyncV2.swift | Wraps live stream processing in withBackgroundTask(...) and stores executer dependency. |
| WireDomain/Sources/WireDomain/Synchronization/IncrementalSync.swift | Wraps live stream processing in withBackgroundTask(...) and stores executer dependency. |
| WireDomain/Sources/WireDomain/Notifications/Protocols/NotificationServiceProtocol.swift | Removes the protocol previously used by the NSE wrapper. |
| WireDomain/Sources/WireDomain/Notifications/NotificationServiceExtension.swift | Removes protocol conformance; adds task state + async cancellation API. |
| WireDomain/Sources/WireDomain/Notifications/Components/NSEUserScope.swift | Threads backgroundTaskExecuter into NSE scopes and refactors payload processing call shape. |
| WireDomain/Sources/WireDomain/Notifications/Components/NSEFlow.swift | Creates a shared PassthroughTaskExecuter for NSE dependency graph. |
| WireDomain/Sources/WireDomain/Notifications/Components/NSEClientScope.swift | Refactors payload processing and injects backgroundTaskExecuter into CoreCrypto provider. |
| WireDomain/Sources/WireDomain/Components/UserSessionComponent.swift | Threads backgroundTaskExecuter through to client session component creation. |
| WireDomain/Sources/WireDomain/Components/ClientSessionComponent.swift | Injects backgroundTaskExecuter into incremental sync initializers. |
| wire-ios/Wire-iOS/Sources/AppRootRouter.swift | Adds backgroundTaskExecuter dependency to router init. |
| wire-ios/Wire-iOS/Sources/AppDelegate.swift | Constructs AppBackgroundTaskExecuter and passes it into session/router wiring. |
| wire-ios/Wire-iOS/Sources/AppBackgroundTaskExecuter.swift | Adds main-app BackgroundTaskExecuter implementation using UIApplication APIs. |
| wire-ios/Wire-iOS.xcodeproj/project.pbxproj | Registers the new executer test file in the Xcode project. |
| wire-ios/Wire-iOS Tests/AppBackgroundTaskExecuterTests.swift | Adds unit tests for background task begin/end + cancellation behaviors. |
| wire-ios/Wire-iOS Share Extension/Sources/Content/PostContent.swift | Adds cancellation logging + expiring-activity wait to keep share extension alive during cancel. |
| wire-ios/Wire Notification Service Extension/NotificationService.swift | Cancels NSE work on expiration and waits (bounded) for cancellation to release file locks. |
| wire-ios/Tests/Sourcery/generated/AutoMockable.generated.swift | Adds a mock for BackgroundTaskApplication used by executer tests. |
| wire-ios-system/Tests/ExpiringActivityTests.swift | Removes tests for the old expiring-activity helper. |
| wire-ios-system/Source/ExpiringActivity.swift | Removes the old expiring-activity helper implementation. |
| wire-ios-system/Source/BackgroundTasks.swift | Introduces BackgroundTaskExecuter, withBackgroundTask, and PassthroughTaskExecuter. |
| wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTestsBase.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests_NetworkState.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-sync-engine/Tests/Source/Use cases/CheckOneOnOneConversationIsReadyUseCaseTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-sync-engine/Tests/Source/Synchronization/SyncAgentTests.swift | Injects PassthroughTaskExecuter into SyncAgent creation in tests. |
| wire-ios-sync-engine/Tests/Source/E2EI/CertificateRevocationListsCheckerTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSessionBuilder.swift | Injects PassthroughTaskExecuter when building user sessions (non-main-app). |
| wire-ios-sync-engine/Source/UserSession/ZMUserSession/ZMUserSession.swift | Threads backgroundTaskExecuter through component construction and sync agent wiring. |
| wire-ios-sync-engine/Source/Synchronization/SyncAgent.swift | Replaces expiring activity usage with withBackgroundTask(...) and stores executer dependency. |
| wire-ios-sync-engine/Source/Synchronization/StrategyDirectory.swift | Adds backgroundTaskExecuter to strategy directory wiring. |
| wire-ios-sync-engine/Source/SessionManager/UserSessionLoader.swift | Threads backgroundTaskExecuter into CoreCrypto provider and session creation. |
| wire-ios-sync-engine/Source/SessionManager/SessionManager.swift | Stores and passes backgroundTaskExecuter down into session loader creation. |
| wire-ios-sync-engine/Source/E2EI/CRL/CertificateRevocationListsChecker.swift | Switches CoreCrypto access type to SafeCoreCrypto. |
| wire-ios-sync-engine/Source/Use cases/GetE2eIdentityCertificatesUseCase.swift | Switches CoreCrypto access type to SafeCoreCrypto for identity fetch. |
| wire-ios-request-strategy/Tests/Helpers/ProteusClientSimulator.swift | Injects PassthroughTaskExecuter into CoreCrypto provider creation in tests. |
| wire-ios-request-strategy/Tests/Helpers/MessagingTestBase.swift | Injects PassthroughTaskExecuter into CoreCrypto provider creation in tests. |
| wire-ios-request-strategy/Sources/Message Sending/MessageSenderTests.swift | Adds PassthroughTaskExecuter to strategy directory creation in tests. |
| wire-ios-request-strategy/Sources/Message Sending/MessageSender.swift | Replaces expiring activity usage with withBackgroundTask(...) and stores executer dependency. |
| wire-ios-request-strategy/Sources/E2EIdentity/E2EIKeyPackageRotatorTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-request-strategy/Sources/E2EIdentity/E2EIKeyPackageRotator.swift | Switches CoreCrypto access type to SafeCoreCrypto. |
| wire-ios-share-engine/WireShareEngineTests/BaseSharingSessionTests.swift | Injects PassthroughTaskExecuter into strategy directory creation in tests. |
| wire-ios-share-engine/Sources/StrategyFactory.swift | Adds backgroundTaskExecuter to strategy directory construction. |
| wire-ios-share-engine/Sources/SharingSessionLoader.swift | Creates and threads a PassthroughTaskExecuter through strategy/core-crypto wiring. |
| wire-ios-share-engine/Sources/SharingSession.swift | Creates and threads a PassthroughTaskExecuter through strategy/core-crypto wiring. |
| wire-ios-data-model/WireDataModel.xcodeproj/project.pbxproj | Adds SafeCoreCrypto.swift to the WireDataModel build. |
| wire-ios-data-model/Tests/UseCases/IsUserE2EICertifiedUseCaseTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-data-model/Tests/Source/E2EIdentity/E2EIVerificationStatusServiceTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-data-model/Tests/Source/E2EIdentity/E2EIServiceTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-data-model/Tests/Proteus/ProteusServiceTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-data-model/Tests/MLS/MLSServiceTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-data-model/Tests/MLS/MLSEncryptionServiceTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-data-model/Tests/MLS/MLSActionExecutorTests.swift | Updates CoreCrypto provider mocking to return SafeCoreCrypto. |
| wire-ios-data-model/Support/Sources/CoreCryptoMocksEnvelope.swift | Wraps mock core crypto in SafeCoreCrypto for support scaffolding. |
| wire-ios-data-model/Support/Sourcery/generated/AutoMockable.generated.swift | Updates CoreCryptoProviderProtocol mock return type to SafeCoreCrypto. |
| wire-ios-data-model/Source/Proteus/ProteusService.swift | Switches CoreCrypto access type to SafeCoreCrypto and uses .transaction. |
| wire-ios-data-model/Source/MLS/MLSService.swift | Switches CoreCrypto access type to SafeCoreCrypto. |
| wire-ios-data-model/Source/MLS/MLSEncryptionService.swift | Switches CoreCrypto access type to SafeCoreCrypto. |
| wire-ios-data-model/Source/MLS/MLSActionExecutor.swift | Switches CoreCrypto access type to SafeCoreCrypto. |
| wire-ios-data-model/Source/MLS/CreateMLSGroupUseCase.swift | Switches CoreCrypto dependency type to SafeCoreCrypto. |
| wire-ios-data-model/Source/E2EIdentity/E2EIVerificationStatusService.swift | Switches CoreCrypto access type to SafeCoreCrypto. |
| wire-ios-data-model/Source/E2EIdentity/E2EISetupService.swift | Switches CoreCrypto access type to SafeCoreCrypto. |
| wire-ios-data-model/Source/E2EIdentity/E2EIService.swift | Switches CoreCrypto access type to SafeCoreCrypto. |
| wire-ios-data-model/Source/Core Crypto/SafeCoreCrypto.swift | Adds wrapper to run CoreCrypto transactions inside withBackgroundTask. |
| wire-ios-data-model/Source/Core Crypto/CoreCryptoProvider.swift | Changes provider API to return SafeCoreCrypto and injects backgroundTaskExecuter. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| public func withBackgroundTask<T: Sendable>( | ||
| name: String? = nil, | ||
| executer: any BackgroundTaskExecuter, | ||
| operation: sending @escaping @isolated(any) () async throws -> T | ||
| ) async throws -> T { | ||
| try await executer.execute(name: name, operation: operation) | ||
| } |
| func cancel(completion: @escaping () -> Void) { | ||
| sendController?.cancel(completion: completion) | ||
| guard let sendController else { return } | ||
|
|
Test Results 6 files 881 suites 9m 29s ⏱️ Results for commit 75b882f. ♻️ This comment has been updated with latest results. Summary: workflow run #28325826861 |
… WPB-23511 (#4880) # Conflicts: # WireDomain/Sources/WireDomain/Notifications/Components/NSEClientScope.swift # WireDomain/Sources/WireDomain/Notifications/NotificationServiceExtension.swift # WireDomain/Tests/WireDomainTests/Synchronization/IncrementalSyncV2Tests.swift # WireDomain/Tests/WireDomainTests/Synchronization/PullPendingUpdateEventsSyncV2Tests.swift # wire-ios-data-model/Source/Core Crypto/CoreCryptoProvider.swift # wire-ios-data-model/Source/Core Crypto/SafeCoreCrypto.swift # wire-ios-data-model/Support/Sources/CoreCryptoMocksEnvelope.swift # wire-ios-data-model/Tests/MLS/MLSActionExecutorTests.swift # wire-ios-data-model/Tests/MLS/MLSEncryptionServiceTests.swift # wire-ios-data-model/Tests/MLS/MLSServiceTests.swift # wire-ios-data-model/Tests/Proteus/ProteusServiceTests.swift # wire-ios-data-model/Tests/Source/E2EIdentity/E2EIServiceTests.swift # wire-ios-data-model/Tests/Source/E2EIdentity/E2EIVerificationStatusServiceTests.swift # wire-ios-data-model/Tests/UseCases/IsUserE2EICertifiedUseCaseTests.swift # wire-ios-request-strategy/Sources/E2EIdentity/E2EIKeyPackageRotatorTests.swift # wire-ios-request-strategy/Tests/Helpers/MessagingTestBase.swift # wire-ios-request-strategy/Tests/Helpers/ProteusClientSimulator.swift # wire-ios-share-engine/Sources/SharingSession.swift # wire-ios-share-engine/Sources/SharingSessionLoader.swift # wire-ios-sync-engine/Source/SessionManager/UserSessionLoader.swift # wire-ios-sync-engine/Tests/Source/E2EI/CertificateRevocationListsCheckerTests.swift # wire-ios-sync-engine/Tests/Source/Use cases/CheckOneOnOneConversationIsReadyUseCaseTests.swift # wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTestsBase.swift # wire-ios-sync-engine/Tests/Source/UserSession/ZMUserSessionTests_NetworkState.swift # wire-ios-system/Source/ExpiringActivity.swift # wire-ios-system/Tests/ExpiringActivityTests.swift # wire-ios/Wire-iOS/Sources/AppDelegate.swift
44a8401 to
75b882f
Compare
|



Issue
This is a cherry pick of #4880 to 4.16.
Some minor manual changes were necessary to make use of they
SafeCoreCryptotype which wasn't present in 4.16Testing
See #4880
Checklist
[WPB-XXX].