Sandboxed Mac应用程序耗尽了安全范围的URL资源

时间:2014-09-02 15:59:04

标签: objective-c macos cocoa sandbox

我正在开发一个Mac应用程序,它使用NSOpenPanel提示用户输入文件。应用程序是沙箱(在OSX 10.9.4上测试)。我注意到如果我打开大量文件(~3000),打开的面板会开始向日志发出错误。如果我尝试在chucks中打开少量文件多次,也会发生这种情况。

第一次出现错误后,每次再次使用NSOpenPanel打开文件时,无论有多少文件,都会再次生成这些错误(直到应用程序关闭)。

错误消息如下所示:

TestPanel[98508:303] __41+[NSSavePanel _consumeSandboxExtensions:]_block_invoke: sandbox_consume_fs_extension failed

我尝试打开的每个文件都有一行。

我设法使用一个简单的应用程序重现了这种行为:一个带有单个按钮的沙盒应用程序调用以下代码:

NSOpenPanel* panel = [NSOpenPanel openPanel];
[panel setAllowsMultipleSelection:YES];
[panel setCanChooseDirectories:NO];
[panel setCanChooseFiles:YES];
[panel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result) {
    NSLog(@"%lu", [panel.URLs count]);
}];

错误出现在代码到达完成处理程序之前。

似乎我仍然可以从完成处理程序中的面板中获取URL,但它确实污染了系统日志。

修改

似乎此问题与NSOpenPanel / NSSavePanel面板没有直接关系。使用drap / drop with files时会发生非常类似的事情。像这样:

- (NSDragOperation)draggingEntered:(id <NSDraggingInfo>)sender {
    ...
    NSPasteboard *pboard = [sender draggingPasteboard];
    if ([[pboard types] containsObject:NSURLPboardType]) {
        NSArray *urls = [pboard readObjectsForClasses:@[[NSURL class]] options:nil];
    }
    ...
}

这会在拖动大量文件时生成以下日志消息(&#34;魔术&#34;数字似乎在2900左右):

Consume sandbox extension for itemIdentifier (2937) from pasteboard failed!

与NSOpenPanel一样,在第一次出现之后,每个丢弃的文件都会在日志中生成相同的错误。

编辑2:

@mahal tertin的回复向我指出了正确的方向。问题确实存在于文件数量和安全范围URL资源有限的事实上。

然而,似乎找不到合理的解决方案。问题是,当用户点击&#34; OK&#34;在NSOpenPanel上(或删除拖放感知控件上的文件),操作系统已经尝试创建这些安全范围的URL并隐式调用startAccessingSecurityScopedResource。因此,如果用户尝试打开的文件超过限制,则资源将耗尽,唯一的选择是关闭并重新启动应用程序。

在返回的网址上调用stopAccessingSecurityScopedResource似乎可以释放资源,但Apple的代表在official developers forums(链接登录后面)后不鼓励使用此解决方案。

似乎应用程序受用户不能打开太多文件的支配。这甚至不是立刻,因为没有批准的方式来释放这些资源。您可以在文档中警告用户,甚至可以通过应用程序内警告警告用户,但是无法防止他们弄乱应用程序并强制重新启动。

因此,如果该应用运行的时间足够长且用户不断打开文件,该应用最终将无法使用。

仍在寻找合理的解决方案。

2 个答案:

答案 0 :(得分:8)

在高低搜索并在各个地方询问之后,我将结束这个问题并得出结论,没有答案或解决方法。我发布已知信息以供将来参考。

建议的所有解决方案都只是可以最大限度地减少问题的解决方法,并尝试引导用户不要尝试打开太多文件。但实际上没有任何办法可以解决这个问题。

以下是有关此问题的已知事实:

  • 无论您做什么,用户都可以尝试在NSOpenPanel对话框中打开太多文件并耗尽安全范围的URL资源
  • 一旦这些资源耗尽,就无法再打开任何文件进行读/写。该应用程序需要关闭并重新打开
  • 即使用户没有尝试一次打开太多文件,如果应用程序运行时间足够长,并且用户随着时间的推移打开了足够的文件,那么应用程序仍可能耗尽这些资源,因为startAccessingSecurityScopedResource会自动调用对于使用NSOpenPanel(或拖放机制)打开的文件,并且没有任何内容关闭这些资源
  • 在打开的面板检索到的所有网址上调用stopAccessingSecurityScopedResource将释放这些资源,但Apple不鼓励这种做法,说它可能与未来的解决方案不兼容
  • 当您收到来自NSOpenPanel(或拖放)的URL列表时,无法判断是否所有URL都已成功访问,或者是否存在超出限制且因此无效的URL。
  • Apple意识到这一点,并可能在将来修复它。它仍然没有在10.10中修复,当然,这对当前/以前的OSX版本上运行的当前应用程序没有帮助。

苹果似乎真的放弃了这一点,沙盒实施似乎非常草率和短视。

答案 1 :(得分:6)

您遇到的行为是因为安全作用域资源有限:

NSURL - (BOOL)startAccessingSecurityScopedResource告诉

  

如果泄露了足够的内核资源,您的应用程序将失去其能力   将文件系统位置添加到其沙箱...

目前的限制大致与您的经历相同。看到: What are the current kernel resource limits on security-scoped bookmarks?

为了防止它:

  • 仅在特定时间开始访问您需要的SSB,然后停止访问它们
  • 开始访问不是文件而是封闭文件夹:要求用户不要选择文件而是选择完整文件夹。这将授予您访问该目录下的整个树
  • 的权限
  • on draggingEntered:显示带有封闭目录的NSOpenPanel以授予访问权限