chromium调试方法小结

前言

上一个实验,增加了web-ui的计划名称,导致执行my://x时,java-script和web-ui中的c++实现不交互,无法操作web-ui了。而直接执行chrome://x是正常的,java-script和c++可以交互。
这个bug是自己改出来的(不是改错了,是没改到位,改漏了),领导也不限时间,反正问题必须要解决. 没有任何推脱的理由。
等解决的时候,已经用掉了11天。以前解决bug,最多用过一个星期,这次又刷新了记录。

装vs2017的高亮插件

vs2017默认的设置,对选择后的元素,是没有高亮的。这样,分析上下文不方便。
找到了一个vs高亮插件, 可以用在vs2017中。
下载点:Highlight all occurrences of selected word
双击一个元素(变量,函数名)时,会高亮,方便在上下文中分析逻辑。
chromium调试方法小结_第1张图片

选择合适的调试工具

调试时,只用vs2017,还不是很方便。
官方资料上提到了MS的vs2017扩展ChildProcessDebugging和google自己的VsChromium.

  • 调试插件下载点

chromium_vs2017调试插件.7z

Automatically attach to child processes

There are two Visual Studio extensions that enable the debugger to automatically attach to all Chrome processes, so you can debug all of Chrome at once. Microsoft's Child Process Debugging Power Tool is a standalone extension for this, and VsChromium is another option that bundles many other additional features. In addition to installing one of these extensions, you must run Visual Studio as Administrator, or it will silently fail to attach to some of Chrome's child processes.

chromium进程架构是多进程的,每个进程根据命令行的不同,干不同的活(browser, crash-report, gpu, render)
VsChromium方便些,附加调试时,可以看到进程的类型. 只附加想调试的进程,调试时,顺畅一些。
chromium调试方法小结_第2张图片
chromium调试方法小结_第3张图片

选择合适的命令行

chromium不带命令行直接运行,会出现多个子进程(browser, gpu, render)
chromium的命令行参数可以控制不同的架构模式, 如果只是找bug,可以选单进程模式, 附加到当前tab页对应的browser进程,所有操作和交互都全了。下断点都能断住。

@echo off
rem @file test_chromium.bat
Z:\chromium\src\out\my_x86_d\chrome.exe --process-per-tab --single-process

可以看到只有browser进程,附加tab页对应的browser进程,调试起来很方便。
chromium调试方法小结_第4张图片

修改日志名称为默认日志名称

chromium工程的官方日志名称为chrome_debug.log
记录到这个日志文件中的日志,只有日志初始化之后(指定了日志名称为chrome_debug.log), 才会记录到chrome_debug.log.

如果在日志初始化之前记录日志,看到日志记录到了debug.log.

我将工程的日志名称都改成了debug.log,这样,所有的日志都在debug.log中。

  • Z:\chromium\src\base\logging.cc
PathString GetDefaultLogFile() {
#if defined(OS_WIN)
  // On Windows we use the same path as the exe.
  wchar_t module_name[MAX_PATH];
  GetModuleFileName(nullptr, module_name, MAX_PATH);

  PathString log_name = module_name;
  PathString::size_type last_backslash = log_name.rfind('\\', log_name.size());
  if (last_backslash != PathString::npos)
    log_name.erase(last_backslash + 1);
  log_name += L"debug.log";
  return log_name;
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
  // On other platforms we just use the current directory.
  return PathString("debug.log");
#endif
}

bool InitializeLogFileHandle() {
  if (g_log_file)
    return true;

  if (!g_log_file_name) {
    // Nobody has called InitLogging to specify a debug log file, so here we
    // initialize the log file name to a default.
    g_log_file_name = new PathString(GetDefaultLogFile());
  }

  if ((g_logging_destination & LOG_TO_FILE) != 0) {
#if defined(OS_WIN)
    // The FILE_APPEND_DATA access mask ensures that the file is atomically
    // appended to across accesses from multiple threads.
    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa364399(v=vs.85).aspx
    // https://msdn.microsoft.com/en-us/library/windows/desktop/aa363858(v=vs.85).aspx
    g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
                            FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
                            OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
    if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
      // We are intentionally not using FilePath or FileUtil here to reduce the
      // dependencies of the logging implementation. For e.g. FilePath and
      // FileUtil depend on shell32 and user32.dll. This is not acceptable for
      // some consumers of base logging like chrome_elf, etc.
      // Please don't change the code below to use FilePath.
      // try the current directory
      wchar_t system_buffer[MAX_PATH];
      system_buffer[0] = 0;
      DWORD len = ::GetCurrentDirectory(arraysize(system_buffer),
                                        system_buffer);
      if (len == 0 || len > arraysize(system_buffer))
        return false;

      *g_log_file_name = system_buffer;
      // Append a trailing backslash if needed.
      if (g_log_file_name->back() != L'\\')
        *g_log_file_name += L"\\";
      *g_log_file_name += L"debug.log";

      g_log_file = CreateFile(g_log_file_name->c_str(), FILE_APPEND_DATA,
                              FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr,
                              OPEN_ALWAYS, FILE_ATTRIBUTE_NORMAL, nullptr);
      if (g_log_file == INVALID_HANDLE_VALUE || g_log_file == nullptr) {
        g_log_file = nullptr;
        return false;
      }
    }
#elif defined(OS_POSIX) || defined(OS_FUCHSIA)
    g_log_file = fopen(g_log_file_name->c_str(), "a");
    if (g_log_file == nullptr)
      return false;
#else
#error Unsupported platform
#endif
  }

  return true;
}


  • Z:\chromium\src\chrome\chrome_watcher\chrome_watcher_main.cc
base::FilePath GetLogFileName(const base::CommandLine& command_line) {
  std::string filename = command_line.GetSwitchValueASCII(switches::kLogFile);
  if (filename.empty())
    base::Environment::Create()->GetVar(env_vars::kLogFileName, &filename);
  if (!filename.empty())
    return base::FilePath::FromUTF8Unsafe(filename);

	// 如果没有指定日志名称,默认的名称是debug.log
	// 改成默认日志名称debug.log, 可以将初始化日志之前打印的日志页收集到一个文件(debug.log)中
  const base::FilePath log_filename(FILE_PATH_LITERAL("debug.log"));
  base::FilePath log_path;

  if (GetLogsPath(&log_path)) {
    log_path = log_path.Append(log_filename);
    return log_path; // Z:\chromium\src\out\my_x86_d\chrome_debug.log
  } else {
    // error with path service, just use some default file somewhere
    return log_filename;
  }
}

  • Z:\chromium\src\chrome\common\logging_chrome.cc
base::FilePath GetLogFileName(const base::CommandLine& command_line) {
  std::string filename = command_line.GetSwitchValueASCII(switches::kLogFile);
  if (filename.empty())
    base::Environment::Create()->GetVar(env_vars::kLogFileName, &filename);
  if (!filename.empty())
    return base::FilePath::FromUTF8Unsafe(filename);

  const base::FilePath log_filename(FILE_PATH_LITERAL("debug.log"));
  base::FilePath log_path;

  if (base::PathService::Get(chrome::DIR_LOGS, &log_path)) {
    log_path = log_path.Append(log_filename);
    return log_path;
  } else {
    // error with path service, just use some default file somewhere
    return log_filename;
  }
}

  • Z:\chromium\src\headless\lib\headless_content_main_delegate.cc
void HeadlessContentMainDelegate::InitLogging(
    const base::CommandLine& command_line) {
  const std::string process_type =
      command_line.GetSwitchValueASCII(switches::kProcessType);
#if !defined(OS_WIN)
  if (!command_line.HasSwitch(switches::kEnableLogging))
    return;
#else
  // Child processes in Windows are not able to initialize logging.
  if (!process_type.empty())
    return;
#endif  // !defined(OS_WIN)

  logging::LoggingDestination log_mode;
  base::FilePath log_filename(FILE_PATH_LITERAL("debug.log"));
  if (command_line.GetSwitchValueASCII(switches::kEnableLogging) == "stderr") {
    log_mode = logging::LOG_TO_SYSTEM_DEBUG_LOG;
  } else {
    base::FilePath custom_filename(
        command_line.GetSwitchValuePath(switches::kEnableLogging));
    if (custom_filename.empty()) {
      log_mode = logging::LOG_TO_ALL;
    } else {
      log_mode = logging::LOG_TO_FILE;
      log_filename = custom_filename;
    }
  }

  if (command_line.HasSwitch(switches::kLoggingLevel) &&
      logging::GetMinLogLevel() >= 0) {
    std::string log_level =
        command_line.GetSwitchValueASCII(switches::kLoggingLevel);
    int level = 0;
    if (base::StringToInt(log_level, &level) && level >= 0 &&
        level < logging::LOG_NUM_SEVERITIES) {
      logging::SetMinLogLevel(level);
    } else {
      DLOG(WARNING) << "Bad log level: " << log_level;
    }
  }

  base::FilePath log_path;
  logging::LoggingSettings settings;

// In release builds we should log into the user profile directory.
#ifdef NDEBUG
  if (!browser_->options()->user_data_dir.empty()) {
    log_path = browser_->options()->user_data_dir;
    log_path = log_path.Append(kDefaultProfileName);
    base::CreateDirectory(log_path);
    log_path = log_path.Append(log_filename);
  }
#endif  // NDEBUG

  // Otherwise we log to where the executable is.
  if (log_path.empty()) {
    if (base::PathService::Get(base::DIR_MODULE, &log_path)) {
      log_path = log_path.Append(log_filename);
    } else {
      log_path = log_filename;
    }
  }

  std::string filename;
  std::unique_ptr env(base::Environment::Create());
  if (env->GetVar(kLogFileName, &filename) && !filename.empty()) {
    log_path = base::FilePath::FromUTF8Unsafe(filename);
  }

  settings.logging_dest = log_mode;
  settings.log_file = log_path.value().c_str();
  settings.lock_log = logging::DONT_LOCK_LOG_FILE;
  settings.delete_old = process_type.empty() ? logging::DELETE_OLD_LOG_FILE
                                             : logging::APPEND_TO_OLD_LOG_FILE;
  bool success = logging::InitLogging(settings);
  DCHECK(success);
}

用日志记录web-ui的参数

记录些调试信息,等程序运行起来后,根据调试信息,再附加程序比较方便。特别是多进程的情况。

  • 记录进程类型
#if !defined(WIN_CONSOLE_APP)
int APIENTRY wWinMain(HINSTANCE instance, HINSTANCE prev, wchar_t*, int) {
#else
int main() {
  HINSTANCE instance = GetModuleHandle(nullptr);
#endif
  install_static::InitializeFromPrimaryModule();
  SignalInitializeCrashReporting();

  // Initialize the CommandLine singleton from the environment.
  base::CommandLine::Init(0, nullptr);
  const base::CommandLine* command_line =
      base::CommandLine::ForCurrentProcess();

	// m_str_command_line_string
	const std::string process_type = command_line->GetSwitchValueASCII(switches::kProcessType);

	if (NULL != command_line) {
		// 打印不出日志来...
		DLOG(WARNING) << "wWinMain : process_type = [" << process_type << "]";

  • 在错误返回处记录错误原因

chromium有一些错误日志,如果在调试程序,可以在错误处加日志。如果运行效果和期望的不同,可以先看下日志。

bool ContentSettingsObserver::AllowScript(bool enabled_per_settings) {
	if (!enabled_per_settings) {
		DLOG(INFO) << "* !ContentSettingsObserver::AllowScript()";
		return false;
	}

  if (IsScriptDisabledForPreview(render_frame())) {
		DLOG(INFO) << "** !ContentSettingsObserver::AllowScript()";
		return false;
	}

  if (is_interstitial_page_) {
		DLOG(INFO) << "*** !ContentSettingsObserver::AllowScript()";
		return true;
	}

  blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
  const auto it = cached_script_permissions_.find(frame);
  if (it != cached_script_permissions_.end()) {
		DLOG(INFO) << "**** !ContentSettingsObserver::AllowScript()";
		return it->second;
	}

  // Evaluate the content setting rules before
  // IsWhitelistedForContentSettings(); if there is only the default rule
  // allowing all scripts, it's quicker this way.
  bool allow = true;
  if (content_setting_rules_) {
    ContentSetting setting = GetContentSettingFromRules(
        content_setting_rules_->script_rules, frame,
        url::Origin(frame->GetDocument().GetSecurityOrigin()).GetURL());
    allow = setting != CONTENT_SETTING_BLOCK;
  }
  allow = allow || IsWhitelistedForContentSettings();

  cached_script_permissions_[frame] = allow;
	if (!allow) {
		DLOG(INFO) << "***** cached_script_permissions_[" << frame << "] = " << allow;
	}

  return allow;
}

  • 在期望执行的逻辑上加日志
    如果期望某段代码被执行,在这段代码上加日志,如果运行不符合预期,就可以看看日志,是不是有些代码块没有被执行。如果没有被执行,就可以继续去找原因了。
void RenderFrameImpl::OnJavaScriptExecuteRequest(
    const base::string16& jscript,
    int id,
    bool notify_result)
{
  TRACE_EVENT_INSTANT0("test_tracing", "OnJavaScriptExecuteRequest",
                       TRACE_EVENT_SCOPE_THREAD);

	do {
		//setup converter
		using convert_type = std::codecvt_utf8;
		std::wstring_convert converter;

		//use converter (.to_bytes: wstr->str, .from_bytes: str->wstr)
		std::string str_jscript = converter.to_bytes(jscript);

		// 记录执行的脚本请求文本, 这里的"脚本请求文本"是c++中执行完js的请求后,将返回的结果送给js 
		// e.g. my_page.addResult(154);
		DLOG(INFO) << "void RenderFrameImpl::OnJavaScriptExecuteRequest(" << str_jscript << ", " << id << ", " << notify_result << ")";
	} while (0);

  v8::HandleScope handle_scope(v8::Isolate::GetCurrent());

	// ExecuteScriptAndReturnValue就是执行js的脚本, 和c++的交互就在这了
  v8::Local result = frame_->ExecuteScriptAndReturnValue(
      WebScriptSource(WebString::FromUTF16(jscript)));

  HandleJavascriptExecutionResult(jscript, id, notify_result, result);
}

  • 查看chromium代码,打印出特有类的文本信息
    chromium封装了很多自己的类,e.g. url类就有好几种,如果参数是url, 要想在日志中看看url是哪个,就需要打印出url的文本字符串。
  • GURL转字符串
bool RenderViewImpl::OnMessageReceived(const IPC::Message& message) {
  WebFrame* main_frame = webview() ? webview()->MainFrame() : nullptr;
  if (main_frame) {
    GURL active_url;
    if (main_frame->IsWebLocalFrame()) {
      active_url = main_frame->ToWebLocalFrame()->GetDocument().Url();
			DLOG(INFO) << "active_url = [" << active_url.spec() << "]";
		}
			
    GetContentClient()->SetActiveURL(
        active_url, main_frame->Top()->GetSecurityOrigin().ToString().Utf8());
  }

  for (auto& observer : observers_) {
    if (observer.OnMessageReceived(message))
      return true;
  }

  • 打印WebSecurityOrigin
bool WebSecurityOrigin::CanAccess(const WebSecurityOrigin& other) const {
	bool b_rc = false;
  
	DCHECK(private_);
  DCHECK(other.private_);

  b_rc = private_->CanAccess(other.private_.Get());
	if (!b_rc) {
		DLOG(INFO) << "!WebSecurityOrigin::CanAccess";
		DLOG(INFO) << "this = [" << this->ToString().Ascii().c_str() << "], other = [" << other.ToString().Ascii().c_str() << "]";
	}
	return b_rc;
}

  • 打印WebURL
bool WebSecurityOrigin::CanRequest(const WebURL& url) const {
	bool b_rc = false;
  DCHECK(private_);
  b_rc = private_->CanRequest(url);
	if (!b_rc) {
		DLOG(INFO) << "!WebSecurityOrigin::CanRequest(" << url.GetString().Ascii() << ")";
	}
	return b_rc;
}

  • 记录IPC发送消息的次数和基本信息
    Z:\chromium\src\content\renderer\render_frame_impl.h
  // Whether url download should be throttled.
  bool ShouldThrottleDownload();

  // Stores the WebLocalFrame we are associated with.  This is null from the
  // constructor until BindToFrame() is called, and it is null after
  // FrameDetached() is called until destruction (which is asynchronous in the
  // case of the main frame, but not subframes).
  blink::WebLocalFrame* frame_;

  // Boolean value indicating whether this RenderFrameImpl object is for the
  // main frame or not. It remains accurate during destruction, even when
  // |frame_| has been invalidated.
  bool is_main_frame_;

	int m_i_RenderFrameImpl_Send_cnt; // RenderFrameImpl::Send() call times

Z:\chromium\src\content\renderer\render_frame_impl.cc

RenderFrameImpl::CreateParams::CreateParams(
    RenderViewImpl* render_view,
    int32_t routing_id,
    service_manager::mojom::InterfaceProviderPtr interface_provider,
    const base::UnguessableToken& devtools_frame_token)
    : render_view(render_view),
      routing_id(routing_id),
      interface_provider(std::move(interface_provider)),
      devtools_frame_token(devtools_frame_token) {}
RenderFrameImpl::CreateParams::~CreateParams() = default;
RenderFrameImpl::CreateParams::CreateParams(CreateParams&&) = default;
RenderFrameImpl::CreateParams& RenderFrameImpl::CreateParams::operator=(
    CreateParams&&) = default;

// RenderFrameImpl ----------------------------------------------------------
RenderFrameImpl::RenderFrameImpl(CreateParams params)
    : frame_(nullptr),
      is_main_frame_(true),
			m_i_RenderFrameImpl_Send_cnt(0),
      unique_name_frame_adapter_(this),

bool RenderFrameImpl::Send(IPC::Message* message) {
	bool b_rc = false;
	m_i_RenderFrameImpl_Send_cnt++;
	DLOG(INFO) << "RenderFrameImpl::Send(), GetCurrentProcessId = " << GetCurrentProcessId() << ",this = " << this << ", m_i_RenderFrameImpl_Send_cnt = " << m_i_RenderFrameImpl_Send_cnt;
	if (NULL != message) {
		DLOG(INFO) << "	, message->routing_id() = " << message->routing_id();
		DLOG(INFO) << "	, message->type() = " << message->type();

		DLOG(INFO) << "	, message->is_sync() = " << message->is_sync();
		DLOG(INFO) << "	, message->is_reply() = " << message->is_reply();
		DLOG(INFO) << "	, message->is_reply_error() = " << message->is_reply_error();
		DLOG(INFO) << "	, message->should_unblock() = " << message->should_unblock();
		DLOG(INFO) << "	, message->is_caller_pumping_messages() = " << message->is_caller_pumping_messages();
		DLOG(INFO) << "	, message->dispatch_error() = " << message->dispatch_error();

		if ((11 == m_i_RenderFrameImpl_Send_cnt)
		 && (5 == message->routing_id()))
		{
			DLOG(INFO) << "bp for chrome://version";
		}
	}

  b_rc = RenderThread::Get()->Send(message);
	return b_rc;
}

  • 记录接收到消息的类型
bool RenderFrameImpl::OnMessageReceived(const IPC::Message& msg) {
  // Forward Page IPCs to the RenderView.
	int i_IPCMessageStart = 0;
	/*
	enum IPCMessageStart {
  // AutomationMsgStart = 0,
  // FrameMsgStart,
  // PageMsgStart,
  // ViewMsgStart,
  // InputMsgStart,
  // TestMsgStart,
  // WorkerMsgStart,
  // NaClMsgStart,
  // GpuChannelMsgStart,
  // MediaMsgStart,
  // PpapiMsgStart,
  // DOMStorageMsgStart,
	*/

	i_IPCMessageStart = (int)IPC_MESSAGE_CLASS(msg);
	DLOG(INFO) << "i_IPCMessageStart = " << i_IPCMessageStart;
	switch (i_IPCMessageStart) {
	case AutomationMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "AutomationMsgStart";
		break;

	case FrameMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "FrameMsgStart";
		break;

	case PageMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "PageMsgStart";
		break;

	case ViewMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ViewMsgStart";
		break;

	case InputMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "InputMsgStart";
		break;

	case TestMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "TestMsgStart";
		break;

	case WorkerMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "WorkerMsgStart";
		break;

	case NaClMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "NaClMsgStart";
		break;

	case GpuChannelMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "GpuChannelMsgStart";
		break;

	case MediaMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "MediaMsgStart";
		break;

	case PpapiMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "PpapiMsgStart";
		break;

	case DOMStorageMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "DOMStorageMsgStart";
		break;

	case SpeechRecognitionMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "SpeechRecognitionMsgStart";
		break;

	case P2PMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "P2PMsgStart";
		break;

	case ResourceMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ResourceMsgStart";
		break;

	case FileSystemMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "FileSystemMsgStart";
		break;

	case BlobMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "BlobMsgStart";
		break;

	case AudioMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "AudioMsgStart";
		break;

	case MidiMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "MidiMsgStart";
		break;

	case ChromeMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ChromeMsgStart";
		break;

	case DragMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "DragMsgStart";
		break;

	case PrintMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "PrintMsgStart";
		break;

	case ExtensionMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ExtensionMsgStart";
		break;

	case TextInputClientMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "TextInputClientMsgStart";
		break;

	case JavaBridgeMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "JavaBridgeMsgStart";
		break;

	case ShellMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ShellMsgStart";
		break;

	case AccessibilityMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "AccessibilityMsgStart";
		break;

	case PrerenderMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "PrerenderMsgStart";
		break;

	case ChromotingMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ChromotingMsgStart";
		break;

	case BrowserPluginMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "BrowserPluginMsgStart";
		break;

	case AndroidWebViewMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "AndroidWebViewMsgStart";
		break;

	case MediaPlayerMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "MediaPlayerMsgStart";
		break;

	case TracingMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "TracingMsgStart";
		break;

	case PeerConnectionTrackerMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "PeerConnectionTrackerMsgStart";
		break;

	case AppShimMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "AppShimMsgStart";
		break;

	case WebRtcLoggingMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "WebRtcLoggingMsgStart";
		break;

	case TtsMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "TtsMsgStart";
		break;

	case NaClHostMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "NaClHostMsgStart";
		break;

	case EncryptedMediaMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "EncryptedMediaMsgStart";
		break;

	case ServiceWorkerMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ServiceWorkerMsgStart";
		break;

	case CastMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "CastMsgStart";
		break;

	case ChromeExtensionMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ChromeExtensionMsgStart";
		break;

	case GinJavaBridgeMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "GinJavaBridgeMsgStart";
		break;

	case ChromeUtilityPrintingMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ChromeUtilityPrintingMsgStart";
		break;

	case AecDumpMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "AecDumpMsgStart";
		break;

	case OzoneGpuMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "OzoneGpuMsgStart";
		break;

	case PlatformNotificationMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "PlatformNotificationMsgStart";
		break;

	case LayoutTestMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "LayoutTestMsgStart";
		break;

	case NetworkHintsMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "NetworkHintsMsgStart";
		break;

	case CastMediaMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "CastMediaMsgStart";
		break;

	case SyncCompositorMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "SyncCompositorMsgStart";
		break;

	case ExtensionsGuestViewMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ExtensionsGuestViewMsgStart";
		break;

	case GuestViewMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "GuestViewMsgStart";
		break;

	case CastCryptoMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "CastCryptoMsgStart";
		break;

	case CastChannelMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "CastChannelMsgStart";
		break;

	case IPCTestMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "IPCTestMsgStart";
		break;

	case MediaPlayerDelegateMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "MediaPlayerDelegateMsgStart";
		break;

	case SurfaceViewManagerMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "SurfaceViewManagerMsgStart";
		break;

	case ExtensionWorkerMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "ExtensionWorkerMsgStart";
		break;

	case SubresourceFilterMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "SubresourceFilterMsgStart";
		break;

	case LastIPCMsgStart:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "LastIPCMsgStart";
		break;

	default:
		DLOG(INFO) << "RenderFrameImpl::OnMessageReceived msg type = " << "unknown_class_msg";
		break;
	}

	/*
// SpeechRecognitionMsgStart,
// P2PMsgStart,
// ResourceMsgStart,
// FileSystemMsgStart,
// BlobMsgStart,
// AudioMsgStart,
// MidiMsgStart,
// ChromeMsgStart,
// DragMsgStart,
// PrintMsgStart,
// ExtensionMsgStart,
// TextInputClientMsgStart,
// JavaBridgeMsgStart,
// ShellMsgStart,
// AccessibilityMsgStart,
// PrerenderMsgStart,
*/

	/*
	// ChromotingMsgStart,
	// BrowserPluginMsgStart,
	// AndroidWebViewMsgStart,
	// MediaPlayerMsgStart,
	// TracingMsgStart,
	// PeerConnectionTrackerMsgStart,
	// AppShimMsgStart,
	// WebRtcLoggingMsgStart,
	// TtsMsgStart,
	// NaClHostMsgStart,
	// EncryptedMediaMsgStart,
	// ServiceWorkerMsgStart,
	// CastMsgStart,
	// ChromeExtensionMsgStart,
	// GinJavaBridgeMsgStart,
	// ChromeUtilityPrintingMsgStart,
	// AecDumpMsgStart,
	// OzoneGpuMsgStart,
	*/

	/*
// PlatformNotificationMsgStart,
// LayoutTestMsgStart,
// NetworkHintsMsgStart,
// CastMediaMsgStart,
// SyncCompositorMsgStart,
// ExtensionsGuestViewMsgStart,
// GuestViewMsgStart,
// Note: CastCryptoMsgStart and CastChannelMsgStart reserved for Chromecast
// internal code. Contact gunsch@ before changing/removing.
// CastCryptoMsgStart,
// CastChannelMsgStart,
// IPCTestMsgStart,
// MediaPlayerDelegateMsgStart,
// SurfaceViewManagerMsgStart,
// ExtensionWorkerMsgStart,
// SubresourceFilterMsgStart,
// LastIPCMsgStart  // Must come last.
};
*/

  if (i_IPCMessageStart == (int)IPCMessageStart::PageMsgStart) {
    if (render_view())
      return render_view()->OnMessageReceived(msg);

    return false;
  }

  • 在程序的入口点记录命令行参数
    Z:\chromium\src\chrome\common\logging_chrome.cc
#if defined(OS_WIN)
  // Enable trace control and transport through event tracing for Windows.
  LogEventProvider::Initialize(kChromeTraceProviderName);

  // Enable logging to the Windows Event Log.
  SetEventSource(base::UTF16ToASCII(
                     install_static::InstallDetails::Get().install_full_name()),
                 BROWSER_CATEGORY, MSG_LOG_MESSAGE);
#endif

  base::StatisticsRecorder::InitLogOnShutdown();

  chrome_logging_initialized_ = true;

	// 打日志时, 必须从这之后打印日志才能打印出日志
	DLOG(INFO) << "first log";
	show_prog_info();
}

// This is a no-op, but we'll keep it around in case
// we need to do more cleanup in the future.
void CleanupChromeLogging() {

int show_prog_info()
{
	LPWSTR *szArglist;
	int nArgs = 0;
	int i = 0;

	DLOG(INFO) << "show_prog_info() PID = [" << GetCurrentProcessId() << "]";
	szArglist = CommandLineToArgvW(GetCommandLineW(), &nArgs);
	if (NULL == szArglist)
	{
		DLOG(INFO) << L"CommandLineToArgvW failed\n";
		return 0;
	}
	else {
		DLOG(INFO) << "argc = [" << nArgs << "]";
		for (i = 0; i < nArgs; i++) {
			DLOG(INFO) << "argv[" << i << "] = [" << szArglist[i] << "]";
		}

		// Free memory allocated for CommandLineToArgvW arguments.
		LocalFree(szArglist);
	}

	return EXIT_SUCCESS;
}

  • 在程序退出点记录日志或弹框
    Z:\chromium\src\services\service_manager\embedder\main.cc
#if defined(OS_MACOSX)
  autorelease_pool.reset();
#endif

  if (process_type == ProcessType::kEmbedder)
    delegate->ShutDownEmbedderProcess();

	do {
		char sz_buf[0x1000] = { '\0' };
		snprintf(sz_buf, sizeof(sz_buf), "exit chromium, pid = %ld", GetCurrentProcessId());
		MessageBoxA(NULL, sz_buf, "debug", MB_OK);
	} while (0);

	return exit_code;
}

}  // namespace service_manager

最重要的调试方法 - 官方文档

最重要的调试方法不是技巧,而是看官方文档后的理解程序和细致程度。
老大说,不看官方文档也可以搞,但是只能搞个边边。说的太对了。
先细致的看官方文档,可以先圈定要排查的范围,这个范围缩小后,开发和调试的效率就高多了。
开始以为chromium是百万行的工程,今天正好闲了一下,用代码工具统计了一下,居然是2000万行的工程…
chromium调试方法小结_第5张图片
chromium调试方法小结_第6张图片
在这种庞大的工程中,如果没有官方文档的指导,想排查一个bug,是不可想象的。如果我要像同事那样,看官方文档那么狠,这bug也不会用掉11天。我是搞了一个星期后,找不到关键点,问同事后,他指出了Z:\chromium\src\content\renderer\render_frame_impl.cc,Z:\chromium\src\content\browser\frame_host\render_frame_host_impl.cc
再排查,效果马上就出来了。

你可能感兴趣的:(chromium调试方法小结)