下面是cefsimple的入口代码,主要分红两个部分windows
// Entry point function for all processes. int APIENTRY wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); // Enable High-DPI support on Windows 7 or newer. CefEnableHighDPISupport(); void* sandbox_info = NULL; #if defined(CEF_USE_SANDBOX) // Manage the life span of the sandbox information object. This is necessary // for sandbox support on Windows. See cef_sandbox_win.h for complete details. CefScopedSandboxInfo scoped_sandbox; sandbox_info = scoped_sandbox.sandbox_info(); #endif // Provide CEF with command-line arguments. CefMainArgs main_args(hInstance); // CEF applications have multiple sub-processes (render, plugin, GPU, etc) // that share the same executable. This function checks the command-line and, // if this is a sub-process, executes the appropriate logic. int exit_code = CefExecuteProcess(main_args, NULL, sandbox_info); if (exit_code >= 0) { // The sub-process has completed so return here. return exit_code; } // Specify CEF global settings here. CefSettings settings; #if !defined(CEF_USE_SANDBOX) settings.no_sandbox = true; #endif // SimpleApp implements application-level callbacks for the browser process. // It will create the first browser instance in OnContextInitialized() after // CEF has initialized. CefRefPtr<SimpleApp> app(new SimpleApp); // Initialize CEF. CefInitialize(main_args, settings, app.get(), sandbox_info); // Run the CEF message loop. This will block until CefQuitMessageLoop() is // called. CefRunMessageLoop(); // Shut down CEF. CefShutdown(); return 0; }
首先是初始化进程的代码,cef的进程结构和chromium相似,都是多进程共用代码。因此cef提供了一些函数来检测主进程(即browser进程)的流程和子进程的流程,以分别执行适合当前执行进程的逻辑。这段代码以下所示。api
// CEF applications have multiple sub-processes (render, plugin, GPU, etc) // that share the same executable. This function checks the command-line and, // if this is a sub-process, executes the appropriate logic. int exit_code = CefExecuteProcess(main_args, NULL, sandbox_info); if (exit_code >= 0) { // The sub-process has completed so return here. return exit_code; }
其中main_args用于获取当前进程的命令行参数,由于在chromium中,进程的区分就是靠命令行参数中的--type
,若是是browser进程,则没有--type参数,其余进程该参数的值为renderer
,gpu
等浏览器
int CefExecuteProcess(const CefMainArgs& args, CefRefPtr<CefApp> application, void* windows_sandbox_info) { #if defined(OS_WIN) #if defined(ARCH_CPU_X86_64) DisableFMA3(); #endif InitInstallDetails(); InitCrashReporter(); #endif base::CommandLine command_line(base::CommandLine::NO_PROGRAM); #if defined(OS_WIN) command_line.ParseFromString(::GetCommandLineW()); #else command_line.InitFromArgv(args.argc, args.argv); #endif // Wait for the debugger as early in process initialization as possible. if (command_line.HasSwitch(switches::kWaitForDebugger)) base::debug::WaitForDebugger(60, true); // If no process type is specified then it represents the browser process and // we do nothing. std::string process_type = command_line.GetSwitchValueASCII(switches::kProcessType); if (process_type.empty()) return -1; #if defined(OS_MACOSX) || defined(OS_WIN) if (process_type == crash_reporter::switches::kCrashpadHandler) return RunAsCrashpadHandler(command_line); #endif CefMainDelegate main_delegate(application); // Execute the secondary process. #if defined(OS_WIN) sandbox::SandboxInterfaceInfo sandbox_info = {0}; if (windows_sandbox_info == NULL) { content::InitializeSandboxInfo(&sandbox_info); windows_sandbox_info = &sandbox_info; } content::ContentMainParams params(&main_delegate); params.instance = args.instance; params.sandbox_info = static_cast<sandbox::SandboxInterfaceInfo*>(windows_sandbox_info); return content::ContentMain(params); #else content::ContentMainParams params(&main_delegate); params.argc = args.argc; params.argv = const_cast<const char**>(args.argv); return content::ContentMain(params); #endif }
只有当非browser进程时才会执行ContentMain
函数,这也符合chromium的逻辑。ContentMain
函数是其余子进程的入口点。
而browser进程则会返回执行CefInitialize
和CefRunMessageLoop
进入browser进程的主循环。当进程须要退出时,CefRunMessageLoop
主循环退出,执行CefShutdown
进程结束。app
第二个部分就是browser进程的主流程,下面是拆分出来的代码。ide
// Initialize CEF. CefInitialize(main_args, settings, app.get(), sandbox_info); // Run the CEF message loop. This will block until CefQuitMessageLoop() is // called. CefRunMessageLoop(); // Shut down CEF. CefShutdown();
首先看CefInitialize
初始化函数,其中app.get()
即CefApp
对象指针的参数尤其重要,在文件libcef/browser/context.cc
中,提供了很多相似CefInitialize
的cef控制函数,初始化,关闭,开启和退出消息循环等函数
bool CefInitialize(const CefMainArgs& args, const CefSettings& settings, CefRefPtr<CefApp> application, void* windows_sandbox_info) { #if defined(OS_WIN) #if defined(ARCH_CPU_X86_64) DisableFMA3(); #endif InitInstallDetails(); InitCrashReporter(); #endif // Return true if the global context already exists. if (g_context) return true; if (settings.size != sizeof(cef_settings_t)) { NOTREACHED() << "invalid CefSettings structure size"; return false; } g_browser_process = new ChromeBrowserProcessStub(); // Create the new global context object. g_context = new CefContext(); // Initialize the global context. return g_context->Initialize(args, settings, application, windows_sandbox_info); }
为的是建立一个全局的CefContext
对象,只有当CefContext
对象被建立完成后,才能进行CreateBrowser
操做,在下面的代码中oop
return g_context->Initialize(args, settings, application, windows_sandbox_info);
Initialize
的主要做用是根据content api开始作浏览器进程启动准备。由于content api要涉及chromium代码,这里就不继续往下追溯,主要看cef的流程ui
bool CefContext::Initialize(const CefMainArgs& args, const CefSettings& settings, CefRefPtr<CefApp> application, void* windows_sandbox_info) { ... main_delegate_.reset(new CefMainDelegate(application)); ... if (CEF_CURRENTLY_ON_UIT()) { OnContextInitialized(); } else { // Continue initialization on the UI thread. CEF_POST_TASK(CEF_UIT, base::Bind(&CefContext::OnContextInitialized, base::Unretained(this))); } ...
CefApp的引用会一直传递到这里,当初始化的流程结束的时候(OnContextInitialized
),就到了CefApp发挥做用的时候了。this
其中main_delegate_
做为一个代理,主要代理整体管理的相关功能,包括资源初始化,浏览器关闭等。那么CefApp对它有什么用呢?主要是为了建立一个全局的CefContentClient
对象。google
CefMainDelegate::CefMainDelegate(CefRefPtr<CefApp> application) : content_client_(application) {
而后当CefContext
初始化完成后,就会从这个全局的CefContentClient
对象中获取CefApp
的引用。而得到引用以后是为了得到handler,以完成对应的回调。
void CefContext::OnContextInitialized() { CEF_REQUIRE_UIT(); static_cast<ChromeBrowserProcessStub*>(g_browser_process) ->OnContextInitialized(); #if BUILDFLAG(ENABLE_WIDEVINE) && BUILDFLAG(ENABLE_LIBRARY_CDMS) CefWidevineLoader::GetInstance()->OnContextInitialized(); #endif // Notify the handler. CefRefPtr<CefApp> app = CefContentClient::Get()->application(); if (app.get()) { CefRefPtr<CefBrowserProcessHandler> handler = app->GetBrowserProcessHandler(); if (handler.get()) handler->OnContextInitialized(); } }
此处主要获取的是browser process handler,这个handler的主要目的是监控并触发browser进程生命周期内各个关键时机的回调。
若是多少用过cef,会知道browser进程中很重要的一个函数就是CreateBrowser
,cefsimple这个demo中,使用在了OnContextInitialized
函数中,这说明,当cef上下文初始化完成以后就能够建立浏览功能了。
void SimpleApp::OnContextInitialized() { CEF_REQUIRE_UI_THREAD(); CefRefPtr<CefCommandLine> command_line = CefCommandLine::GetGlobalCommandLine(); #if defined(OS_WIN) || defined(OS_LINUX) // Create the browser using the Views framework if "--use-views" is specified // via the command-line. Otherwise, create the browser using the native // platform framework. The Views framework is currently only supported on // Windows and Linux. const bool use_views = command_line->HasSwitch("use-views"); #else const bool use_views = false; #endif // SimpleHandler implements browser-level callbacks. CefRefPtr<SimpleHandler> handler(new SimpleHandler(use_views)); // Specify CEF browser settings here. CefBrowserSettings browser_settings; std::string url; // Check if a "--url=" value was provided via the command-line. If so, use // that instead of the default URL. url = command_line->GetSwitchValue("url"); if (url.empty()) url = "http://www.google.com"; if (use_views) { // Create the BrowserView. CefRefPtr<CefBrowserView> browser_view = CefBrowserView::CreateBrowserView( handler, url, browser_settings, NULL, NULL, NULL); // Create the Window. It will show itself after creation. CefWindow::CreateTopLevelWindow(new SimpleWindowDelegate(browser_view)); } else { // Information used when creating the native window. CefWindowInfo window_info; #if defined(OS_WIN) // On Windows we need to specify certain flags that will be passed to // CreateWindowEx(). window_info.SetAsPopup(NULL, "cefsimple"); #endif // Create the first browser window. CefBrowserHost::CreateBrowser(window_info, handler, url, browser_settings, NULL, NULL); } }
而对应的ShutdownBrowser
则是在CefContext::Shutdown()
中被调用。并不须要开发者过多操做。