chromium browser process 与 render process 间通信通道的建立

       本文介绍browser 进程和 render 进程通信通道的建立, browser 进程与其他子进程, 比如 GPU 进程,Plugin 进程间通信通道的建立是类似的.

       Chromium ipc 正在转向Mojom. Mojom 将会在后续的博文中介绍. 本文的介绍是建立在Mojom  背景知识之上的.  另外, 有关render process 进程的启动过程,也请读者先参考罗升阳分享的文章《Chromium的Render进程启动过程分析 》 本文关注的是进程间通道建立的细节.


     在 browser 进程创建新的 进程前,会先 new RenderProcessHostImpl 的一个实体, 在RenderProcessHostImpl的构造函数里会调用RenderProcessHostImpl::InitializeChannelProxy(). 在 RenderProcessHostImpl::InitializeChannelProxy()中有为进程间通信做准备工作.

void RenderProcessHostImpl::InitializeChannelProxy() {
  // Generate a token used to identify the new child process.
  child_token_ = mojo::edk::GenerateRandomToken();

  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
      BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);

  // Acquire a Connector which will route connections to a new instance of the
  // renderer service.
  service_manager::Connector* connector =
      BrowserContext::GetConnectorFor(browser_context_);
  if (!connector) {
    // Note that some embedders (e.g. Android WebView) may not initialize a
    // Connector per BrowserContext. In those cases we fall back to the
    // browser-wide Connector.
    if (!ServiceManagerConnection::GetForProcess()) {
      // Additionally, some test code may not initialize the process-wide
      // ServiceManagerConnection prior to this point. This class of test code
      // doesn't care about render processes, so we can initialize a dummy
      // connection.
      service_manager::mojom::ServiceRequest request(&test_service_);
      ServiceManagerConnection::SetForProcess(ServiceManagerConnection::Create(
          std::move(request), io_task_runner));
    }
    connector = ServiceManagerConnection::GetForProcess()->GetConnector();
  }

  // Establish a ServiceManager connection for the new render service instance.
  child_connection_.reset(new ChildConnection(
      mojom::kRendererServiceName,
      base::StringPrintf("%d_%d", id_, instance_id_++), child_token_, connector,
      io_task_runner));

  // Send an interface request to bootstrap the IPC::Channel. Note that this
  // request will happily sit on the pipe until the process is launched and
  // connected to the ServiceManager. We take the other end immediately and
  // plug it into a new ChannelProxy.
  IPC::mojom::ChannelBootstrapPtr bootstrap;
  GetRemoteInterfaces()->GetInterface(&bootstrap);
  std::unique_ptr<IPC::ChannelFactory> channel_factory =
      IPC::ChannelMojo::CreateServerFactory(
          bootstrap.PassInterface().PassHandle(), io_task_runner);

  ResetChannelProxy();

  // Do NOT expand ifdef or run time condition checks here! Synchronous
  // IPCs from browser process are banned. It is only narrowly allowed
  // for Android WebView to maintain backward compatibility.
  // See crbug.com/526842 for details.
#if defined(OS_ANDROID)
  if (GetContentClient()->UsingSynchronousCompositing()) {
    channel_ = IPC::SyncChannel::Create(
        this, io_task_runner.get(), &never_signaled_);
  }
#endif  // OS_ANDROID
  if (!channel_)
    channel_.reset(new IPC::ChannelProxy(this, io_task_runner.get()));
  channel_->Init(std::move(channel_factory), true /* create_pipe_now */);

  // See OnProcessLaunched() for some additional details of this somewhat
  // surprising behavior.
  channel_->GetRemoteAssociatedInterface(&remote_route_provider_);
  channel_->GetRemoteAssociatedInterface(&renderer_interface_);

  // We start the Channel in a paused state. It will be briefly unpaused again
  // in Init() if applicable, before process launch is initiated.
  channel_->Pause();
}

这段code 在src/content/browser/render_host/render_process_host_impl.cc中. 请大家先注意child_token_, connector, ChildConnection,channel_factory 几个关键点.

下面一一探究.

     child_token_ 是一串随机字串, 是为后面Render 进程与Browser 进程握手时使用的标志符. 它被传递给了ChildConnection. 后文还会有详细介绍.

     connector  service_manager::Connector* connector = BrowserContext::GetConnectorFor(browser_context_);

     这里的connector 在browser main process 启动时已经创建好了.  看下面的code:

// static
service_manager::Connector* BrowserContext::GetConnectorFor(
    BrowserContext* browser_context) {
  ServiceManagerConnection* connection =
      GetServiceManagerConnectionFor(browser_context);
  return connection ? connection->GetConnector() : nullptr;
}

// static
ServiceManagerConnection* BrowserContext::GetServiceManagerConnectionFor(
    BrowserContext* browser_context) {
  BrowserContextServiceManagerConnectionHolder* connection_holder =
      static_cast<BrowserContextServiceManagerConnectionHolder*>(
          browser_context->GetUserData(kServiceManagerConnection));
  return connection_holder ? connection_holder->service_manager_connection()
                           : nullptr;
}
// static
void BrowserContext::Initialize(
    BrowserContext* browser_context,
    const base::FilePath& path) {

  std::string new_id;
  if (GetContentClient() && GetContentClient()->browser()) {
    new_id = GetContentClient()->browser()->GetServiceUserIdForBrowserContext(
        browser_context);
  } else {
    // Some test scenarios initialize a BrowserContext without a content client.
    new_id = base::GenerateGUID();
  }

  ServiceUserIdHolder* holder = static_cast<ServiceUserIdHolder*>(
      browser_context->GetUserData(kServiceUserId));
  if (holder)
    file::ForgetServiceUserIdUserDirAssociation(holder->user_id());
  file::AssociateServiceUserIdWithUserDir(new_id, path);
  RemoveBrowserContextFromUserIdMap(browser_context);
  g_user_id_to_context.Get()[new_id] = browser_context;
  browser_context->SetUserData(kServiceUserId,
                               new ServiceUserIdHolder(new_id));

  browser_context->SetUserData(kMojoWasInitialized,
                               new base::SupportsUserData::Data);

  ServiceManagerConnection* service_manager_connection =
      ServiceManagerConnection::GetForProcess();
  if (service_manager_connection && base::ThreadTaskRunnerHandle::IsSet()) {
    // NOTE: Many unit tests create a TestBrowserContext without initializing
    // Mojo or the global service manager connection.

    service_manager::mojom::ServicePtr service;
    service_manager::mojom::ServiceRequest service_request(&service);

    service_manager::mojom::PIDReceiverPtr pid_receiver;
    service_manager::Identity identity(mojom::kBrowserServiceName, new_id);
    service_manager_connection->GetConnector()->StartService(
        identity, std::move(service), mojo::MakeRequest(&pid_receiver));
    pid_receiver->SetPID(b
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
您可以使用 JxBrowser 库中的 `PopupHandler` 类来监听打开新窗口页面。以下是一个示例代码片段: ```java import com.teamdev.jxbrowser.chromium.Browser; import com.teamdev.jxbrowser.chromium.PopupContainer; import com.teamdev.jxbrowser.chromium.PopupHandler; import com.teamdev.jxbrowser.chromium.swing.BrowserView; import javax.swing.*; import java.awt.*; public class PopupExample { public static void main(String[] args) { Browser browser = new Browser(); BrowserView view = new BrowserView(browser); JFrame frame = new JFrame(); frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); frame.add(view, BorderLayout.CENTER); frame.setSize(800, 600); frame.setLocationRelativeTo(null); frame.setVisible(true); browser.setPopupHandler(new PopupHandler() { @Override public PopupContainer handlePopup(PopupParams popupParams) { // This method is called when a new window is requested. // You can create a new Browser instance and return it // to open the new window in the same window or in a new window. Browser newBrowser = new Browser(); BrowserView newView = new BrowserView(newBrowser); JFrame newFrame = new JFrame(); newFrame.add(newView, BorderLayout.CENTER); newFrame.setSize(800, 600); newFrame.setLocationRelativeTo(null); newFrame.setVisible(true); // Return a new PopupContainer that contains the new Browser instance. return new PopupContainer(newBrowser, newFrame); } }); browser.loadURL("https://www.google.com"); } } ``` 在上面的示例中,当您在浏览器中单击打开新窗口页面时,`handlePopup` 方法将被调用。在该方法中,您可以创建一个新的 `Browser` 实例和 `BrowserView` 实例,并将它们添加到新的 `JFrame` 中。最后,您需要将新的 `Browser` 实例封装在一个 `PopupContainer` 中,并将其返回。这将导致新窗口页面在同一个窗口或新窗口中打开。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值