SystemExtension getting replacement delegate callback with same version

In recent versions of macOS Big Sur and Monterey, SystemExtnesions are getting replaced with same version.

We have an application with a system extension and UI in the app displays status of the system extension to remind users to approve it in case they have not. Since there is no way to query the status of a SystemExtnesion, to display the status in UI, we would submit the SystemExtension request every time UI is displayed and update the status as per the delegate callback. Earlier, if SystemExtension is already approved, with would immediately get .completed result.

However, since recently we are noticing that whenever the app submits the extension request, if there is already an approved SystemExtension, then replacement delegate callback is triggered for same extension version. If we return .replace action, the existing SystemExtension is getting disabled and replaced with SystemExtension of same version. This is contradictory to the documentation of replacement delegate callback which indicates that replacement request will only be called when an extension of different version is found.

From the documentation:

The manager calls this method when it encounters an existing extension with the same team and bundle identifiers, but with different version identifiers. It uses the CFBundleVersion and CFBundleShortVersionString identifiers to determine if the existing and new versions differ. The delegate must make a decision on whether to replace the existing extension.

This issue is noticed in development as well as production signed version of our application and in the same run of the same application process.

This unexpected behaviour is causing issues in our app. For example, when the existing SystemExtension is being disabled, all our network extensions are being stopped. This is resulting in loss of functionality.

Here are some relevant console logs, attached.

Answered by ForumsContributor in

I don’t have any insight into your main issue but I found this strange:

Since there is no way to query the status of a [system extension]

Starting with macOS 12 you can use the propertiesRequest(forExtensionWithIdentifier:queue:) class method to get info like this. The docs are less than ideal — please do file bug about that — but there’s useful info in the <SystemExtensions/SystemExtensions.h> header.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@" + "apple.com"

Thanks for the tip @eskimo. Currently we are supporting macOS 11+ but will definitely use the new API for Monterey. Here is the feedback for documentation update: FB9964722

As for the original issue, we noticed that replacement with same version only happens when developer mode is enabled (systemextensionsctl developer on), on the machine, regardless of SIP status. Once we turn off developer mode, the API starts working properly and we do not get delegate callback for replacement of same version. It directly jumps to completed result.

I am not sure why this behaviour and could not find any documentation regarding this.

I hope this information helps others in future.

Accepted Answer

@dispatchMain - This behavior is documented:

If the local system has System Extension developer mode enabled, the manager always calls this method when it finds an existing installation, even if the version identifiers match.

SystemExtension getting replacement delegate callback with same version
 
 
Q