应用程序退出时CEF base :: ThreadRestrictions :: AssertIOAllowed()断言失败

时间:2014-11-20 18:28:04

标签: c++ macos chromium-embedded

我有一个简单的OSX应用程序,它基于提供的cefsample应用程序。一个值得注意的变化是我在单进程模式(settings.single_process = true)中运行。由于断言失败,我在退出时遇到了崩溃。奇怪的是,此崩溃也发生在发布版本中,而不仅仅是调试版本。

任何人(CEF大师)都可以帮我理解这里的问题是什么吗?堆栈跟踪表示我正在调用“仅限IO”"来自不允许IO的线程的函数。我唯一做的就是我从应用包中加载静态html文件。这似乎不应该需要特殊处理。但是,好吧,让我们假设它确实要求我在这个线程的启动中调整对base :: ThreadRestrictions :: SetIOAllowed()的调用"正如断言错误中所建议的那样 - 我不知道如何或在何处这样做。

这是stacktrace:

[1120/110258:FATAL:thread_restrictions.cc(38)] Function marked as IO-only was called from a thread that disallows IO!  If this thread really should be allowed to make IO calls, adjust the call to base::ThreadRestrictions::SetIOAllowed() in this thread's startup.
0   Chromium Embedded Framework         0x0068b8cf base::debug::StackTrace::StackTrace() + 63
1   Chromium Embedded Framework         0x0068b92b base::debug::StackTrace::StackTrace() + 43
2   Chromium Embedded Framework         0x00719d52 logging::LogMessage::~LogMessage() + 82
3   Chromium Embedded Framework         0x00718a8b logging::LogMessage::~LogMessage() + 43
4   Chromium Embedded Framework         0x00832984 base::ThreadRestrictions::AssertIOAllowed() + 276
5   Chromium Embedded Framework         0x00810100 base::PlatformThread::Join(base::PlatformThreadHandle) + 48
6   Chromium Embedded Framework         0x008263a3 base::Thread::Stop() + 131
7   Chromium Embedded Framework         0x08413d8f content::InProcessRendererThread::~InProcessRendererThread() + 63
8   Chromium Embedded Framework         0x08413e0b content::InProcessRendererThread::~InProcessRendererThread() + 43
9   Chromium Embedded Framework         0x08413e5e content::InProcessRendererThread::~InProcessRendererThread() + 46
10  Chromium Embedded Framework         0x07bab824 base::DefaultDeleter<base::Thread>::operator()(base::Thread*) const + 68
11  Chromium Embedded Framework         0x07bab7aa base::internal::scoped_ptr_impl<base::Thread, base::DefaultDeleter<base::Thread> >::reset(base::Thread*) + 122
12  Chromium Embedded Framework         0x07b93bc9 scoped_ptr<base::Thread, base::DefaultDeleter<base::Thread> >::reset(base::Thread*) + 57
13  Chromium Embedded Framework         0x07b85dc8 content::RenderProcessHostImpl::~RenderProcessHostImpl() + 392
14  Chromium Embedded Framework         0x07b8632b content::RenderProcessHostImpl::~RenderProcessHostImpl() + 43
15  Chromium Embedded Framework         0x07b864be content::RenderProcessHostImpl::~RenderProcessHostImpl() + 46
16  Chromium Embedded Framework         0x00534d88 CefContentRendererClient::RunSingleProcessCleanupOnUIThread() + 872
17  Chromium Embedded Framework         0x00534888 CefContentRendererClient::RunSingleProcessCleanup() + 344
18  Chromium Embedded Framework         0x003d6ab5 CefContext::FinalizeShutdown() + 69
19  Chromium Embedded Framework         0x003d5b26 CefContext::Shutdown() + 694
20  Chromium Embedded Framework         0x003d5750 CefShutdown() + 512
21  Chromium Embedded Framework         0x0027dbe7 cef_shutdown + 39
22  CEFSimpleSample                     0x000c1a37 CefShutdown() + 39
23  CEFSimpleSample                     0x000baefc main + 388
24  libdyld.dylib                       0x96e33701 start + 1
25  ???                                 0x00000003 0x0 + 3

这是我的应用程序的一部分。断言在CEFShutdown()方法中失败,是一个框架方法:

// Entry point function for the browser process.
int main(int argc, char* argv[]) {
    // Provide CEF with command-line arguments.
    CefMainArgs main_args(argc, argv);

    // ClientHandler implements application-level callbacks. It will create the first
    // browser instance in OnContextInitialized() after CEF has initialized.
    CefRefPtr<ClientHandler> app(new ClientHandler);

    // Initialize the AutoRelease pool.
    NSAutoreleasePool* autopool = [[NSAutoreleasePool alloc] init];

    // Initialize the SimpleApplication instance.
    [SimpleApplication sharedApplication];

    // Specify CEF global settings here.
    CefSettings settings;
    settings.single_process = true;

    // Initialize CEF for the browser process.
    CefInitialize(main_args, settings, app.get(), NULL);

    // Create the application delegate.
    NSObject* delegate = [[SimpleAppDelegate alloc] init];
    [delegate performSelectorOnMainThread:@selector(createApplication:)
                               withObject:nil
                            waitUntilDone:NO];

    // Run the CEF message loop. This will block until CefQuitMessageLoop() is
    // called.
    CefRunMessageLoop();

    // Shut down CEF.
    CefShutdown();

    // Release the delegate.
    [delegate release];

    // Release the AutoRelease pool.
    [autopool release];

    return 0;
}

1 个答案:

答案 0 :(得分:2)

这是CEF的已知错误:

https://code.google.com/p/chromiumembedded/issues/detail?id=1182

Chromium通常将UI线程与IO线程区分开来,而消息是这些消息混淆的断言。它与您自己的IO无关。

您需要查看堆栈以了解正在发生的事情。具有命名空间的函数通常属于Chromium,而全局命名空间中的函数是CEF本身的一部分。与CEF相关的崩溃往往是由于嵌入铬的粘合剂......

guilty函数可能是CefContentRendererClient的方法RunSingleProcessCleanupOnUIThread。该名称暗示它意味着在UI线程上运行。

void CefContentRendererClient::RunSingleProcessCleanupOnUIThread() {
  DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));

  // Clean up the single existing RenderProcessHost.
  content::RenderProcessHost* host = NULL;
  content::RenderProcessHost::iterator iterator(
      content::RenderProcessHost::AllHostsIterator());
  if (!iterator.IsAtEnd()) {
    host = iterator.GetCurrentValue();
    host->Cleanup();
    iterator.Advance();
    DCHECK(iterator.IsAtEnd());
  }
  DCHECK(host);

  // Clear the run_renderer_in_process() flag to avoid a DCHECK in the
  // RenderProcessHost destructor.
  content::RenderProcessHost::SetRunRendererInProcess(false);

  // Deletion of the RenderProcessHost object will stop the render thread and
  // result in a call to WillDestroyCurrentMessageLoop.
  // Cleanup() will cause deletion to be posted as a task on the UI thread but
  // this task will only execute when running in multi-threaded message loop
  // mode (because otherwise the UI message loop has already stopped). Therefore
  // we need to explicitly delete the object when not running in this mode.
  if (!CefContext::Get()->settings().multi_threaded_message_loop)
    delete host;
}

崩溃发生在功能的最后部位。确实multi_threaded_message_loop是假的(multi_threaded_message_loop仅适用于Windows),我们可以跟踪堆栈跟踪中的崩溃到RenderProcessHostImpl析构函数。

从代码和评论中可以清楚地看出,这是围绕Chromium的一个肮脏的黑客,试图重现Chromium在别处做的事情。我实际上相信DCHECK(Chromium断言宏)解决方法已过时,因为g_run_renderer_in_process_设置为false,这里不会在析构函数中检查。

BrowserMainLoop::ShutdownThreadsAndCleanUp()中的以下评论可能提供线索:

// Teardown may start in PostMainMessageLoopRun, and during teardown we
// need to be able to perform IO.
base::ThreadRestrictions::SetIOAllowed(true);
BrowserThread::PostTask(
    BrowserThread::IO, FROM_HERE,
    base::Bind(base::IgnoreResult(&base::ThreadRestrictions::SetIOAllowed),
             true));

修复可能是在base::ThreadRestrictions::SetIOAllowed(true);方法中调用析构函数之前调用RunSingleProcessCleanupOnUIThread()。不幸的是,您需要为此目的重新编译CEF,并且您不能在主函数中调用此表达式(在调用CefShutdown()之前),因为CEF不会公开这些Chromium内部。