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

cef源码分析之cefsimple的更多相关文章

  1. ABP源码分析一:整体项目结构及目录

    ABP是一套非常优秀的web应用程序架构,适合用来搭建集中式架构的web应用程序. 整个Abp的Infrastructure是以Abp这个package为核心模块(core)+15个模块(module ...

  2. HashMap与TreeMap源码分析

    1. 引言     在红黑树--算法导论(15)中学习了红黑树的原理.本来打算自己来试着实现一下,然而在看了JDK(1.8.0)TreeMap的源码后恍然发现原来它就是利用红黑树实现的(很惭愧学了Ja ...

  3. nginx源码分析之网络初始化

    nginx作为一个高性能的HTTP服务器,网络的处理是其核心,了解网络的初始化有助于加深对nginx网络处理的了解,本文主要通过nginx的源代码来分析其网络初始化. 从配置文件中读取初始化信息 与网 ...

  4. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  5. zookeeper源码分析之四服务端(单机)处理请求流程

    上文: zookeeper源码分析之一服务端启动过程 中,我们介绍了zookeeper服务器的启动过程,其中单机是ZookeeperServer启动,集群使用QuorumPeer启动,那么这次我们分析 ...

  6. zookeeper源码分析之三客户端发送请求流程

    znode 可以被监控,包括这个目录节点中存储的数据的修改,子节点目录的变化等,一旦变化可以通知设置监控的客户端,这个功能是zookeeper对于应用最重要的特性,通过这个特性可以实现的功能包括配置的 ...

  7. java使用websocket,并且获取HttpSession,源码分析

    转载请在页首注明作者与出处 http://www.cnblogs.com/zhuxiaojie/p/6238826.html 一:本文使用范围 此文不仅仅局限于spring boot,普通的sprin ...

  8. ABP源码分析二:ABP中配置的注册和初始化

    一般来说,ASP.NET Web应用程序的第一个执行的方法是Global.asax下定义的Start方法.执行这个方法前HttpApplication 实例必须存在,也就是说其构造函数的执行必然是完成 ...

  9. ABP源码分析三:ABP Module

    Abp是一种基于模块化设计的思想构建的.开发人员可以将自定义的功能以模块(module)的形式集成到ABP中.具体的功能都可以设计成一个单独的Module.Abp底层框架提供便捷的方法集成每个Modu ...

随机推荐

  1. pandas时间序列学习笔记

    目录 创建一个时间序列 pd.date_range() info() asfred() shifted(),滞后函数 diff()求差分 加减乘除 DataFrame.reindex() 通过data ...

  2. 《深入理解java虚拟机》读书笔记一——第二章

    第二章 Java内存区域与内存溢出异常 1.运行时数据区域 程序计数器: 当前线程所执行的字节码的行号指示器,用于存放下一条需要运行的指令. 运行速度最快位于处理器内部. 线程私有. 虚拟机栈: 描述 ...

  3. [CF546C] Soldier and Cards - 模拟

    两个人玩牌,首先两个人都拿出自己手牌的最上面的进行拼点,两张拼点牌将都给拼点赢得人,这两张牌放入手牌的顺序是:先放对方的牌再放自己的.若最后有一个人没有手牌了,那么他就输了,求输出拼点的次数和赢得人的 ...

  4. [CF994B] Knights of a Polygonal Table - 贪心,堆

    有 n 个骑士想决战.每个骑士都有能力值(互不相同),且身上带有一些金币.如果骑士 A 的能力值大于骑士 B ,那么骑士 A 就可以杀死骑士 B ,并获得骑士 B 身上的所有金币.但就算是骑士也不会残 ...

  5. navicat异常 - 1130-host ... is not allowed to connect to this MySql server

    错误描述 用navicat连接数据库报错:1130-host ... is not allowed to connect to this MySql server如何处理 解决方案 1.连接服务器: ...

  6. hackme.inndy.tw的一些Writeup(5月30更新)

    hackme.inndy.tw的一些Writeup(6月3日更新) 原文链接:http://www.cnblogs.com/WangAoBo/p/7706719.html 推荐一下https://ha ...

  7. git上传代码技巧

    1.一定要先在git上面创建项目然后把文件拉到本地先 1.1克隆到本地(orgin=>'你的远程仓库地址') git clone orgin 1.2初始化项目文件夹 git init 2.操作之 ...

  8. Mac 上完美解决SVN问题及svn软件

    注:本文是转自https://blog.csdn.net/qq_40144558/article/details/80630466 svn对Mac的支持不算美好,几乎所有软件都很繁琐,我们作为开发其实 ...

  9. 多源最短路(floyd算法)

    Floyd算法: 如何简单方便的求出图中任意两点的最短路径 Floyd-Warshall算法(O(n)比较适用于边较多的稠密图(Dense Graph)) Floyd算法用来找出每对顶点之间的最短距离 ...

  10. mysql慢日志分析pt-query-digest

    一.pt-query-digest 安装pt-query-digest yum install perl-DBI yum install perl-DBD-MySQL yum install perl ...