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进程则会返回执行CefInitialize和CefRunMessageLoop进入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()中被调用。并不需要开发者过多操作。
cef源码分析之cefsimple的更多相关文章
- ABP源码分析一:整体项目结构及目录
		
ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...
 - HashMap与TreeMap源码分析
		
1. 引言 在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...
 - nginx源码分析之网络初始化
		
nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...
 - zookeeper源码分析之五服务端(集群leader)处理请求流程
		
leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...
 - zookeeper源码分析之四服务端(单机)处理请求流程
		
上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...
 - zookeeper源码分析之三客户端发送请求流程
		
znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...
 - java使用websocket,并且获取HttpSession,源码分析
		
转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...
 - ABP源码分析二:ABP中配置的注册和初始化
		
一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...
 - ABP源码分析三:ABP Module
		
Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...
 
随机推荐
- .Net Core 智能提示汉化包
			
在.Net Core 2.x 版本,Microsoft 官方没有提供 .Net Core 正式版的多语言安装包.因此,我们在用.Net Core 2.x 版本作为框架目标编写代码时,智能提成是英文的. ...
 - jQuery---淘宝精品案例
			
淘宝精品案例 <!DOCTYPE html> <html> <head lang="en"> <meta charset="UT ...
 - 0005 uwsgi配置
			
在配置文件目录Configurations下创建一个名为uwsgi.ini的文件,用于uwsgi服务配置. uwsgi在服务器上使用,接收nginx的转发请求. 内容如下: # 配置文件:这一行必须有 ...
 - 《深入理解java虚拟机》读书笔记十——第十一章
			
第十一章 晚期(运行期)优化 1.HotSpot虚拟机内的即时编译 解释器与编译器: 许多Java虚拟机的执行引擎在执行Java代码的时候都有解释执行(通过解释器执行)和编译执行(通过即时编译器产生 ...
 - [CQOI2012] 交换棋子 - 费用流
			
有一个n行m列的黑白棋盘,你每次可以交换两个相邻格子(相邻是指有公共边或公共顶点)中的棋子,最终达到目标状态.要求第i行第j列的格子只能参与mi,j次交换. Solution 一个点拆三份,入点,主点 ...
 - Nginx实现前端访问后端本地接口
			
Nginx配置两个地方就行: 先是配置好自己项目的服务,确保自己的项目能运行: location / { root /web/xiangmu/public; // 本地项目的路径 index inde ...
 - Oracle - 拼接多个字段 - wm_concat()函数
			
Oracle wm_concat()函数oracle wm_concat(column)函数使我们经常会使用到的,下面就教您如何使用oraclewm_concat(column)函数实现字段合并如:s ...
 - 理解 Oracle 多租户体系中(12c,18c,19c)创建用户作用域范围
			
本篇探讨以下几个问题:你可提前猜测下面6个场景语句中,哪几个可以成功创建用户? 1. 在CDB级别中创建公共用户,不带 container 子句的效果: 2. 在CDB级别中创建公共用户,带 cont ...
 - maven打包忽略test文件夹
			
当在项目中的test中写了单元测试后,在mvn install打包时会自动进行所有单元测试,所以这时需要忽略test文件夹 有两种方法: 1.用命令的方式:mvn install -Dmaven.te ...
 - NVMe概况
			
简介 NVMe是为满足企业和客户系统需求,利用基于PCIe的固态存储,而精心设计的一个优化的,高效的,可伸缩主机控制器接口.NVMe是为非易失性内存(NVM)技术从头开始全新构建的,目的在于超越硬盘驱 ...