下面是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()
中被調用。並不須要開發者過多操做。