ScreenSaver: legacyScreenSaver process?

I'm having lots of trouble with screen savers in the first 10.15 beta. Console is showing messages from a new "legacyScreenSaver" process.


The ScreenSaver API doesn't show any documented changes, however.

https://developer.apple.com/documentation/screensaver?changes=latest_minor


Anyone else seeing this?
In particular, I'm having trouble with a Swfit-based screensaver.
One example:


ScreenSaver.init(frame:isPreview:) is being called with isPreview=True, even when running normally fullscreen.

Replies

Yes, I'm seeing the exact same thing. Looks like legacyScreenSaver is now running our .saver files and I haven't seen anything in documentation about a new API or anything specific about changes.


Some other things I saw here with Aerial :

- /Library/Caches/Aerial and ~/Library/Caches/Aerial are now the same thing (and the cache got wiped on update, which is I guess expected)

- Looks like you can install a screensaver for all users still, I'm not sure where the file go then if /Library is locked down (there's a session about the new system lockdown later this week that will probably clarify this)

- Loading a nib from my .saver bundle (for the preference panel) crashes a thread in system


Still early here, hopefully there are workaround for these issues.


Any clarity on changes for screensaver would be truly helpful !


(tried to reply to you yesterday but my message was in moderation limbo since !)

Some more findings :

- Your screensaver needs to be signed/notarized, while you can override on install an unknown developper build, it will error out again every time you open System Preferences

- legacyScreenSaver is a sandboxing mechanism ! So if you ask for cache paths, you'll get this :

localCachePath : ["/Library/Caches"]

userCachePath : ["/Users/glouel/Library/Containers/com.apple.ScreenSaver.Engine.legacyScreenSaver/Data/Library/Caches"]


The first one looks weird ? I'm unfamiliar with sandboxing, anyone with more info please chime in. Using the second one works, files are located there as expected, I don't think the first one is usable ?

- Preferences also are located in that container (/Preferences/ByHost/ instead of /Caches in previous url)


This breaks my workaround for Xcode to compile my screensaver's control panel as an app in a window, and breaks update path for settings for customers migrating from Mojave to Catalina.


Some more stuff,

- I can confirm that we are only called once in multiple monitor configuration (you used to get called once per screen). For some reason it's on my secondary screen, main screen doesn't get the view init.

- I can also confirm that we are called that one time with the preview flag on which is not nice.

Thanks for the updates (sorry for the slow reply, was out of town for a week).


* Have you submitted bug reports for any of these?

* Any improvements in beta 2?

"- Your screensaver needs to be signed/notarized, while you can override on install an unknown developper build, it will error out again every time you open System Preferences"


I wasn't seeing this problem, but my screensaver is installed using an installer (the installer itself is code-signed, but not notarized).

How are you installing the screensaver - double-clicking in the Finder perhaps?

Hi XMI


- Radar filled for every single bug yes (still marked as open)

- No change on beta 2, every bug still there

I didn't see it on my system, but only on users system. I package Aerial as a zip, and the user installs by double clicking, yes. This way, the .saver appears with the quarantine xattr bit, and that triggers GateKeeper verification which requires signing and (my understanding of WWDC sessions) notarization.


Our users who installed via homebrew had the same issue, and so were the ones copying the screensaver manually to the system folder.


According to WWDC sessions I did assume notarization was 100% necessary when going through gatekeeper. It's less painful that it seems (and takes about a min per release to get the cert back). Maybe using a pkg lets you avoid the quarantine flag and thus gatekeeper doesn't kick in ?

I see now that software signed after June 1st must be notarized, this could explain the differences we are seeing ?

Yep must be it 😉 They were pretty clear about notarization being needed, but no idea how that interacts with an installer.


I try to keep a list of changes/bugs on our github repo in any case if you are interested (just look up Aerial). One thing we saw was despite being sandboxed, we still have read only access to the disk in b1/b2. And that the non legacy mechanism seems to be XPC based.

I just updated to the Developer Beta #3 (19A501i) and am not seeing any improvements on any of the screensaver-related issues.

This breaks my workaround for Xcode to compile my screensaver's control panel as an app in a window, and breaks update path for settings for customers migrating from Mojave to Catalina.



DId you solve this problem? I have a similar architecture: my .saver bundle contains a helper app, and when the preferences are launched, it simply creates a new Process task and launches the app:


privatefunc configProcessLaunch() {
            // if already running, just bring it frontmost
            if (configProcess != nil && configProcess!.isRunning)
            {
                log("  [\(screenNumber)] Config Process already running, bringing frontmost")
                configProcessActivate()
                return
            }
           
            // otherwise create and launch it
           
            configProcessTerminateIgnoreFlag = false
            let path = childAppPath()
            let f = self.bounds
            let f2 = self.convert(f, to: nil)
            let f3 = self.window?.convertToScreen(f2)
            let x = f3!.origin.x
            let y = f3!.origin.y + f.size.height
            let arguments = ["-C", String(format: "-XY=%d,%d", Int(x), Int(y)) ]
           
            log("# Configure Process Launch, \(dump(arguments)) path=\(path)")
            configProcess = Process()
            configProcess?.arguments = arguments
            configProcess?.launchPath = path
            configProcess?.terminationHandler = configTerminatedHandler
            configProcess?.launch()
        }



The problem is that I'm trying to share preferences between the .saver and the .app, but when the .app tries to read (using CFPreferneces) I get these sorts of errors. Note that neither my .saver nor my .app have sandboxing enabled.


error12:44:08.892297-0700151cfprefsdrejecting read of { com.mycompany.saver.77300306, kCFPreferencesAnyUser, kCFPreferencesCurrentHost, no container, managed: 0 } from process 1281 (myScreensaver) because accessing preferences outside an application's container requires user-preference-read or file-read-data sandbox access

Developer Beta 5 seems to fix some issues:

screensavers are now launchecd properly on each screen in a multi-monitor setup


But it also seems to create some new issues:

the "Preview" icon (that shows up when you mouse-over the screensaver Preview) only works once for me. The second time clicked, nothing happens. Activating the screensaver using a hot corner seems to work properly multiple times.

Hey @XMI


Really sorry for not following up with you, I don't get notifications for this forum (despite "following", whatever that means), so you may not see this or it might be too late. If you do, here's what I know so far.


Screen savers are now plugins that are ran by legacyScreenSaver. legacyScreenSaver is the one that is sandboxed, and *all* our 3rd party screen savers are living with it's constraints, within it's container.


So to give you an example, if you want to create an Aerial folder in "Application Support", while you would expect it to be created in


~/LibraryApplication Support/Aerial


as it is in Mojave, in Catalina your folder using the same system commands go here :


~/Library/Containers/com.apple.ScreenSaver.Engine.legacyScreenSaver/Data/Library/Application Support/Aerial


The same goes for your preferences, your screensaver will read preferences, assuming you already use ScreenSaverDefaults in your screensaver and don't try something fancy (don't, you can't) in the container :


~/Library/Containers/com.apple.ScreenSaver.Engine.legacyScreenSaver/Data/Library/Preferences/ByHost/your.thing.plist


I would assume that your screensaver cannot load anything but this. As for your helper app, a 3rd party app can read/write inside the container usually (I edit my logs with sublime text for example inside the container). Your mention this which I don't understand though "my .saver bundle contains a helper app" My guess is you distribute both alongside eachother ? Where does the helper app go, in /Applications ? My guess is that app can read your preferences inside the container, the other way around won't work.


As you may have found out, there's a ton of restrictions imposed upon us by legacyScreenSaver:

- You no longer have access to the keyboard (for example, I used to allow user to press the right arrow key to skip a video, can't do that anymore).

- You cannot write outside the container. This is a big one for me as we download large video files, you can only write to your container.

- You can read (with limitations) outside the container, but on the local disk only, and maybe not all the files/folders. You cannot read from a network volume or any attached device. You cannot workaround this with symlinks.

- I'm doubtful that you can launch a process as your code is trying to do here from screensaver, that's probably a big no-no now.


You can workaround all this if you disable SIP, which you shouldn't do and your users shouldn't do either).


It's really all clamped down, possibly for good reasons in terms of security. But with no ability to make the "new" format of screensavers (.appex, where you can ask for your own permissions), it's really a terrible setback for the very tiny world of 3rd party screensavers and my hopes aren't high for things improving in the final build.


Hopefully you figured things out since then. Best of luck.