zoukankan      html  css  js  c++  java
  • cef源码分析之cefsimple

    下面是cefsimple的入口代码,主要分成两个部分

    // 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进程)的流程和子进程的流程,以分别执行适合当前执行进程的逻辑。这段代码如下所示。

    // 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进程则会返回执行CefInitializeCefRunMessageLoop进入browser进程的主循环。当进程需要退出时,CefRunMessageLoop主循环退出,执行CefShutdown进程结束。

    cef的browser进程启动

    第二个部分就是browser进程的主流程,下面是拆分出来的代码。

      // 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操作,在下面的代码中

    return g_context->Initialize(args, settings, application,
                                   windows_sandbox_info);
    

    Initialize的主要作用是根据content api开始做浏览器进程启动准备。因为content api要涉及chromium代码,这里就不继续往下追溯,主要看cef的流程

    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发挥作用的时候了。

    其中main_delegate_作为一个代理,主要代理总体管理的相关功能,包括资源初始化,浏览器关闭等。那么CefApp对它有什么用呢?主要是为了创建一个全局的CefContentClient对象。

    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()中被调用。并不需要开发者过多操作。

  • 相关阅读:
    Vue- 对象语法 v-bind:class与对象语法的使用(重要)
    关于vue中$emit事件问题
    深入理解vue.js2.0指令v-for使用及索引获取
    到底vuex是什么?
    Vue.js学习系列二 —— vuex学习实践笔记(附DEMO)
    前端HTML5几种存储方式的总结
    JSON和JS对象之间的互转
    Vue2.0子父组件通信
    C#字符串和16进制转换
    C#中int32 的有效值范围
  • 原文地址:https://www.cnblogs.com/lenomirei/p/12195915.html
Copyright © 2011-2022 走看看