首页
课程
问答
CTF
社区
招聘
峰会
发现
排行榜
知识库
工具下载
看雪20年
看雪商城
证书查询
登录
注册
首页
社区
课程
招聘
发现
问答
CTF
排行榜
知识库
工具下载
峰会
看雪商城
证书查询
社区
WEB安全
发新帖
4
24
[原创]chromium 的启动
发表于: 2025-11-4 21:07
3257
[原创]chromium 的启动
nothing233
1
2025-11-4 21:07
3257
## 简介 简单串一下浏览器启动的整个流程. 这样可以将 chromium 的框架串起来, 作者志大才疏, 有写的不好地方还请指出. Chromium 的入口文件设计是不同系统有各自的入口文件, 最终都会汇总到统一的核心启动逻辑: - Windows: chrome\app\chrome_exe_main_win.cc - Linux: chrome\app\chrome_exe_main_aura.cc - Mac: chrome\app\chrome_exe_main_mac.cc - 最终汇聚: chrome\app\chrome_main.cc ## 先简单看一下三个平台的入口文件 ### chrome\app\chrome_exe_main_aura.cc 这个最短: ```cpp #include "build/build_config.h" extern "C" { int ChromeMain(int argc, const char** argv); } int main(int argc, const char** argv) { return ChromeMain(argc, argv); } ``` 该文件仅用于 Linux 等类 Unix 系统, 是基于 Aura 界面框架的入口实现, 其核心是直接调用 ChromeMain(argc, argv), 无需中间 DLL 加载层, 与 Windows 需通过 chrome.dll 启动的逻辑完全不同. ### chrome\app\chrome_exe_main_mac.cc 贴出主要部分: ```cpp // 定义对外可见的main函数, 作为程序入口点 // 参数: argc - 命令行参数数量; argv - 命令行参数数组 __attribute__((visibility("default"))) int main(int argc, char* argv[]) { // 早期注册PartitionAlloc内存分配器的malloc区域(初始化内存分配器) partition_alloc::EarlyMallocZoneRegistration(); uint32_t exec_path_size = 0; // 用于存储可执行文件路径的长度 // 第一次调用_NSGetExecutablePath获取路径长度(传入NULL时仅返回所需长度) int rv = _NSGetExecutablePath(NULL, &exec_path_size); if (rv != -1) { // 正常情况下应返回-1(表示需要分配缓冲区), 否则报错 FatalError("_NSGetExecutablePath: get length failed."); } // 根据获取的长度分配缓冲区存储可执行文件路径 std::unique_ptr<char[]> exec_path(new char[exec_path_size]); // 第二次调用_NSGetExecutablePath获取实际路径 rv = _NSGetExecutablePath(exec_path.get(), &exec_path_size); if (rv != 0) { // 返回0表示成功, 非0则路径获取失败 FatalError("_NSGetExecutablePath: get path failed."); } #if defined(HELPER_EXECUTABLE) // 如果是辅助可执行程序(Helper) // 创建沙箱服务端并解析启动参数(macOS沙箱机制) sandbox::SeatbeltExecServer::CreateFromArgumentsResult seatbelt = sandbox::SeatbeltExecServer::CreateFromArguments(exec_path.get(), argc, argv); if (seatbelt.sandbox_required) { // 如果需要启用沙箱 if (!seatbelt.server) { // 沙箱服务端创建失败 FatalError("Failed to create seatbelt sandbox server."); } if (!seatbelt.server->InitializeSandbox()) { // 沙箱初始化失败 FatalError("Failed to initialize sandbox."); } } // 辅助程序位于版本化框架目录中, 通过相对路径定位主框架 const char rel_path[] = "../../../../" PRODUCT_FULLNAME_STRING " Framework"; #else // 非辅助程序(主程序) // 主程序通过相对路径定位框架(版本化路径, 包含版本号) const char rel_path[] = "../Frameworks/" PRODUCT_FULLNAME_STRING " Framework.framework/Versions/" CHROME_VERSION_STRING "/" PRODUCT_FULLNAME_STRING " Framework"; #endif // defined(HELPER_EXECUTABLE) // 从可执行文件路径中提取父目录, 拼接相对路径得到框架完整路径 const char* parent_dir = dirname(exec_path.get()); // 获取父目录路径 if (!parent_dir) { // dirname失败(如路径无效) FatalError("dirname %s: %s.", exec_path.get(), strerror(errno)); } // 计算拼接路径所需的缓冲区大小 const size_t parent_dir_len = strlen(parent_dir); // 父目录长度 const size_t rel_path_len = strlen(rel_path); // 相对路径长度 // +2 用于容纳路径分隔符'/'和字符串结束符'\0' const size_t framework_path_size = parent_dir_len + rel_path_len + 2; // 分配缓冲区存储框架完整路径 std::unique_ptr<char[]> framework_path(new char[framework_path_size]); // 拼接父目录和相对路径, 生成框架的完整路径 snprintf(framework_path.get(), framework_path_size, "%s/%s", parent_dir, rel_path); // 加载框架动态库(RTLD_LAZY: 延迟绑定;RTLD_LOCAL: 符号仅本模块可见;RTLD_FIRST: 优先从该库查找符号) void* library = dlopen(framework_path.get(), RTLD_LAZY | RTLD_LOCAL | RTLD_FIRST); if (!library) { // 动态库加载失败 FatalError("dlopen %s: %s.", framework_path.get(), dlerror()); } // 从加载的动态库中查找"ChromeMain"符号(核心启动函数) const ChromeMainPtr chrome_main = reinterpret_cast<ChromeMainPtr>(dlsym(library, "ChromeMain")); if (!chrome_main) { // 未找到ChromeMain函数 FatalError("dlsym ChromeMain: %s.", dlerror()); } // 调用ChromeMain函数, 传入命令行参数, 执行核心启动逻辑 rv = chrome_main(argc, argv); // 使用exit而非return, 避免尾调用优化导致main函数从栈回溯中消失 exit(rv); } ``` 主要是在通过 `dlopen` 动态加载框架, 从加载的框架中查找并调用 ChromeMain 函数, 传入命令行参数, 最终通过 exit 退出以保证栈回溯完整性 ### chrome\app\chrome_exe_main_win.cc 只贴出主要的 main 函数: ```cpp // 根据是否为控制台应用, 选择不同的程序入口函数 #if !defined(WIN_CONSOLE_APP) // GUI应用入口:wWinMain(宽字符版本) int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) { #else // 控制台应用入口:main int main() { HINSTANCE instance = GetModuleHandle(nullptr); // 获取当前模块实例句柄 #endif // !defined(WIN_CONSOLE_APP) // 32位构建专用:纤程切换逻辑(扩大主线程栈空间) #if defined(ARCH_CPU_32_BITS) enum class FiberStatus { kConvertFailed, kCreateFiberFailed, kSuccess }; FiberStatus fiber_status = FiberStatus::kSuccess; DWORD fiber_error = ERROR_SUCCESS; // 纤程操作失败时的错误码 if (!::IsThreadAFiber()) { // 当前线程未转换为纤程, 执行转换逻辑 constexpr size_t kStackSize = 4 * 1024 * 1024; // 大栈空间大小(4MiB, 对标64位的8MiB) // 将主线程转换为纤程(FIBER_FLAG_FLOAT_SWITCH支持浮点寄存器切换) LPVOID original_fiber = ::ConvertThreadToFiberEx(nullptr, FIBER_FLAG_FLOAT_SWITCH); if (original_fiber) { FiberState fiber_state = {instance, original_fiber}; // 初始化纤程状态 // 创建大栈纤程, 绑定启动函数FiberBinder和状态参数 LPVOID big_stack_fiber = ::CreateFiberEx( 0, kStackSize, FIBER_FLAG_FLOAT_SWITCH, FiberBinder, &fiber_state); if (big_stack_fiber) { ::SwitchToFiber(big_stack_fiber); // 切换到大栈纤程执行 // 执行完成后清理纤程资源(避免TLS相关的关闭崩溃) ::DeleteFiber(big_stack_fiber); ::ConvertFiberToThread(); return fiber_state.fiber_result; // 返回纤程执行结果 } fiber_status = FiberStatus::kCreateFiberFailed; // 大栈纤程创建失败 } else { fiber_status = FiberStatus::kConvertFailed; // 线程转纤程失败 } // 记录错误码(供崩溃报告分析) fiber_error = ::GetLastError(); base::debug::Alias(&fiber_error); } // 若已为纤程, 直接继续执行 #endif // defined(ARCH_CPU_32_BITS) // 1. 设置浏览器进程的工作目录 SetCwdForBrowserProcess(); // 2. 从主模块初始化安装信息(如版本, 渠道) install_static::InitializeFromPrimaryModule(); // 3. 信号通知:初始化崩溃报告机制 SignalInitializeCrashReporting(); // 4. 浏览器进程禁用延迟加载失败钩子(避免启动时钩子干扰) if (IsBrowserProcess()) chrome::DisableDelayLoadFailureHooksForMainExecutable(); // 5. 32位构建:检查纤程切换是否成功, 失败则崩溃 #if defined(ARCH_CPU_32_BITS) CHECK_EQ(fiber_status, FiberStatus::kSuccess); #endif // defined(ARCH_CPU_32_BITS) // 启用内存不足时的终止机制(确保OOM错误正确通知系统) base::EnableTerminationOnOutOfMemory(); // 注册Abseil库的崩溃钩子(统一崩溃处理) logging::RegisterAbslAbortHook(); // 初始化命令行单例(从环境变量解析命令行) base::CommandLine::Init(0, nullptr); const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); // 获取进程类型(如浏览器进程, 渲染进程, Crashpad进程等) const std::string process_type = command_line->GetSwitchValueASCII(switches::kProcessType); // 非组件构建且启用DCHECK时的特殊处理 #if !defined(COMPONENT_BUILD) && DCHECK_IS_ON() // 禁用FeatureList的默认访问(避免chrome.exe中未初始化的FeatureList被误访问) base::FeatureList::FailOnFeatureAccessWithoutFeatureList(); // 修补IAT(导入地址表), 检测第三方代码对Chrome句柄的篡改 base::debug::HandleHooks::AddIATPatch(CURRENT_MODULE()); #endif // !defined(COMPONENT_BUILD) && DCHECK_IS_ON() // 验证非浏览器进程是否包含有效的/prefetch参数(确保预加载正确) DCHECK(process_type.empty() || HasValidWindowsPrefetchArgument(*command_line)); // 分支1:当前为Crashpad崩溃处理进程 if (process_type == crash_reporter::switches::kCrashpadHandler) { std::unique_ptr<ExitCodeWatcher> exit_code_watcher; // 进程退出码监视器 // 初始化备用崩溃处理 crash_reporter::SetupFallbackCrashHandling(*command_line); // 非周期性任务进程(监控浏览器进程, 而非其他Crashpad进程) if (!command_line->HasSwitch("no-periodic-tasks")) { // 从命令行解析初始客户端数据(获取父进程信息) crashpad::InitialClientData initial_client_data; if (initial_client_data.InitializeFromString( command_line->GetSwitchValueASCII("initial-client-data"))) { // 复制父进程句柄(用于监控退出状态) HANDLE duplicate_handle = INVALID_HANDLE_VALUE; if (DuplicateHandle( ::GetCurrentProcess(), initial_client_data.client_process(), ::GetCurrentProcess(), &duplicate_handle, PROCESS_QUERY_INFORMATION, FALSE, DUPLICATE_SAME_ACCESS)) { base::Process parent_process(duplicate_handle); // 创建并启动退出码监视器 exit_code_watcher = std::make_unique<ExitCodeWatcher>(); if (exit_code_watcher->Initialize(std::move(parent_process))) { exit_code_watcher->StartWatching(); } } } } // 强制检查命令行是否包含用户数据目录参数(Crashpad必需) DCHECK(command_line->HasSwitch(switches::kUserDataDir)); // 获取用户数据目录, 启动Crashpad处理器 base::FilePath user_data_dir = command_line->GetSwitchValuePath(switches::kUserDataDir); int crashpad_status = crash_reporter::RunAsCrashpadHandler( *base::CommandLine::ForCurrentProcess(), user_data_dir, switches::kProcessType, switches::kUserDataDir); // 若Crashpad初始化失败, 停止监视器以正常退出 if (crashpad_status != 0 && exit_code_watcher) { exit_code_watcher->StopWatching(); } return crashpad_status; } // 分支2:当前为备用崩溃处理进程 else if (process_type == crash_reporter::switches::kFallbackCrashHandler) { return RunFallbackCrashHandler(*command_line); } // 记录程序入口时间戳(用于启动性能分析) const base::TimeTicks exe_entry_point_ticks = base::TimeTicks::Now(); // 信号通知ChromeElf模块:Chrome开始启动(安全模块初始化) SignalChromeElf(); // 初始化退出管理器(负责单例对象的析构) base::AtExitManager exit_manager; // 尝试快速通知已运行的Chrome(单实例逻辑), 成功则直接退出 if (AttemptFastNotify(*command_line)) return 0; // 加载并启动chrome.dll(核心逻辑均在DLL中实现) VLOG(1) << "About to load main DLL."; MainDllLoader* loader = MakeMainDllLoader(); // 创建DLL加载器 // 启动DLL, 传入实例句柄和入口时间戳 int rc = loader->Launch(instance, exe_entry_point_ticks); // 检查是否需要重启Chrome(如版本更新后) loader->RelaunchChromeBrowserWithNewCommandLineIfNeeded(); delete loader; // 释放加载器资源 // 工具进程(UtilityProcess)直接强制终止(避免关闭时崩溃, 更安全高效) if (process_type == switches::kUtilityProcess) { base::Process::TerminateCurrentProcessImmediately(rc); } return rc; // 返回退出码 } ``` 初始化命令行, 设置工作目录, 各种奔溃处理..., 实际上是 `loader->Launch` 在进一步加载, 进入 `chrome\app\main_dll_loader_win.cc`: ```cpp // 启动逻辑核心:加载对应DLL并调用其入口函数 // 派生类可通过重写OnBeforeLaunch回调函数添加自定义逻辑 int MainDllLoader::Launch(HINSTANCE instance, base::TimeTicks exe_entry_point_ticks) { // 获取当前进程的命令行对象(用于解析参数) const base::CommandLine& cmd_line = *base::CommandLine::ForCurrentProcess(); // 从命令行读取进程类型(如浏览器进程, 渲染进程等, 空字符串表示浏览器进程) process_type_ = cmd_line.GetSwitchValueASCII(switches::kProcessType); // 初始化沙箱接口信息(默认所有字段为空) sandbox::SandboxInterfaceInfo sandbox_info = {nullptr}; const bool is_browser = process_type_.empty(); // 判断是否为浏览器进程 // 判断是否启用沙箱:通过命令行解析沙箱类型, 非"无沙箱"模式即为启用 // 注:此处不使用IsUnsandboxedSandboxType(), 因该函数依赖尚未初始化的特性标志 const bool is_sandboxed = sandbox::policy::SandboxTypeFromCommandLine(cmd_line) != sandbox::mojom::Sandbox::kNoSandbox; // 浏览器进程或启用沙箱的子进程, 初始化沙箱信息 if (is_browser || is_sandboxed) { // 非沙箱子进程无需初始化沙箱信息, 否则会被误判为沙箱代理(类似浏览器进程) content::InitializeSandboxInfo( &sandbox_info, // 若设置了扩展点禁用, 添加对应沙箱缓解措施;否则为0 IsExtensionPointDisableSet() ? sandbox::MITIGATION_EXTENSION_POINT_DISABLE : 0); } // 记录DLL预读取的开始和结束时间戳(用于性能分析) base::TimeTicks preread_begin_ticks; base::TimeTicks preread_end_ticks; base::FilePath file; // 存储加载的DLL文件路径 // 加载核心DLL(chrome.dll), 传入命令行, 是否为浏览器进程及时间戳参数 dll_ = Load(&file, cmd_line, is_browser, preread_begin_ticks, preread_end_ticks); if (!dll_) // DLL加载失败, 返回"缺失数据"错误码 return CHROME_RESULT_CODE_MISSING_DATA; // 非浏览器进程:设置进程关闭优先级(确保浏览器退出后子进程优先被系统终止) if (!is_browser) { // 浏览器进程默认关闭优先级为0x280, 子进程优先级设为更高(数值更大), 实现"先杀子进程" // SHUTDOWN_NORETRY:关闭时不重试, 避免注销/关机时出现无效标签页 ::SetProcessShutdownParameters(kNonBrowserShutdownPriority - 1, SHUTDOWN_NORETRY); } // 启动前回调:允许派生类注入自定义逻辑(如参数修改, 环境配置) OnBeforeLaunch(process_type_, file); // 从加载的DLL中获取ChromeMain函数地址(DLL的核心入口点) DLL_MAIN chrome_main = reinterpret_cast<DLL_MAIN>(::GetProcAddress(dll_, "ChromeMain")); // 调用ChromeMain启动核心逻辑, 传入实例句柄, 沙箱信息和时间戳(转换为内部值) int rc = chrome_main(instance, &sandbox_info, exe_entry_point_ticks.ToInternalValue(), preread_begin_ticks.ToInternalValue(), preread_end_ticks.ToInternalValue()); return rc; // 返回ChromeMain的执行结果(退出码) } ``` 仍然是用进入 `ChromeMain` 函数. ## 再来跟着 chrome_main.cc 向下看 ```cpp // 跨平台Chrome核心入口函数:根据操作系统定义不同签名 #if BUILDFLAG(IS_WIN) // Windows平台 // 导出ChromeMain函数(供exe调用), 参数包含实例句柄, 沙箱信息和时间戳 DLLEXPORT int __cdecl ChromeMain(HINSTANCE instance, sandbox::SandboxInterfaceInfo* sandbox_info, int64_t exe_entry_point_ticks, // 程序入口时间戳(内部值) int64_t preread_begin_ticks, // 预读取开始时间戳(内部值) int64_t preread_end_ticks) { // 预读取结束时间戳(内部值) #elif BUILDFLAG(IS_POSIX) // POSIX兼容平台(Linux, macOS等) // 入口函数签名:接收命令行参数 int ChromeMain(int argc, const char** argv) { #else #error Unknown platform. // 未识别的平台, 编译报错 #endif #if BUILDFLAG(IS_LINUX) // Linux平台专用:可能从可执行文件路径推断Chrome渠道(如稳定版, 测试版) PossiblyDetermineFallbackChromeChannel(argv[0]); #endif #if BUILDFLAG(IS_WIN) // Windows平台初始化逻辑 // 从主模块初始化安装信息(版本, 渠道等) install_static::InitializeFromPrimaryModule(); // 非组件构建且启用DCHECK时:修补IAT(导入地址表), 检测第三方代码篡改Chrome句柄 // 注:exe的IAT修补在chrome_exe_main_win.cc中单独处理 #if !defined(COMPONENT_BUILD) && DCHECK_IS_ON() base::debug::HandleHooks::AddIATPatch(CURRENT_MODULE()); #endif // !defined(COMPONENT_BUILD) && DCHECK_IS_ON() // 构造启动时间戳结构体(将内部值转换为TimeTicks类型) StartupTimestamps timestamps{ base::TimeTicks::FromInternalValue(exe_entry_point_ticks), base::TimeTicks::FromInternalValue(preread_begin_ticks), base::TimeTicks::FromInternalValue(preread_end_ticks)}; // 创建Chrome主委托对象(封装Chrome的启动配置和回调) ChromeMainDelegate chrome_main_delegate(timestamps); #else // 非Windows平台:创建主委托对象, 仅记录程序入口时间戳 ChromeMainDelegate chrome_main_delegate( {.exe_entry_point_ticks = base::TimeTicks::Now()}); #endif // 初始化Content模块参数(Content是Chromium的核心内容模块, 传入主委托对象) content::ContentMainParams params(&chrome_main_delegate); #if BUILDFLAG(IS_WIN) // Windows平台专用配置 // 设置进程异常终止时崩溃(正常返回时自动重置该配置) auto crash_on_detach_resetter = base::ScopedClosureRunner( base::BindOnce(&base::win::SetShouldCrashOnProcessDetach, base::win::ShouldCrashOnProcessDetach())); base::win::SetShouldCrashOnProcessDetach(true); // 配置崩溃报告的终止行为(确保崩溃信息完整) base::win::SetAbortBehaviorForCrashReporting(); // 给Content参数赋值:实例句柄和沙箱信息 params.instance = instance; params.sandbox_info = sandbox_info; // 设置无崩溃转储函数(使用chrome_elf模块通过加载时动态链接解析的函数) base::debug::SetDumpWithoutCrashingFunction(&DumpProcessWithoutCrash); // 验证chrome_elf模块与当前chrome.dll版本是否一致, 不一致则触发无崩溃转储 if (install_static::InstallDetails::Get().VersionMismatch()) base::debug::DumpWithoutCrashing(); #else // 非Windows平台:给Content参数赋值命令行参数 params.argc = argc; params.argv = argv; // 初始化命令行单例(从参数解析) base::CommandLine::Init(params.argc, params.argv); #endif // BUILDFLAG(IS_WIN) // 初始化命令行单例(若未初始化, 此处兜底) base::CommandLine::Init(0, nullptr); // 获取当前进程的命令行对象([[maybe_unused]]避免未使用警告) [[maybe_unused]] base::CommandLine* command_line( base::CommandLine::ForCurrentProcess()); #if BUILDFLAG(IS_WIN) // Windows平台:若命令行带--raise-timer-frequency, 提高定时器中断频率(1ms) if (base::CommandLine::ForCurrentProcess()->HasSwitch( ::switches::kRaiseTimerFrequency)) { timeBeginPeriod(1); } #endif #if BUILDFLAG(IS_MAC) // macOS平台:设置Bundle覆盖(处理资源路径等) SetUpBundleOverrides(); #endif #if BUILDFLAG(IS_LINUX) // Linux平台:向命令行追加额外参数 AppendExtraArgumentsToCommandLine(command_line); #endif // 初始化泊松分配采样器(用于内存分配采样分析) // 需在主线程栈采样分析器之前初始化, 避免TLS插槽分配导致的重入问题 base::PoissonAllocationSampler::Init(); // 无头模式(Headless)处理:无GUI的Chrome运行模式 std::unique_ptr<headless::HeadlessModeHandle> headless_mode_handle; if (headless::IsHeadlessMode()) { // 检测是否启用无头模式 // 无头模式不支持多个目标参数, 否则报错 if (command_line->GetArgs().size() > 1) { LOG(ERROR) << "Multiple targets are not supported in headless mode."; return CHROME_RESULT_CODE_UNSUPPORTED_PARAM; } // 初始化无头模式, 失败则输出错误并退出 auto init_headless_mode = headless::InitHeadlessMode(); if (!init_headless_mode.has_value()) { LOG(ERROR) << init_headless_mode.error(); return EXIT_FAILURE; } // 保存无头模式句柄(管理无头模式生命周期) headless_mode_handle = std::move(init_headless_mode.value()); } else { // 非无头模式:处理旧版无头模式提示 #ifdef ENABLE_OLD_HEADLESS_INFO if (headless::IsOldHeadlessMode()) { ShowOldHeadlessInfoMaybe(command_line); // 显示旧版无头模式提示信息 return EXIT_FAILURE; } #endif // ENABLE_OLD_HEADLESS_INFO } #if BUILDFLAG(IS_MAC) // macOS平台:若辅助程序被系统或第三方应用意外启动, 优雅退出 if (IsHelperAppLaunchedBySystemOrThirdPartyApplication()) { return 0; } #endif // 启动Content模块主逻辑(Chromium核心启动入口), 传入参数并获取返回值 int rv = content::ContentMain(std::move(params)); // 若返回码为正常结果, 统一返回Content模块的正常退出码;否则返回原始返回码 if (IsNormalResultCode(static_cast<ResultCode>(rv))) { return content::RESULT_CODE_NORMAL_EXIT; } return rv; } ``` 又是各种乱七八糟的不同平台的参数处理, 初始化等等, 值得注意的是在这里处理了无头模式, 然后调用 `ContentMain` 进一步启动, 来到 `content\public\app\content_main.h`: ```cpp #if BUILDFLAG(IS_ANDROID) // Android平台专用声明 // 说明:Android平台中, Content模块的启动入口是ContentMain.java(Java层) // 该函数提供了一种方式, 为ContentMainRunner设置ContentMainDelegate委托对象 // 调用限制:必须在ContentMainRunner实际运行之前调用, 且仅能调用一次 // 内存 ownership:|delegate|的所有权会转移给ContentMainRunner(调用方无需再管理其生命周期) CONTENT_EXPORT void SetContentMainDelegate(ContentMainDelegate* delegate); #else // 非Android平台(Windows, Linux, macOS等) // 说明:ContentMain需由嵌入者(如Chrome)的main()函数调用, 完成每个进程的初始化设置 // 定制能力:嵌入者可通过ContentMainDelegate接口自定义启动流程 // 可选委托:若嵌入者无需覆盖默认启动逻辑, 可传入nullptr作为|delegate|参数 // 返回值:返回进程退出码(标识启动结果或运行状态) CONTENT_EXPORT int ContentMain(ContentMainParams params); #endif ``` 在跟入默认实现 `content\app\content_main.cc`: ```cpp NO_STACK_PROTECTOR int ContentMain(ContentMainParams params) { // 创建ContentMainRunner实例(Content模块的核心运行器, 负责进程启动和生命周期管理) auto runner = ContentMainRunner::Create(); // 执行内容进程启动逻辑:传入参数和runner实例, 返回进程退出码 return RunContentProcess(std::move(params), runner.get()); } NO_STACK_PROTECTOR int RunContentProcess( ContentMainParams params, ContentMainRunner* content_main_runner) { // 未初始化FeatureList时访问特性直接失败(避免默认行为导致的隐藏问题) base::FeatureList::FailOnFeatureAccessWithoutFeatureList(); int exit_code = -1; // 进程退出码, 默认初始化为-1(表示未正常启动) #if BUILDFLAG(IS_MAC) // macOS平台:创建自动释放池(管理Objective-C对象生命周期) base::apple::ScopedNSAutoreleasePool autorelease_pool; #endif // 标记是否已初始化的静态变量:Android平台可能不重启进程而重新运行Main(), 需避免重复初始化 static bool is_initialized = false; #if !BUILDFLAG(IS_ANDROID) // 非Android平台强制检查:确保仅初始化一次(DCHECK断言失败会崩溃) DCHECK(!is_initialized); #endif // 已初始化:重新初始化参数(适用于Android平台进程复用场景) if (is_initialized) { content_main_runner->ReInitializeParams(std::move(params)); } // 未初始化:执行首次初始化流程 else { is_initialized = true; // 标记为已初始化 #if BUILDFLAG(IS_APPLE) && PA_BUILDFLAG(USE_ALLOCATOR_SHIM) // Apple平台且启用分配器垫片:初始化垫片 allocator_shim::InitializeAllocatorShim(); #endif // 启用内存不足时的终止机制(确保OOM错误正确通知系统) base::EnableTerminationOnOutOfMemory(); // 注册Abseil库的崩溃钩子(统一崩溃处理流程) logging::RegisterAbslAbortHook(); #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // Linux/ChromeOS平台:禁用DBUS自动启动 // 未设置DBUS_SESSION_BUS_ADDRESS时, 强制设为"disabled:", 避免自动启动导致的hang问题 // 如需恢复自动启动, 可在启动前设置环境变量为"autolaunch:" const int kNoOverrideIfAlreadySet = 0; setenv("DBUS_SESSION_BUS_ADDRESS", "disabled:", kNoOverrideIfAlreadySet); #endif #if BUILDFLAG(IS_WIN) // Windows平台专用初始化 // 注册无效参数处理函数(捕获CRT库的无效参数错误) base::win::RegisterInvalidParamHandler(); // 创建ATL模块(支持UI组件的COM对象) ui::win::CreateATLModuleIfNeeded(); #endif // BUILDFLAG(IS_WIN) #if !BUILDFLAG(IS_ANDROID) // 非Android平台:初始化命令行 // Android平台在库加载时已初始化命令行, 无需重复处理 int argc = 0; const char** argv = nullptr; #if !BUILDFLAG(IS_WIN) // 非Windows平台:从参数获取命令行(Windows平台忽略argc/argv) argc = params.argc; argv = params.argv; #endif // 初始化命令行单例 base::CommandLine::Init(argc, argv); #if BUILDFLAG(IS_POSIX) // POSIX平台:从文件描述符表填充文件描述符存储 PopulateFileDescriptorStoreFromFdTable(); #endif // 启用堆损坏时的终止机制(检测堆篡改并崩溃) base::EnableTerminationOnHeapCorruption(); // 根据命令行设置进程标题 base::SetProcessTitleFromCommandLine(argv); #endif // !BUILDFLAG(IS_ANDROID) // 初始化Unix时间戳基准(确保TimeTicks与Unix时间戳对齐) InitTimeTicksAtUnixEpoch(); // POSIX平台(排除Android):设置区域和信号处理 #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) // 设置C库区域为系统默认:确保命令行解析和文件名编码正确 setlocale(LC_ALL, ""); // 强制数字区域为"C" locale:避免区域敏感的数字格式转换(UI数字转换通过ICU处理) setlocale(LC_NUMERIC, "C"); // 设置信号处理器(如捕获崩溃信号生成栈跟踪) SetupSignalHandlers(); #endif #if BUILDFLAG(IS_WIN) // Windows平台:初始化CRT(C运行时库) base::win::SetupCRT(*base::CommandLine::ForCurrentProcess()); #endif #if BUILDFLAG(IS_MAC) // macOS平台专用初始化 // 将自动释放池赋值给参数(供后续主循环刷新) params.autorelease_pool = &autorelease_pool; // 初始化macOS平台相关配置(如安全设置, 资源路径) InitializeMac(); #endif #if BUILDFLAG(IS_IOS) // iOS平台专用配置 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); // 启用视口支持和移动User-Agent command_line->AppendSwitch(switches::kEnableViewport); command_line->AppendSwitch(embedder_support::kUseMobileUserAgent); #if BUILDFLAG(IS_IOS_TVOS) // tvOS平台:默认启用单进程模式和空间导航 command_line->AppendSwitch(switches::kSingleProcess); command_line->AppendSwitch(switches::kEnableSpatialNavigation); #endif #endif #if (BUILDFLAG(IS_CHROMEOS) || BUILDFLAG(IS_LINUX)) && !defined(COMPONENT_BUILD) // ChromeOS/Linux非组件构建:启用文件描述符所有权强制检查(安全机制) base::subtle::EnableFDOwnershipEnforcement(true); #endif // 注册UI路径提供器(供资源加载时解析路径) ui::RegisterPathProvider(); // 初始化ContentMainRunner(传入参数, 返回退出码) exit_code = content_main_runner->Initialize(std::move(params)); // 初始化失败(退出码>=0):直接返回结果(不执行后续运行逻辑) if (exit_code >= 0) { return exit_code; } #if BUILDFLAG(IS_WIN) // Windows平台:路由标准输入输出到控制台 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); if (command_line->HasSwitch(switches::kHeadless)) { // 无头模式:路由stdio到控制台(不自动创建控制台) base::RouteStdioToConsole(/*create_console_if_not_found*/ false); } else if (command_line->HasSwitch(switches::kEnableLogging)) { // 启用日志:根据参数决定是否创建控制台(避免子进程重复创建) bool create_console = command_line->GetSwitchValueASCII( switches::kEnableLogging) != "handle"; base::RouteStdioToConsole(create_console); } #endif // 添加跟踪启用状态观察者 base::trace_event::TraceLog::GetInstance()->AddOwnedEnabledStateObserver( base::WrapUnique(new TracingEnabledStateObserver)); } // 子进程:执行通用子进程初始化 if (IsSubprocess()) CommonSubprocessInit(); // 运行ContentMainRunner(启动核心逻辑, 如主循环, 进程任务) exit_code = content_main_runner->Run(); #if !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_IOS) // 非Android/iOS平台:执行关闭清理 content_main_runner->Shutdown(); #endif return exit_code; // 返回进程退出码 } ``` 又是初始化一堆, 接着跟入 `content_main_runner->Run`, 来到 `content\app\content_main_runner_impl.cc`: ```cpp NO_STACK_PROTECTOR int ContentMainRunnerImpl::Run() { // 断言校验:确保已初始化, 参数有效, 未执行关闭操作(DCHECK失败会崩溃, 仅调试模式生效) DCHECK(is_initialized_); DCHECK(content_main_params_); DCHECK(!is_shutdown_); // 获取当前进程的命令行对象, 解析进程类型(如浏览器进程, 渲染进程, GPU进程等) const base::CommandLine* command_line = base::CommandLine::ForCurrentProcess(); std::string process_type = command_line->GetSwitchValueASCII(switches::kProcessType); // 空字符串表示浏览器主进程 #if defined(ADDRESS_SANITIZER) // 启用地址 sanitizer(内存检测工具)时 // 初始化ASAN服务, 注册错误回调函数(用于上报进程信息, 辅助内存错误调试) base::debug::AsanService::GetInstance()->Initialize(); base::debug::AsanService::GetInstance()->AddErrorCallback(AsanProcessInfoCB); #endif // 子进程(非浏览器主进程)专属初始化逻辑 bool needs_startup_tracing_after_sandbox_init = false; // 标记是否需在沙箱初始化后启动跟踪 if (!process_type.empty()) { // 排除Zygote进程(进程孵化器, 无需以下初始化) if (process_type != switches::kZygoteProcess) { // 委托对象决定是否创建特性列表:初始化实验特性和字段试用配置 if (delegate_->ShouldCreateFeatureList( ContentMainDelegate::InvokedInChildProcess())) { InitializeFieldTrialAndFeatureList(); } #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // Linux/ChromeOS平台:初始化跟踪系统 if (process_type == switches::kGpuProcess) { // GPU进程:初始化跟踪(禁用消费者, 支持线程重启跟踪) tracing::InitTracingPostFeatureList(/*enable_consumer=*/false, /*will_trace_thread_restart=*/true); } else { // 其他子进程:标记需在沙箱初始化后启动跟踪 needs_startup_tracing_after_sandbox_init = true; } #else // 非Linux/ChromeOS平台:初始化跟踪(禁用消费者, 不支持线程重启跟踪) tracing::InitTracingPostFeatureList(/*enable_consumer=*/false, /*will_trace_thread_restart=*/false); #endif // 委托对象决定是否初始化Mojo核心(进程间通信框架) if (delegate_->ShouldInitializeMojo( ContentMainDelegate::InvokedInChildProcess())) { InitializeMojoCore(); } // 委托对象执行早期初始化后回调(子进程专属后续配置) delegate_->PostEarlyInitialization( ContentMainDelegate::InvokedInChildProcess()); // 根据进程类型重新配置分区分配器(内存分配优化) base::allocator::PartitionAllocSupport::Get() ->ReconfigureAfterFeatureListInit(process_type); } } // 构造主函数参数对象(传递给具体进程类型的启动逻辑) MainFunctionParams main_params(command_line); // 传递UI任务, 创建主组件的回调函数, 沙箱后跟踪标记 main_params.ui_task = std::move(content_main_params_->ui_task); main_params.created_main_parts_closure = std::move(content_main_params_->created_main_parts_closure); main_params.needs_startup_tracing_after_sandbox_init = needs_startup_tracing_after_sandbox_init; #if BUILDFLAG(IS_WIN) // Windows平台:传递沙箱信息 main_params.sandbox_info = content_main_params_->sandbox_info; #elif BUILDFLAG(IS_MAC) // macOS平台:传递自动释放池 main_params.autorelease_pool = content_main_params_->autorelease_pool; #endif // 标记是否启用最小浏览器模式(仅加载核心组件, 用于轻量场景) const bool start_minimal_browser = content_main_params_->minimal_browser_mode; // 释放ContentMainParams资源(后续不再复用) // 注:因MainFunctionParams位于common目录, 无法直接依赖ContentMainParams, 故通过逐个字段传递 content_main_params_.reset(); // 注册主线程工厂(用于创建主线程相关组件, 如消息循环) RegisterMainThreadFactories(); // 进程类型为空(浏览器主进程):执行浏览器进程启动逻辑 if (process_type.empty()) return RunBrowser(std::move(main_params), start_minimal_browser); // 子进程:执行对应类型进程的启动逻辑(如渲染进程, GPU进程等) return RunOtherNamedProcessTypeMain(process_type, std::move(main_params), delegate_); } ``` 主进程启动时不携带 `--type` 参数, 则 `process_type.empty()` 是 `true`, 所以我们先不管子进程, 也就是 `if (!process_type.empty())` 中的逻辑. ### RegisterMainThreadFactories 注册一下这三种进程的回调类: ```cpp static void RegisterMainThreadFactories() { UtilityProcessHost::RegisterUtilityMainThreadFactory( CreateInProcessUtilityThread); RenderProcessHostImpl::RegisterRendererMainThreadFactory( CreateInProcessRendererThread); content::RegisterGpuMainThreadFactory(CreateInProcessGpuThread); } // utility UtilityMainThreadFactoryFunction g_utility_main_thread_factory = nullptr; void UtilityProcessHost::RegisterUtilityMainThreadFactory( UtilityMainThreadFactoryFunction create) { g_utility_main_thread_factory = create; } base::Thread* CreateInProcessUtilityThread( const InProcessChildThreadParams& params) { return new InProcessUtilityThread(params); } // renderer RendererMainThreadFactoryFunction g_renderer_main_thread_factory = nullptr; void RenderProcessHostImpl::RegisterRendererMainThreadFactory( RendererMainThreadFactoryFunction create) { g_renderer_main_thread_factory = create; } base::Thread* CreateInProcessRendererThread( const InProcessChildThreadParams& params, int32_t renderer_client_id) { return new InProcessRendererThread(params, renderer_client_id); } // gpu GpuMainThreadFactoryFunction g_gpu_main_thread_factory = nullptr; void RegisterGpuMainThreadFactory(GpuMainThreadFactoryFunction create) { g_gpu_main_thread_factory = create; } base::Thread* CreateInProcessGpuThread( const InProcessChildThreadParams& params, const gpu::GpuPreferences& gpu_preferences) { return new InProcessGpuThread(params, gpu_preferences); } ``` ### RunBrowser ```cpp int ContentMainRunnerImpl::RunBrowser(MainFunctionParams main_params, bool start_minimal_browser) { TRACE_EVENT_INSTANT0("startup", "ContentMainRunnerImpl::RunBrowser(begin)", TRACE_EVENT_SCOPE_THREAD); // 检查浏览器主循环是否已启动, 避免重复执行 if (is_browser_main_loop_started_) return -1; // 非单进程模式下(默认多进程):禁用Mojo同步调用中断 // 多进程场景下需要稳定的IPC通信, 防止同步调用被中断 if (!base::CommandLine::ForCurrentProcess()->HasSwitch( switches::kSingleProcess)) { mojo::SyncCallRestrictions::DisableSyncCallInterrupts(); } // 可能解压Variations状态文件(Variations是Chrome的A/B测试框架) // 加载测试配置, 功能开关等信息 variations::MaybeUnpackVariationsStateFile(); // 如果Mojo IPC支持未初始化(首次进入), 执行初始化流程 if (!mojo_ipc_support_) { // 标记当前是否在浏览器进程中执行(区分测试/正式环境) const ContentMainDelegate::InvokedInBrowserProcess invoked_in_browser{ .is_running_test = !main_params.ui_task.is_null()}; // 委托类判断是否需要创建功能列表(FeatureList管理所有功能开关) if (delegate_->ShouldCreateFeatureList(invoked_in_browser)) { // 初始化字段试验列表和功能列表, 故意泄漏对象(进程生命周期内持续使用) // 无需在进程退出时清理, 无性能损失 base::FieldTrialList* leaked_field_trial_list = SetUpFieldTrialsAndFeatureList().release(); // 标记对象为泄漏(避免内存检测工具误报) ANNOTATE_LEAKING_OBJECT_PTR(leaked_field_trial_list); // 忽略未使用变量警告(实际已通过泄漏方式使用) std::ignore = leaked_field_trial_list; } // 委托类判断是否需要初始化Mojo(IPC通信核心) if (delegate_->ShouldInitializeMojo(invoked_in_browser)) { InitializeMojoCore(); // 初始化Mojo核心服务 } // 创建浏览器内存消费者注册表(用于内存使用监控和分析) browser_memory_consumer_registry_ = std::make_unique< base::ScopedMemoryConsumerRegistry<BrowserMemoryConsumerRegistry>>(); // 执行浏览器主流程前的预处理(委托给子类实现, 如初始化第三方组件) std::optional<int> pre_browser_main_exit_code = delegate_->PreBrowserMain(); // 如果预处理返回退出码, 直接终止流程(如预处理失败) if (pre_browser_main_exit_code.has_value()) return pre_browser_main_exit_code.value(); #if BUILDFLAG(IS_WIN) // Windows平台特有处理 // 如果未设置区域覆盖(locale), 使用用户首选的UI语言覆盖区域设置 // 测试环境会手动设置locale, 避免此处覆盖(保证测试一致性) if (l10n_util::GetLocaleOverrides().empty()) { l10n_util::OverrideLocaleWithUILanguageList(); } #endif // 注册浏览器线程的任务执行器(TaskExecutor) // 注意:在此之前不能向BrowserThreads投递任务(线程未初始化) // 作用:初始化主线程的UI消息循环(后续在BrowserMainLoop中标记为BrowserThread::UI) BrowserTaskExecutor::Create(); // 创建Variations ID提供器(用于A/B测试标识分配) auto* provider = delegate_->CreateVariationsIdsProvider(); if (!provider) { // 委托未创建时, 使用默认实现(基于登录状态分配ID) variations::VariationsIdsProvider::CreateInstance( variations::VariationsIdsProvider::Mode::kUseSignedInState); } // 早期初始化后的后续处理(委托给子类, 如初始化扩展服务) std::optional<int> post_early_initialization_exit_code = delegate_->PostEarlyInitialization(invoked_in_browser); // 若返回退出码, 终止流程 if (post_early_initialization_exit_code.has_value()) return post_early_initialization_exit_code.value(); // 启动挂起监控器(HangWatcher):需在功能列表可用, IO线程启动前初始化 // 用于检测主线程/IO线程挂起, 收集堆栈信息辅助调试 if (base::HangWatcher::IsEnabled()) { base::HangWatcher::CreateHangWatcherInstance(); // 创建挂起监控实例 // 注册主线程到挂起监控器, 且不取消注册(监控器为泄漏对象, 进程生命周期有效) base::ScopedClosureRunner unregister_thread_closure( base::HangWatcher::RegisterThread( base::HangWatcher::ThreadType::kMainThread)); // 释放闭包所有权(避免自动取消注册) std::ignore = unregister_thread_closure.Release(); base::HangWatcher::GetInstance()->Start(); // 启动挂起监控 } #if BUILDFLAG(IS_ANDROID) // Android平台特有:初始化性能追踪(Perfetto) // WebView可能已初始化Perfetto, 由委托判断是否需要在此处初始化 if (delegate_->ShouldInitializePerfetto(invoked_in_browser)) { tracing::InitTracingPostFeatureList( /*enable_consumer=*/true, // 启用追踪消费者(接收追踪数据) /*will_trace_thread_restart=*/false, // 不追踪线程重启 base::BindRepeating(&ShouldAllowSystemTracingConsumer)); // 系统追踪消费者权限判断 } #else // 非Android平台:直接初始化Perfetto追踪 tracing::InitTracingPostFeatureList( /*enable_consumer=*/true, /*will_trace_thread_restart=*/false, base::BindRepeating(&ShouldAllowSystemTracingConsumer)); #endif // 启动浏览器线程池(ThreadPool):需在FeatureList创建后执行 // 线程池用于处理后台任务(如下载, 缓存清理等) StartBrowserThreadPool(); // 安装PartitionAlloc内存分配器的调度循环隔离任务观察者 // 作用:监控内存分配/释放, 处理隔离区(quarantine)逻辑, 提升内存安全性 BrowserTaskExecutor:: InstallPartitionAllocSchedulerLoopQuarantineTaskObserver(); // 初始化电源监控器(PowerMonitor):精简模式下也需要 // BrowserMainLoop会判断是否已初始化, 避免重复执行 // 参数1:电源监控设备源(获取设备电源状态) // 参数2:是否发送全局事件(通知其他模块电源状态变化) base::PowerMonitor::GetInstance()->Initialize( MakePowerMonitorDeviceSource(), /*emit_global_event=*/true); // 确保进程可见性追踪器在主线程创建(单例模式) // 用于监控浏览器进程是否处于前台/后台状态 ProcessVisibilityTracker::GetInstance(); #if BUILDFLAG(IS_ANDROID) // Android平台特有:初始化性能/电池指标 SetupCpuTimeMetrics(); // 配置CPU时间指标收集 // 创建Android电池指标实例(依赖PowerMonitor已初始化) AndroidBatteryMetrics::CreateInstance(); #endif // 通知浏览器客户端:设置是否为最小化模式 GetContentClient()->browser()->SetIsMinimalMode(start_minimal_browser); if (start_minimal_browser) { ForceInProcessNetworkService(); // 强制启用进程内网络服务(最小化模式简化架构) // 最小化模式不通过常规方式初始化First-Party Sets(第一方集合) // 手动初始化:使用空路径和本地集合声明 content::FirstPartySetsHandlerImpl::GetInstance()->Init( base::FilePath(), net::LocalSetDeclaration()); } // 创建可释放共享内存管理器 // 用于管理可回收的共享内存(如渲染进程间共享的缓存数据) discardable_shared_memory_manager_ = std::make_unique<discardable_memory::DiscardableSharedMemoryManager>(); // 初始化Mojo IPC支持:创建IO线程并绑定 // Mojo IPC的核心线程, 负责跨进程通信的IO操作 mojo_ipc_support_ = std::make_unique<MojoIpcSupport>(BrowserTaskExecutor::CreateIOThread()); // 绑定浏览器控制接口:处理Mojo邀请(跨进程通信初始化) GetContentClient()->browser()->BindBrowserControlInterface( MaybeAcceptMojoInvitation()); // 为下载模块设置IO线程任务执行器 // 下载任务需在IO线程执行(网络请求, 文件写入等) download::SetIOTaskRunner(mojo_ipc_support_->io_thread()->task_runner()); // 初始化浏览器内存监控客户端 // 用于收集和上报浏览器进程内存使用数据 InitializeBrowserMemoryInstrumentationClient(); #if BUILDFLAG(IS_ANDROID) // Android平台特有:最小化模式启动完成通知 if (start_minimal_browser) { // 向主线程任务队列投递"最小化浏览器启动完成"任务 base::SingleThreadTaskRunner::GetCurrentDefault()->PostTask( FROM_HERE, base::BindOnce(&MinimalBrowserStartupComplete)); } #endif } // 未指定进程类型时, 默认为浏览器进程 // 初始化PartitionAlloc内存分配器(FeatureList初始化后) base::allocator::PartitionAllocSupport::Get() ->ReconfigureAfterFeatureListInit(""); // 初始化PartitionAlloc内存分配器(任务执行器初始化后) base::allocator::PartitionAllocSupport::Get()->ReconfigureAfterTaskRunnerInit( ""); // 最小化模式下:打印日志并返回(无需启动完整浏览器流程) if (start_minimal_browser) { DVLOG(0) << "Chrome is running in minimal browser mode."; // 日志级别0(强制输出) return -1; } // 标记浏览器主循环已启动(防止重复执行) is_browser_main_loop_started_ = true; // 创建浏览器启动数据并传入主参数(包含Mojo IPC配置等) main_params.startup_data = mojo_ipc_support_->CreateBrowserStartupData(); // 执行浏览器进程主逻辑, 返回退出码 return RunBrowserProcessMain(std::move(main_params), delegate_); } ``` 这段代码, 初始化了 Mojo, 用于进程通信, 然后又初始化一大堆, 可以自己读读. 在跟入 `RunBrowserProcessMain`: ```cpp int RunBrowserProcessMain(MainFunctionParams main_function_params, ContentMainDelegate* delegate) { #if BUILDFLAG(IS_WIN) // Windows平台特有:处理控制台控制事件(如Ctrl+C, 关闭控制台窗口) // 由委托判断是否需要处理控制台控制事件(浏览器进程通常需要响应此类事件以优雅退出) if (delegate->ShouldHandleConsoleControlEvents()) { // 安装控制台控制处理器, 标记当前为浏览器进程(用于区分不同进程的事件处理逻辑) InstallConsoleControlHandler(/*is_browser_process=*/true); } #endif // 委托执行进程运行逻辑:传入空字符串(表示默认进程类型, 即浏览器进程)和启动参数 // 返回值为variant类型(二选一): // 1. int类型:直接返回的进程退出码(表示进程无需继续执行核心逻辑, 直接退出) // 2. MainFunctionParams类型:经过委托处理后的启动参数(需继续执行BrowserMain核心流程) auto exit_code = delegate->RunProcess("", std::move(main_function_params)); // 检查返回值是否为int类型(即委托已决定进程退出码) if (std::holds_alternative<int>(exit_code)) { // 断言退出码非负(符合系统退出码规范:非负表示正常/指定退出, 负表示异常) DCHECK_GE(std::get<int>(exit_code), 0); // 返回委托提供的退出码, 进程终止 return std::get<int>(exit_code); } // 若返回值为MainFunctionParams类型:提取参数并执行浏览器核心主流程 return BrowserMain(std::move(std::get<MainFunctionParams>(exit_code))); } ``` `delegate->RunProcess` 对一些平台做了些处理, 不太重要, 继续跟入 `BrowserMain`, 来到 `content\browser\browser_main.cc`: ```cpp int BrowserMain(MainFunctionParams parameters) { // 记录启动跟踪事件:标记浏览器核心主流程开始(用于性能分析, 追踪启动耗时) TRACE_EVENT_INSTANT0("startup", "BrowserMain", TRACE_EVENT_SCOPE_THREAD); // 设置当前进程类型为"浏览器进程"(标记进程角色, 供其他模块判断进程类型) base::CurrentProcess::GetInstance().SetProcessType( base::CurrentProcessType::PROCESS_BROWSER); // 创建浏览器主运行器实例(BrowserMainRunnerImpl 封装了浏览器核心运行逻辑) // 采用智能指针(std::unique_ptr)管理, 自动释放资源, 避免内存泄漏 std::unique_ptr<BrowserMainRunnerImpl> main_runner( BrowserMainRunnerImpl::Create()); // 初始化浏览器主运行器:传入启动参数, 执行初始化流程(如组件初始化, 配置加载等) int exit_code = main_runner->Initialize(std::move(parameters)); // 若初始化返回非负退出码(表示初始化失败或需要直接退出), 直接返回该退出码 if (exit_code >= 0) return exit_code; // 初始化成功(exit_code < 0), 运行浏览器主循环(进入核心业务逻辑) // 此处会阻塞直到浏览器退出(如用户关闭所有窗口, 主动退出等) exit_code = main_runner->Run(); // 记录关闭开始时间(以秒为单位), 用于问题排查(如分析进程挂起) // 可与 ReportThreadHang(), TaskAnnotator::RunTaskImpl() 等地方记录的时间对比 const int64_t shutdown_time = base::TimeTicks::Now().since_origin().InSeconds(); // 强制保留该变量在调试符号中(避免编译器优化删除, 方便调试时查看) base::debug::Alias(&shutdown_time); // 执行浏览器关闭流程:释放资源, 终止子进程, 保存配置等 main_runner->Shutdown(); // 返回浏览器运行/关闭后的最终退出码 return exit_code; } ``` 这个就是生命周期控制函数, 首先看下 `main_runner->Initialize`, 跟入, 来到 `content\browser\browser_main_runner_impl.cc`: ```cpp int BrowserMainRunnerImpl::Initialize(MainFunctionParams parameters) { // 1. 性能指标采集:记录 BrowserMainRunnerImpl 初始化的耗时(长期计时器, 用于 UMA 统计) // UMA(User Metrics Analysis)是 Chrome 用于收集用户场景性能数据的框架, 此指标用于分析启动性能瓶颈 SCOPED_UMA_HISTOGRAM_LONG_TIMER( "Startup.BrowserMainRunnerImplInitializeLongTime"); // 2. 启动跟踪:添加 Trace 事件, 用于性能分析工具(如 chrome://tracing)标记初始化开始 TRACE_EVENT0("startup", "BrowserMainRunnerImpl::Initialize"); // 3. Android 平台特殊逻辑:防止重复初始化 // 说明:Android 通常通过 UI 线程的一系列任务分步初始化浏览器, 若初始化过程中收到 // 系统或其他应用的二次启动请求, 需避免重复执行初始化核心流程(防止资源冲突/内存泄漏) if (!initialization_started_) { initialization_started_ = true; // 标记为已开始初始化, 阻止二次进入 // 4. 初始化 Skia 图形库核心:Skia 是 Chrome 的底层图形渲染引擎(绘制 UI, 网页内容等) // 必须在所有图形相关操作前初始化, 提供绘图, 字体渲染等基础能力 SkGraphics::Init(); // 5. 调试模式支持:若命令行带 --wait-for-debugger, 等待调试器附加(超时 60 秒) // 第二个参数 true 表示允许在后台线程等待(不阻塞主线程初始化基础逻辑) if (parameters.command_line->HasSwitch(switches::kWaitForDebugger)) { base::debug::WaitForDebugger(60, true); } // 6. 调试模式扩展:若带 --browser-startup-dialog, 弹出调试等待对话框(显式提示用户) // 常用于开发/调试场景, 手动控制初始化流程的断点时机 if (parameters.command_line->HasSwitch(switches::kBrowserStartupDialog)) { WaitForDebugger("Browser"); } #if BUILDFLAG(IS_WIN) // 7. Windows 平台:启用高 DPI 支持(适配 4K/Retina 屏幕, 避免 UI 模糊) base::win::EnableHighDPISupport(); // 8. Windows 平台:初始化 OLE(对象链接与嵌入) // 必要性:Windows 8 Metro 模式下, TSF(文本服务框架, 处理输入法, 文本编辑) // 需与消息泵交互, 必须在消息泵启动前初始化 OLE ole_initializer_ = std::make_unique<ui::ScopedOleInitializer>(); #endif // BUILDFLAG(IS_WIN) // 9. 初始化字体系统:加载系统字体配置, 为 UI 控件, 网页文本渲染提供字体支持 gfx::InitializeFonts(); // 10. 提取"主部件创建完成"回调:参数中携带的闭包, 将在 BrowserMainParts 创建后执行 // 用途:嵌入者(如 Chrome 浏览器)可通过此回调注入自定义逻辑(如初始化第三方组件) auto created_main_parts_closure = std::move(parameters.created_main_parts_closure); // 11. 创建 BrowserMainLoop 实例(浏览器主循环核心) // 传递启动参数和执行围栏(scoped_execution_fence_, 用于控制初始化流程的并发安全) // BrowserMainLoop 管理整个浏览器的生命周期(初始化, 运行, 关闭)和核心组件调度 main_loop_ = std::make_unique<BrowserMainLoop>( std::move(parameters), std::move(scoped_execution_fence_)); // 12. BrowserMainLoop 基础初始化:初始化内部状态, 参数解析等轻量操作 main_loop_->Init(); // 13. 执行主部件创建回调:若存在自定义闭包, 传入 BrowserMainParts 实例执行 // 此时 BrowserMainParts 已创建, 可通过其访问浏览器核心组件接口 if (created_main_parts_closure) { std::move(created_main_parts_closure).Run(main_loop_->parts()); } // 14. 早期初始化:执行核心组件的前置初始化(如沙箱, Mojo IPC, Zygote 进程等) // 返回值 >0 表示初始化失败, 需提前退出 const int early_init_error_code = main_loop_->EarlyInitialization(); if (early_init_error_code > 0) { // 失败时创建"早期关闭"专用消息循环(确保资源正常释放, 避免崩溃) main_loop_->CreateMessageLoopForEarlyShutdown(); return early_init_error_code; // 返回错误码, 终止初始化流程 } // 15. 初始化 UI 工具包(如 Aura, Views 等):必须在使用消息循环或显示 UI 前完成 // 工具包提供窗口管理, 控件渲染, 事件处理等基础 UI 能力, 初始化失败则退出 if (!main_loop_->InitializeToolkit()) { main_loop_->CreateMessageLoopForEarlyShutdown(); return 1; } // 16. 主消息循环创建前置操作:初始化消息循环依赖的组件(如线程本地存储, 任务调度器) main_loop_->PreCreateMainMessageLoop(); // 17. 创建主消息循环:启动主线程的消息泵(如 Windows 的 GetMessage, POSIX 的 epoll) // 主消息循环是浏览器的"心脏", 负责处理 UI 事件, 网络回调, 定时任务等 main_loop_->CreateMainMessageLoop(); // 18. 主消息循环创建后置操作:注册消息处理回调, 启动辅助线程等 main_loop_->PostCreateMainMessageLoop(); // 警告:若收到 WM_ENDSESSION(Windows 系统关机/注销事件), 栈上创建的对象不会被析构 // 注意:若需在关机时执行清理逻辑, 需将代码添加到 browser_shutdown::Shutdown 或 // BrowserProcess::EndSession 中(确保关机流程能触发) // 19. 初始化输入方法框架:支持输入法切换, 文本输入, 候选词显示等功能 // 必须在 UI 工具包初始化后执行, 依赖窗口系统的输入事件接口 ui::InitializeInputMethod(); } // 20. 创建启动任务队列:将后续初始化任务(如加载扩展, 恢复标签页, 启动网络服务) // 加入主消息循环的任务队列, 等待主循环启动后按顺序执行 main_loop_->CreateStartupTasks(); // 21. 获取初始化结果码:若结果码 >0 表示存在启动错误, 直接返回 int result_code = main_loop_->GetResultCode(); if (result_code > 0) { return result_code; } // 返回 -1 表示初始化成功, 无早期终止(符合 BrowserMain 的判断逻辑:负数值表示继续执行) return -1; } ``` 可以看到这里初始化一大堆, 什么 ui, font, skia..., 再跟入 `main_runner->Run`: ```cpp int BrowserMainRunnerImpl::Run() { DCHECK(initialization_started_); DCHECK(!is_shutdown_); main_loop_->RunMainMessageLoop(); return main_loop_->GetResultCode(); } ``` 在跟入 `RunMainMessageLoop`: ```cpp void BrowserMainLoop::RunMainMessageLoop() { #if BUILDFLAG(IS_ANDROID) // Android平台特殊处理 // Android的主消息循环由Java层消息循环(Looper)接管, 不使用本C++层实现 // NOTREACHED():断言该代码路径不会被执行(防止误调用) NOTREACHED(); #else // 非Android平台(Windows/macOS/Linux等) // 拦截主消息循环运行:允许自定义逻辑中断/修改循环运行(如调试, 特殊启动场景) // ProceedWithMainMessageLoopRun(true) 表示默认允许继续运行循环 // 若拦截返回值 != 允许运行的标识, 则直接返回, 不启动主循环 if (InterceptMainMessageLoopRun() != ProceedWithMainMessageLoopRun(true)) return; // 创建主消息循环对象(base::RunLoop封装了消息循环的核心逻辑) // 智能指针管理, 自动释放资源 auto main_run_loop = std::make_unique<base::RunLoop>(); // parts_ 是浏览器主循环的功能组件集合(如UI, 网络, 渲染等模块) // 通知所有组件:主消息循环即将运行(组件可在此做最后的初始化, 如注册事件回调) if (parts_) parts_->WillRunMainMessageLoop(main_run_loop); #if BUILDFLAG(IS_MAC) // macOS平台特有:回收自动释放池 // 尽可能晚地调用Recycle(), 在进入循环前执行 // 原因:之前的初始化步骤(如创建主窗口)可能已向自动释放池添加了对象 // 回收可释放临时对象, 减少内存占用 if (parameters_.autorelease_pool) parameters_.autorelease_pool->Recycle(); #endif // BUILDFLAG(IS_MAC) // 断言主消息循环对象已创建(避免空指针调用) DCHECK(main_run_loop); // 启动主消息循环:进入阻塞状态, 持续处理消息队列中的任务(UI事件, 网络回调, 定时任务等) // 直到调用 Quit() 才会退出循环(如用户关闭浏览器) main_run_loop->Run(); #endif // BUILDFLAG(IS_ANDROID) } ``` 不管三七二十一, 跟入 `main_run_loop->Run`, 来到了 `base\task\sequence_manager\thread_controller_with_message_pump_impl.cc`: ```cpp void ThreadControllerWithMessagePumpImpl::Run(bool application_tasks_allowed, TimeDelta timeout) { // 断言:当前调用线程必须是该控制器绑定的任务执行线程 // 消息循环与线程强绑定, 避免跨线程调用导致的任务执行混乱 DCHECK(RunsTasksInCurrentSequence()); // 开启RunLoop期间的同步任务执行权限: // 此时任务源的所有相关操作(互斥, 顺序依赖)都会被追踪, 同步执行任务不会引发线程安全问题 // 用于优化任务执行效率(无需异步投递, 直接在当前调用栈执行) main_thread_only().task_source->SetRunTaskSynchronouslyAllowed(true); // 延迟初始化循环启动时间(LazyNow:首次调用Now()才获取时间, 减少无效计算) // time_source_为时间提供源, 支持测试场景下的时间模拟 LazyNow lazy_now_run_loop_start(time_source_); // 嵌套RunLoop的退出时间状态保护: // 退出时自动恢复之前的quit_runloop_after值(避免嵌套循环修改全局状态) // 计算当前循环的退出截止时间:无限等待则设为最大时间, 否则为启动时间+超时时长 // 不使用饱和算术, 因部分测试会校验时间接口的调用次数 AutoReset<TimeTicks> quit_runloop_after( &main_thread_only().quit_runloop_after, (timeout == TimeDelta::Max()) ? TimeTicks::Max() : lazy_now_run_loop_start.Now() + timeout); // 通知运行级别追踪器:当前RunLoop已启动 run_level_tracker_.OnRunLoopStarted(RunLevelTracker::kInBetweenWorkItems, lazy_now_run_loop_start); // 清除退出标记:Quit()可能在Run()外部被调用(如外部主动终止循环) // 此处确保循环启动时无退出待处理状态, 避免刚启动就退出 // 注意:Quit()中不能用InTopLevelDoWork()判断当前状态, 因可能处于Run()内但非顶层任务执行阶段 main_thread_only().quit_pending = false; // 启动挂起监控:创建监控作用域, 开始检测消息循环是否长时间阻塞(如任务执行超时) // 作用域结束时自动停止监控, 避免资源泄漏 hang_watch_scope_.emplace(); // 分支1:允许应用层任务, 且当前任务执行被禁用(仅嵌套RunLoop场景) if (application_tasks_allowed && !main_thread_only().task_execution_allowed) { // 断言当前是嵌套循环(顶层循环不会进入此分支) DCHECK(RunLoop::IsNestedOnCurrentThread()); main_thread_only().task_execution_allowed = true; // 临时启用任务执行权限 pump_->Run(this); // 启动底层消息泵, 阻塞线程并处理任务(核心阻塞逻辑) main_thread_only().task_execution_allowed = false; // 退出后恢复禁用状态, 避免影响外层循环 } else { // 分支2:顶层循环或无需特殊权限控制, 直接启动消息泵执行任务 pump_->Run(this); } // 通知运行级别追踪器:当前RunLoop已结束(更新嵌套层级计数) run_level_tracker_.OnRunLoopEnded(); main_thread_only().quit_pending = false; // 再次清除退出标记, 确保状态干净 // 挂起监控的生命周期管理: // 1. 嵌套循环退出后:重新创建监控作用域, 继续监控外层任务的执行(避免嵌套期间漏监控) // 2. 顶层循环退出后:销毁监控作用域, 停止挂起监控(循环已结束, 无需继续检测) if (RunLoop::IsNestedOnCurrentThread()) { hang_watch_scope_.emplace(); } else { hang_watch_scope_.reset(); } // 递增工作ID:标记当前循环执行的任务批次, 辅助调试时追溯任务执行顺序 work_id_provider_->IncrementWorkId(); // 关闭同步任务执行权限: // RunLoop退出后, 任务源的操作不再被全程追踪, 同步执行可能引发线程安全问题 // 仅当所有RunLoop都退出(运行级别为0)时才禁用, 嵌套循环未退出时仍保持允许 if (run_level_tracker_.num_run_levels() == 0) { main_thread_only().task_source->SetRunTaskSynchronouslyAllowed(false); } } ``` 在跟入 `pump_->Run`, 发现不同平台还是有不同的实现:  我们看 `base\message_loop\message_pump_default.cc` 中的: ```cpp // 默认消息泵(MessagePumpDefault)的运行方法:实现基础的任务循环(无平台特定优化) // 负责阻塞等待事件, 调度任务执行, 是 POSIX 平台(Linux/macOS)的默认消息泵实现 // 参数:delegate - 任务委托对象(即 ThreadControllerWithMessagePumpImpl) // 核心逻辑:循环执行“处理立即任务→处理空闲任务→等待事件”, 直到停止信号触发 void MessagePumpDefault::Run(Delegate* delegate) { // 自动重置 keep_running_ 标记:作用域结束时恢复为初始值(true→false) // 确保循环退出后状态干净, 避免影响下次运行 AutoReset<bool> auto_reset_keep_running(&keep_running_, true); // 无限循环:消息泵的核心任务循环, 直到 keep_running_ 为 false 时退出 for (;;) { #if BUILDFLAG(IS_APPLE) // Apple 平台(macOS/iOS)特有:创建自动释放池 // 每次循环创建新的自动释放池, 循环结束时自动回收临时对象, 减少内存泄漏风险 apple::ScopedNSAutoreleasePool autorelease_pool; #endif // 1. 处理立即执行的任务(高优先级任务, 如 UI 事件, 紧急回调) // 调用委托的 DoWork() 方法, 从任务队列中取出并执行所有就绪任务 // 返回值 next_work_info:包含下一个延迟任务的信息(执行时间, 剩余延迟) Delegate::NextWorkInfo next_work_info = delegate->DoWork(); // 判断是否还有更多立即任务(next_work_info 标记为“立即执行”) bool has_more_immediate_work = next_work_info.is_immediate(); // 检查是否需要停止循环(如外部调用 Quit() 设置 keep_running_ 为 false) if (!keep_running_) { break; // 退出循环, 终止消息泵 } // 若有更多立即任务, 跳过后续步骤, 直接回到循环开头继续处理(优先执行高优先级任务) if (has_more_immediate_work) { continue; } // 2. 处理空闲任务(低优先级任务, 如缓存清理, 日志上报) // 仅当无立即任务时执行, 避免占用高优先级任务的执行时间 delegate->DoIdleWork(); // 再次检查停止信号(防止空闲任务执行期间触发退出) if (!keep_running_) { break; } // 3. 等待事件触发(阻塞当前线程, 避免空循环占用 CPU) base::TimeTicks before; // 记录等待开始时间(用于统计等待时长) // 判断是否允许忙等待(max_busy_loop_time_ > 0 表示允许短时间忙等待) bool may_busy_loop = max_busy_loop_time_.is_positive(); if (may_busy_loop) { before = base::TimeTicks::Now(); // 记录忙等待开始时间 } // 根据下一个延迟任务的状态, 选择不同的等待方式 if (next_work_info.delayed_run_time.is_max()) { // 情况 1:无后续延迟任务(delayed_run_time 为最大值)→ 无限等待 if (ShouldBusyLoop()) { // 允许忙等待:短时间内循环检查事件(减少线程唤醒延迟) // 若忙等待期间未收到信号(无新任务), 则进入阻塞等待 bool signaled = BusyWaitOnEvent(before); if (!signaled) { event_.Wait(); // 阻塞等待, 直到 event_ 被触发(如新增任务, 外部唤醒) } } else { // 不允许忙等待:直接进入阻塞等待, 直到被唤醒 event_.Wait(); } } else { // 情况 2:有后续延迟任务 → 定时等待(等待到下一个任务执行时间) // 简化逻辑:不处理极短延迟(避免频繁唤醒, 提升性能) if (ShouldBusyLoop() && next_work_info.remaining_delay() > max_busy_loop_time_) { // 允许忙等待, 且剩余延迟大于忙等待最大时长 → 先忙等待, 再定时等待 bool signaled = BusyWaitOnEvent(before); if (!signaled) { // 忙等待未触发信号, 更新当前时间, 进入定时等待 next_work_info.recent_now = base::TimeTicks::Now(); // 等待到下一个延迟任务的剩余时间, 超时或被唤醒后继续循环 event_.TimedWait(next_work_info.remaining_delay()); } } else { // 不允许忙等待, 或剩余延迟较短 → 直接定时等待 event_.TimedWait(next_work_info.remaining_delay()); } } // 记录等待时长(仅当允许忙等待时统计, 用于优化忙等待参数) if (may_busy_loop) { RecordWaitTime(base::TimeTicks::Now() - before); } // 注:event_ 是自动重置事件(AutoResetEvent), 唤醒后自动重置为未触发状态 // 无需手动重置, 后续等待会自动阻塞, 直到再次被触发(如新增任务, 延迟任务到期) } } ``` 大体上就是一套任务队列机制, 所有任务(UI 事件, 网络回调, 延迟任务, 空闲任务等)最终都会被放入任务队列中, 消息泵循环的核心就是"从队列取任务→执行→再取"的循环, 这是整套机制的底层基础. ## 其他进程的启动 回到最开始 `ContentMainRunnerImpl::Run`, 还记得有一个主进程子进程的分流吗, 我们从这里开始看, 跟人 `RunOtherNamedProcessTypeMain` 来到 `content\app\content_main_runner_impl.cc`: ```cpp NO_STACK_PROTECTOR int RunOtherNamedProcessTypeMain( const std::string& process_type, MainFunctionParams main_function_params, ContentMainDelegate* delegate) { #if BUILDFLAG(IS_MAC) // macOS 平台特殊逻辑:设置当前进程任务的默认角色(适配系统权限管理, 确保子进程正常运行) base::Process::SetCurrentTaskDefaultRole(); #endif #if BUILDFLAG(IS_WIN) // Windows 平台特殊逻辑:处理控制台控制事件(如 Ctrl+C 关闭) // 标记为非浏览器进程, 与主进程的事件处理区分开(子进程通常无需独立处理控制台事件) if (delegate->ShouldHandleConsoleControlEvents()) InstallConsoleControlHandler(/*is_browser_process=*/false); #endif // 核心映射表:进程类型字符串 → 对应子进程的主函数(MainFunction) // 预定义 Chromium 核心子进程的启动入口, 通过进程类型匹配对应的执行逻辑 static const auto kMainFunctions = std::to_array<MainFunction>({ {switches::kUtilityProcess, UtilityMain}, // "utility" 类型 → 工具进程主函数 {switches::kRendererProcess, RendererMain}, // "renderer" 类型 → 渲染进程主函数 {switches::kGpuProcess, GpuMain}, // "gpu" 类型 → GPU 进程主函数 }); // 初始化子进程的内存消费者注册表(尽早创建, 用于内存监控和调试) base::ScopedMemoryConsumerRegistry<ChildMemoryConsumerRegistry> child_memory_consumer_registry; // 初始化挂起监控器(HangWatcher):检测子进程是否卡死, 需在 IO 线程启动前初始化 base::ScopedClosureRunner unregister_thread_closure; if (base::HangWatcher::IsEnabled()) { // 创建挂起监控器实例(全局单例, 用于监控当前子进程的线程挂起状态) base::HangWatcher::CreateHangWatcherInstance(); // 注册当前主线程到监控器(标记为主线程, 便于定位挂起位置) unregister_thread_closure = base::HangWatcher::RegisterThread( base::HangWatcher::ThreadType::kMainThread); #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // Linux/ChromeOS 特殊逻辑:挂起监控器需在沙箱初始化后启动 // 原因:沙箱初始化时不能有多个线程, 否则会失败 // 通过命令行解析沙箱类型, 判断是否为非沙箱进程(非沙箱进程可立即启动监控器) const bool start_hang_watcher_now = IsUnsandboxedSandboxType( SandboxTypeFromCommandLine(*main_function_params.command_line)); #else // 其他平台:立即启动挂起监控器(无需等待沙箱初始化) const bool start_hang_watcher_now = true; #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // 根据平台条件启动挂起监控器, 非立即启动时记录当前时间(后续补启动时用) if (start_hang_watcher_now) { base::HangWatcher::GetInstance()->Start(); } else { main_function_params.hang_watcher_not_started_time = base::TimeTicks::Now(); } } // 核心分发逻辑:遍历进程类型-主函数映射表, 匹配当前子进程类型 for (const MainFunction& main_function : kMainFunctions) { if (process_type == main_function.name) { // 步骤1:通过 delegate 分发子进程启动逻辑(上层应用可定制启动行为) auto exit_code = delegate->RunProcess(process_type, std::move(main_function_params)); // 步骤2:处理 delegate 返回结果 if (std::holds_alternative<int>(exit_code)) { // 若返回 int → 直接退出, 返回该退出码(定制逻辑中启动失败) DCHECK_GE(std::get<int>(exit_code), 0); return std::get<int>(exit_code); } // 若返回 MainFunctionParams → 执行对应子进程的主函数(进入专属初始化) // 例如:process_type 为 "gpu" 时, 调用 GpuMain() 启动 GPU 子进程核心逻辑 return main_function.function( std::move(std::get<MainFunctionParams>(exit_code))); } } #if BUILDFLAG(USE_ZYGOTE) // Zygote 进程特殊处理(仅 Linux/ChromeOS 等使用 Zygote 的平台) // Zygote 进程不直接使用 ZygoteMain, 需通过 RunZygote 函数启动(处理孵化子进程的特殊逻辑) if (process_type == switches::kZygoteProcess) return RunZygote(delegate); #endif // BUILDFLAG(USE_ZYGOTE) // 兜底逻辑:若进程类型未匹配(未知子进程类型), 交给 delegate 处理 // 上层应用(如 Chrome)需处理自定义子进程类型, 否则返回错误码 auto exit_code = delegate->RunProcess(process_type, std::move(main_function_params)); // 断言 delegate 必须返回 int 退出码(未知进程类型应直接退出, 避免异常) DCHECK(std::holds_alternative<int>(exit_code)); DCHECK_GE(std::get<int>(exit_code), 0); return std::get<int>(exit_code); } ``` 一个个来看. ### UtilityMain ```cpp // Utility 进程的核心执行函数:作为 Utility 子进程的入口点, 完成该进程的初始化, 沙箱配置, // 任务调度器启动等核心逻辑, 最终进入消息循环等待并处理主进程下发的任务. int UtilityMain(MainFunctionParams parameters) { // 测试场景专用逻辑:若命令行携带 "utility-immediate-crash-for-testing" 参数, 立即崩溃进程(用于测试异常处理) if (parameters.command_line->HasSwitch( switches::kUtilityImmediateCrashForTesting)) { base::ImmediateCrash(); } // 确定消息循环泵类型: // 1. 若命令行带 "message-loop-type=ui" 参数, 使用 UI 类型消息泵(适配需要 UI 循环的任务); // 2. 否则使用默认类型消息泵(通用任务处理) base::MessagePumpType message_pump_type = parameters.command_line->HasSwitch(switches::kMessageLoopTypeUi) ? base::MessagePumpType::UI : base::MessagePumpType::DEFAULT; #if BUILDFLAG(IS_MAC) // macOS 平台特殊逻辑:根据命令行解析沙箱类型, 若为非沙箱进程则跳过 auto sandbox_type = sandbox::policy::SandboxTypeFromCommandLine(*parameters.command_line); if (sandbox_type != sandbox::mojom::Sandbox::kNoSandbox) { // 说明:macOS 中 UI 类型的消息泵依赖 NSApplication 循环, 但沙箱化的 Utility 进程中, // NSApp 会尝试获取沙箱不允许的 Mach 资源, 导致崩溃. // 解决方案:重写 UI 类型消息泵的创建工厂, 改用 NSRunLoop 类型消息泵(仅处理系统任务源, 不依赖受限资源) base::MessagePump::OverrideMessagePumpForUIFactory( []() -> std::unique_ptr<base::MessagePump> { return std::make_unique<base::MessagePumpNSRunLoop>(); }); } #endif #if BUILDFLAG(IS_FUCHSIA) // Fuchsia 平台特殊逻辑:强制使用 IO 类型消息泵, 确保支持 FIDL 通信(Fuchsia 进程间通信标准) if (message_pump_type == base::MessagePumpType::DEFAULT) message_pump_type = base::MessagePumpType::IO; #endif // BUILDFLAG(IS_FUCHSIA) // 初始化 Utility 进程的主线程任务调度器:绑定前面确定的消息泵类型, 标记为当前进程的主线程 base::SingleThreadTaskExecutor main_thread_task_executor( message_pump_type, /*is_main_thread=*/true); // 从命令行获取 Utility 进程的子类型(如 "video_decoder", "speech_recognition", 区分具体任务场景) const std::string utility_sub_type = parameters.command_line->GetSwitchValueASCII(switches::kUtilitySubType); // 设置主线程名称(含子类型, 便于调试和性能分析, 如 "Utility:VideoDecoder") SetUtilityThreadName(utility_sub_type); // 调试场景支持:若命令行携带 "utility-startup-dialog" 参数, 阻塞等待调试器附加 if (parameters.command_line->HasSwitch(switches::kUtilityStartupDialog)) { auto dialog_match = parameters.command_line->GetSwitchValueASCII( switches::kUtilityStartupDialog); // 若参数值为空(匹配所有子类型)或与当前子类型一致, 则触发等待 if (dialog_match.empty() || dialog_match == utility_sub_type) { WaitForDebugger(utility_sub_type.empty() ? "Utility" : utility_sub_type); } } // 特定子类型预处理:若为设备端模型服务(OnDeviceModelService), 执行沙箱初始化前的准备工作 if (utility_sub_type == on_device_model::mojom::OnDeviceModelService::Name_) { CHECK(on_device_model::PreSandboxInit()); // 断言初始化成功, 失败则崩溃 } #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // Linux/ChromeOS 平台:VA-API 视频解码相关预处理 #if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION) && BUILDFLAG(USE_VAAPI) // 若为视频解码器子进程, 提前初始化 VA-API 包装器(无论沙箱状态, 解码依赖该组件) if (utility_sub_type == media::mojom::VideoDecoderFactoryProcess::Name_) { media::VaapiWrapper::PreSandboxInitialization( /*allow_disabling_global_lock=*/true); } #endif // BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION) && BUILDFLAG(USE_VAAPI) // 初始化线程类型处理器:需在创建其他线程前执行, 避免沙箱初始化时出现线程竞争 // 作用:管理进程内线程的类型标记(如 IO 线程, 工作线程), 适配系统调度策略 SandboxedProcessThreadTypeHandler::Create(); // 沙箱初始化(核心安全逻辑):在创建任何线程前执行, 确保进程启动即处于沙箱保护中 // TODO(jorgelo):后续需将沙箱初始化移到 GTK 初始化之后, 以支持更严格的 Seccomp-BPF 策略 auto sandbox_type = sandbox::policy::SandboxTypeFromCommandLine(*parameters.command_line); sandbox::policy::SandboxLinux::Options sandbox_options; // 沙箱配置选项 sandbox::policy::SandboxLinux::PreSandboxHook pre_sandbox_hook; // 沙箱初始化前置钩子 // 根据沙箱类型, 绑定对应的前置钩子(不同沙箱类型需要不同的资源预分配/权限配置) switch (sandbox_type) { case sandbox::mojom::Sandbox::kNetwork: // 网络沙箱:绑定网络相关前置钩子(初始化网络上下文目录) pre_sandbox_hook = base::BindOnce(&network::NetworkPreSandboxHook, GetNetworkContextsParentDirectories()); break; case sandbox::mojom::Sandbox::kPrintBackend: #if BUILDFLAG(ENABLE_OOP_PRINTING) // 打印后端沙箱:绑定打印相关前置钩子(初始化打印设备资源) pre_sandbox_hook = base::BindOnce(&printing::PrintBackendPreSandboxHook); break; #else NOTREACHED(); // 未启用 OOP 打印时, 该沙箱类型不应该出现 #endif // BUILDFLAG(ENABLE_OOP_PRINTING) case sandbox::mojom::Sandbox::kAudio: // 音频沙箱:绑定音频相关前置钩子(初始化音频设备) pre_sandbox_hook = base::BindOnce(&audio::AudioPreSandboxHook); break; case sandbox::mojom::Sandbox::kOnDeviceModelExecution: // 设备端模型执行沙箱:添加专属配置, 绑定前置钩子 on_device_model::AddSandboxLinuxOptions(sandbox_options); pre_sandbox_hook = base::BindOnce(&on_device_model::PreSandboxHook); break; case sandbox::mojom::Sandbox::kSpeechRecognition: // 语音识别沙箱:绑定语音识别前置钩子 pre_sandbox_hook = base::BindOnce(&speech::SpeechRecognitionPreSandboxHook); break; #if BUILDFLAG(ENABLE_ON_DEVICE_TRANSLATION) && BUILDFLAG(IS_LINUX) case sandbox::mojom::Sandbox::kOnDeviceTranslation: // 设备端翻译沙箱:绑定翻译相关前置钩子 pre_sandbox_hook = base::BindOnce( &on_device_translation::OnDeviceTranslationSandboxHook); break; #endif // BUILDFLAG(ENABLE_ON_DEVICE_TRANSLATION) && BUILDFLAG(IS_LINUX) case sandbox::mojom::Sandbox::kScreenAI: #if BUILDFLAG(ENABLE_SCREEN_AI_SERVICE) // ScreenAI 服务沙箱:绑定前置钩子(传递 AI 二进制文件路径) pre_sandbox_hook = base::BindOnce(&screen_ai::ScreenAIPreSandboxHook, parameters.command_line->GetSwitchValuePath( screen_ai::GetBinaryPathSwitch())); break; #else NOTREACHED(); // 未启用 ScreenAI 时, 该沙箱类型不应该出现 #endif #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) case sandbox::mojom::Sandbox::kShapeDetection: // 形状检测沙箱:绑定形状检测前置钩子 pre_sandbox_hook = base::BindOnce(&shape_detection::ShapeDetectionPreSandboxHook); break; #if BUILDFLAG(ALLOW_OOP_VIDEO_DECODER) case sandbox::mojom::Sandbox::kHardwareVideoDecoding: // 硬件视频解码沙箱:绑定视频解码前置钩子 pre_sandbox_hook = base::BindOnce(&media::HardwareVideoDecodingPreSandboxHook); break; #endif // BUILDFLAG(ALLOW_OOP_VIDEO_DECODER) #if BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION) case sandbox::mojom::Sandbox::kHardwareVideoEncoding: // 硬件视频编码沙箱:绑定视频编码前置钩子 pre_sandbox_hook = base::BindOnce(&media::HardwareVideoEncodingPreSandboxHook); break; #endif // BUILDFLAG(USE_LINUX_VIDEO_ACCELERATION) #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) #if BUILDFLAG(IS_CHROMEOS) case sandbox::mojom::Sandbox::kIme: // 输入法沙箱(ChromeOS 专属):绑定输入法前置钩子 pre_sandbox_hook = base::BindOnce(&ash::ime::ImePreSandboxHook); break; case sandbox::mojom::Sandbox::kTts: // 文本转语音沙箱(ChromeOS 专属):绑定 TTS 前置钩子 pre_sandbox_hook = base::BindOnce(&chromeos::tts::TtsPreSandboxHook); break; #endif // BUILDFLAG(IS_CHROMEOS) default: // 其他沙箱类型无需特殊前置处理, 直接跳过 break; } // 执行沙箱初始化:满足以下条件时触发 // 1. 非"无沙箱"类型;2. 是 Zygote 孵化的子进程 或 有前置钩子需要执行 if (!sandbox::policy::IsUnsandboxedSandboxType(sandbox_type) && (parameters.zygote_child || !pre_sandbox_hook.is_null())) { // 适配 AMD GPU 相关沙箱策略 sandbox_options.use_amd_specific_policies = ShouldUseAmdGpuPolicy(sandbox_type); // 启动沙箱:应用沙箱类型, 前置钩子和配置选项 sandbox::policy::Sandbox::Initialize( sandbox_type, std::move(pre_sandbox_hook), sandbox_options); } // 沙箱初始化后启动追踪(特定场景): // 启动追踪会创建额外线程, 与单线程沙箱初始化冲突, 因此延迟到沙箱就绪后启动 if (parameters.needs_startup_tracing_after_sandbox_init) { tracing::InitTracingPostFeatureList(/*enable_consumer=*/false, /*will_trace_thread_restart=*/false); } // 启动挂起监控器(若未启动):沙箱就绪后补启动, 避免监控线程干扰沙箱初始化 if (base::HangWatcher::IsEnabled() && !base::HangWatcher::GetInstance()->IsStarted()) { DCHECK(parameters.hang_watcher_not_started_time.has_value()); // 记录监控器未启动的时间(用于 UMA 统计, 分析启动延迟) base::TimeDelta uncovered_hang_watcher_time = base::TimeTicks::Now() - parameters.hang_watcher_not_started_time.value(); base::UmaHistogramTimes("HangWatcher.UtilityProcess.UncoveredStartupTime", uncovered_hang_watcher_time); // 启动监控器, 开始检测进程挂起 base::HangWatcher::GetInstance()->Start(); } #elif BUILDFLAG(IS_WIN) // Windows 平台特殊逻辑:UI 类型消息泵需初始化 COM 组件(组件对象模型, Windows 系统级接口) std::optional<base::win::ScopedCOMInitializer> scoped_com_initializer; if (message_pump_type == base::MessagePumpType::UI) { scoped_com_initializer.emplace(); // 初始化 COM CHECK(scoped_com_initializer->Succeeded()); // 断言 COM 初始化成功 } // 保存沙箱目标服务(用于后续沙箱权限控制) g_utility_target_services = parameters.sandbox_info->target_services; // 执行沙箱锁定前的钩子:使用 UtilitySandboxedProcessLauncherDelegate 传递的数据 // 必须在 IO 线程启动前执行, 避免 Mojo 服务提前启动导致权限问题 if (g_utility_target_services) { auto delegate_data = g_utility_target_services->GetDelegateData(); if (delegate_data.has_value() && !delegate_data->empty()) { PreLockdownSandboxHook(delegate_data.value()); } } // 解析沙箱类型并打印日志(调试用) auto sandbox_type = sandbox::policy::SandboxTypeFromCommandLine(*parameters.command_line); DVLOG(1) << "Sandbox type: " << static_cast<int>(sandbox_type); // Windows 兼容性修复(针对 Windows 11 以下版本): // 问题:shell32.dll 提前卸载导致进程退出时崩溃(关联 bug:1076771, 1075487, 1139752) // 解决方案:提前加载 shell32.dll 并保持引用, 防止卸载 if (base::win::GetVersion() < base::win::Version::WIN11) { HMODULE shell32_pin = ::LoadLibrary(L"shell32.dll"); UNREFERENCED_PARAMETER(shell32_pin); // 消除"未使用变量"警告 } // DPI 感知配置(仅特定沙箱类型需要): // 说明:Utility 进程无需默认启用 DPI 感知, 仅媒体基础 CDM 沙箱需要(视频输出需适配显示器 DPI) // 避免在 Win32K 锁定沙箱中启用, 否则会崩溃(参考 bug:978133) if (sandbox_type == sandbox::mojom::Sandbox::kMediaFoundationCdm) { base::win::EnableHighDPISupport(); } // 沙箱权限降级(特定沙箱类型): // 非沙箱/CDM/媒体基础 CDM 类型跳过, 其他类型降低进程令牌权限 if (!sandbox::policy::IsUnsandboxedSandboxType(sandbox_type) && sandbox_type != sandbox::mojom::Sandbox::kCdm && sandbox_type != sandbox::mojom::Sandbox::kMediaFoundationCdm) { if (!g_utility_target_services) return false; // 沙箱服务未初始化, 直接退出 sandbox::policy::WarmupRandomnessInfrastructure(); // 预热随机数生成基础设施 sandbox::policy::MaybeDelayloadDbghelp(); // 延迟加载 dbghelp.dll(调试相关) g_utility_target_services->LowerToken(); // 降低进程令牌权限, 强化安全 } #endif // 初始化 Utility 子进程核心对象:传入主线程类型(默认类型) ChildProcess utility_process(base::ThreadType::kDefault); // 通知 ContentClient:IO 线程已创建(上层应用可执行 IO 线程相关初始化) GetContentClient()->utility()->PostIOThreadCreated( utility_process.io_task_runner()); // 创建主消息循环(RunLoop):用于阻塞主线程, 等待任务触发 base::RunLoop run_loop; // 绑定 Utility 线程实现:将消息循环的退出回调(QuitClosure)传入, 任务完成后退出循环 utility_process.set_main_thread( new UtilityThreadImpl(run_loop.QuitClosure())); // 高分辨率定时器管理器初始化(条件触发): // 说明:服务型 Utility 进程(无 Service Manager 连接)未初始化 PowerMonitor, // 而高分辨率定时器依赖 PowerMonitor, 因此仅在 PowerMonitor 就绪时创建 std::optional<base::HighResolutionTimerManager> hi_res_timer_manager; if (base::PowerMonitor::GetInstance()->IsInitialized()) { hi_res_timer_manager.emplace(); } // 内存分配器配置:任务调度器初始化后, 重新配置 PartitionAlloc 内存分配器(适配 Utility 进程场景) base::allocator::PartitionAllocSupport::Get()->ReconfigureAfterTaskRunnerInit( switches::kUtilityProcess); // 启动主消息循环:阻塞主线程, 开始处理任务(如主进程下发的解码, 识别等任务) // 任务处理完成后, 通过 UtilityThreadImpl 触发 QuitClosure, 退出循环 run_loop.Run(); // 特定子类型清理:设备端模型服务进程退出前执行关闭逻辑 if (utility_sub_type == on_device_model::mojom::OnDeviceModelService::Name_) { CHECK(on_device_model::Shutdown()); // 断言关闭成功 } #if defined(LEAK_SANITIZER) // 内存泄漏检测:在 Utility 线程关闭前执行 LeakSanitizer 检查, 避免误报退出阶段的"泄漏" __lsan_do_leak_check(); #endif // 进程正常退出, 返回 0 return 0; } ``` ### RendererMain ```cpp // 渲染进程(Renderer Process)的核心入口函数:作为浏览器的“网页渲染与执行引擎”, // 负责解析 HTML/CSS/JavaScript, 构建 DOM/渲染树, 执行 JS 逻辑, 处理页面交互, // 并与主进程(Browser), GPU 进程协作完成页面渲染, 是实现网页功能的核心载体(多进程架构中每个标签页对应一个独立渲染进程). int RendererMain(MainFunctionParams parameters) { // 记录瞬时 Trace 事件:标记渲染进程启动开始(使用 INSTANT 而非普通 TRACE_EVENT, // 因为追踪基础设施不期望线程主循环周围出现同步事件, 避免影响性能分析准确性) TRACE_EVENT_INSTANT0("startup", "RendererMain", TRACE_EVENT_SCOPE_THREAD); #if BUILDFLAG(IS_MAC) // macOS 平台特殊逻辑:声明当前进程已启用 CPU 安全缓解措施(对应渲染进程沙箱启动器委托中的 EnableCpuSecurityMitigations 配置) // 必须在首次调用 base::SysInfo::NumberOfProcessors() 前执行, 确保 CPU 核心数统计不受安全措施影响 base::SysInfo::SetCpuSecurityMitigationsEnabled(); #endif // 标记当前进程类型为渲染进程(供其他模块判断进程角色, 如 Mojo 通信, 权限控制, 日志上报) base::CurrentProcess::GetInstance().SetProcessType( base::CurrentProcessType::PROCESS_RENDERER); // 提取当前进程的命令行对象(后续解析渲染进程相关配置参数) const base::CommandLine& command_line = *parameters.command_line; #if BUILDFLAG(IS_MAC) // 保存 macOS 自动释放池(从启动参数传入, 用于管理 Objective-C 对象内存, 避免泄漏) base::apple::ScopedNSAutoreleasePool* pool = parameters.autorelease_pool; #endif // BUILDFLAG(IS_MAC) #if BUILDFLAG(IS_CHROMEOS) // ChromeOS 平台特殊配置: // 1. 初始化 ICU 默认 locale(语言区域):Zygote 进程启动早于浏览器进程, Locale 需单独为渲染进程设置, // 用于字体 fallback 选择, 文本排版等依赖语言环境的功能 if (command_line.HasSwitch(switches::kLang)) { const std::string locale = command_line.GetSwitchValueASCII(switches::kLang); base::i18n::SetICUDefaultLocale(locale); } // 2. 启用核心调度(Core Scheduling):若系统支持, 开启该特性以提升进程调度安全性和性能 chromeos::system::EnableCoreSchedulingIfAvailable(); #if defined(ARCH_CPU_X86_64) // 3. 用户空间交换(Userspace Swap)初始化:ChromeOS 64 位平台专属, 用于内存压缩/交换, 缓解内存压力 using UserspaceSwapInit = ash::memory::userspace_swap::UserspaceSwapRendererInitializationImpl; std::optional<UserspaceSwapInit> swap_init; if (UserspaceSwapInit::UserspaceSwapSupportedAndEnabled()) { swap_init.emplace(); // 创建初始化对象 // 执行沙箱前准备工作, 失败则打印错误日志 PLOG_IF(ERROR, !swap_init->PreSandboxSetup()) << "Unable to complete presandbox userspace swap initialization"; } #endif // defined(ARCH_CPU_X86_64) #endif // BUILDFLAG(IS_CHROMEOS) // 初始化 Skia 图形库(渲染进程核心图形绘制依赖, 负责 HTML/CSS 渲染, Canvas 绘制等) InitializeSkia(); // 处理渲染进程调试/测试参数:若命令行携带 --renderer-startup-dialog, 阻塞进程等待调试器附加 // 注意:该逻辑不能下移, 确保能调试后续所有初始化流程(如沙箱启动, Blink 初始化) HandleRendererErrorTestParameters(command_line); // 创建渲染进程平台委托对象(封装不同平台的差异化逻辑, 如沙箱启动, 系统资源初始化) RendererMainPlatformDelegate platform(parameters); // 设置渲染进程主线程名称(便于调试和性能分析, 如 Chrome 任务管理器中显示“CrRendererMain”) base::PlatformThread::SetName("CrRendererMain"); // 设置 Mojo 通信的线程名后缀(区分渲染进程的 Mojo 端点, 便于统计分析) mojo::InterfaceEndpointClient::SetThreadNameSuffixForMetrics("RendererMain"); // 强制初始化主线程标记:通过 RenderThread::IsMainThread() 确认当前线程为渲染进程主线程, // 后续 Blink 引擎, JS 执行等模块依赖该标记判断线程角色 RenderThread::IsMainThread(); // 初始化 Blink 引擎(Web 渲染核心, 负责 HTML 解析, DOM 构建, CSS 样式计算, JS 执行等核心能力) blink::Platform::InitializeBlink(); // 创建 Blink 主线程调度器(管理主线程任务优先级, 如用户输入, JS 执行, 渲染更新等, 避免任务阻塞导致页面卡顿) std::unique_ptr<blink::scheduler::WebThreadScheduler> main_thread_scheduler = blink::scheduler::WebThreadScheduler::CreateMainThreadScheduler( CreateMainThreadMessagePump()); // 创建主线程消息泵(驱动任务循环) // 执行平台差异化初始化(由平台委托对象封装, 如 Windows 平台的 COM 初始化, Linux 平台的资源限制配置) platform.PlatformInitialize(); // 沙箱启动前初始化 WebRTC 模块:WebRTC 依赖部分系统资源, 需在沙箱限制前完成初始化 // 注意:Linux 平台可能已在 Zygote 进程中初始化, 但同一线程多次调用无影响 InitializeWebRtcModuleBeforeSandbox(); // 初始化渲染进程内存协调器策略(管理内存使用, 如页面内存回收, 资源缓存策略, 适配不同场景的内存限制) RendererMemoryCoordinatorPolicy render_memory_coordinator_policy( static_cast<ChildMemoryConsumerRegistry&>( base::MemoryConsumerRegistry::Get())); { // 获取 Content 渲染进程客户端(上层应用定制渲染进程行为的扩展点, 如 Chrome 专属渲染逻辑) content::ContentRendererClient* client = GetContentClient()->renderer(); bool should_run_loop = true; // 标记是否需要启动消息循环(沙箱启动失败时可能为 false) // 判断是否需要启用沙箱(命令行无 --no-sandbox 则启用, 渲染进程沙箱是核心安全机制) bool need_sandbox = !command_line.HasSwitch(sandbox::policy::switches::kNoSandbox); if (!need_sandbox) { // 无沙箱模式:仍需执行沙箱后的初始化回调(上层应用可能依赖该回调完成后续配置) if (client) { client->PostSandboxInitialized(); } } #if !BUILDFLAG(IS_WIN) && !BUILDFLAG(IS_MAC) // 非 Windows/macOS 平台:在 RenderProcess 初始化前启用沙箱(符合这些平台的沙箱安全模型) // TODO(markus): 后续验证是否可移除 Windows/macOS 的条件判断, 统一沙箱启动时机 if (need_sandbox) { should_run_loop = platform.EnableSandbox(); // 启用沙箱, 返回是否允许继续运行 need_sandbox = false; // 已启动沙箱, 避免重复执行 if (client) { client->PostSandboxInitialized(); // 通知上层沙箱已初始化 } } #endif #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // Linux/ChromeOS 平台:初始化线程类型处理器(需在创建其他线程前执行) // 作用:管理线程类型标记(如显示关键线程, 后台线程), 适配系统调度策略; // 必须在沙箱初始化前完成, 避免多线程与沙箱单线程初始化冲突 SandboxedProcessThreadTypeHandler::Create(); #endif // 设置渲染主线程类型: // 1. 启用 kInputScenarioPriorityBoost 特性时:默认线程类型(仅用户输入时提升为显示关键线程); // 2. 未启用时:显示关键线程(优先调度, 确保页面渲染, JS 执行不卡顿, 实验证明该配置提升用户感知性能) base::ThreadType thread_type = base::FeatureList::IsEnabled( blink::features::kInputScenarioPriorityBoost) ? base::ThreadType::kDefault : base::ThreadType::kDisplayCritical; base::PlatformThread::SetCurrentThreadType(thread_type); // 沙箱初始化后启动追踪(特定场景): // 启动追踪会创建额外线程, 与单线程沙箱初始化冲突, 因此延迟到沙箱就绪后启动 if (parameters.needs_startup_tracing_after_sandbox_init) { tracing::InitTracingPostFeatureList(/*enable_consumer=*/false, /*will_trace_thread_restart=*/false); // 记录瞬时 Trace 事件, 标记追踪已初始化 TRACE_EVENT_INSTANT1("startup", "RendererMain", TRACE_EVENT_SCOPE_THREAD, "needs_startup_tracing_after_sandbox_init", true); } // 创建渲染进程核心对象(RenderProcessImpl 是具体实现, 管理渲染进程全局状态, IPC 通信, 沙箱策略等) std::unique_ptr<RenderProcess> render_process = RenderProcessImpl::Create(); // 创建主消息循环(RunLoop):阻塞主线程, 等待处理页面渲染, JS 执行, 主进程 IPC 消息等任务 base::RunLoop run_loop; // 创建渲染线程核心对象(RenderThreadImpl):绑定消息循环退出回调, 移交主线程调度器所有权 // 注意:RenderThread 生命周期与渲染进程一致, 此处不释放(非内存泄漏) new RenderThreadImpl(run_loop.QuitClosure(), std::move(main_thread_scheduler)); #if BUILDFLAG(IS_CHROMEOS) && defined(ARCH_CPU_X86_64) // ChromeOS 64 位平台:用户空间交换 FD 传递/清理 // 沙箱启动后, 渲染线程初始化完成, 将相关文件描述符(FD)传递给主进程, 失败则关闭 FD // 必须调用该方法, 即使 FD 创建失败也需传递错误码给主进程 if (swap_init) { swap_init->TransferFDsOrCleanup(base::BindOnce( &RenderThread::BindHostReceiver, // Unretained 安全:TransferFDsOrCleanup 是同步执行, RenderThread 不会在此期间销毁 base::Unretained(RenderThread::Get()))); swap_init.reset(); // 完成后释放初始化对象, 不再需要 } #endif #if BUILDFLAG(IS_WIN) // Windows 平台:启用 DirectCompositorThreadIpc 特性时, 在沙箱启动前初始化 Mojo 直接接收传输 // 作用:优化合成线程的 IPC 通信性能, 减少消息转发开销 if (base::FeatureList::IsEnabled( blink::features::kDirectCompositorThreadIpc)) { mojo::CreateDirectReceiverTransportBeforeSandbox(); } #endif // BUILDFLAG(IS_WIN) // Windows/macOS 平台:执行沙箱启动(与其他平台沙箱启动时机差异化处理) if (need_sandbox) { should_run_loop = platform.EnableSandbox(); // 启用沙箱, 返回是否允许继续运行 if (client) { client->PostSandboxInitialized(); // 通知上层沙箱已初始化 } } // 启动挂起监控器(若未启动):沙箱就绪后补启动, 避免监控线程干扰沙箱初始化 if (base::HangWatcher::IsEnabled() && !base::HangWatcher::GetInstance()->IsStarted()) { DCHECK(parameters.hang_watcher_not_started_time.has_value()); // 记录监控器未启动的时间(用于 UMA 统计, 分析启动延迟对监控的影响) base::TimeDelta uncovered_hang_watcher_time = base::TimeTicks::Now() - parameters.hang_watcher_not_started_time.value(); base::UmaHistogramTimes( "HangWatcher.RendererProcess.UncoveredStartupTime", uncovered_hang_watcher_time); // 启动监控器, 检测渲染进程是否卡死(如 JS 执行阻塞, 渲染任务超时) base::HangWatcher::GetInstance()->Start(); } #if BUILDFLAG(IS_ANDROID) // Android 平台:注册渲染主线程到线程优先级监控器, 启动监控(确保主线程调度优先级) base::PlatformThreadPriorityMonitor::Get().RegisterCurrentThread( "RendererMain"); base::PlatformThreadPriorityMonitor::Get().Start(); #endif // BUILDFLAG(IS_ANDROID) #if BUILDFLAG(MOJO_RANDOM_DELAYS_ENABLED) // 启用 Mojo 随机延迟(测试场景):模拟网络延迟, 验证 IPC 通信稳定性 mojo::BeginRandomMojoDelays(); #endif // 内存分配器配置:任务调度器初始化后, 重新配置 PartitionAlloc 内存分配器(适配渲染进程的内存使用场景, 如 JS 堆, DOM 节点内存) base::allocator::PartitionAllocSupport::Get() ->ReconfigureAfterTaskRunnerInit(switches::kRendererProcess); // 初始化高分辨率定时器管理器(用于精确计时, 如 JS 定时器, 动画帧同步, 页面交互响应计时) base::HighResolutionTimerManager hi_res_timer_manager; // 若沙箱启动成功, 启动主消息循环, 开始处理渲染任务 if (should_run_loop) { #if BUILDFLAG(IS_MAC) // macOS 平台:回收自动释放池(清理初始化阶段的 Objective-C 对象, 释放内存) if (pool) pool->Recycle(); #endif // 记录瞬时 Trace 事件:标记渲染进程消息循环启动 TRACE_EVENT_INSTANT0("toplevel", "RendererMain.START_MSG_LOOP", TRACE_EVENT_SCOPE_THREAD); const base::TimeTicks run_loop_start_time = base::TimeTicks::Now(); // 记录消息循环启动时间(用于统计启动耗时, 供性能分析) RenderThreadImpl::current()->set_run_loop_start_time(run_loop_start_time); LogTimeToStartRunLoop(command_line, run_loop_start_time); // 启动消息循环:阻塞主线程, 处理页面渲染, JS 执行, 主进程 IPC 消息等任务 run_loop.Run(); } #if defined(LEAK_SANITIZER) // 内存泄漏检测:在 RenderProcessImpl 销毁前执行 LeakSanitizer 检查, 避免误报退出阶段的“泄漏” __lsan_do_leak_check(); #endif } // 执行平台差异化清理(由平台委托对象封装, 如释放系统资源, 关闭句柄等) platform.PlatformUninitialize(); // 渲染进程正常退出, 返回 0 return 0; } ``` ### GpuMain ```cpp // GPU 子进程的核心入口函数:负责完成 GPU 进程从初始化, 沙箱配置, 图形资源准备到消息循环启动的全流程, // 最终接收主进程下发的 GPU 渲染任务(如网页图形渲染, 视频硬件加速), 是浏览器图形渲染能力的核心载体. int GpuMain(MainFunctionParams parameters) { // 记录 Trace 事件:标记 GPU 进程启动阶段开始, 用于 chrome://tracing 等工具分析启动耗时 TRACE_EVENT("gpu,startup", "GpuMain"); // 标记当前进程类型为 GPU 进程(供其他模块判断进程角色, 如 Mojo 通信, 日志上报) base::CurrentProcess::GetInstance().SetProcessType( base::CurrentProcessType::PROCESS_GPU); // 提取当前进程的命令行对象(后续解析 GPU 相关配置参数) const base::CommandLine& command_line = *parameters.command_line; // 初始化 GPU 配置偏好(存储 GPU 进程的核心配置, 如是否启用调试, 消息泵类型等) gpu::GpuPreferences gpu_preferences; if (command_line.HasSwitch(switches::kGpuPreferences)) { // 从命令行提取配置字符串, 解析为 GpuPreferences 对象 std::string value = command_line.GetSwitchValueASCII(switches::kGpuPreferences); bool success = gpu_preferences.FromSwitchValue(value); CHECK(success); // 断言解析成功, 失败则崩溃(配置错误会导致 GPU 进程无法正常工作) } // 禁用 GPU 进程的 Mojo 同步调用: // 原因:同步调用可能导致 IPC 消息乱序(如 CrGpuMain 线程与 VizCompositorThreads 消息冲突), // 而 GPU 渲染依赖消息顺序性(如帧渲染指令, 资源释放指令), 乱序会导致渲染异常 mojo::SyncCallRestrictions::DisallowSyncCall(); // 调试场景支持:若 GPU 配置偏好中启用“启动调试对话框”, 阻塞进程等待调试器附加 if (gpu_preferences.gpu_startup_dialog) WaitForDebugger("Gpu"); // 记录 GPU 进程启动开始时间(用于后续统计初始化耗时) base::TimeTicks start_time = base::TimeTicks::Now(); #if BUILDFLAG(IS_WIN) // Windows 平台特殊初始化: // 1. 启用高 DPI 支持(适配 4K/Retina 屏幕, 避免 GPU 渲染的图形模糊) base::win::EnableHighDPISupport(); // 2. 禁用系统错误弹窗(如 DLL 加载失败时, 避免弹出模态对话框阻塞进程) SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX); // 3. 禁用高分辨率定时器节流(防止系统因节能策略降低定时器精度, 影响 GPU 帧渲染同步) base::win::SetProcessTimerThrottleState( base::GetCurrentProcessHandle(), base::win::ProcessPowerState::kDisabled); // 4. 初始化 COM 组件(MTA 模式, 多线程单元): // GPU 进程中 Windows Media Foundation 等组件依赖 COM, MTA 模式避免单线程消息泵阻塞问题 base::win::ScopedCOMInitializer com_initializer( base::win::ScopedCOMInitializer::kMTA); // 5. 提升 GPU 进程优先级(设为 ABOVE_NORMAL_PRIORITY_CLASS): // 确保 GPU 进程调度优先级高于渲染进程, 避免因 CPU 资源不足导致图形渲染卡顿 ::SetPriorityClass(::GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS); #endif // 安装 GPU 日志管理器的预初始化日志处理器: // 作用:在 GpuServiceImpl(GPU 服务核心)启动前, 暂存日志信息;服务启动后统一发送给主进程的 GpuProcessHost, // 确保初始化阶段的日志不丢失(如 GPU 设备检测日志, 沙箱启动日志) viz::GpuLogMessageManager::GetInstance()->InstallPreInitializeLogHandler(); // 初始化主线程任务调度器(堆上创建, 规避内存踩踏问题): // 背景:历史问题(crbug.com/662802, 609252)显示, 栈上创建任务调度器可能因内存踩踏导致崩溃, // 堆上创建可提升稳定性, 负责调度 GPU 进程主线程的任务(如渲染指令, 配置更新) std::unique_ptr<base::SingleThreadTaskExecutor> main_thread_task_executor; std::unique_ptr<ui::PlatformEventSource> event_source; // 平台事件源(如窗口事件, 设备事件) // 根据是否为无头模式(--headless), 选择不同的消息泵类型: if (command_line.HasSwitch(switches::kHeadless)) { #if BUILDFLAG(IS_MAC) // macOS 无头模式:使用 NS_RUNLOOP 消息泵(因 CADisplayLink 硬件垂直同步回调依赖该类型) main_thread_task_executor = std::make_unique<base::SingleThreadTaskExecutor>( base::MessagePumpType::NS_RUNLOOP, /*is_main_thread=*/true); main_thread_task_executor->SetWorkBatchSize(2); // 设置每次任务批处理大小, 平衡性能与响应性 #else // 其他平台无头模式:使用默认消息泵(通用后台任务处理) main_thread_task_executor = std::make_unique<base::SingleThreadTaskExecutor>( base::MessagePumpType::DEFAULT, /*is_main_thread=*/true); #endif } else { // 非无头模式(正常带 GUI 渲染):按平台选择消息泵类型 #if BUILDFLAG(IS_WIN) // Windows:使用默认消息泵(GPU 主线程无需处理 UI 消息, 避免消息循环冲突) main_thread_task_executor = std::make_unique<base::SingleThreadTaskExecutor>( base::MessagePumpType::DEFAULT, /*is_main_thread=*/true); #elif BUILDFLAG(IS_OZONE) // Ozone 平台(如 ChromeOS 部分场景):使用 GPU 配置偏好中指定的消息泵类型(运行时动态适配硬件) if (!main_thread_task_executor) { main_thread_task_executor = std::make_unique<base::SingleThreadTaskExecutor>( gpu_preferences.message_pump_type, /*is_main_thread=*/true); } #elif BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // 未支持的 Linux 平台:编译报错(强制开发者明确适配) #error "Unsupported Linux platform." #elif BUILDFLAG(IS_MAC) // macOS 非无头模式:使用 NS_RUNLOOP 消息泵(原因:1. 跨进程 CoreAnimation 渲染依赖;2. 避免高负载下饿死;3. CADisplayLink 垂直同步回调依赖) main_thread_task_executor = std::make_unique<base::SingleThreadTaskExecutor>( base::MessagePumpType::NS_RUNLOOP, /*is_main_thread=*/true); main_thread_task_executor->SetWorkBatchSize(2); // 保持与旧行为一致, 避免渲染 regression #else // 其他平台:使用默认消息泵 main_thread_task_executor = std::make_unique<base::SingleThreadTaskExecutor>( base::MessagePumpType::DEFAULT, /*is_main_thread=*/true); #endif } // 设置 GPU 主线程名称(便于调试和性能分析, 如 Chrome 任务管理器中显示“CrGpuMain”) base::PlatformThread::SetName("CrGpuMain"); // 设置 MTA 指标的线程名后缀(区分 GPU 进程的 MTA 通信, 便于统计分析) mojo::InterfaceEndpointClient::SetThreadNameSuffixForMetrics("GpuMain"); #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // Linux/ChromeOS 平台:初始化线程类型处理器(需在创建其他线程前执行) // 作用:管理进程内线程的类型标记(如显示关键线程, 后台线程), 适配系统调度策略; // 必须在沙箱初始化前完成, 避免多线程与沙箱单线程初始化冲突 SandboxedProcessThreadTypeHandler::Create(); #endif // BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS) // 将 GPU 主线程标记为“显示关键线程”: // 系统调度时优先分配 CPU 资源, 确保 GPU 渲染任务(如帧合成, 视频解码)不被抢占, 避免画面卡顿 base::PlatformThread::SetCurrentThreadType( base::ThreadType::kDisplayCritical); // 创建 GPU 初始化核心对象(负责 GPU 设备检测, 驱动适配, 沙箱启动) auto gpu_init = std::make_unique<gpu::GpuInit>(); // 创建沙箱辅助对象(传递沙箱配置信息, 如 Windows 平台的沙箱服务接口) ContentSandboxHelper sandbox_helper; #if BUILDFLAG(IS_WIN) sandbox_helper.set_sandbox_info(parameters.sandbox_info); #endif // 将沙箱辅助对象绑定到 GPU 初始化对象, 供后续沙箱启动使用 gpu_init->set_sandbox_helper(&sandbox_helper); // 初始化 Skia 图形库(GPU 渲染依赖 Skia 进行图形绘制, 必须在 GPU 初始化前启动) { TRACE_EVENT("gpu,startup", "gpu_main::InitializeSkia"); InitializeSkia(); } // 断言线程池已创建(GPU 初始化依赖线程池, 如 angle::InitializePlatform() 会使用线程池资源) DCHECK(base::ThreadPoolInstance::Get()); // 执行 GPU 核心初始化与沙箱启动: // 核心操作:检测 GPU 设备, 适配驱动版本, 启动沙箱(限制 GPU 进程权限, 防止恶意代码利用图形接口) // 注意:即使初始化失败(init_success=false), 也不立即退出, 需等待 IPC 通道建立后再退出(避免主进程无法检测崩溃) const bool init_success = gpu_init->InitializeAndStartSandbox( const_cast<base::CommandLine*>(&command_line), gpu_preferences); #if BUILDFLAG(IS_CHROMEOS) // ChromeOS 平台:打印 GPU 初始化结果日志(便于问题排查) LOG(WARNING) << "gpu initialization completed init_success:" << init_success; #endif // 标记 GPU 进程是否“启动即死亡”(初始化失败则为 true, 后续退出时返回对应错误码) const bool dead_on_arrival = !init_success; // 通知 ContentClient:GPU 沙箱已初始化(上层应用可执行沙箱后的配置, 如启用硬件加速) auto* client = GetContentClient()->gpu(); if (client) { client->PostSandboxInitialized(); } // 启动挂起监控器(若未启动):沙箱就绪后补启动, 避免监控线程干扰沙箱初始化 if (base::HangWatcher::IsEnabled() && !base::HangWatcher::GetInstance()->IsStarted()) { DCHECK(parameters.hang_watcher_not_started_time.has_value()); // 记录监控器未启动的时间(用于 UMA 统计, 分析启动延迟对监控的影响) base::TimeDelta uncovered_hang_watcher_time = base::TimeTicks::Now() - parameters.hang_watcher_not_started_time.value(); base::UmaHistogramTimes("HangWatcher.GpuProcess.UncoveredStartupTime", uncovered_hang_watcher_time); // 启动监控器, 开始检测 GPU 进程是否卡死(如渲染任务阻塞) base::HangWatcher::GetInstance()->Start(); } #if BUILDFLAG(IS_ANDROID) // Android 平台:注册 GPU 主线程到线程优先级监控器, 启动监控(确保主线程调度优先级) base::PlatformThreadPriorityMonitor::Get().RegisterCurrentThread("GpuMain"); base::PlatformThreadPriorityMonitor::Get().Start(); #endif // BUILDFLAG(IS_ANDROID) // 沙箱初始化后启动追踪(特定场景): // 启动追踪会创建额外线程, 与单线程沙箱初始化冲突, 因此延迟到沙箱就绪后启动 if (parameters.needs_startup_tracing_after_sandbox_init) { tracing::InitTracingPostFeatureList(/*enable_consumer=*/false, /*will_trace_thread_restart=*/false); } // 将 GPU 设备信息(如型号, 驱动版本, 支持的特性)同步给 ContentClient, 供上层应用使用(如渲染策略选择) GetContentClient()->SetGpuInfo(gpu_init->gpu_info()); // 设置 IO 线程类型为“显示关键线程”(GPU 进程的 IO 线程负责与主进程通信, 需优先调度) base::ThreadType io_thread_type = base::ThreadType::kDisplayCritical; // 创建 GPU 子进程核心对象:启动线程池(沙箱初始化后才能安全启动线程) ChildProcess gpu_process(io_thread_type); DCHECK(base::ThreadPoolInstance::Get()->WasStarted()); // 断言线程池已启动 // 通知 ContentClient:IO 线程已创建(上层应用可绑定 IO 线程任务, 如 Mojo 通信回调) if (client) { client->PostIOThreadCreated(gpu_process.io_task_runner()); } // 创建主消息循环(RunLoop):阻塞主线程, 等待 GPU 任务触发(如主进程下发的渲染指令) base::RunLoop run_loop; // 创建 GPU 子线程核心对象:绑定消息循环退出回调(任务完成后触发 Quit, 退出进程), 移交 GPU 初始化对象所有权 GpuChildThread* child_thread = new GpuChildThread(run_loop.QuitClosure(), std::move(gpu_init)); // 初始化 GPU 子线程:传递启动时间(统计初始化耗时), 序列管理器(任务调度) child_thread->Init(start_time, main_thread_task_executor->sequence_manager()); // 将 GPU 子线程设置为进程的主线程(负责处理核心渲染任务) gpu_process.set_main_thread(child_thread); #if BUILDFLAG(IS_MAC) // macOS 平台:注册 GPU 设备移除时的优雅退出逻辑 // 背景:系统弹出“安全弹出 GPU”时, GPU 进程需释放图形资源并退出, 避免资源泄漏; // 即使浏览器进程设置“wait”策略(负责协调子进程退出), GPU 进程仍需自行处理设备移除通知 metal::RegisterGracefulExitOnDeviceRemoval(); #endif #if BUILDFLAG(IS_ANDROID) // Android 平台:注册内存 dump 提供器(用于内存监控工具收集 GPU 进程内存使用数据) base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( tracing::GraphicsMemoryDumpProvider::GetInstance(), "AndroidGraphics", nullptr); // 初始化 Android 内存信息 dump 提供器(收集系统内存状态) base::android::MeminfoDumpProvider::Initialize(); #endif // 内存分配器配置:任务调度器初始化后, 重新配置 PartitionAlloc 内存分配器(适配 GPU 进程的内存使用场景) base::allocator::PartitionAllocSupport::Get()->ReconfigureAfterTaskRunnerInit( switches::kGpuProcess); // 初始化高分辨率定时器管理器(用于 GPU 渲染的精确时间控制, 如帧同步, 动画计时) base::HighResolutionTimerManager hi_res_timer_manager; // 启用 GPU 主线程的时间管理器指标(命令行带 --enable-gpu-main-time-keeper-metrics 时): // 记录消息泵的任务执行耗时, 指标名后缀为“CrGpuMain”, 便于性能分析 if (command_line.HasSwitch(switches::kEnableGpuMainTimeKeeperMetrics)) { base::CurrentThread::Get()->EnableMessagePumpTimeKeeperMetrics( "CrGpuMain", /*wall_time_based_metrics_enabled_for_testing=*/true); } // 断言追踪系统已初始化(确保 GPU 进程的性能数据可被收集) DCHECK(tracing::IsTracingInitialized()); // 启动主消息循环:阻塞主线程, 开始处理 GPU 渲染任务(如主进程下发的纹理创建, 帧合成指令) { TRACE_EVENT0("gpu", "Run Message Loop"); run_loop.Run(); } // 返回退出码:根据 GPU 初始化结果, 返回“启动即死亡”错误码或正常退出码 return dead_on_arrival ? RESULT_CODE_GPU_DEAD_ON_ARRIVAL : 0; } ``` 仍然是启动子进程加入消息队列. 等待主进程派发任务. 好了, 到此为止吧.
回复或点赞可查看完整内容
冰与火的战歌:Windows内核攻防实战高级班!从零到实战,融合AI与Windows内核攻防全技术栈,打造具备自动化能力的内核开发高手。
最后于
2025-11-5 08:13 被nothing233编辑 ,原因:
#其他
收藏
・
4
点赞
・
24
打赏
分享
分享到微信
分享到QQ
分享到微博
赞赏记录
参与人
雪币
留言
时间
git_51951meggadf3df
非常支持你的观点!
2026-9-11 13:33
mb_lthgjpwj
为你点赞!
2026-8-21 08:25
wx_晨梦
感谢你分享这么好的资源!
2026-7-16 08:17
afishlong
为你点赞!
2026-7-14 18:47
mb_dtyggysq
为你点赞!
2026-5-11 20:28
wjdidi
为你点赞!
2026-5-7 09:20
npc0vo
这个讨论对我很有帮助,谢谢!
2026-4-25 21:45
LIU.YZ
为你点赞!
2026-2-3 15:51
git_47499test-look
期待更多优质内容的分享,论坛有你更精彩!
2026-1-15 04:33
jjjo
感谢你分享这么好的资源!
2026-1-12 14:01
Dy1an
为你点赞!
2025-12-19 13:18
mb_nzgynsev
非常支持你的观点!
2025-11-19 20:50
dob_C
你的帖子非常有用,感谢分享!
2025-11-14 17:00
MochaCo
为你点赞!
2025-11-10 23:30
冲冲冲
谢谢你的细致分析,受益匪浅!
2025-11-10 15:42
git_20293russellcrosby73
期待更多优质内容的分享,论坛有你更精彩!
2025-11-10 14:22
爱吃菠菜
这个讨论对我很有帮助,谢谢!
2025-11-5 23:58
cxbcxb
感谢你分享这么好的资源!
2025-11-5 22:24
appview
你的分享对大家帮助很大,非常感谢!
2025-11-5 19:29
mb_wpitiize
感谢你分享这么好的资源!
2025-11-5 14:47
令狐双
谢谢你的细致分析,受益匪浅!
2025-11-5 10:23
顽劣
为你点赞!
2025-11-4 23:53
东方玻璃
谢谢你的细致分析,受益匪浅!
2025-11-4 23:10
huangyalei
为你点赞!
2025-11-4 22:03
查看更多
赞赏
×
1 雪花
5 雪花
10 雪花
20 雪花
50 雪花
80 雪花
100 雪花
150 雪花
200 雪花
支付方式:
微信支付
赞赏留言:
快捷留言
感谢分享~
精品文章~
原创内容~
精彩转帖~
助人为乐~
感谢分享~
最新回复
(
3
)
mb_ldbucrik
雪 币:
6
能力值:
( LV1,RANK:0 )
在线值:
发帖
0
回帖
691
粉丝
7
关注
私信
mb_ldbucrik
2
楼
YYDS,向大佬学习
2025-11-4 22:17
0
Imxz
雪 币:
112
活跃值:
(9405)
能力值:
( LV2,RANK:10 )
在线值:
发帖
6
回帖
750
粉丝
9
关注
私信
Imxz
3
楼
TQL
2025-11-5 12:11
0
fengvmu
雪 币:
5874
活跃值:
(3705)
能力值:
( LV2,RANK:10 )
在线值:
发帖
0
回帖
69
粉丝
0
关注
私信
fengvmu
4
楼
666
2025-12-21 12:34
0
游客
登录
|
注册
方可回帖
回帖
表情
雪币赚取及消费
高级回复
返回
nothing233
1
17
发帖
18
回帖
90
RANK
关注
私信
他的文章
[原创]LLVM: ADCEPass
2454
[原创]llvm: InstSimplifyPass
3780
[原创]一个 ELF 文件的运行
34835
[原创]capstone学习: 反汇编器如何实现的
15458
[原创]chromium 的启动
3257
关于我们
联系我们
企业服务
看雪公众号
专注于PC、移动、智能设备安全研究及逆向工程的开发者社区
看原图
赞赏
×
雪币:
+
留言:
快捷留言
为你点赞!
返回
顶部