Logo Search packages:      
Sourcecode: chromium-browser version File versions  Download package

render_process_host.cc

// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/renderer_host/render_process_host.h"

#include "base/rand_util.h"
#include "base/sys_info.h"
#include "chrome/browser/child_process_security_policy.h"
#include "chrome/common/child_process_info.h"
#include "chrome/common/chrome_constants.h"
#include "chrome/common/notification_service.h"

namespace {

size_t max_renderer_count_override = 0;

size_t GetMaxRendererProcessCount() {
  if (max_renderer_count_override)
    return max_renderer_count_override;

  // Defines the maximum number of renderer processes according to the
  // amount of installed memory as reported by the OS. The table
  // values are calculated by assuming that you want the renderers to
  // use half of the installed ram and assuming that each tab uses
  // ~40MB, however the curve is not linear but piecewise linear with
  // interleaved slopes of 3 and 2.
  // If you modify this table you need to adjust browser\browser_uitest.cc
  // to match the expected number of processes.

  static const size_t kMaxRenderersByRamTier[] = {
    3,                        // less than 256MB
    6,                        //  256MB
    9,                        //  512MB
    12,                       //  768MB
    14,                       // 1024MB
    18,                       // 1280MB
    20,                       // 1536MB
    22,                       // 1792MB
    24,                       // 2048MB
    26,                       // 2304MB
    29,                       // 2560MB
    32,                       // 2816MB
    35,                       // 3072MB
    38,                       // 3328MB
    40                        // 3584MB
  };

  static size_t max_count = 0;
  if (!max_count) {
    size_t memory_tier = base::SysInfo::AmountOfPhysicalMemoryMB() / 256;
    if (memory_tier >= arraysize(kMaxRenderersByRamTier))
      max_count = chrome::kMaxRendererProcessCount;
    else
      max_count = kMaxRenderersByRamTier[memory_tier];
  }
  return max_count;
}

// Returns true if the given host is suitable for launching a new view
// associated with the given profile.
static bool IsSuitableHost(RenderProcessHost* host, Profile* profile,
                           RenderProcessHost::Type type) {
  if (host->profile() != profile)
    return false;

  RenderProcessHost::Type host_type = RenderProcessHost::TYPE_NORMAL;
  if (ChildProcessSecurityPolicy::GetInstance()->HasDOMUIBindings(host->id()))
    host_type = RenderProcessHost::TYPE_DOMUI;
  if (ChildProcessSecurityPolicy::GetInstance()->
        HasExtensionBindings(host->id()))
    host_type = RenderProcessHost::TYPE_EXTENSION;

  return host_type == type;
}

// the global list of all renderer processes
IDMap<RenderProcessHost> all_hosts;

}  // namespace

// static
bool RenderProcessHost::run_renderer_in_process_ = false;

// static
void RenderProcessHost::SetMaxRendererProcessCount(size_t count) {
  max_renderer_count_override = count;
}

RenderProcessHost::RenderProcessHost(Profile* profile)
    : max_page_id_(-1),
      fast_shutdown_started_(false),
      id_(ChildProcessInfo::GenerateChildProcessUniqueId()),
      profile_(profile),
      sudden_termination_allowed_(true),
      ignore_input_events_(false) {
  all_hosts.AddWithID(this, id());
  all_hosts.set_check_on_null_data(true);
  // Initialize |child_process_activity_time_| to a reasonable value.
  mark_child_process_activity_time();
}

RenderProcessHost::~RenderProcessHost() {
  // In unit tests, Release() might not have been called.
  if (all_hosts.Lookup(id()))
    all_hosts.Remove(id());
}

void RenderProcessHost::Attach(IPC::Channel::Listener* listener,
                               int routing_id) {
  listeners_.AddWithID(listener, routing_id);
}

void RenderProcessHost::Release(int listener_id) {
  DCHECK(listeners_.Lookup(listener_id) != NULL);
  listeners_.Remove(listener_id);

  // Make sure that all associated resource requests are stopped.
  CancelResourceRequests(listener_id);

  // When no other owners of this object, we can delete ourselves
  if (listeners_.IsEmpty()) {
    NotificationService::current()->Notify(
        NotificationType::RENDERER_PROCESS_TERMINATED,
        Source<RenderProcessHost>(this), NotificationService::NoDetails());
    MessageLoop::current()->DeleteSoon(FROM_HERE, this);

    // Remove ourself from the list of renderer processes so that we can't be
    // reused in between now and when the Delete task runs.
    all_hosts.Remove(id());
  }
}

void RenderProcessHost::ReportExpectingClose(int32 listener_id) {
  listeners_expecting_close_.insert(listener_id);
}

void RenderProcessHost::UpdateMaxPageID(int32 page_id) {
  if (page_id > max_page_id_)
    max_page_id_ = page_id;
}

bool RenderProcessHost::FastShutdownForPageCount(size_t count) {
  if (listeners_.size() == count)
    return FastShutdownIfPossible();
  return false;
}

// static
RenderProcessHost::iterator RenderProcessHost::AllHostsIterator() {
  return iterator(&all_hosts);
}

// static
RenderProcessHost* RenderProcessHost::FromID(int render_process_id) {
  return all_hosts.Lookup(render_process_id);
}

// static
bool RenderProcessHost::ShouldTryToUseExistingProcessHost() {
  size_t renderer_process_count = all_hosts.size();

  // NOTE: Sometimes it's necessary to create more render processes than
  //       GetMaxRendererProcessCount(), for instance when we want to create
  //       a renderer process for a profile that has no existing renderers.
  //       This is OK in moderation, since the GetMaxRendererProcessCount()
  //       is conservative.

  return run_renderer_in_process() ||
         (renderer_process_count >= GetMaxRendererProcessCount());
}

// static
RenderProcessHost* RenderProcessHost::GetExistingProcessHost(Profile* profile,
                                                             Type type) {
  // First figure out which existing renderers we can use.
  std::vector<RenderProcessHost*> suitable_renderers;
  suitable_renderers.reserve(all_hosts.size());

  iterator iter(AllHostsIterator());
  while (!iter.IsAtEnd()) {
    if (run_renderer_in_process() ||
        IsSuitableHost(iter.GetCurrentValue(), profile, type))
      suitable_renderers.push_back(iter.GetCurrentValue());

    iter.Advance();
  }

  // Now pick a random suitable renderer, if we have any.
  if (!suitable_renderers.empty()) {
    int suitable_count = static_cast<int>(suitable_renderers.size());
    int random_index = base::RandInt(0, suitable_count - 1);
    return suitable_renderers[random_index];
  }

  return NULL;
}

Generated by  Doxygen 1.6.0   Back to index