App sandbox migration often fails to migrate user defaults

Number:rdar://23679335 Date Originated:27-Nov-2015 08:20 PM
Status:Open Resolved:
Product:OS X Product Version:Mac OS X 10.11.1 (15B42)
Classification:Other Bug Reproducible:Sometimes
When launching a sandboxed version of an existing app for the first time, preferences saved using NSUserDefaults by a previous, unsandboxed version of the app are not reliably migrated.

Steps to Reproduce:
1. Run an unsandboxed app that sets at least one key/value pair using NSUserDefaults.
2. Quit the app.
3. Run a sandboxed version of the app for the first time and note the values it reads from NSUserDefaults.

Expected Results:
The preferences plist for the app is migrated into the sandbox container and the sandboxed version of the app sees the same values using NSUserDefaults as were set by the unsandboxed version before migration.

Actual Results:
While the preferences plist is moved into the sandbox container, when the sandboxed version of the app reads its defaults using NSUserDefaults, the values set by the unsandboxed version of the app (and stored in the plist) are not returned. Rather, NSUserDefaults behaves as if the app is being run for the first time.

This does not happen *every* time, only sometimes, but it happens quite often. In my testing so far, rebooting, or forcing cfprefsd to restart (using killall cfprefsd) prevents the problem from occurring.

Another interesting behavior is this: After running the sandboxed version, and seeing it fail to read previously set user defaults, if I then launch the *un*sandboxed version again, it continues to correctly read the value(s) it saved previously even though the plist is no longer in ~/Library/Preferences, but rather in the app sandbox container.

Here is a very minimal example app that can be used to reproduce this behavior: It simply registers a default value for the key "SomeDefaultsKey" in +[AppDelegate initialize], then sets another value when the "Set Preferences" button is clicked. The value for "SomeDefaultsKey" is bound to a label in the app's window, so the current value can be easily seen.

Also included are two compiled versions of this app, one with sandboxing disabled, the other with sandboxing enabled. Reproducing the problem is as simple as:

1. Run Preferences Migration Test (Unsandboxed)
2. Click "Set Preferences". Note that the user defaults value changes to "initialized".
3. Quit the app.
4. Run Preferences Migration Test (Sandboxed)
5. Notice that com.openreelsoftware.prefs-test.plist does get moved from ~/Library/Preferences into ~/Library/Containers/com.openreelsoftware.prefs-test/Data/Library/Preferences
6. Note that (often) the value is again "uninitialized".

If repeating the test, the sandbox container should be deleted, and defaults delete com.openreelsoftware.prefs-test should be run to reset user defaults and force another sandbox migration.


Please note: Reports posted here will not necessarily be seen by Apple. All problems should be submitted at before they are posted here. Please only post information for Radars that you have filed yourself, and please do not include Apple confidential information in your posts. Thank you!