objective-c NSDocumentController RecentDocuments Sandbox (странная) проблема
Я использую objective-c, Xcode 11, macOS, а не iOS, изолированное приложение.
Мне нужно вручную обновить меню последних документов. Я храню URL-адреса в закладках, чтобы получить к ним доступ в песочнице.
Что странно, так это то, что код A работает, а B - нет. У кого-нибудь есть объяснение этому?
// Code A
NSURL* bookmarkURL = (some valid URL from bookmark);
[bookmarkURL startAccessingSecurityScopedResource]; <- returns TRUE
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:bookmarkURL];
//[bookmarkURL stopAccessingSecurityScopedResource]; <-- Without closing access it works
// Code B
NSURL* bookmarkURL = (some valid URL from bookmark);
[bookmarkURL startAccessingSecurityScopedResource]; <- returns TRUE
[[NSDocumentController sharedDocumentController] noteNewRecentDocumentURL:bookmarkURL];
[bookmarkURL stopAccessingSecurityScopedResource];
B не работает (с закрытием безопасного доступа)! Неправильно не закрывать безопасный доступ. Для случая B выдается следующая ошибка
Insert failed for list identifier com.apple.LSSharedFileList.ApplicationRecentDocuments Error: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (Restricted by sandbox) UserInfo={NSDebugDescription=Restricted by sandbox}
Без запуска доступа безопасности выдается такая же ошибка (очевидно).
1 ответ
Похоже, что приложение должно сохранять разрешение в области безопасности до тех пор, пока документ находится в списке последних (управляемых вручную).
В моем случае ошибка заключалась в том, что
- пункт меню «Очистить меню» в меню «Файл» / «Открыть недавние» остался серым
- недавний список не сохранялся при запуске приложения
- недавний список не появился на доке.
- Я получил ошибки в Console.app, говорящие
Не удалось вставить идентификатор списка com.apple.LSSharedFileList.ApplicationRecentDocuments Ошибка: Ошибка Domain=NSPOSIXErrorDomain Code=1 «Операция не разрешена» (Доступ к списку запрещен) UserInfo={NSDebugDescription=Доступ к списку запрещен}
Похоже, что внутренне список последних документов управляется отдельным потоком, который, в свою очередь, взаимодействует с системным процессом.sharedfilelistd
. Если яstopAccessingSecurityScopedResource
, я могу наблюдатьsandboxd
нарушение в Console.app со следующим стеком вызовов (сокращенно):
Sandbox: MyApp(24093) deny(1) file-read-data /path/to/recent/document
Thread 1 (id: 364320):
0 libsystem_kernel.dylib 0x00007ff81b2265b2 mach_msg2_trap + 10
1 libsystem_kernel.dylib 0x00007ff81b22d5e4 mach_msg_overwrite + 692
2 libsystem_kernel.dylib 0x00007ff81b22689a mach_msg + 19
3 libdispatch.dylib 0x00007ff81b0dce6f _dispatch_mach_send_and_wait_for_reply + 518
4 libdispatch.dylib 0x00007ff81b0dd273 dispatch_mach_send_with_result_and_wait_for_reply + 50
5 libxpc.dylib 0x00007ff81afacb97 xpc_connection_send_message_with_reply_sync + 238
6 Foundation 0x00007ff81c18b423 __NSXPCCONNECTION_IS_WAITING_FOR_A_SYNCHRONOUS_REPLY__ + 9
7 Foundation 0x00007ff81c1893c1 -[NSXPCConnection _sendInvocation:orArguments:count:methodSignature:selector:withProxy:] + 3215
8 Foundation 0x00007ff81c188723 -[NSXPCConnection _sendInvocation:withProxy:] + 91
9 CoreFoundation 0x00007ff81b3234c6 ___forwarding___ + 671
10 CoreFoundation 0x00007ff81b323198 _CF_forwarding_prep_0 + 120
11 SharedFileList 0x00007ff823244145 __44-[SFLGenericList _insertItem:atIndex:error:]_block_invoke + 695
12 libsystem_trace.dylib 0x00007ff81afeaa0e _os_activity_initiate_impl + 51
13 SharedFileList 0x00007ff823243ddc -[SFLGenericList _insertItem:atIndex:error:] + 301
14 SharedFileList 0x00007ff823243ba5 __46-[SFLGenericList _insertItem:afterItem:error:]_block_invoke + 378
15 libsystem_trace.dylib 0x00007ff81afeaa0e _os_activity_initiate_impl + 51
16 SharedFileList 0x00007ff823243961 -[SFLGenericList _insertItem:afterItem:error:] + 316
17 SharedFileList 0x00007ff8232433b2 -[SFLGenericList insertItem:afterItem:error:] + 100
18 SharedFileList 0x00007ff82323c085 +[SFLList(LSSharedFileListSupport) itemByInsertingAfterItem:name:URL:propertiesToSet:propertiesToClear:list:] + 1370
19 SharedFileList 0x00007ff82323f3f7 LSSharedFileListInsertItemURL + 183
20 AppKit 0x00007ff81e80868f -[_NSRecentItemsMenuController _notePendingRecentDocumentURLsForKey:documentsSnapshot:] + 677
21 Foundation 0x00007ff81c1ada71 __NSBLOCKOPERATION_IS_CALLING_OUT_TO_A_BLOCK__ + 7
22 Foundation 0x00007ff81c1ad969 -[NSBlockOperation main] + 98
23 Foundation 0x00007ff81c1ad902 __NSOPERATION_IS_INVOKING_MAIN__ + 17
24 Foundation 0x00007ff81c1acc02 -[NSOperation start] + 782
25 Foundation 0x00007ff81c1ac8e8 __NSOPERATIONQUEUE_IS_STARTING_AN_OPERATION__ + 17
26 Foundation 0x00007ff81c1ac7b6 __NSOQSchedule_f + 182
27 libdispatch.dylib 0x00007ff81b0d1771 _dispatch_block_async_invoke2 + 83
...
Это показывает, что системой запущен поток, выполняющий некоторую асинхронно отправленную операцию, называемую[_NSRecentItemsMenuController _notePendingRecentDocumentURLs...]
, который, в свою очередь, отправляет вызовы XPC к SFL (общему списку файлов), что каким-то образом приводит к попытке прочитать указанный документ, который блокируется App Sandbox.
Таким образом, мы можем заключить, что после вызоваnoteNewRecentDocumentURL
, приложение по-прежнему должно сохранять разрешение на доступ к файлу, поскольку фактическое управление последним списком происходит асинхронно в другом потоке, и этот поток должен иметь возможность проверять существование файла или читать его по какой-либо другой причине.
Я переписал свое приложение так, чтобы оно удерживало ресурсы области безопасности, пока связанные файлы находятся в списке последних, и прекращало доступ к ним, когда они удаляются из списка. Интернет-мудрость подсказывает, что доступно несколько тысяч таких ресурсов, см. Каковы текущие ограничения ресурсов ядра для закладок с областью безопасности?. Поскольку мой недавний список никогда не вырастет до такого размера, мое приложение никогда не исчерпает ресурсы ядра.
См. также https://developer.apple.com/forums/thread/710278 .