obsproject / obs-studio

OBS Studio - Free and open source software for live streaming and screen recording
https://obsproject.com
GNU General Public License v2.0
57.19k stars 7.71k forks source link

mac-virtualcam: No easy way to uninstall system extension if app is removed without using Finder #9714

Open niw opened 8 months ago

niw commented 8 months ago

Operating System Info

macOS 13

Other OS

No response

OBS Studio Version

30.0.0-rc1

OBS Studio Version (Other)

No response

OBS Studio Log URL

https://obsproject.com/logs/YBw0Kw8hOZbeYFav

OBS Studio Crash Log URL

No response

Expected Behavior

mac-virtualcam plugin only provides the code that installs system extension but doesn't provide any way to uninstall it. The previous DAL plugin can be uninstalled manually by users operations, but for the system extension, the container app should provide the interface to do so by deactivationRequestForExtension API, otherwise users can't remove it.

The expected code is like this (there is missing static in the code, by the way.)

diff --git a/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm b/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm
index 2bea96a30..8d2b65ada 100644
--- a/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm
+++ b/plugins/mac-virtualcam/src/obs-plugin/plugin-main.mm
@@ -13,7 +13,8 @@ MODULE_EXPORT const char *obs_module_description(void)
     return "macOS virtual webcam output";
 }

-NSString *const OBSDalDestination = @"/Library/CoreMediaIO/Plug-Ins/DAL";
+static NSString *const OBSDalDestination = @"/Library/CoreMediaIO/Plug-Ins/DAL";
+static NSString *const SystemExtensionIdentifier = @"com.obsproject.obs-studio.mac-camera-extension";

 static bool cmio_extension_supported()
 {
@@ -125,13 +126,22 @@ struct virtualcam_data {
 static void install_cmio_system_extension(struct virtualcam_data *vcam)
 {
     OSSystemExtensionRequest *request = [OSSystemExtensionRequest
-        activationRequestForExtension:@"com.obsproject.obs-studio.mac-camera-extension"
+        activationRequestForExtension:SystemExtensionIdentifier
                                 queue:dispatch_get_main_queue()];
     request.delegate = vcam->extensionDelegate;

     [[OSSystemExtensionManager sharedManager] submitRequest:request];
 }

+static void uninstall_cmio_system_extension(struct virtualcam_data *vcam)
+{
+    OSSystemExtensionRequest *request = [OSSystemExtensionRequest
+        deactivationRequestForExtension:SystemExtensionIdentifier
+                                  queue:dispatch_get_main_queue()];
+
+    [[OSSystemExtensionManager sharedManager] submitRequest:request];
+}
+
 typedef enum {
     OBSDalPluginNotInstalled,
     OBSDalPluginInstalled,

This is not enough of course, because we need to add also an user interface to call this uninstall_cmio_system_extension from somewhere, such as in the menu action.

Current Behavior

Users can't uninstall system extension once the app launched.

Steps to Reproduce

  1. Place OBS.app on /Applications
  2. Launch it, which will install an system extension to the system. Approve it in Settings app.
  3. Uninstall OBS.app, by dragging it to the trash.
  4. Restart macOS, if you want.
  5. Run systemextensionsctl list

Expected behavior OBS virtual camera system extension should not be there, or provide a way to unstall it before step 3.

Actual behavior OBS virtual camera system extension stay there and users have no way to remove it.

Anything else we should know?

Note that systemextensionsctl uninstall doesn't work on macOS without disabling SIP, which is highly not recommended to do so and that is not what regular users can do.

$ systemextensionsctl uninstall - com.obsproject.obs-studio.mac-camera-extension
At this time, this tool cannot be used if System Integrity Protection is enabled.
This limitation will be removed in the near future.
Please remember to re-enable System Integrity Protection!
niw commented 8 months ago

@gxalpha Just fyi, wondering if you have already a good idea to provide a way to uninstall the system extension.

gxalpha commented 8 months ago

I'm a bit torn on this one personally. In theory, step 3 ("Uninstall OBS.app, by dragging it to the trash") also uninstalls the system extension, and if it doesn’t that’s usually a system issue. There are known ways to screw this up however (e.g. I believe by rm -rf-ing the app instead of using the finder, or by fiddling with the contents of the installed bundle) and I wouldn’t want to make users use systemextensionsctl for the reason you stated above.

Anyways @PatTheMav probably has opinions here as well.

niw commented 8 months ago

@gxalpha Thank you for replying, and I tried step 3 again by copying OBS.app in /Application again, then now Finder shows a dialog about uninstalling the system extension... but it was not appering. As you mentioned, likely it was a system issue (and I am sure I was not using rm -rf before just using Finder to remove it...)

I wonder if adding deactivationRequestForExtension:queue: helps such situations (not sure how it's common,) or probably just noting about retrying trash the app with Finder (like here, this issue) would be enough.

gxalpha commented 8 months ago

Interesting. Did you initially only use official OBS builds or did you also build OBS yourself?

PatTheMav commented 8 months ago

I'm not against this possibility in principle - the removal of the app and macOS' automatic extension removal are a nice convenience feature, but allowing users to explicitly uninstall/install the extension is a nice thing to have.

Code-wise it's simple enough, I think the UX/UI work might take more effort.

In an ideal world I'd like to have explicit buttons to install/uninstall either the camera extension or DAL plugin (UX-wise it makes no difference, should be the same buttons) and also a prompt asking whether a missing "thing" (either plugin or extension) should be installed.

There is one scenario that will require testing however:

  1. Install OBS Studio
  2. Install Camera Extension
  3. Remove OBS Studio manually
  4. Install OBS Studio again
  5. Attempt to uninstall Camera Extension

My hunch is that there is some internal mechanism in macOS that matches system extension installations with Application Bundle instances. I've ended up with the system extension being installed twice (because bundleVersion was different), but removing the app only ever removed one instance of the extension.

niw commented 8 months ago

@gxalpha I had the binary built from the source separately actually in the different path, which may be related. Thus, probably it was my specific environment issue... and rare or limited corner case. Thus, I rephased the issue title to make thing clear.

niw commented 8 months ago

@PatTheMav I certainly agree if we could have such user interface, or even command line actions, that would be nice. I also wonder if deactivationRequestForExtension:queue: call can handle the all installed versions or, probably only the specific version... that may be related to this 61a492236493c7c0db851a3e143c82021b8e3adc commit.

PatTheMav commented 8 months ago

@PatTheMav I certainly agree if we could have such user interface, or even command line actions, that would be nice. I also wonder if deactivationRequestForExtension:queue: call can handle the all installed versions or, probably only the specific version... that may be related to this 61a4922 commit.

I would expect it to only handle one installed version, because there is a 1-to-1 mapping of extension to application, so if we ask to uninstall the extension it will only affect the version that is mapped to the version of the application bundle on the system.

The deactivation request only takes the identifier of the extension, because the expectation for them is to have only one variant installed in the system. Duplicates are more of a bug than a supported/expected state of the system.

elkinjosetm commented 7 months ago

Hi, is there a way to uninstall the camera without disabling SIP? I had to install OBS 30 to try something, but now that I removed it, I still see the camera as "available"

PatTheMav commented 7 months ago

Hi, is there a way to uninstall the camera without disabling SIP? I had to install OBS 30 to try something, but now that I removed it, I still see the camera as "available"

The canonical way is to delete the application in Finder - it will pop up a warning that the application contains a system extension and requires your approval that it should continue with the removal.

The system extension will then be removed manually. Do note that you can only remove a specific version of the extension with the associated version of the app - so if the installed extension is 30.0.0-rc1 you have to remove the identical version of the app from the Applications directory.

elkinjosetm commented 7 months ago

The canonical way is to delete the application in Finder - it will pop up a warning that the application contains a system extension and requires your approval that it should continue with the removal.

The system extension will then be removed manually. Do note that you can only remove a specific version of the extension with the associated version of the app - so if the installed extension is 30.0.0-rc1 you have to remove the identical version of the app from the Applications directory.

Oh, I removed OBS using AppCleaner, I guess it did not remove the extension, cuz' when I run systemextensionsctl list it is still there:

*   *   2MMRE5MTB8  com.obsproject.obs-studio.mac-camera-extension (30.0.0/6689064803)  com.obsproject.obs-studio.mac-camera-extension  [activated enabled]
niw commented 7 months ago

Yeah, if the app removed by non Finder app such as AppCleaner, the extension removal dialog will not be appearing and it sticks there, which is the concern of this issue and may we want to have some alternative solution within the app, yet it’s also related to app version matching etc, so a bit complicated. That’s current state for this, as my understanding.

Put OSB.app into /Applications again and trash it on Finder will trigger that dialog to remove it.

elkinjosetm commented 7 months ago

Makes sense, I just installed the rc2 from github, like you said, and removed it from Finder, I did get the extension removal message, but after removing it, the extension is still there, so that makes me wonder that it was not the same version(?), how do I know which rc is 30.0.0/6689064803?

elkinjosetm commented 7 months ago

Actually, never mind, I had to restart the computer for it to take effect, now is gone. Thank you so much!

tnaftali commented 2 months ago

This issue is still happening, I cannot remove the OBS Virtual Camera even though I already uninstalled the app and cleaned up the related files using AppCleaner. Are there plans to fix this?

PatTheMav commented 2 months ago

This issue is still happening, I cannot remove the OBS Virtual Camera even though I already uninstalled the app and cleaned up the related files using AppCleaner. Are there plans to fix this?

Using AppCleaner is usually the best way to break everything - AppCleaner is (at least to my knowledge) not capable of detecting that an application ships an extension and if it's deleted, the extension will linger around.

Right now only deleting the application in Finder will give you a prompt to also remove the extension.

If you inadvertently deleted OBS.app by other means (using something like AppCleaner or deleting it in Terminal) what you can try is:

systemextensionsctl list will tell you which version you have installed, e.g. 30.1.0/8254614054. In that case you would have to install >=30.1.1 or <=30.0.2 to ensure the extension is replaced with a different version.

PatTheMav commented 2 months ago

So here's my "lingering" extension that I cannot uninstall (OBS.app is gone):

*   *   2MMRE5MTB8  com.obsproject.obs-studio.mac-camera-extension (30.1.0/8254614054)  com.obsproject.obs-studio.mac-camera-extension  [activated enabled]

I downloaded OBS 30.1.2 and installed and ran it and even without starting the virtual camera I got this state now:

*   *   2MMRE5MTB8  com.obsproject.obs-studio.mac-camera-extension (30.1.2/8576208847)  com.obsproject.obs-studio.mac-camera-extension  [activated enabled]
        2MMRE5MTB8  com.obsproject.obs-studio.mac-camera-extension (30.1.0/8254614054)  com.obsproject.obs-studio.mac-camera-extension  [terminated waiting to uninstall on reboot]

OBS detected an existing version that was different from the one it shipped and thus removed the "lingering" variant.

tnaftali commented 2 months ago

@PatTheMav thank you! that worked.

niw commented 2 months ago

I wonder if extension can detect if OBS.app is removed from /Applications, then probably it can do something when itself lingering there e.g. at least prompting it to the users. Haven't explored much about such as extension's sandbox etc yet tho.

PatTheMav commented 2 months ago

I wonder if extension can detect if OBS.app is removed from /Applications, then probably it can do something when itself lingering there e.g. at least prompting it to the users. Haven't explored much about such as extension's sandbox etc yet tho.

It cannot because extensions are always sandboxed and have no access to anything outside of it (particularly the file system). Extensions are entirely managed by macOS and run as part of the specific frameworks they extend.

The host application is just the delivery method of the extension.

niw commented 2 months ago

Makes sense... kinda macOS itself problem that designed extension in this way and tight coupled with Finder's operation.

ShadowJonathan commented 2 weeks ago

FWIW Homebrew is running into this, and there appears to be a way to request the system to uninstall the extension: https://github.com/Homebrew/homebrew-cask/issues/175497

https://developer.apple.com/documentation/systemextensions/ossystemextensionrequest/deactivationrequest(forextensionwithidentifier:queue:)

Maybe this could be implemented as a command-line option, or something similar that management tools could access, as a pre-install step?