Commit message: None
CVE: CVE-2018-6063
CWE: CWE-787
Vulnerability description: Incorrect use of mojo::WrapSharedMemoryHandle in Mojo in Google Chrome prior to 65.0.3325.146 allowed a remote attacker who had compromised the renderer process to perform an out of bounds memory write via a crafted HTML page.

Project: Chrome

ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(
    size_t size) {
  base::AutoLock lock(lock_);

  DCHECK_NE(size, 0u);

  auto size_in_kb = static_cast<base::HistogramBase::Sample>(size / 1024);
  UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.DiscardableAllocationSize",
                              size_in_kb,  // In KB
                              1,
                              4 * 1024 * 1024,  // 4 GB
                              50);

  size_t pages =
      std::max((size + base::GetPageSize() - 1) / base::GetPageSize(),
               static_cast<size_t>(1));

  size_t allocation_pages = kAllocationSize / base::GetPageSize();

  size_t slack = 0;
  if (pages < allocation_pages)
    slack = allocation_pages - pages;

  size_t heap_size_prior_to_releasing_purged_memory = heap_->GetSize();
  for (;;) {
    std::unique_ptr<DiscardableSharedMemoryHeap::Span> free_span =
        heap_->SearchFreeLists(pages, slack);
    if (!free_span.get())
      break;

    if (free_span->shared_memory()->Lock(
            free_span->start() * base::GetPageSize() -
                reinterpret_cast<size_t>(free_span->shared_memory()->memory()),
            free_span->length() * base::GetPageSize()) ==
        base::DiscardableSharedMemory::FAILED) {
      DCHECK(!free_span->shared_memory()->IsMemoryResident());
      heap_->ReleasePurgedMemory();
      DCHECK(!free_span->shared_memory());
      continue;
    }

    free_span->set_is_locked(true);

    MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists());

    return base::MakeUnique<DiscardableMemoryImpl>(this, std::move(free_span));
  }

  heap_->ReleasePurgedMemory();

  if (heap_->GetSize() != heap_size_prior_to_releasing_purged_memory)
    MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists());

  size_t pages_to_allocate =
      std::max(kAllocationSize / base::GetPageSize(), pages);
  size_t allocation_size_in_bytes = pages_to_allocate * base::GetPageSize();

  int32_t new_id = g_next_discardable_shared_memory_id.GetNext();

  std::unique_ptr<base::DiscardableSharedMemory> shared_memory =
      AllocateLockedDiscardableSharedMemory(allocation_size_in_bytes, new_id);

  std::unique_ptr<DiscardableSharedMemoryHeap::Span> new_span(heap_->Grow(
      std::move(shared_memory), allocation_size_in_bytes, new_id,
      base::Bind(
          &ClientDiscardableSharedMemoryManager::DeletedDiscardableSharedMemory,
          base::Unretained(this), new_id)));
  new_span->set_is_locked(true);

  if (pages < pages_to_allocate) {
    std::unique_ptr<DiscardableSharedMemoryHeap::Span> leftover =
        heap_->Split(new_span.get(), pages);
    leftover->shared_memory()->Unlock(
        leftover->start() * base::GetPageSize() -
            reinterpret_cast<size_t>(leftover->shared_memory()->memory()),
        leftover->length() * base::GetPageSize());
    leftover->set_is_locked(false);
    heap_->MergeIntoFreeLists(std::move(leftover));
  }

  MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists());

  return base::MakeUnique<DiscardableMemoryImpl>(this, std::move(new_span));
}

Project: Chrome

ClientDiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
    size_t size,
    int32_t id) {
  TRACE_EVENT2("renderer",
               "ClientDiscardableSharedMemoryManager::"
               "AllocateLockedDiscardableSharedMemory",
               "size", size, "id", id);
  base::SharedMemoryHandle handle;
  base::WaitableEvent event(base::WaitableEvent::ResetPolicy::MANUAL,
                            base::WaitableEvent::InitialState::NOT_SIGNALED);
  base::ScopedClosureRunner event_signal_runner(
      base::Bind(&base::WaitableEvent::Signal, base::Unretained(&event)));
  io_task_runner_->PostTask(
      FROM_HERE, base::Bind(&ClientDiscardableSharedMemoryManager::AllocateOnIO,
                            base::Unretained(this), size, id, &handle,
                            base::Passed(&event_signal_runner)));
  event.Wait();
  auto memory = base::MakeUnique<base::DiscardableSharedMemory>(handle);
  if (!memory->Map(size))
    base::TerminateBecauseOutOfMemory(size);
  return memory;
}

Project: Chrome

void ClientDiscardableSharedMemoryManager::AllocateOnIO(
    size_t size,
    int32_t id,
    base::SharedMemoryHandle* handle,
    base::ScopedClosureRunner closure_runner) {
  (*manager_mojo_)
      ->AllocateLockedDiscardableSharedMemory(
          static_cast<uint32_t>(size), id,
          base::Bind(
              &ClientDiscardableSharedMemoryManager::AllocateCompletedOnIO,
              base::Unretained(this), handle, base::Passed(&closure_runner)));
}

Project: Chrome

ClientDiscardableSharedMemoryManager::ClientDiscardableSharedMemoryManager(
    mojom::DiscardableSharedMemoryManagerPtr manager,
    scoped_refptr<base::SingleThreadTaskRunner> io_task_runner)
    : io_task_runner_(std::move(io_task_runner)),
      manager_mojo_(new mojom::DiscardableSharedMemoryManagerPtr),
      heap_(new DiscardableSharedMemoryHeap(base::GetPageSize())) {
  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
      this, "ClientDiscardableSharedMemoryManager",
      base::ThreadTaskRunnerHandle::Get());
  mojom::DiscardableSharedMemoryManagerPtrInfo info = manager.PassInterface();
  io_task_runner_->PostTask(
      FROM_HERE, base::Bind(&InitManagerMojoOnIO, manager_mojo_.get(),
                            base::Passed(&info)));
}

Project: Chrome

ClientDiscardableSharedMemoryManager::CreateMemoryAllocatorDump(
    DiscardableSharedMemoryHeap::Span* span,
    const char* name,
    base::trace_event::ProcessMemoryDump* pmd) const {
  base::AutoLock lock(lock_);
  return heap_->CreateMemoryAllocatorDump(span, name, pmd);
}

Project: Chrome

void ClientDiscardableSharedMemoryManager::DeletedDiscardableSharedMemory(
    int32_t id) {
  io_task_runner_->PostTask(
      FROM_HERE,
      base::Bind(&DeletedDiscardableSharedMemoryOnIO, manager_mojo_.get(), id));
}

Project: Chrome

void DeletedDiscardableSharedMemoryOnIO(
    mojom::DiscardableSharedMemoryManagerPtr* manager_mojo,
    int32_t id) {
  (*manager_mojo)->DeletedDiscardableSharedMemory(id);
}

Project: Chrome

  DiscardableMemoryImpl(ClientDiscardableSharedMemoryManager* manager,
                        std::unique_ptr<DiscardableSharedMemoryHeap::Span> span)
      : manager_(manager), span_(std::move(span)), is_locked_(true) {}

Project: Chrome

void InitManagerMojoOnIO(mojom::DiscardableSharedMemoryManagerPtr* manager_mojo,
                         mojom::DiscardableSharedMemoryManagerPtrInfo info) {
  manager_mojo->Bind(std::move(info));
}

Project: Chrome

bool ClientDiscardableSharedMemoryManager::OnMemoryDump(
    const base::trace_event::MemoryDumpArgs& args,
    base::trace_event::ProcessMemoryDump* pmd) {
  base::AutoLock lock(lock_);
  if (args.level_of_detail ==
      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
    base::trace_event::MemoryAllocatorDump* total_dump =
        pmd->CreateAllocatorDump(
            base::StringPrintf("discardable/child_0x%" PRIXPTR,
                               reinterpret_cast<uintptr_t>(this)));
    const size_t total_size = heap_->GetSize();
    const size_t freelist_size = heap_->GetSizeOfFreeLists();
    total_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
                          base::trace_event::MemoryAllocatorDump::kUnitsBytes,
                          total_size - freelist_size);
    total_dump->AddScalar("freelist_size",
                          base::trace_event::MemoryAllocatorDump::kUnitsBytes,
                          freelist_size);
    return true;
  }

  return heap_->OnMemoryDump(pmd);
}

Project: Chrome

void ClientDiscardableSharedMemoryManager::ReleaseFreeMemory() {
  base::AutoLock lock(lock_);

  size_t heap_size_prior_to_releasing_memory = heap_->GetSize();

  heap_->ReleasePurgedMemory();
  heap_->ReleaseFreeMemory();

  if (heap_->GetSize() != heap_size_prior_to_releasing_memory)
    MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists());
}

Project: Chrome

void ClientDiscardableSharedMemoryManager::ReleaseSpan(
    std::unique_ptr<DiscardableSharedMemoryHeap::Span> span) {
  base::AutoLock lock(lock_);

  if (!span->shared_memory())
    return;

  heap_->MergeIntoFreeLists(std::move(span));

  MemoryUsageChanged(heap_->GetSize(), heap_->GetSizeOfFreeLists());
}

Project: Chrome

ClientDiscardableSharedMemoryManager::~ClientDiscardableSharedMemoryManager() {
  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
      this);
  if (heap_->GetSize())
    MemoryUsageChanged(0, 0);

  heap_.reset();

  bool posted = io_task_runner_->DeleteSoon(FROM_HERE, manager_mojo_.release());
  if (!posted)
    manager_mojo_.reset();
}

Project: Chrome

DiscardableSharedMemoryManager::AllocateLockedDiscardableMemory(size_t size) {
  DCHECK_NE(size, 0u);

  int32_t new_id = g_next_discardable_shared_memory_id.GetNext();

  base::SharedMemoryHandle handle;
  AllocateLockedDiscardableSharedMemory(kInvalidUniqueClientID, size, new_id,
                                        &handle);
  std::unique_ptr<base::DiscardableSharedMemory> memory(
      new base::DiscardableSharedMemory(handle));
  if (!memory->Map(size))
    base::TerminateBecauseOutOfMemory(size);
  memory->Close();
  return std::make_unique<DiscardableMemoryImpl>(
      std::move(memory),
      base::Bind(
          &DiscardableSharedMemoryManager::DeletedDiscardableSharedMemory,
          base::Unretained(this), new_id, kInvalidUniqueClientID));
}

Project: Chrome

void DiscardableSharedMemoryManager::AllocateLockedDiscardableSharedMemory(
    int client_id,
    size_t size,
    int32_t id,
    base::SharedMemoryHandle* shared_memory_handle) {
  base::AutoLock lock(lock_);

  MemorySegmentMap& client_segments = clients_[client_id];
  if (client_segments.find(id) != client_segments.end()) {
    LOG(ERROR) << "Invalid discardable shared memory ID";
    *shared_memory_handle = base::SharedMemoryHandle();
    return;
  }

  size_t limit = 0;
  if (size < memory_limit_)
    limit = memory_limit_ - size;

  if (bytes_allocated_ > limit)
    ReduceMemoryUsageUntilWithinLimit(limit);

  std::unique_ptr<base::DiscardableSharedMemory> memory(
      new base::DiscardableSharedMemory);
  if (!memory->CreateAndMap(size)) {
    *shared_memory_handle = base::SharedMemoryHandle();
    return;
  }

  base::CheckedNumeric<size_t> checked_bytes_allocated = bytes_allocated_;
  checked_bytes_allocated += memory->mapped_size();
  if (!checked_bytes_allocated.IsValid()) {
    *shared_memory_handle = base::SharedMemoryHandle();
    return;
  }

  bytes_allocated_ = checked_bytes_allocated.ValueOrDie();
  BytesAllocatedChanged(bytes_allocated_);

  *shared_memory_handle = base::SharedMemory::DuplicateHandle(memory->handle());
  memory->Close();

  scoped_refptr<MemorySegment> segment(new MemorySegment(std::move(memory)));
  client_segments[id] = segment.get();
  segments_.push_back(segment.get());
  std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);

  if (bytes_allocated_ > memory_limit_)
    ScheduleEnforceMemoryPolicy();
}

Project: Chrome

    AllocateLockedDiscardableSharedMemoryForClient(
        int client_id,
        size_t size,
        int32_t id,
        base::SharedMemoryHandle* shared_memory_handle) {
  AllocateLockedDiscardableSharedMemory(client_id, size, id,
                                        shared_memory_handle);
}

Project: Chrome

void DiscardableSharedMemoryManager::Bind(
    mojom::DiscardableSharedMemoryManagerRequest request,
    const service_manager::BindSourceInfo& source_info) {
  DCHECK(!mojo_thread_message_loop_ ||
         mojo_thread_message_loop_ == base::MessageLoop::current());
  if (!mojo_thread_message_loop_) {
    mojo_thread_message_loop_ = base::MessageLoop::current();
    mojo_thread_message_loop_->AddDestructionObserver(this);
  }

  mojo::MakeStrongBinding(
      std::make_unique<MojoDiscardableSharedMemoryManagerImpl>(
          next_client_id_++, mojo_thread_weak_ptr_factory_.GetWeakPtr()),
      std::move(request));
}

Project: Chrome

void DiscardableSharedMemoryManager::BytesAllocatedChanged(
    size_t new_bytes_allocated) const {
  static crash_reporter::CrashKeyString<24> total_discardable_memory(
      "total-discardable-memory-allocated");
  total_discardable_memory.Set(base::NumberToString(new_bytes_allocated));
}

Project: Chrome

void DiscardableSharedMemoryManager::ClientDeletedDiscardableSharedMemory(
    int32_t id,
    int client_id) {
  DeletedDiscardableSharedMemory(id, client_id);
}

Project: Chrome

void DiscardableSharedMemoryManager::ClientRemoved(int client_id) {
  base::AutoLock lock(lock_);

  auto it = clients_.find(client_id);
  if (it == clients_.end())
    return;

  size_t bytes_allocated_before_releasing_memory = bytes_allocated_;

  for (auto& segment_it : it->second)
    ReleaseMemory(segment_it.second->memory());

  clients_.erase(it);

  if (bytes_allocated_ != bytes_allocated_before_releasing_memory)
    BytesAllocatedChanged(bytes_allocated_);
}

Project: Chrome

void DiscardableSharedMemoryManager::DeletedDiscardableSharedMemory(
    int32_t id,
    int client_id) {
  base::AutoLock lock(lock_);

  MemorySegmentMap& client_segments = clients_[client_id];

  MemorySegmentMap::iterator segment_it = client_segments.find(id);
  if (segment_it == client_segments.end()) {
    LOG(ERROR) << "Invalid discardable shared memory ID";
    return;
  }

  size_t bytes_allocated_before_releasing_memory = bytes_allocated_;

  ReleaseMemory(segment_it->second->memory());

  client_segments.erase(segment_it);

  if (bytes_allocated_ != bytes_allocated_before_releasing_memory)
    BytesAllocatedChanged(bytes_allocated_);
}

Project: Chrome

  DiscardableMemoryImpl(
      std::unique_ptr<base::DiscardableSharedMemory> shared_memory,
      const base::Closure& deleted_callback)
      : shared_memory_(std::move(shared_memory)),
        deleted_callback_(deleted_callback),
        is_locked_(true) {}

Project: Chrome

DiscardableSharedMemoryManager::DiscardableSharedMemoryManager()
    : next_client_id_(1),
      default_memory_limit_(GetDefaultMemoryLimit()),
      memory_limit_(default_memory_limit_),
      bytes_allocated_(0),
      memory_pressure_listener_(new base::MemoryPressureListener(
          base::Bind(&DiscardableSharedMemoryManager::OnMemoryPressure,
                     base::Unretained(this)))),
      enforce_memory_policy_task_runner_(base::ThreadTaskRunnerHandle::Get()),
      enforce_memory_policy_pending_(false),
      mojo_thread_message_loop_(nullptr),
      weak_ptr_factory_(this),
      mojo_thread_weak_ptr_factory_(this) {
  DCHECK_NE(memory_limit_, 0u);
  enforce_memory_policy_callback_ =
      base::Bind(&DiscardableSharedMemoryManager::EnforceMemoryPolicy,
                 weak_ptr_factory_.GetWeakPtr());
  base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider(
      this, "DiscardableSharedMemoryManager",
      base::ThreadTaskRunnerHandle::Get());
  base::MemoryCoordinatorClientRegistry::GetInstance()->Register(this);
}

Project: Chrome

void DiscardableSharedMemoryManager::EnforceMemoryPolicy() {
  base::AutoLock lock(lock_);

  enforce_memory_policy_pending_ = false;
  ReduceMemoryUsageUntilWithinMemoryLimit();
}

Project: Chrome

size_t DiscardableSharedMemoryManager::GetBytesAllocated() {
  base::AutoLock lock(lock_);

  return bytes_allocated_;
}

Project: Chrome

int64_t GetDefaultMemoryLimit() {
  const int kMegabyte = 1024 * 1024;

#if defined(OS_ANDROID)
  int64_t max_default_memory_limit = 128 * kMegabyte;
#else
  int64_t max_default_memory_limit = 512 * kMegabyte;
#endif

  if (base::SysInfo::IsLowEndDevice())
    max_default_memory_limit /= 8;

#if defined(OS_LINUX)
  base::FilePath shmem_dir;
  if (base::GetShmemTempDir(false, &shmem_dir)) {
    int64_t shmem_dir_amount_of_free_space =
        base::SysInfo::AmountOfFreeDiskSpace(shmem_dir);
    DCHECK_GT(shmem_dir_amount_of_free_space, 0);
    int64_t shmem_dir_amount_of_free_space_mb =
        shmem_dir_amount_of_free_space / kMegabyte;

    UMA_HISTOGRAM_CUSTOM_COUNTS("Memory.ShmemDir.AmountOfFreeSpace",
                                shmem_dir_amount_of_free_space_mb, 1,
                                4 * 1024,  // 4 GB
                                50);

    if (shmem_dir_amount_of_free_space_mb < 64) {
      LOG(WARNING) << "Less than 64MB of free space in temporary directory for "
                      "shared memory files: "
                   << shmem_dir_amount_of_free_space_mb;
    }

    max_default_memory_limit =
        std::min(max_default_memory_limit, shmem_dir_amount_of_free_space / 2);
  }
#endif

  return std::min(max_default_memory_limit,
                  base::SysInfo::AmountOfPhysicalMemory() / 4);
}

Project: Chrome

void DiscardableSharedMemoryManager::InvalidateMojoThreadWeakPtrs(
    base::WaitableEvent* event) {
  DCHECK_EQ(mojo_thread_message_loop_, base::MessageLoop::current());
  mojo_thread_weak_ptr_factory_.InvalidateWeakPtrs();
  mojo_thread_message_loop_->RemoveDestructionObserver(this);
  mojo_thread_message_loop_ = nullptr;
  if (event)
    event->Signal();
}

Project: Chrome

DiscardableSharedMemoryManager::MemorySegment::MemorySegment(
    std::unique_ptr<base::DiscardableSharedMemory> memory)
    : memory_(std::move(memory)) {}

Project: Chrome

base::Time DiscardableSharedMemoryManager::Now() const {
  return base::Time::Now();
}

Project: Chrome

bool DiscardableSharedMemoryManager::OnMemoryDump(
    const base::trace_event::MemoryDumpArgs& args,
    base::trace_event::ProcessMemoryDump* pmd) {
  if (args.level_of_detail ==
      base::trace_event::MemoryDumpLevelOfDetail::BACKGROUND) {
    base::trace_event::MemoryAllocatorDump* total_dump =
        pmd->CreateAllocatorDump("discardable");
    total_dump->AddScalar(base::trace_event::MemoryAllocatorDump::kNameSize,
                          base::trace_event::MemoryAllocatorDump::kUnitsBytes,
                          GetBytesAllocated());
    return true;
  }

  base::AutoLock lock(lock_);
  for (const auto& client_entry : clients_) {
    const int client_id = client_entry.first;
    const MemorySegmentMap& client_segments = client_entry.second;
    for (const auto& segment_entry : client_segments) {
      const int segment_id = segment_entry.first;
      const MemorySegment* segment = segment_entry.second.get();
      if (!segment->memory()->mapped_size())
        continue;

      std::string dump_name = base::StringPrintf(
          "discardable/process_%x/segment_%d", client_id, segment_id);
      base::trace_event::MemoryAllocatorDump* dump =
          pmd->CreateAllocatorDump(dump_name);

      dump->AddScalar("virtual_size",
                      base::trace_event::MemoryAllocatorDump::kUnitsBytes,
                      segment->memory()->mapped_size());

      dump->AddScalar(
          "locked_size", base::trace_event::MemoryAllocatorDump::kUnitsBytes,
          segment->memory()->IsMemoryLocked() ? segment->memory()->mapped_size()
                                              : 0u);

      segment->memory()->CreateSharedMemoryOwnershipEdge(dump, pmd,
                                                         /*is_owned=*/false);
    }
  }
  return true;
}

Project: Chrome

void DiscardableSharedMemoryManager::OnMemoryPressure(
    base::MemoryPressureListener::MemoryPressureLevel memory_pressure_level) {
  base::AutoLock lock(lock_);

  switch (memory_pressure_level) {
    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_NONE:
      break;
    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_MODERATE:
      ReduceMemoryUsageUntilWithinLimit(memory_limit_ / 2);
      break;
    case base::MemoryPressureListener::MEMORY_PRESSURE_LEVEL_CRITICAL:
      ReduceMemoryUsageUntilWithinLimit(0);
      break;
  }
}

Project: Chrome

void DiscardableSharedMemoryManager::OnPurgeMemory() {
  base::AutoLock lock(lock_);
  ReduceMemoryUsageUntilWithinLimit(0);
}

Project: Chrome

void DiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinLimit(
    size_t limit) {
  TRACE_EVENT1("renderer_host",
               "DiscardableSharedMemoryManager::"
               "ReduceMemoryUsageUntilWithinLimit",
               "bytes_allocated", bytes_allocated_);

  base::Time current_time = Now();

  lock_.AssertAcquired();
  size_t bytes_allocated_before_purging = bytes_allocated_;
  while (!segments_.empty()) {
    if (bytes_allocated_ <= limit)
      break;

    if (segments_.front()->memory()->last_known_usage() >= current_time)
      break;

    std::pop_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);
    scoped_refptr<MemorySegment> segment = segments_.back();
    segments_.pop_back();

    if (!segment->memory()->mapped_size())
      continue;

    if (segment->memory()->Purge(current_time)) {
      ReleaseMemory(segment->memory());
      continue;
    }

    segments_.push_back(segment.get());
    std::push_heap(segments_.begin(), segments_.end(), CompareMemoryUsageTime);
  }

  if (bytes_allocated_ != bytes_allocated_before_purging)
    BytesAllocatedChanged(bytes_allocated_);
}

Project: Chrome

void DiscardableSharedMemoryManager::ReduceMemoryUsageUntilWithinMemoryLimit() {
  lock_.AssertAcquired();

  if (bytes_allocated_ <= memory_limit_)
    return;

  ReduceMemoryUsageUntilWithinLimit(memory_limit_);
  if (bytes_allocated_ > memory_limit_)
    ScheduleEnforceMemoryPolicy();
}

Project: Chrome

void DiscardableSharedMemoryManager::ReleaseMemory(
    base::DiscardableSharedMemory* memory) {
  lock_.AssertAcquired();

  size_t size = memory->mapped_size();
  DCHECK_GE(bytes_allocated_, size);
  bytes_allocated_ -= size;

  memory->Unmap();
  memory->Close();
}

Project: Chrome

void DiscardableSharedMemoryManager::ScheduleEnforceMemoryPolicy() {
  lock_.AssertAcquired();

  if (enforce_memory_policy_pending_)
    return;

  enforce_memory_policy_pending_ = true;
  DCHECK(enforce_memory_policy_task_runner_);
  enforce_memory_policy_task_runner_->PostDelayedTask(
      FROM_HERE, enforce_memory_policy_callback_,
      base::TimeDelta::FromMilliseconds(kEnforceMemoryPolicyDelayMs));
}

Project: Chrome

void DiscardableSharedMemoryManager::SetMemoryLimit(size_t limit) {
  base::AutoLock lock(lock_);

  memory_limit_ = limit;
  ReduceMemoryUsageUntilWithinMemoryLimit();
}

Project: Chrome

void DiscardableSharedMemoryManager::WillDestroyCurrentMessageLoop() {
  DCHECK_EQ(mojo_thread_message_loop_, base::MessageLoop::current());
  DLOG_IF(WARNING, mojo_thread_weak_ptr_factory_.HasWeakPtrs())
      << "Some MojoDiscardableSharedMemoryManagerImpls are still alive. They "
         "will be leaked.";
  InvalidateMojoThreadWeakPtrs(nullptr);
}

Project: Chrome

DiscardableSharedMemoryManager::~DiscardableSharedMemoryManager() {
  base::MemoryCoordinatorClientRegistry::GetInstance()->Unregister(this);
  base::trace_event::MemoryDumpManager::GetInstance()->UnregisterDumpProvider(
      this);

  if (mojo_thread_message_loop_) {
    if (mojo_thread_message_loop_ == base::MessageLoop::current()) {
      mojo_thread_message_loop_->RemoveDestructionObserver(this);
      mojo_thread_message_loop_ = nullptr;
    } else {
      base::WaitableEvent event(
          base::WaitableEvent::ResetPolicy::MANUAL,
          base::WaitableEvent::InitialState::NOT_SIGNALED);
      bool result = mojo_thread_message_loop_->task_runner()->PostTask(
          FROM_HERE,
          base::BindOnce(
              &DiscardableSharedMemoryManager::InvalidateMojoThreadWeakPtrs,
              base::Unretained(this), &event));
      LOG_IF(ERROR, !result) << "Invalidate mojo weak ptrs failed!";
      if (result)
        event.Wait();
    }
  }
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::AllPagesRendered() {
  DCHECK_EQ(RENDERING, state_);
  state_ = DONE;
  prep_frame_view_->FinishPrinting();
}

Project: Chrome

bool PrepareFrameAndViewForPrint::AllowsBrokenNullLayerTreeView() const {
  return true;
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::CalculateIsModifiable() {
  is_modifiable_ = !PrintingNodeOrPdfFrame(source_frame(), source_node_);
}

Project: Chrome

bool PrintRenderFrameHelper::CalculateNumberOfPages(blink::WebLocalFrame* frame,
                                                    const blink::WebNode& node,
                                                    int* number_of_pages) {
  DCHECK(frame);
  bool fit_to_paper_size = !(PrintingNodeOrPdfFrame(frame, node));
  if (!InitPrintSettings(fit_to_paper_size)) {
    notify_browser_of_print_failure_ = false;
    Send(new PrintHostMsg_ShowInvalidPrinterSettingsError(routing_id()));
    return false;
  }

  const PrintMsg_Print_Params& params = print_pages_params_->params;
  PrepareFrameAndViewForPrint prepare(params, frame, node, ignore_css_margins_);
  prepare.StartPrinting();

  *number_of_pages = prepare.GetExpectedPageCount();
  return true;
}

Project: Chrome

void CalculatePageLayoutFromPrintParams(
    const PrintMsg_Print_Params& params,
    double scale_factor,
    PageSizeMargins* page_layout_in_points) {
  bool fit_to_page = IsWebPrintScalingOptionFitToPage(params);
  int dpi = GetDPI(&params);
  int content_width = params.content_size.width();
  int content_height = params.content_size.height();
  bool scale = fit_to_page || params.print_to_pdf;
  if (scale && scale_factor >= PrintRenderFrameHelper::kEpsilon) {
    content_width =
        static_cast<int>(static_cast<double>(content_width) * scale_factor);
    content_height =
        static_cast<int>(static_cast<double>(content_height) * scale_factor);
  }

  int margin_bottom =
      params.page_size.height() - content_height - params.margin_top;
  int margin_right =
      params.page_size.width() - content_width - params.margin_left;

  page_layout_in_points->content_width =
      ConvertUnit(content_width, dpi, kPointsPerInch);
  page_layout_in_points->content_height =
      ConvertUnit(content_height, dpi, kPointsPerInch);
  page_layout_in_points->margin_top =
      ConvertUnit(params.margin_top, dpi, kPointsPerInch);
  page_layout_in_points->margin_right =
      ConvertUnit(margin_right, dpi, kPointsPerInch);
  page_layout_in_points->margin_bottom =
      ConvertUnit(margin_bottom, dpi, kPointsPerInch);
  page_layout_in_points->margin_left =
      ConvertUnit(params.margin_left, dpi, kPointsPerInch);
}

Project: Chrome

PrintMsg_Print_Params CalculatePrintParamsForCss(
    blink::WebLocalFrame* frame,
    int page_index,
    const PrintMsg_Print_Params& page_params,
    bool ignore_css_margins,
    bool fit_to_page,
    double* scale_factor) {
  PrintMsg_Print_Params css_params =
      GetCssPrintParams(frame, page_index, page_params);

  PrintMsg_Print_Params params = page_params;
  EnsureOrientationMatches(css_params, &params);

  params.content_size = ScaleAndRoundSize(params.content_size, *scale_factor);
  if (ignore_css_margins && fit_to_page)
    return params;

  PrintMsg_Print_Params result_params = css_params;
  bool scale = !params.print_to_pdf;
  double page_scaling = scale ? *scale_factor : 1.0f;
  if (!fit_to_page) {
    result_params.page_size =
        ScaleAndRoundSize(result_params.page_size, page_scaling);
  }
  if (ignore_css_margins) {
    params.margin_left = ScaleAndRound(params.margin_left, page_scaling);
    params.margin_top = ScaleAndRound(params.margin_top, page_scaling);
    params.page_size = ScaleAndRoundSize(params.page_size, page_scaling);

    result_params.margin_top = params.margin_top;
    result_params.margin_left = params.margin_left;

    DCHECK(!fit_to_page);
    int default_margin_right = params.page_size.width() -
                               params.content_size.width() - params.margin_left;
    int default_margin_bottom = params.page_size.height() -
                                params.content_size.height() -
                                params.margin_top;
    result_params.content_size =
        gfx::Size(result_params.page_size.width() - result_params.margin_left -
                      default_margin_right,
                  result_params.page_size.height() - result_params.margin_top -
                      default_margin_bottom);
  } else {
    result_params.content_size =
        ScaleAndRoundSize(result_params.content_size, *scale_factor);
    if (fit_to_page) {
      double factor = FitPrintParamsToPage(params, &result_params);
      if (scale_factor)
        *scale_factor *= factor;
    } else {
      result_params.margin_left =
          ScaleAndRound(result_params.margin_left, page_scaling);
      result_params.margin_top =
          ScaleAndRound(result_params.margin_top, page_scaling);
    }
  }

  return result_params;
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::ClearContext() {
  prep_frame_view_.reset();
  metafile_.reset();
  pages_to_render_.clear();
  error_ = PREVIEW_ERROR_NONE;
}

Project: Chrome

void PrintRenderFrameHelper::ComputePageLayoutInPointsForCss(
    blink::WebLocalFrame* frame,
    int page_index,
    const PrintMsg_Print_Params& page_params,
    bool ignore_css_margins,
    double* scale_factor,
    PageSizeMargins* page_layout_in_points) {
  double input_scale_factor = *scale_factor;
  PrintMsg_Print_Params params = CalculatePrintParamsForCss(
      frame, page_index, page_params, ignore_css_margins,
      IsWebPrintScalingOptionFitToPage(page_params), scale_factor);
  CalculatePageLayoutFromPrintParams(params, input_scale_factor,
                                     page_layout_in_points);
}

Project: Chrome

void ComputeWebKitPrintParamsInDesiredDpi(
    const PrintMsg_Print_Params& print_params,
    blink::WebPrintParams* webkit_print_params) {
  int dpi = GetDPI(&print_params);
  webkit_print_params->printer_dpi = dpi;
  webkit_print_params->rasterize_pdf = print_params.rasterize_pdf;
  webkit_print_params->print_scaling_option = print_params.print_scaling_option;

  webkit_print_params->print_content_area.width =
      ConvertUnit(print_params.content_size.width(), dpi, kPointsPerInch);
  webkit_print_params->print_content_area.height =
      ConvertUnit(print_params.content_size.height(), dpi, kPointsPerInch);

  webkit_print_params->printable_area.x =
      ConvertUnit(print_params.printable_area.x(), dpi, kPointsPerInch);
  webkit_print_params->printable_area.y =
      ConvertUnit(print_params.printable_area.y(), dpi, kPointsPerInch);
  webkit_print_params->printable_area.width =
      ConvertUnit(print_params.printable_area.width(), dpi, kPointsPerInch);
  webkit_print_params->printable_area.height =
      ConvertUnit(print_params.printable_area.height(), dpi, kPointsPerInch);

  webkit_print_params->paper_size.width =
      ConvertUnit(print_params.page_size.width(), dpi, kPointsPerInch);
  webkit_print_params->paper_size.height =
      ConvertUnit(print_params.page_size.height(), dpi, kPointsPerInch);
}

Project: Chrome

void PrepareFrameAndViewForPrint::CopySelection(
    const WebPreferences& preferences) {
  ResizeForPrinting();
  std::string url_str = "data:text/html;charset=utf-8,";
  url_str.append(
      net::EscapeQueryParamValue(frame()->SelectionAsMarkup().Utf8(), false));
  RestoreSize();
  WebPreferences prefs = preferences;
  prefs.javascript_enabled = false;

  blink::WebView* web_view = blink::WebView::Create(
      /* client = */ this, blink::mojom::PageVisibilityState::kVisible,
      /* opener = */ nullptr);
  owns_web_view_ = true;
  content::RenderView::ApplyWebPreferences(prefs, web_view);
  blink::WebLocalFrame* main_frame =
      blink::WebLocalFrame::CreateMainFrame(web_view, this, nullptr, nullptr);
  frame_.Reset(main_frame);
  blink::WebFrameWidget::Create(this, main_frame);
  node_to_print_.Reset();

  blink::WebURLRequest request = blink::WebURLRequest(GURL(url_str));
  frame()->LoadRequest(request);
}

Project: Chrome

bool PrintRenderFrameHelper::CreatePreviewDocument() {
  if (!print_pages_params_ || CheckForCancel())
    return false;

  UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
                            PREVIEW_EVENT_CREATE_DOCUMENT, PREVIEW_EVENT_MAX);

  const PrintMsg_Print_Params& print_params = print_pages_params_->params;
  const std::vector<int>& pages = print_pages_params_->pages;

  if (!print_preview_context_.CreatePreviewDocument(
          std::move(prep_frame_view_), pages, print_params.printed_doc_type)) {
    return false;
  }

  PageSizeMargins default_page_layout;
  double scale_factor =
      print_params.scale_factor >= kEpsilon ? print_params.scale_factor : 1.0f;

  ComputePageLayoutInPointsForCss(print_preview_context_.prepared_frame(), 0,
                                  print_params, ignore_css_margins_,
                                  &scale_factor, &default_page_layout);
  bool has_page_size_style =
      PrintingFrameHasPageSizeStyle(print_preview_context_.prepared_frame(),
                                    print_preview_context_.total_page_count());
  int dpi = GetDPI(&print_params);

  gfx::Rect printable_area_in_points(
      ConvertUnit(print_params.printable_area.x(), dpi, kPointsPerInch),
      ConvertUnit(print_params.printable_area.y(), dpi, kPointsPerInch),
      ConvertUnit(print_params.printable_area.width(), dpi, kPointsPerInch),
      ConvertUnit(print_params.printable_area.height(), dpi, kPointsPerInch));

  double fit_to_page_scale_factor = 1.0f;
  if (!print_preview_context_.IsModifiable()) {
    blink::WebLocalFrame* source_frame = print_preview_context_.source_frame();
    const blink::WebNode& source_node = print_preview_context_.source_node();
    blink::WebPrintPresetOptions preset_options;
    if (source_frame->GetPrintPresetOptionsForPlugin(source_node,
                                                     &preset_options)) {
      if (preset_options.is_page_size_uniform) {
        bool is_printable_area_landscape = printable_area_in_points.width() >
                                           printable_area_in_points.height();
        bool is_preset_landscape = preset_options.uniform_page_size.width >
                                   preset_options.uniform_page_size.height;
        bool rotate = is_printable_area_landscape != is_preset_landscape;
        double printable_width = rotate ? printable_area_in_points.height()
                                        : printable_area_in_points.width();
        double printable_height = rotate ? printable_area_in_points.width()
                                         : printable_area_in_points.height();
        double scale_width =
            printable_width /
            static_cast<double>(preset_options.uniform_page_size.width);
        double scale_height =
            printable_height /
            static_cast<double>(preset_options.uniform_page_size.height);
        fit_to_page_scale_factor = std::min(scale_width, scale_height);
      } else {
        fit_to_page_scale_factor = 0.0f;
      }
    }
  }
  int fit_to_page_scaling = static_cast<int>(100.0f * fit_to_page_scale_factor);
  Send(new PrintHostMsg_DidGetDefaultPageLayout(
      routing_id(), default_page_layout, printable_area_in_points,
      has_page_size_style));

  PrintHostMsg_DidGetPreviewPageCount_Params params;
  params.page_count = print_preview_context_.total_page_count();
  params.fit_to_page_scaling = fit_to_page_scaling;
  params.preview_request_id = print_params.preview_request_id;
  params.clear_preview_data = print_preview_context_.generate_draft_pages() ||
                              !print_preview_context_.IsModifiable();
  Send(new PrintHostMsg_DidGetPreviewPageCount(routing_id(), params));
  if (CheckForCancel())
    return false;

  while (!print_preview_context_.IsFinalPageRendered()) {
    int page_number = print_preview_context_.GetNextPageNumber();
    DCHECK_GE(page_number, 0);
    if (!RenderPreviewPage(page_number, print_params))
      return false;

    if (CheckForCancel())
      return false;

    if (print_preview_context_.IsFinalPageRendered())
      print_preview_context_.AllPagesRendered();

    if (print_preview_context_.IsLastPageOfPrintReadyMetafile()) {
      DCHECK(print_preview_context_.IsModifiable() ||
             print_preview_context_.IsFinalPageRendered());
      if (!FinalizePrintReadyDocument())
        return false;
    }
  }
  print_preview_context_.Finished();
  return true;
}

Project: Chrome

bool PrintRenderFrameHelper::PrintPreviewContext::CreatePreviewDocument(
    std::unique_ptr<PrepareFrameAndViewForPrint> prepared_frame,
    const std::vector<int>& pages,
    SkiaDocumentType doc_type) {
  DCHECK_EQ(INITIALIZED, state_);
  state_ = RENDERING;

  prep_frame_view_ = std::move(prepared_frame);
  prep_frame_view_->StartPrinting();

  total_page_count_ = prep_frame_view_->GetExpectedPageCount();
  if (total_page_count_ == 0) {
    LOG(ERROR) << "CreatePreviewDocument got 0 page count";
    set_error(PREVIEW_ERROR_ZERO_PAGES);
    return false;
  }

  metafile_ = base::MakeUnique<PdfMetafileSkia>(doc_type);
  CHECK(metafile_->Init());

  current_page_index_ = 0;
  pages_to_render_ = pages;
  std::sort(pages_to_render_.begin(), pages_to_render_.end());
  pages_to_render_.resize(
      std::unique(pages_to_render_.begin(), pages_to_render_.end()) -
      pages_to_render_.begin());
  pages_to_render_.resize(std::lower_bound(pages_to_render_.begin(),
                                           pages_to_render_.end(),
                                           total_page_count_) -
                          pages_to_render_.begin());
  print_ready_metafile_page_count_ = pages_to_render_.size();
  if (pages_to_render_.empty()) {
    print_ready_metafile_page_count_ = total_page_count_;
    for (int i = 0; i < total_page_count_; ++i)
      pages_to_render_.push_back(i);
  } else if (generate_draft_pages_) {
    int pages_index = 0;
    for (int i = 0; i < total_page_count_; ++i) {
      if (pages_index < print_ready_metafile_page_count_ &&
          i == pages_to_render_[pages_index]) {
        pages_index++;
        continue;
      }
      pages_to_render_.push_back(i);
    }
  }

  document_render_time_ = base::TimeDelta();
  begin_time_ = base::TimeTicks::Now();

  return true;
}

Project: Chrome

PrepareFrameAndViewForPrint::CreateURLLoaderFactory() {
  return blink::Platform::Current()->CreateDefaultURLLoaderFactory();
}

Project: Chrome

void PrintRenderFrameHelper::DidFailProvisionalLoad(
    const blink::WebURLError& error) {
  DidFinishLoad();
}

Project: Chrome

void PrintRenderFrameHelper::DidFinishLoad() {
  is_loading_ = false;
  if (!on_stop_loading_closure_.is_null()) {
    on_stop_loading_closure_.Run();
    on_stop_loading_closure_.Reset();
  }
}

Project: Chrome

void PrintRenderFrameHelper::DidFinishPrinting(PrintingResult result) {
  int cookie =
      print_pages_params_ ? print_pages_params_->params.document_cookie : 0;
  switch (result) {
    case OK:
      break;

    case FAIL_PRINT_INIT:
      DCHECK(!notify_browser_of_print_failure_);
      break;

    case FAIL_PRINT:
      if (notify_browser_of_print_failure_ && print_pages_params_) {
        Send(new PrintHostMsg_PrintingFailed(routing_id(), cookie));
      }
      break;

#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
    case FAIL_PREVIEW:
      if (!is_print_ready_metafile_sent_) {
        if (notify_browser_of_print_failure_) {
          LOG(ERROR) << "CreatePreviewDocument failed";
          Send(new PrintHostMsg_PrintPreviewFailed(routing_id(), cookie));
        } else {
          Send(new PrintHostMsg_PrintPreviewCancelled(routing_id(), cookie));
        }
      }
      print_preview_context_.Failed(notify_browser_of_print_failure_);
      break;
    case INVALID_SETTINGS:
      Send(new PrintHostMsg_PrintPreviewInvalidPrinterSettings(routing_id(),
                                                               cookie));
      print_preview_context_.Failed(false);
      break;
#endif  // BUILDFLAG(ENABLE_PRINT_PREVIEW)
  }
  prep_frame_view_.reset();
  print_pages_params_.reset();
  notify_browser_of_print_failure_ = true;
}

Project: Chrome

void PrintRenderFrameHelper::DidStartProvisionalLoad(
    blink::WebDocumentLoader* document_loader) {
  is_loading_ = true;
}

Project: Chrome

void PrepareFrameAndViewForPrint::DidStopLoading() {
  DCHECK(!on_ready_.is_null());
  base::ThreadTaskRunnerHandle::Get()->PostTask(
      FROM_HERE, base::Bind(&PrepareFrameAndViewForPrint::CallOnReady,
                            weak_ptr_factory_.GetWeakPtr()));
}

Project: Chrome

void PrintRenderFrameHelper::DisablePreview() {
  g_is_preview_enabled = false;
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::Failed(bool report_error) {
  DCHECK(state_ == INITIALIZED || state_ == RENDERING);
  state_ = INITIALIZED;
  if (report_error) {
    DCHECK_NE(PREVIEW_ERROR_NONE, error_);
    UMA_HISTOGRAM_ENUMERATION("PrintPreview.RendererError", error_,
                              PREVIEW_ERROR_LAST_ENUM);
  }
  ClearContext();
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::FinalizePrintReadyDocument() {
  DCHECK(IsRendering());

  base::TimeTicks begin_time = base::TimeTicks::Now();
  metafile_->FinishDocument();

  if (print_ready_metafile_page_count_ <= 0) {
    NOTREACHED();
    return;
  }

  UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderToPDFTime",
                             document_render_time_);
  base::TimeDelta total_time =
      (base::TimeTicks::Now() - begin_time) + document_render_time_;
  UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTime",
                             total_time);
  UMA_HISTOGRAM_MEDIUM_TIMES("PrintPreview.RenderAndGeneratePDFTimeAvgPerPage",
                             total_time / pages_to_render_.size());
}

Project: Chrome

void PrintRenderFrameHelper::FinishFramePrinting() {
  prep_frame_view_.reset();
}

Project: Chrome

void PrepareFrameAndViewForPrint::FinishPrinting() {
  blink::WebLocalFrame* frame = frame_.GetFrame();
  if (frame) {
    blink::WebView* web_view = frame->View();
    if (is_printing_started_) {
      is_printing_started_ = false;
      if (!owns_web_view_) {
        web_view->GetSettings()->SetShouldPrintBackgrounds(false);
        RestoreSize();
      }
      frame->PrintEnd();
    }
    if (owns_web_view_) {
      DCHECK(!frame->IsLoading());
      owns_web_view_ = false;
      web_view->Close();
    }
  }
  frame_.Reset(nullptr);
  on_ready_.Reset();
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::Finished() {
  DCHECK_EQ(DONE, state_);
  state_ = INITIALIZED;
  ClearContext();
}

Project: Chrome

FrameReference::FrameReference() {
  Reset(nullptr);
}

Project: Chrome

PrintMsg_Print_Params GetCssPrintParams(
    blink::WebLocalFrame* frame,
    int page_index,
    const PrintMsg_Print_Params& page_params) {
  PrintMsg_Print_Params page_css_params = page_params;
  int dpi = GetDPI(&page_params);

  blink::WebDoubleSize page_size_in_pixels(
      ConvertUnitDouble(page_params.page_size.width(), dpi, kPixelsPerInch),
      ConvertUnitDouble(page_params.page_size.height(), dpi, kPixelsPerInch));
  int margin_top_in_pixels =
      ConvertUnit(page_params.margin_top, dpi, kPixelsPerInch);
  int margin_right_in_pixels = ConvertUnit(
      page_params.page_size.width() - page_params.content_size.width() -
          page_params.margin_left,
      dpi, kPixelsPerInch);
  int margin_bottom_in_pixels = ConvertUnit(
      page_params.page_size.height() - page_params.content_size.height() -
          page_params.margin_top,
      dpi, kPixelsPerInch);
  int margin_left_in_pixels =
      ConvertUnit(page_params.margin_left, dpi, kPixelsPerInch);

  if (frame) {
    frame->PageSizeAndMarginsInPixels(
        page_index, page_size_in_pixels, margin_top_in_pixels,
        margin_right_in_pixels, margin_bottom_in_pixels, margin_left_in_pixels);
  }

  double new_content_width = page_size_in_pixels.Width() -
                             margin_left_in_pixels - margin_right_in_pixels;
  double new_content_height = page_size_in_pixels.Height() -
                              margin_top_in_pixels - margin_bottom_in_pixels;

  if (new_content_width < 1 || new_content_height < 1) {
    CHECK(frame != nullptr);
    page_css_params = GetCssPrintParams(nullptr, page_index, page_params);
    return page_css_params;
  }

  page_css_params.page_size =
      gfx::Size(ConvertUnit(page_size_in_pixels.Width(), kPixelsPerInch, dpi),
                ConvertUnit(page_size_in_pixels.Height(), kPixelsPerInch, dpi));
  page_css_params.content_size =
      gfx::Size(ConvertUnit(new_content_width, kPixelsPerInch, dpi),
                ConvertUnit(new_content_height, kPixelsPerInch, dpi));

  page_css_params.margin_top =
      ConvertUnit(margin_top_in_pixels, kPixelsPerInch, dpi);
  page_css_params.margin_left =
      ConvertUnit(margin_left_in_pixels, kPixelsPerInch, dpi);
  return page_css_params;
}

Project: Chrome

blink::WebLocalFrame* FrameReference::GetFrame() {
  if (view_ == nullptr || frame_ == nullptr)
    return nullptr;
  for (blink::WebFrame* frame = view_->MainFrame(); frame != nullptr;
       frame = frame->TraverseNext()) {
    if (frame == frame_)
      return frame_;
  }
  return nullptr;
}

Project: Chrome

MarginType GetMarginsForPdf(blink::WebLocalFrame* frame,
                            const blink::WebNode& node,
                            const PrintMsg_Print_Params& params) {
  return PDFShouldDisableScaling(frame, node, params, false)
             ? NO_MARGINS
             : PRINTABLE_AREA_MARGINS;
}

Project: Chrome

int PrintRenderFrameHelper::PrintPreviewContext::GetNextPageNumber() {
  DCHECK_EQ(RENDERING, state_);
  if (IsFinalPageRendered())
    return -1;
  return pages_to_render_[current_page_index_++];
}

Project: Chrome

void PrintRenderFrameHelper::GetPageSizeAndContentAreaFromPageLayout(
    const PageSizeMargins& page_layout_in_points,
    gfx::Size* page_size,
    gfx::Rect* content_area) {
  *page_size = gfx::Size(
      page_layout_in_points.content_width + page_layout_in_points.margin_right +
          page_layout_in_points.margin_left,
      page_layout_in_points.content_height + page_layout_in_points.margin_top +
          page_layout_in_points.margin_bottom);
  *content_area = gfx::Rect(page_layout_in_points.margin_left,
                            page_layout_in_points.margin_top,
                            page_layout_in_points.content_width,
                            page_layout_in_points.content_height);
}

Project: Chrome

blink::WebPlugin* GetPlugin(const blink::WebLocalFrame* frame) {
  return frame->GetDocument().IsPluginDocument()
             ? frame->GetDocument().To<blink::WebPluginDocument>().Plugin()
             : nullptr;
}

Project: Chrome

blink::WebPrintScalingOption GetPrintScalingOption(
    blink::WebLocalFrame* frame,
    const blink::WebNode& node,
    bool source_is_html,
    const base::DictionaryValue& job_settings,
    const PrintMsg_Print_Params& params) {
  if (params.print_to_pdf)
    return blink::kWebPrintScalingOptionSourceSize;

  if (!source_is_html) {
    if (!FitToPageEnabled(job_settings))
      return blink::kWebPrintScalingOptionNone;

    bool no_plugin_scaling = PDFShouldDisableScaling(frame, node, params, true);
    if (params.is_first_request && no_plugin_scaling)
      return blink::kWebPrintScalingOptionNone;
  }
  return blink::kWebPrintScalingOptionFitToPrintableArea;
}

Project: Chrome

void PrintRenderFrameHelper::GetPrintSettingsFromUser(
    blink::WebLocalFrame* frame,
    const blink::WebNode& node,
    int expected_pages_count,
    bool is_scripted,
    PrintMsg_PrintPages_Params* print_settings) {
  PrintHostMsg_ScriptedPrint_Params params;
  params.cookie = print_pages_params_->params.document_cookie;
  params.has_selection = frame->HasSelection();
  params.expected_pages_count = expected_pages_count;
  MarginType margin_type = DEFAULT_MARGINS;
  if (PrintingNodeOrPdfFrame(frame, node))
    margin_type = GetMarginsForPdf(frame, node, print_pages_params_->params);
  params.margin_type = margin_type;
  params.is_scripted = is_scripted;
  params.is_modifiable = !PrintingNodeOrPdfFrame(frame, node);

  Send(new PrintHostMsg_DidShowPrintDialog(routing_id()));

  print_pages_params_.reset();

  auto msg = base::MakeUnique<PrintHostMsg_ScriptedPrint>(routing_id(), params,
                                                          print_settings);
  msg->EnableMessagePumping();
  Send(msg.release());
}

Project: Chrome

bool PrintRenderFrameHelper::PrintPreviewContext::HasSelection() {
  return IsModifiable() && source_frame()->HasSelection();
}

Project: Chrome

bool PrintRenderFrameHelper::InitPrintSettings(bool fit_to_paper_size) {
  PrintMsg_PrintPages_Params settings;
  Send(new PrintHostMsg_GetDefaultPrintSettings(routing_id(),
                                                &settings.params));
  bool result = true;
  if (!PrintMsg_Print_Params_IsValid(settings.params))
    result = false;

  ignore_css_margins_ = false;
  settings.pages.clear();

  settings.params.print_scaling_option =
      fit_to_paper_size ? blink::kWebPrintScalingOptionFitToPrintableArea
                        : blink::kWebPrintScalingOptionSourceSize;

  SetPrintPagesParams(settings);
  return result;
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::InitWithFrame(
    blink::WebLocalFrame* web_frame) {
  DCHECK(web_frame);
  DCHECK(!IsRendering());
  state_ = INITIALIZED;
  source_frame_.Reset(web_frame);
  source_node_.Reset();
  CalculateIsModifiable();
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::InitWithNode(
    const blink::WebNode& web_node) {
  DCHECK(!web_node.IsNull());
  DCHECK(web_node.GetDocument().GetFrame());
  DCHECK(!IsRendering());
  state_ = INITIALIZED;
  source_frame_.Reset(web_node.GetDocument().GetFrame());
  source_node_ = web_node;
  CalculateIsModifiable();
}

Project: Chrome

bool PrintRenderFrameHelper::ScriptingThrottler::IsAllowed(
    blink::WebLocalFrame* frame) {
  const int kMinSecondsToIgnoreJavascriptInitiatedPrint = 2;
  const int kMaxSecondsToIgnoreJavascriptInitiatedPrint = 32;
  bool too_frequent = false;

  if (count_ > 0) {
    base::TimeDelta diff = base::Time::Now() - last_print_;
    int min_wait_seconds = kMinSecondsToIgnoreJavascriptInitiatedPrint;
    if (count_ > 3) {
      min_wait_seconds =
          std::min(kMinSecondsToIgnoreJavascriptInitiatedPrint << (count_ - 3),
                   kMaxSecondsToIgnoreJavascriptInitiatedPrint);
    }
    if (diff.InSeconds() < min_wait_seconds) {
      too_frequent = true;
    }
  }

  if (!too_frequent) {
    ++count_;
    last_print_ = base::Time::Now();
    return true;
  }

  blink::WebString message(
      blink::WebString::FromUTF8("Ignoring too frequent calls to print()."));
  frame->AddMessageToConsole(blink::WebConsoleMessage(
      blink::WebConsoleMessage::kLevelWarning, message));
  return false;
}

Project: Chrome

bool PrintRenderFrameHelper::Delegate::IsAskPrintSettingsEnabled() {
  return true;
}

Project: Chrome

bool PrintRenderFrameHelper::PrintPreviewContext::IsFinalPageRendered() const {
  DCHECK(IsRendering());
  return static_cast<size_t>(current_page_index_) == pages_to_render_.size();
}

Project: Chrome

    IsLastPageOfPrintReadyMetafile() const {
  DCHECK(IsRendering());
  return current_page_index_ == print_ready_metafile_page_count_;
}

Project: Chrome

  bool IsLoadingSelection() {
    return owns_web_view_ && frame() && frame()->IsLoading();
  }

Project: Chrome

bool PrintRenderFrameHelper::PrintPreviewContext::IsModifiable() const {
  DCHECK(state_ != UNINITIALIZED);
  return is_modifiable_;
}

Project: Chrome

bool IsPrintToPdfRequested(const base::DictionaryValue& job_settings) {
  bool print_to_pdf = false;
  if (!job_settings.GetBoolean(kSettingPrintToPDF, &print_to_pdf))
    NOTREACHED();
  return print_to_pdf;
}

Project: Chrome

bool PrintRenderFrameHelper::IsPrintingEnabled() const {
  return is_printing_enabled_;
}

Project: Chrome

bool PrintRenderFrameHelper::PrintPreviewContext::IsRendering() const {
  return state_ == RENDERING || state_ == DONE;
}

Project: Chrome

bool PrintRenderFrameHelper::IsScriptInitiatedPrintAllowed(
    blink::WebLocalFrame* frame,
    bool user_initiated) {
  if (!is_printing_enabled_ || !delegate_->IsScriptedPrintEnabled())
    return false;

  return user_initiated || g_is_preview_enabled ||
         scripting_throttler_.IsAllowed(frame);
}

Project: Chrome

bool PrintRenderFrameHelper::Delegate::IsScriptedPrintEnabled() {
  return true;
}

Project: Chrome

bool IsWebPrintScalingOptionFitToPage(const PrintMsg_Print_Params& params) {
  return params.print_scaling_option ==
         blink::kWebPrintScalingOptionFitToPrintableArea;
}

Project: Chrome

void PrintRenderFrameHelper::OnClosePrintPreviewDialog() {
  print_preview_context_.source_frame()->DispatchAfterPrintEvent();
}

Project: Chrome

void PrintRenderFrameHelper::OnDestruct() {
  if (ipc_nesting_level_ > 0) {
    render_frame_gone_ = true;
    return;
  }
  delete this;
}

Project: Chrome

void PrintRenderFrameHelper::OnFramePreparedForPreviewDocument() {
  if (reset_prep_frame_view_) {
    PrepareFrameForPreviewDocument();
    return;
  }
  DidFinishPrinting(CreatePreviewDocument() ? OK : FAIL_PREVIEW);
}

Project: Chrome

void PrintRenderFrameHelper::OnFramePreparedForPrintPages() {
  PrintPages();
  FinishFramePrinting();
}

Project: Chrome

void PrintRenderFrameHelper::OnInitiatePrintPreview(bool has_selection) {
  if (ipc_nesting_level_ > 1)
    return;

  blink::WebLocalFrame* frame = render_frame()->GetWebFrame();

  auto plugin = delegate_->GetPdfElement(frame);
  if (!plugin.IsNull()) {
    PrintNode(plugin);
    return;
  }
  print_preview_context_.InitWithFrame(frame);
  RequestPrintPreview(has_selection
                          ? PRINT_PREVIEW_USER_INITIATED_SELECTION
                          : PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME);
}

Project: Chrome

void PrintRenderFrameHelper::OnPrintForSystemDialog() {
  if (ipc_nesting_level_ > 1)
    return;
  blink::WebLocalFrame* frame = print_preview_context_.source_frame();
  if (!frame) {
    NOTREACHED();
    return;
  }
  auto weak_this = weak_ptr_factory_.GetWeakPtr();
  Print(frame, print_preview_context_.source_node(), false);
  if (weak_this)
    frame->DispatchAfterPrintEvent();
}

Project: Chrome

void PrintRenderFrameHelper::OnPrintPages() {
  if (ipc_nesting_level_ > 1)
    return;

  auto weak_this = weak_ptr_factory_.GetWeakPtr();
  blink::WebLocalFrame* frame = render_frame()->GetWebFrame();
  frame->DispatchBeforePrintEvent();
  if (!weak_this)
    return;

  auto plugin = delegate_->GetPdfElement(frame);
  Print(frame, plugin, false /* is_scripted? */);
  if (weak_this)
    frame->DispatchAfterPrintEvent();
}

Project: Chrome

void PrintRenderFrameHelper::OnPrintPreview(
    const base::DictionaryValue& settings) {
  if (ipc_nesting_level_ > 1)
    return;

  print_preview_context_.OnPrintPreview();

  UMA_HISTOGRAM_ENUMERATION("PrintPreview.PreviewEvent",
                            PREVIEW_EVENT_REQUESTED, PREVIEW_EVENT_MAX);

  if (!print_preview_context_.source_frame()) {
    DidFinishPrinting(FAIL_PREVIEW);
    return;
  }

  if (!UpdatePrintSettings(print_preview_context_.source_frame(),
                           print_preview_context_.source_node(), settings)) {
    if (print_preview_context_.last_error() != PREVIEW_ERROR_BAD_SETTING) {
      DidFinishPrinting(INVALID_SETTINGS);
    } else {
      DidFinishPrinting(FAIL_PREVIEW);
    }
    return;
  }

  if (print_pages_params_->params.is_first_request &&
      !print_preview_context_.IsModifiable()) {
    PrintHostMsg_SetOptionsFromDocument_Params options;
    if (SetOptionsFromPdfDocument(&options))
      Send(new PrintHostMsg_SetOptionsFromDocument(routing_id(), options));
  }

  is_print_ready_metafile_sent_ = false;

  print_pages_params_->params.supports_alpha_blend = true;

  bool generate_draft_pages = false;
  if (!settings.GetBoolean(kSettingGenerateDraftData, &generate_draft_pages)) {
    NOTREACHED();
  }
  print_preview_context_.set_generate_draft_pages(generate_draft_pages);

  PrepareFrameForPreviewDocument();
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::OnPrintPreview() {
  DCHECK_EQ(INITIALIZED, state_);
  ClearContext();
}

Project: Chrome

void PrintRenderFrameHelper::OnSetPrintingEnabled(bool enabled) {
  is_printing_enabled_ = enabled;
}

Project: Chrome

bool PDFShouldDisableScaling(blink::WebLocalFrame* frame,
                             const blink::WebNode& node,
                             const PrintMsg_Print_Params& params,
                             bool ignore_page_size) {
  const bool kDefaultPDFShouldDisableScalingSetting = true;
  blink::WebPrintPresetOptions preset_options;
  if (!frame->GetPrintPresetOptionsForPlugin(node, &preset_options))
    return kDefaultPDFShouldDisableScalingSetting;
  return PDFShouldDisableScalingBasedOnPreset(preset_options, params,
                                              ignore_page_size);
}

Project: Chrome

bool PDFShouldDisableScalingBasedOnPreset(
    const blink::WebPrintPresetOptions& options,
    const PrintMsg_Print_Params& params,
    bool ignore_page_size) {
  if (options.is_scaling_disabled)
    return true;

  if (!options.is_page_size_uniform)
    return false;

  int dpi = GetDPI(&params);
  if (!dpi) {
    return true;
  }

  if (ignore_page_size)
    return false;

  blink::WebSize page_size(
      ConvertUnit(params.page_size.width(), dpi, kPointsPerInch),
      ConvertUnit(params.page_size.height(), dpi, kPointsPerInch));
  return options.uniform_page_size == page_size;
}

Project: Chrome

PrepareFrameAndViewForPrint::PrepareFrameAndViewForPrint(
    const PrintMsg_Print_Params& params,
    blink::WebLocalFrame* frame,
    const blink::WebNode& node,
    bool ignore_css_margins)
    : frame_(frame),
      node_to_print_(node),
      owns_web_view_(false),
      expected_pages_count_(0),
      should_print_backgrounds_(params.should_print_backgrounds),
      should_print_selection_only_(params.selection_only),
      is_printing_started_(false),
      weak_ptr_factory_(this) {
  PrintMsg_Print_Params print_params = params;
  if (!should_print_selection_only_ ||
      !PrintingNodeOrPdfFrame(frame, node_to_print_)) {
    bool fit_to_page =
        ignore_css_margins && IsWebPrintScalingOptionFitToPage(print_params);
    ComputeWebKitPrintParamsInDesiredDpi(params, &web_print_params_);
    frame->PrintBegin(web_print_params_, node_to_print_);
    double scale_factor = 1.0f;
    if (print_params.scale_factor >= PrintRenderFrameHelper::kEpsilon)
      scale_factor = print_params.scale_factor;
    print_params = CalculatePrintParamsForCss(
        frame, 0, print_params, ignore_css_margins, fit_to_page, &scale_factor);
    frame->PrintEnd();
  }
  ComputeWebKitPrintParamsInDesiredDpi(print_params, &web_print_params_);
}

Project: Chrome

void PrintRenderFrameHelper::PrepareFrameForPreviewDocument() {
  reset_prep_frame_view_ = false;

  if (!print_pages_params_ || CheckForCancel()) {
    DidFinishPrinting(FAIL_PREVIEW);
    return;
  }

  if (prep_frame_view_ && prep_frame_view_->IsLoadingSelection()) {
    reset_prep_frame_view_ = true;
    return;
  }

  const PrintMsg_Print_Params& print_params = print_pages_params_->params;
  prep_frame_view_ = base::MakeUnique<PrepareFrameAndViewForPrint>(
      print_params, print_preview_context_.source_frame(),
      print_preview_context_.source_node(), ignore_css_margins_);
  prep_frame_view_->CopySelectionIfNeeded(
      render_frame()->GetWebkitPreferences(),
      base::Bind(&PrintRenderFrameHelper::OnFramePreparedForPreviewDocument,
                 weak_ptr_factory_.GetWeakPtr()));
}

Project: Chrome

void PrintRenderFrameHelper::Print(blink::WebLocalFrame* frame,
                                   const blink::WebNode& node,
                                   bool is_scripted) {
  if (prep_frame_view_)
    return;

  FrameReference frame_ref(frame);

  int expected_page_count = 0;
  if (!CalculateNumberOfPages(frame, node, &expected_page_count)) {
    DidFinishPrinting(FAIL_PRINT_INIT);
    return;  // Failed to init print page settings.
  }

  if (!expected_page_count) {
    DidFinishPrinting(FAIL_PRINT);
    return;
  }

  if (delegate_->IsAskPrintSettingsEnabled()) {
    blink::WebPrintScalingOption scaling_option =
        print_pages_params_->params.print_scaling_option;

    PrintMsg_PrintPages_Params print_settings;
    auto self = weak_ptr_factory_.GetWeakPtr();
    GetPrintSettingsFromUser(frame_ref.GetFrame(), node, expected_page_count,
                             is_scripted, &print_settings);
    if (!self)
      return;

    print_settings.params.print_scaling_option = scaling_option;
    SetPrintPagesParams(print_settings);
    if (!print_settings.params.dpi || !print_settings.params.document_cookie) {
      DidFinishPrinting(OK);  // Release resources and fail silently on failure.
      return;
    }
  }

  if (!RenderPagesForPrint(frame_ref.GetFrame(), node)) {
    LOG(ERROR) << "RenderPagesForPrint failed";
    DidFinishPrinting(FAIL_PRINT);
  }
  scripting_throttler_.Reset();
}

Project: Chrome

void PrintRenderFrameHelper::PrintHeaderAndFooter(
    blink::WebCanvas* canvas,
    int page_number,
    int total_pages,
    const blink::WebLocalFrame& source_frame,
    float webkit_scale_factor,
    const PageSizeMargins& page_layout,
    const PrintMsg_Print_Params& params) {
  cc::PaintCanvasAutoRestore auto_restore(canvas, true);
  canvas->scale(1 / webkit_scale_factor, 1 / webkit_scale_factor);

  blink::WebSize page_size(page_layout.margin_left + page_layout.margin_right +
                               page_layout.content_width,
                           page_layout.margin_top + page_layout.margin_bottom +
                               page_layout.content_height);

  blink::WebView* web_view = blink::WebView::Create(
      /* client = */ nullptr, blink::mojom::PageVisibilityState::kVisible,
      /* opener = */ nullptr);
  web_view->GetSettings()->SetJavaScriptEnabled(true);

  class HeaderAndFooterClient final : public blink::WebFrameClient {
   public:
    void BindToFrame(blink::WebLocalFrame* frame) override { frame_ = frame; }
    void FrameDetached(DetachType detach_type) override {
      frame_->FrameWidget()->Close();
      frame_->Close();
      frame_ = nullptr;
    }

   private:
    blink::WebLocalFrame* frame_;
  };
  HeaderAndFooterClient frame_client;
  blink::WebLocalFrame* frame = blink::WebLocalFrame::CreateMainFrame(
      web_view, &frame_client, nullptr, nullptr);
  blink::WebWidgetClient web_widget_client;
  blink::WebFrameWidget::Create(&web_widget_client, frame);

  base::Value html(base::UTF8ToUTF16(
      ui::ResourceBundle::GetSharedInstance().GetRawDataResource(
          IDR_PRINT_PREVIEW_PAGE)));
  ExecuteScript(frame, kPageLoadScriptFormat, html);

  auto options = base::MakeUnique<base::DictionaryValue>();
  options->SetDouble(kSettingHeaderFooterDate, base::Time::Now().ToJsTime());
  options->SetDouble("width", page_size.width);
  options->SetDouble("height", page_size.height);
  options->SetDouble("topMargin", page_layout.margin_top);
  options->SetDouble("bottomMargin", page_layout.margin_bottom);
  options->SetInteger("pageNumber", page_number);
  options->SetInteger("totalPages", total_pages);
  options->SetString("url", params.url);
  base::string16 title = source_frame.GetDocument().Title().Utf16();
  options->SetString("title", title.empty() ? params.title : title);
  options->SetString("headerTemplate", params.header_template);
  options->SetString("footerTemplate", params.footer_template);

  ExecuteScript(frame, kPageSetupScriptFormat, *options);

  blink::WebPrintParams webkit_params(page_size);
  webkit_params.printer_dpi = GetDPI(&params);

  frame->PrintBegin(webkit_params);
  frame->PrintPage(0, canvas);
  frame->PrintEnd();

  web_view->Close();
}

Project: Chrome

bool PrintMsg_Print_Params_IsValid(const PrintMsg_Print_Params& params) {
  return !params.content_size.IsEmpty() && !params.page_size.IsEmpty() &&
         !params.printable_area.IsEmpty() && params.document_cookie &&
         params.dpi && params.margin_top >= 0 && params.margin_left >= 0 &&
         params.dpi > kMinDpi && params.document_cookie != 0;
}

Project: Chrome

void PrintRenderFrameHelper::PrintNode(const blink::WebNode& node) {
  if (node.IsNull() || !node.GetDocument().GetFrame()) {
    return;
  }

  if (print_node_in_progress_) {
    return;
  }

  print_node_in_progress_ = true;

  if (g_is_preview_enabled) {
#if BUILDFLAG(ENABLE_PRINT_PREVIEW)
    print_preview_context_.InitWithNode(node);
    RequestPrintPreview(PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE);
#endif
  } else {
#if BUILDFLAG(ENABLE_BASIC_PRINTING)
    blink::WebNode duplicate_node(node);

    auto self = weak_ptr_factory_.GetWeakPtr();
    Print(duplicate_node.GetDocument().GetFrame(), duplicate_node,
          false /* is_scripted? */);
    if (!self)
      return;
#endif
  }

  print_node_in_progress_ = false;
}

Project: Chrome

void PrintRenderFrameHelper::PrintPageInternal(
    const PrintMsg_Print_Params& params,
    int page_number,
    int page_count,
    blink::WebLocalFrame* frame,
    PdfMetafileSkia* metafile,
    gfx::Size* page_size_in_dpi,
    gfx::Rect* content_area_in_dpi) {
  double css_scale_factor =
      params.scale_factor >= kEpsilon ? params.scale_factor : 1.0f;

  gfx::Size original_page_size = params.page_size;
  PageSizeMargins page_layout_in_points;
  ComputePageLayoutInPointsForCss(frame, page_number, params,
                                  ignore_css_margins_, &css_scale_factor,
                                  &page_layout_in_points);

  gfx::Size page_size;
  gfx::Rect content_area;
  GetPageSizeAndContentAreaFromPageLayout(page_layout_in_points, &page_size,
                                          &content_area);

  if (page_size_in_dpi)
    *page_size_in_dpi = original_page_size;

  if (content_area_in_dpi) {
    *content_area_in_dpi =
        gfx::Rect(0, 0, page_size_in_dpi->width(), page_size_in_dpi->height());
  }

  gfx::Rect canvas_area =
      params.display_header_footer ? gfx::Rect(page_size) : content_area;

#if defined(OS_WIN)
  float webkit_page_shrink_factor = frame->GetPrintPageShrink(page_number);
  float scale_factor = css_scale_factor * webkit_page_shrink_factor;
#else
  float scale_factor = css_scale_factor;
#endif

  cc::PaintCanvas* canvas =
      metafile->GetVectorCanvasForNewPage(page_size, canvas_area, scale_factor);
  if (!canvas)
    return;

  MetafileSkiaWrapper::SetMetafileOnCanvas(canvas, metafile);

  if (params.display_header_footer) {
#if defined(OS_WIN)
    const float fudge_factor = 1;
#else
    const float fudge_factor = kPrintingMinimumShrinkFactor;
#endif
    PrintHeaderAndFooter(canvas, page_number + 1, page_count, *frame,
                         scale_factor / fudge_factor, page_layout_in_points,
                         params);
  }

  float webkit_scale_factor = RenderPageContent(
      frame, page_number, canvas_area, content_area, scale_factor, canvas);
  DCHECK_GT(webkit_scale_factor, 0.0f);

  bool ret = metafile->FinishPage();
  DCHECK(ret);
 }

Project: Chrome

void PrintRenderFrameHelper::PrintPages() {
  if (!prep_frame_view_)  // Printing is already canceled or failed.
    return;

  prep_frame_view_->StartPrinting();

  int page_count = prep_frame_view_->GetExpectedPageCount();
  if (!page_count) {
    LOG(ERROR) << "Can't print 0 pages.";
    return DidFinishPrinting(FAIL_PRINT);
  }

  const PrintMsg_PrintPages_Params& params = *print_pages_params_;
  const PrintMsg_Print_Params& print_params = params.params;

#if !defined(OS_ANDROID)
  Send(new PrintHostMsg_DidGetPrintedPagesCount(
      routing_id(), print_params.document_cookie, page_count));
#endif  // !defined(OS_ANDROID)

  if (print_params.preview_ui_id < 0) {
    int printed_count = params.pages.empty() ? page_count : params.pages.size();
    UMA_HISTOGRAM_COUNTS("PrintPreview.PageCount.SystemDialog", printed_count);
  }

  if (!PrintPagesNative(prep_frame_view_->frame(), page_count)) {
    LOG(ERROR) << "Printing failed.";
    return DidFinishPrinting(FAIL_PRINT);
  }
}

Project: Chrome

PrintRenderFrameHelper::PrintPreviewContext::PrintPreviewContext()
    : total_page_count_(0),
      current_page_index_(0),
      generate_draft_pages_(true),
      is_modifiable_(true),
      print_ready_metafile_page_count_(0),
      error_(PREVIEW_ERROR_NONE),
      state_(UNINITIALIZED) {}

Project: Chrome

bool PrintingFrameHasPageSizeStyle(blink::WebLocalFrame* frame,
                                   int total_page_count) {
  if (!frame)
    return false;
  bool frame_has_custom_page_size_style = false;
  for (int i = 0; i < total_page_count; ++i) {
    if (frame->HasCustomPageSizeStyle(i)) {
      frame_has_custom_page_size_style = true;
      break;
    }
  }
  return frame_has_custom_page_size_style;
}

Project: Chrome

float PrintRenderFrameHelper::RenderPageContent(blink::WebLocalFrame* frame,
                                                int page_number,
                                                const gfx::Rect& canvas_area,
                                                const gfx::Rect& content_area,
                                                double scale_factor,
                                                blink::WebCanvas* canvas) {
  cc::PaintCanvasAutoRestore auto_restore(canvas, true);
  canvas->translate((content_area.x() - canvas_area.x()) / scale_factor,
                    (content_area.y() - canvas_area.y()) / scale_factor);
  return frame->PrintPage(page_number, canvas);
}

Project: Chrome

bool PrintRenderFrameHelper::RenderPagesForPrint(blink::WebLocalFrame* frame,
                                                 const blink::WebNode& node) {
  if (!frame || prep_frame_view_)
    return false;

  const PrintMsg_PrintPages_Params& params = *print_pages_params_;
  const PrintMsg_Print_Params& print_params = params.params;
  prep_frame_view_ = base::MakeUnique<PrepareFrameAndViewForPrint>(
      print_params, frame, node, ignore_css_margins_);
  DCHECK(!print_pages_params_->params.selection_only ||
         print_pages_params_->pages.empty());
  prep_frame_view_->CopySelectionIfNeeded(
      render_frame()->GetWebkitPreferences(),
      base::Bind(&PrintRenderFrameHelper::OnFramePreparedForPrintPages,
                 weak_ptr_factory_.GetWeakPtr()));
  return true;
}

Project: Chrome

bool PrintRenderFrameHelper::RenderPreviewPage(
    int page_number,
    const PrintMsg_Print_Params& print_params) {
  std::unique_ptr<PdfMetafileSkia> draft_metafile;
  PdfMetafileSkia* initial_render_metafile = print_preview_context_.metafile();
  if (print_preview_context_.IsModifiable() && is_print_ready_metafile_sent_) {
    draft_metafile =
        base::MakeUnique<PdfMetafileSkia>(print_params.printed_doc_type);
    initial_render_metafile = draft_metafile.get();
  }

  base::TimeTicks begin_time = base::TimeTicks::Now();
  PrintPageInternal(print_params, page_number,
                    print_preview_context_.total_page_count(),
                    print_preview_context_.prepared_frame(),
                    initial_render_metafile, nullptr, nullptr);
  print_preview_context_.RenderedPreviewPage(base::TimeTicks::Now() -
                                             begin_time);
  if (draft_metafile.get()) {
    draft_metafile->FinishDocument();
  } else if (print_preview_context_.IsModifiable() &&
             print_preview_context_.generate_draft_pages()) {
    DCHECK(!draft_metafile.get());
    draft_metafile =
        print_preview_context_.metafile()->GetMetafileForCurrentPage(
            print_params.printed_doc_type);
  }
  return PreviewPageRendered(page_number, draft_metafile.get());
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::RenderedPreviewPage(
    const base::TimeDelta& page_time) {
  DCHECK_EQ(RENDERING, state_);
  document_render_time_ += page_time;
  UMA_HISTOGRAM_TIMES("PrintPreview.RenderPDFPageTime", page_time);
}

Project: Chrome

void PrintRenderFrameHelper::RequestPrintPreview(PrintPreviewRequestType type) {
  auto weak_this = weak_ptr_factory_.GetWeakPtr();
  print_preview_context_.source_frame()->DispatchBeforePrintEvent();
  if (!weak_this)
    return;
  const bool is_modifiable = print_preview_context_.IsModifiable();
  const bool has_selection = print_preview_context_.HasSelection();
  PrintHostMsg_RequestPrintPreview_Params params;
  params.is_modifiable = is_modifiable;
  params.has_selection = has_selection;
  switch (type) {
    case PRINT_PREVIEW_SCRIPTED: {
      is_scripted_preview_delayed_ = true;
      if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
        on_stop_loading_closure_ =
            base::Bind(&PrintRenderFrameHelper::ShowScriptedPrintPreview,
                       weak_ptr_factory_.GetWeakPtr());
      } else {
        base::ThreadTaskRunnerHandle::Get()->PostTask(
            FROM_HERE,
            base::Bind(&PrintRenderFrameHelper::ShowScriptedPrintPreview,
                       weak_ptr_factory_.GetWeakPtr()));
      }
      auto msg = base::MakeUnique<PrintHostMsg_SetupScriptedPrintPreview>(
          routing_id());
      msg->EnableMessagePumping();
      auto self = weak_ptr_factory_.GetWeakPtr();
      Send(msg.release());
      if (self)
        is_scripted_preview_delayed_ = false;
      return;
    }
    case PRINT_PREVIEW_USER_INITIATED_ENTIRE_FRAME: {
      if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
        on_stop_loading_closure_ =
            base::Bind(&PrintRenderFrameHelper::RequestPrintPreview,
                       weak_ptr_factory_.GetWeakPtr(), type);
        return;
      }

      break;
    }
    case PRINT_PREVIEW_USER_INITIATED_SELECTION: {
      DCHECK(has_selection);
      DCHECK(!GetPlugin(print_preview_context_.source_frame()));
      params.selection_only = has_selection;
      break;
    }
    case PRINT_PREVIEW_USER_INITIATED_CONTEXT_NODE: {
      if (is_loading_ && GetPlugin(print_preview_context_.source_frame())) {
        on_stop_loading_closure_ =
            base::Bind(&PrintRenderFrameHelper::RequestPrintPreview,
                       weak_ptr_factory_.GetWeakPtr(), type);
        return;
      }

      params.webnode_only = true;
      break;
    }
    default: {
      NOTREACHED();
      return;
    }
  }
  Send(new PrintHostMsg_RequestPrintPreview(routing_id(), params));
}

Project: Chrome

void FrameReference::Reset(blink::WebLocalFrame* frame) {
  if (frame) {
    view_ = frame->View();
    DCHECK(view_);
    frame_ = frame;
  } else {
    view_ = nullptr;
    frame_ = nullptr;
  }
}

Project: Chrome

void PrintRenderFrameHelper::ScriptingThrottler::Reset() {
  count_ = 0;
}

Project: Chrome

void PrepareFrameAndViewForPrint::ResizeForPrinting() {
  gfx::Size print_layout_size(web_print_params_.print_content_area.width,
                              web_print_params_.print_content_area.height);
  print_layout_size.set_height(
      ScaleAndRound(print_layout_size.height(), kPrintingMinimumShrinkFactor));

  if (!frame())
    return;

  if (PrintingNodeOrPdfFrame(frame(), node_to_print_))
    return;

  blink::WebView* web_view = frame_.view();
  if (blink::WebFrame* web_frame = web_view->MainFrame()) {
    if (web_frame->IsWebLocalFrame())
      prev_scroll_offset_ = web_frame->ToWebLocalFrame()->GetScrollOffset();
  }
  prev_view_size_ = web_view->Size();
  web_view->Resize(print_layout_size);
}

Project: Chrome

void PrepareFrameAndViewForPrint::RestoreSize() {
  if (!frame())
    return;

  if (PrintingNodeOrPdfFrame(frame(), node_to_print_))
    return;

  blink::WebView* web_view = frame_.GetFrame()->View();
  web_view->Resize(prev_view_size_);
  if (blink::WebFrame* web_frame = web_view->MainFrame()) {
    if (web_frame->IsWebLocalFrame())
      web_frame->ToWebLocalFrame()->SetScrollOffset(prev_scroll_offset_);
  }
}

Project: Chrome

int ScaleAndRound(int value, double scaling) {
  return static_cast<int>(static_cast<double>(value) / scaling);
}

Project: Chrome

PrintRenderFrameHelper::ScriptingThrottler::ScriptingThrottler() : count_(0) {}

Project: Chrome

bool PrintRenderFrameHelper::SetOptionsFromPdfDocument(
    PrintHostMsg_SetOptionsFromDocument_Params* options) {
  blink::WebLocalFrame* source_frame = print_preview_context_.source_frame();
  const blink::WebNode& source_node = print_preview_context_.source_node();

  blink::WebPrintPresetOptions preset_options;
  if (!source_frame->GetPrintPresetOptionsForPlugin(source_node,
                                                    &preset_options)) {
    return false;
  }

  options->is_scaling_disabled = PDFShouldDisableScalingBasedOnPreset(
      preset_options, print_pages_params_->params, false);
  options->copies = preset_options.copies;

  switch (preset_options.duplex_mode) {
    case blink::kWebSimplex:
      options->duplex = SIMPLEX;
      break;
    case blink::kWebLongEdge:
      options->duplex = LONG_EDGE;
      break;
    default:
      options->duplex = UNKNOWN_DUPLEX_MODE;
      break;
  }
  return true;
}

Project: Chrome

void PrintRenderFrameHelper::SetPrintPagesParams(
    const PrintMsg_PrintPages_Params& settings) {
  print_pages_params_ = base::MakeUnique<PrintMsg_PrintPages_Params>(settings);
  Send(new PrintHostMsg_DidGetDocumentCookie(routing_id(),
                                             settings.params.document_cookie));
}

Project: Chrome

void PrintRenderFrameHelper::ShowScriptedPrintPreview() {
  if (is_scripted_preview_delayed_) {
    is_scripted_preview_delayed_ = false;
    Send(new PrintHostMsg_ShowScriptedPrintPreview(
        routing_id(), print_preview_context_.IsModifiable()));
  }
}

Project: Chrome

void PrepareFrameAndViewForPrint::StartPrinting() {
  ResizeForPrinting();
  blink::WebView* web_view = frame_.view();
  web_view->GetSettings()->SetShouldPrintBackgrounds(should_print_backgrounds_);
  expected_pages_count_ =
      frame()->PrintBegin(web_print_params_, node_to_print_);
  is_printing_started_ = true;
}

Project: Chrome

void PrintRenderFrameHelper::UpdateFrameMarginsCssInfo(
    const base::DictionaryValue& settings) {
  int margins_type = 0;
  if (!settings.GetInteger(kSettingMarginsType, &margins_type))
    margins_type = DEFAULT_MARGINS;
  ignore_css_margins_ = (margins_type != DEFAULT_MARGINS);
}

Project: Chrome

bool PrintRenderFrameHelper::PrintPreviewContext::generate_draft_pages() const {
  return generate_draft_pages_;
}

Project: Chrome

int PrintRenderFrameHelper::PrintPreviewContext::last_error() const {
  return error_;
}

Project: Chrome

PdfMetafileSkia* PrintRenderFrameHelper::PrintPreviewContext::metafile() {
  DCHECK(IsRendering());
  return metafile_.get();
}

Project: Chrome

PrintRenderFrameHelper::PrintPreviewContext::prepared_frame() {
  DCHECK(state_ != UNINITIALIZED);
  return prep_frame_view_->frame();
}

Project: Chrome

PrintRenderFrameHelper::PrintPreviewContext::prepared_node() const {
  DCHECK(state_ != UNINITIALIZED);
  return prep_frame_view_->node();
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::set_error(
    enum PrintPreviewErrorBuckets error) {
  error_ = error;
}

Project: Chrome

void PrintRenderFrameHelper::PrintPreviewContext::set_generate_draft_pages(
    bool generate_draft_pages) {
  DCHECK_EQ(INITIALIZED, state_);
  generate_draft_pages_ = generate_draft_pages;
}

Project: Chrome

PrintRenderFrameHelper::PrintPreviewContext::source_frame() {
  DCHECK(state_ != UNINITIALIZED);
  return source_frame_.GetFrame();
}

Project: Chrome

const blink::WebNode& PrintRenderFrameHelper::PrintPreviewContext::source_node()
    const {
  DCHECK(state_ != UNINITIALIZED);
  return source_node_;
}

Project: Chrome

int PrintRenderFrameHelper::PrintPreviewContext::total_page_count() const {
  DCHECK(state_ != UNINITIALIZED);
  return total_page_count_;
}

Project: Chrome

PrintRenderFrameHelper::PrintPreviewContext::~PrintPreviewContext() {}

Project: Chrome

bool SaveToFD(const printing::Metafile& metafile,
              const base::FileDescriptor& fd) {
  DCHECK_GT(metafile.GetDataSize(), 0U);

  if (fd.fd < 0) {
    DLOG(ERROR) << "Invalid file descriptor!";
    return false;
  }
  base::File file(fd.fd);
  bool result = metafile.SaveTo(&file);
  DLOG_IF(ERROR, !result) << "Failed to save file with fd " << fd.fd;

  if (!fd.auto_close)
    file.TakePlatformFile();
  return result;
}

Project: Chrome

  void Create(service_manager::mojom::ServiceFactoryRequest request) {
    service_factory_bindings_.AddBinding(this, std::move(request));
  }

Project: Chrome

  PdfCompositorServiceTest() : ServiceTest("pdf_compositor_service_unittest") {}

Project: Chrome

  explicit PdfCompositorTestService(const std::string& creator)
      : PdfCompositorService(creator) {}

Project: Chrome

  explicit PdfServiceTestClient(service_manager::test::ServiceTest* test)
      : service_manager::test::ServiceTestClient(test) {
    registry_.AddInterface<service_manager::mojom::ServiceFactory>(
        base::Bind(&PdfServiceTestClient::Create, base::Unretained(this)));
  }

Project: Chrome

void PdfCompositorClient::Connect(service_manager::Connector* connector) {
  DCHECK(!compositor_.is_bound());
  connector->BindInterface(mojom::kServiceName, &compositor_);
}

Project: Chrome

void OnCompositePdf(
    printing::mojom::PdfCompositorPtr compositor,
    printing::mojom::PdfCompositor::CompositePdfCallback callback,
    scoped_refptr<base::SequencedTaskRunner> task_runner,
    mojom::PdfCompositor::Status status,
    mojo::ScopedSharedBufferHandle pdf_handle) {
  task_runner->PostTask(FROM_HERE, base::BindOnce(std::move(callback), status,
                                                  base::Passed(&pdf_handle)));
}

Project: Chrome

PdfCompositorClient::PdfCompositorClient() : compositor_(nullptr) {}

Project: Chrome

PdfCompositorClient::~PdfCompositorClient() {}

Project: Chrome

scoped_refptr<base::RefCountedBytes> GetDataFromMojoHandle(
    mojo::ScopedSharedBufferHandle handle) {
  std::unique_ptr<base::SharedMemory> shm =
      GetShmFromMojoHandle(std::move(handle));
  if (!shm)
    return nullptr;

  return base::MakeRefCounted<base::RefCountedBytes>(
      reinterpret_cast<const unsigned char*>(shm->memory()),
      shm->mapped_size());
}

Project: Chrome

std::unique_ptr<SharedBitmap> ClientSharedBitmapManager::AllocateSharedBitmap(
    const gfx::Size& size) {
  TRACE_EVENT2("renderer", "ClientSharedBitmapManager::AllocateSharedBitmap",
               "width", size.width(), "height", size.height());
  size_t memory_size;
  if (!SharedBitmap::SizeInBytes(size, &memory_size))
    return nullptr;
  SharedBitmapId id = SharedBitmap::GenerateId();
  std::unique_ptr<base::SharedMemory> memory =
      AllocateSharedMemory(memory_size);
  if (!memory || !memory->Map(memory_size))
    CollectMemoryUsageAndDie(size, memory_size);

  uint32_t sequence_number = NotifyAllocatedSharedBitmap(memory.get(), id);

  memory->Close();

  return std::make_unique<ClientSharedBitmap>(
      shared_bitmap_allocation_notifier_, std::move(memory), id,
      sequence_number);
}

Project: Chrome

std::unique_ptr<base::SharedMemory> AllocateSharedMemory(size_t buf_size) {
  mojo::ScopedSharedBufferHandle mojo_buf =
      mojo::SharedBufferHandle::Create(buf_size);
  if (!mojo_buf->is_valid()) {
    LOG(WARNING) << "Browser failed to allocate shared memory";
    return nullptr;
  }

  base::SharedMemoryHandle shared_buf;
  if (mojo::UnwrapSharedMemoryHandle(std::move(mojo_buf), &shared_buf, nullptr,
                                     nullptr) != MOJO_RESULT_OK) {
    LOG(WARNING) << "Browser failed to allocate shared memory";
    return nullptr;
  }

  return std::make_unique<base::SharedMemory>(shared_buf, false);
}

Project: Chrome

  ClientSharedBitmap(
      scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
          shared_bitmap_allocation_notifier,
      std::unique_ptr<base::SharedMemory> shared_memory_holder,
      const SharedBitmapId& id,
      uint32_t sequence_number)
      : ClientSharedBitmap(std::move(shared_bitmap_allocation_notifier),
                           shared_memory_holder.get(),
                           id,
                           sequence_number) {
    shared_memory_holder_ = std::move(shared_memory_holder);
  }

Project: Chrome

ClientSharedBitmapManager::ClientSharedBitmapManager(
    scoped_refptr<mojom::ThreadSafeSharedBitmapAllocationNotifierPtr>
        shared_bitmap_allocation_notifier)
    : shared_bitmap_allocation_notifier_(
          std::move(shared_bitmap_allocation_notifier)) {}

Project: Chrome

ClientSharedBitmapManager::GetBitmapForSharedMemory(base::SharedMemory* mem) {
  SharedBitmapId id = SharedBitmap::GenerateId();
  uint32_t sequence_number = NotifyAllocatedSharedBitmap(mem, id);
  return std::make_unique<ClientSharedBitmap>(
      shared_bitmap_allocation_notifier_, mem, id, sequence_number);
}

Project: Chrome

std::unique_ptr<SharedBitmap> ClientSharedBitmapManager::GetSharedBitmapFromId(
    const gfx::Size&,
    const SharedBitmapId&) {
  NOTREACHED();
  return nullptr;
}

Project: Chrome

ClientSharedBitmapManager::~ClientSharedBitmapManager() {}

Project: Chrome

void BrowserChildProcessHostImpl::AddFilter(BrowserMessageFilter* filter) {
  child_process_host_->AddFilter(filter->GetFilter());
}

Project: Chrome

void BrowserChildProcessHostImpl::AddObserver(
    BrowserChildProcessObserver* observer) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  g_browser_child_process_observers.Get().AddObserver(observer);
}

Project: Chrome

BrowserChildProcessHostImpl::BrowserChildProcessHostImpl(
    content::ProcessType process_type,
    BrowserChildProcessHostDelegate* delegate,
    const std::string& service_name)
    : data_(process_type),
      delegate_(delegate),
      broker_client_invitation_(new mojo::edk::OutgoingBrokerClientInvitation),
      channel_(nullptr),
      is_channel_connected_(false),
      notify_child_disconnected_(false),
      weak_factory_(this) {
  data_.id = ChildProcessHostImpl::GenerateChildProcessUniqueId();

  child_process_host_.reset(ChildProcessHost::Create(this));
  AddFilter(new TraceMessageFilter(data_.id));

  g_child_process_list.Get().push_back(this);
  GetContentClient()->browser()->BrowserChildProcessHostCreated(this);

  if (!service_name.empty()) {
    DCHECK_CURRENTLY_ON(BrowserThread::IO);
    service_manager::Identity child_identity(
        service_name, service_manager::mojom::kInheritUserID,
        base::StringPrintf("%d", data_.id));
    child_connection_.reset(
        new ChildConnection(child_identity, broker_client_invitation_.get(),
                            ServiceManagerContext::GetConnectorForIOThread(),
                            base::ThreadTaskRunnerHandle::Get()));
  }

  CreateMetricsAllocator();
}

Project: Chrome

bool BrowserChildProcessHostImpl::CanShutdown() {
  return delegate_->CanShutdown();
}

Project: Chrome

void BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(
    base::CommandLine* cmd_line) {
  base::FieldTrialList::CopyFieldTrialStateToFlags(
      switches::kFieldTrialHandle, switches::kEnableFeatures,
      switches::kDisableFeatures, cmd_line);
}

Project: Chrome

BrowserChildProcessHost* BrowserChildProcessHost::Create(
    content::ProcessType process_type,
    BrowserChildProcessHostDelegate* delegate) {
  return Create(process_type, delegate, std::string());
}

Project: Chrome

BrowserChildProcessHost* BrowserChildProcessHost::Create(
    content::ProcessType process_type,
    BrowserChildProcessHostDelegate* delegate,
    const std::string& service_name) {
  return new BrowserChildProcessHostImpl(process_type, delegate, service_name);
}

Project: Chrome

void BrowserChildProcessHostImpl::CreateMetricsAllocator() {
  if (!base::GlobalHistogramAllocator::Get())
    return;

  size_t memory_size;
  base::StringPiece metrics_name;
  switch (data_.process_type) {
    case PROCESS_TYPE_UTILITY:
      memory_size = 256 << 10;  // 256 KiB
      metrics_name = "UtilityMetrics";
      break;

    case PROCESS_TYPE_ZYGOTE:
      memory_size = 64 << 10;  // 64 KiB
      metrics_name = "ZygoteMetrics";
      break;

    case PROCESS_TYPE_SANDBOX_HELPER:
      memory_size = 64 << 10;  // 64 KiB
      metrics_name = "SandboxHelperMetrics";
      break;

    case PROCESS_TYPE_GPU:
      memory_size = 64 << 10;  // 64 KiB
      metrics_name = "GpuMetrics";
      break;

    case PROCESS_TYPE_PPAPI_PLUGIN:
      memory_size = 64 << 10;  // 64 KiB
      metrics_name = "PpapiPluginMetrics";
      break;

    case PROCESS_TYPE_PPAPI_BROKER:
      memory_size = 64 << 10;  // 64 KiB
      metrics_name = "PpapiBrokerMetrics";
      break;

    default:
      int process_type = data_.process_type;
      if (process_type >= PROCESS_TYPE_CONTENT_END)
        process_type += 1000 - PROCESS_TYPE_CONTENT_END;
      base::UmaHistogramSparse(
          "UMA.SubprocessMetricsProvider.UntrackedProcesses", process_type);
      return;
  }

  std::unique_ptr<base::SharedMemory> shm(new base::SharedMemory());
  if (!shm->CreateAndMapAnonymous(memory_size))
    return;
  metrics_allocator_.reset(new base::SharedPersistentMemoryAllocator(
      std::move(shm), static_cast<uint64_t>(data_.id), metrics_name,
      /*readonly=*/false));
}

Project: Chrome

void BrowserChildProcessHostImpl::ForceShutdown() {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  g_child_process_list.Get().remove(this);
  child_process_host_->ForceShutdown();
}

Project: Chrome

BrowserChildProcessHost* BrowserChildProcessHost::FromID(int child_process_id) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  BrowserChildProcessHostImpl::BrowserChildProcessList* process_list =
      g_child_process_list.Pointer();
  for (BrowserChildProcessHostImpl* host : *process_list) {
    if (host->GetData().id == child_process_id)
      return host;
  }
  return nullptr;
}

Project: Chrome

const ChildProcessData& BrowserChildProcessHostImpl::GetData() const {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  return data_;
}

Project: Chrome

ChildProcessHost* BrowserChildProcessHostImpl::GetHost() const {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  return child_process_host_.get();
}

Project: Chrome

    BrowserChildProcessHostImpl::GetIterator() {
  return g_child_process_list.Pointer();
}

Project: Chrome

const base::Process& BrowserChildProcessHostImpl::GetProcess() const {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  DCHECK(child_process_.get())
      << "Requesting a child process handle before launching.";
  DCHECK(child_process_->GetProcess().IsValid())
      << "Requesting a child process handle before launch has completed OK.";
  return child_process_->GetProcess();
}

Project: Chrome

base::TerminationStatus BrowserChildProcessHostImpl::GetTerminationStatus(
    bool known_dead, int* exit_code) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  if (!child_process_)  // If the delegate doesn't use Launch() helper.
    return base::GetTerminationStatus(data_.handle, exit_code);
  return child_process_->GetChildTerminationStatus(known_dead,
                                                   exit_code);
}

Project: Chrome

void BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
    ProcessType process_type) {
  UMA_HISTOGRAM_ENUMERATION("ChildProcess.BadMessgeTerminated", process_type,
                            PROCESS_TYPE_MAX);
}

Project: Chrome

bool BrowserChildProcessHostImpl::IsProcessLaunched() const {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);

  return child_process_.get() && child_process_->GetProcess().IsValid();
}

Project: Chrome

void BrowserChildProcessHostImpl::Launch(
    std::unique_ptr<SandboxedProcessLauncherDelegate> delegate,
    std::unique_ptr<base::CommandLine> cmd_line,
    bool terminate_on_shutdown) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);

  GetContentClient()->browser()->AppendExtraCommandLineSwitches(cmd_line.get(),
                                                                data_.id);

  const base::CommandLine& browser_command_line =
      *base::CommandLine::ForCurrentProcess();
  static const char* const kForwardSwitches[] = {
      service_manager::switches::kDisableInProcessStackTraces,
      switches::kDisableLogging,
      switches::kEnableLogging,
      switches::kIPCConnectionTimeout,
      switches::kLoggingLevel,
      switches::kTraceToConsole,
      switches::kV,
      switches::kVModule,
  };
  cmd_line->CopySwitchesFrom(browser_command_line, kForwardSwitches,
                             arraysize(kForwardSwitches));

  if (child_connection_) {
    cmd_line->AppendSwitchASCII(switches::kServiceRequestChannelToken,
                                child_connection_->service_token());
  }

  DCHECK(broker_client_invitation_);
  notify_child_disconnected_ = true;
  child_process_.reset(new ChildProcessLauncher(
      std::move(delegate), std::move(cmd_line), data_.id, this,
      std::move(broker_client_invitation_),
      base::Bind(&BrowserChildProcessHostImpl::OnMojoError,
                 weak_factory_.GetWeakPtr(),
                 base::ThreadTaskRunnerHandle::Get()),
      terminate_on_shutdown));
}

Project: Chrome

void NotifyProcessCrashed(const ChildProcessData& data, int exit_code) {
  for (auto& observer : g_browser_child_process_observers.Get())
    observer.BrowserChildProcessCrashed(data, exit_code);
}

Project: Chrome

void NotifyProcessHostDisconnected(const ChildProcessData& data) {
  for (auto& observer : g_browser_child_process_observers.Get())
    observer.BrowserChildProcessHostDisconnected(data);
}

Project: Chrome

void NotifyProcessKilled(const ChildProcessData& data, int exit_code) {
  for (auto& observer : g_browser_child_process_observers.Get())
    observer.BrowserChildProcessKilled(data, exit_code);
}

Project: Chrome

void NotifyProcessLaunchedAndConnected(const ChildProcessData& data) {
  for (auto& observer : g_browser_child_process_observers.Get())
    observer.BrowserChildProcessLaunchedAndConnected(data);
}

Project: Chrome

void BrowserChildProcessHostImpl::OnBadMessageReceived(
    const IPC::Message& message) {
  std::string log_message = "Bad message received of type: ";
  if (message.IsValid()) {
    log_message += std::to_string(message.type());
  } else {
    log_message += "unknown";
  }
  TerminateOnBadMessageReceived(log_message);
}

Project: Chrome

void BrowserChildProcessHostImpl::OnChannelConnected(int32_t peer_pid) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);

  is_channel_connected_ = true;
  notify_child_disconnected_ = true;

#if defined(OS_WIN)
  early_exit_watcher_.StopWatching();
#endif

  BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                          base::BindOnce(&NotifyProcessHostConnected, data_));

  delegate_->OnChannelConnected(peer_pid);

  if (IsProcessLaunched()) {
    ShareMetricsAllocatorToProcess();
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        base::BindOnce(&NotifyProcessLaunchedAndConnected, data_));
  }
}

Project: Chrome

void BrowserChildProcessHostImpl::OnChannelError() {
  delegate_->OnChannelError();
}

Project: Chrome

void BrowserChildProcessHostImpl::OnChannelInitialized(IPC::Channel* channel) {
  channel_ = channel;
}

Project: Chrome

void BrowserChildProcessHostImpl::OnChildDisconnected() {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
#if defined(OS_WIN)
  early_exit_watcher_.StopWatching();
#endif
  if (child_process_.get() || data_.handle) {
    int exit_code;
    base::TerminationStatus status = GetTerminationStatus(
        true /* known_dead */, &exit_code);
    switch (status) {
      case base::TERMINATION_STATUS_PROCESS_CRASHED:
      case base::TERMINATION_STATUS_ABNORMAL_TERMINATION: {
        delegate_->OnProcessCrashed(exit_code);
        BrowserThread::PostTask(
            BrowserThread::UI, FROM_HERE,
            base::BindOnce(&NotifyProcessCrashed, data_, exit_code));
        UMA_HISTOGRAM_ENUMERATION("ChildProcess.Crashed2",
                                  static_cast<ProcessType>(data_.process_type),
                                  PROCESS_TYPE_MAX);
        break;
      }
#if defined(OS_ANDROID)
      case base::TERMINATION_STATUS_OOM_PROTECTED:
#endif
#if defined(OS_CHROMEOS)
      case base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM:
#endif
      case base::TERMINATION_STATUS_PROCESS_WAS_KILLED: {
        delegate_->OnProcessCrashed(exit_code);
        BrowserThread::PostTask(
            BrowserThread::UI, FROM_HERE,
            base::BindOnce(&NotifyProcessKilled, data_, exit_code));
        UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2",
                                  static_cast<ProcessType>(data_.process_type),
                                  PROCESS_TYPE_MAX);
        break;
      }
      case base::TERMINATION_STATUS_STILL_RUNNING: {
        UMA_HISTOGRAM_ENUMERATION("ChildProcess.DisconnectedAlive2",
                                  static_cast<ProcessType>(data_.process_type),
                                  PROCESS_TYPE_MAX);
      }
      default:
        break;
    }
    UMA_HISTOGRAM_ENUMERATION("ChildProcess.Disconnected2",
                              static_cast<ProcessType>(data_.process_type),
                              PROCESS_TYPE_MAX);
#if defined(OS_CHROMEOS)
    if (status == base::TERMINATION_STATUS_PROCESS_WAS_KILLED_BY_OOM) {
      UMA_HISTOGRAM_ENUMERATION("ChildProcess.Killed2.OOM",
                                static_cast<ProcessType>(data_.process_type),
                                PROCESS_TYPE_MAX);
    }
#endif
  }
  channel_ = nullptr;
  delete delegate_;  // Will delete us
}

Project: Chrome

bool BrowserChildProcessHostImpl::OnMessageReceived(
    const IPC::Message& message) {
  return delegate_->OnMessageReceived(message);
}

Project: Chrome

void BrowserChildProcessHostImpl::OnMojoError(
    base::WeakPtr<BrowserChildProcessHostImpl> process,
    scoped_refptr<base::SingleThreadTaskRunner> task_runner,
    const std::string& error) {
  if (!task_runner->BelongsToCurrentThread()) {
    task_runner->PostTask(
        FROM_HERE, base::BindOnce(&BrowserChildProcessHostImpl::OnMojoError,
                                  process, task_runner, error));
    return;
  }
  if (!process)
    return;
  HistogramBadMessageTerminated(
      static_cast<ProcessType>(process->data_.process_type));
  if (base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableKillAfterBadIPC)) {
    return;
  }
  LOG(ERROR) << "Terminating child process for bad Mojo message: " << error;

  base::debug::ScopedCrashKeyString scoped_error_key(
      bad_message::GetMojoErrorCrashKey(), error);
  base::debug::DumpWithoutCrashing();
  process->child_process_->GetProcess().Terminate(
      RESULT_CODE_KILLED_BAD_MESSAGE, false);
}

Project: Chrome

void BrowserChildProcessHostImpl::OnObjectSignaled(HANDLE object) {
  OnChildDisconnected();
}

Project: Chrome

void BrowserChildProcessHostImpl::OnProcessLaunchFailed(int error_code) {
  delegate_->OnProcessLaunchFailed(error_code);
  notify_child_disconnected_ = false;
  delete delegate_;  // Will delete us
}

Project: Chrome

void BrowserChildProcessHostImpl::OnProcessLaunched() {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);

  const base::Process& process = child_process_->GetProcess();
  DCHECK(process.IsValid());

  if (child_connection_)
    child_connection_->SetProcessHandle(process.Handle());

#if defined(OS_WIN)
  DCHECK(!early_exit_watcher_.GetWatchedObject());
  early_exit_watcher_.StartWatchingOnce(process.Handle(), this);
#endif

  data_.handle = process.Handle();
  delegate_->OnProcessLaunched();

  if (is_channel_connected_) {
    ShareMetricsAllocatorToProcess();
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        base::BindOnce(&NotifyProcessLaunchedAndConnected, data_));
  }
}

Project: Chrome

void BrowserChildProcessHostImpl::RemoveObserver(
    BrowserChildProcessObserver* observer) {
  g_browser_child_process_observers.Get().RemoveObserver(observer);
}

Project: Chrome

bool BrowserChildProcessHostImpl::Send(IPC::Message* message) {
  return child_process_host_->Send(message);
}

Project: Chrome

void BrowserChildProcessHostImpl::SetHandle(base::ProcessHandle handle) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  data_.handle = handle;
}

Project: Chrome

void BrowserChildProcessHostImpl::SetName(const base::string16& name) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  data_.name = name;
}

Project: Chrome

BrowserChildProcessHostImpl::TakeInProcessServiceRequest() {
  DCHECK(broker_client_invitation_);
  auto invitation = std::move(broker_client_invitation_);
  return service_manager::mojom::ServiceRequest(
      invitation->ExtractInProcessMessagePipe(
          child_connection_->service_token()));
}

Project: Chrome

BrowserChildProcessHostImpl::TakeMetricsAllocator() {
  return std::move(metrics_allocator_);
}

Project: Chrome

void BrowserChildProcessHostImpl::TerminateAll() {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  BrowserChildProcessList copy = g_child_process_list.Get();
  for (BrowserChildProcessList::iterator it = copy.begin();
       it != copy.end(); ++it) {
    delete (*it)->delegate();  // ~*HostDelegate deletes *HostImpl.
  }
}

Project: Chrome

void RenderProcessHostImpl::AddExpectedNavigationToSite(
    BrowserContext* browser_context,
    RenderProcessHost* render_process_host,
    const GURL& site_url) {
  if (!ShouldTrackProcessForSite(browser_context, render_process_host,
                                 site_url))
    return;

  SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>(
      browser_context->GetUserData(kPendingSiteProcessCountTrackerKey));
  if (!tracker) {
    tracker = new SiteProcessCountTracker();
    browser_context->SetUserData(kPendingSiteProcessCountTrackerKey,
                                 base::WrapUnique(tracker));
  }
  tracker->IncrementSiteProcessCount(site_url, render_process_host->GetID());
}

Project: Chrome

void RenderProcessHostImpl::AddFrameWithSite(
    BrowserContext* browser_context,
    RenderProcessHost* render_process_host,
    const GURL& site_url) {
  if (!ShouldTrackProcessForSite(browser_context, render_process_host,
                                 site_url))
    return;

  SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>(
      browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey));
  if (!tracker) {
    tracker = new SiteProcessCountTracker();
    browser_context->SetUserData(kCommittedSiteProcessCountTrackerKey,
                                 base::WrapUnique(tracker));
  }
  tracker->IncrementSiteProcessCount(site_url, render_process_host->GetID());
}

Project: Chrome

void RenderProcessHostImpl::AddPendingView() {
  pending_views_++;
  UpdateProcessPriority();
}

Project: Chrome

void RenderProcessHostImpl::AppendRendererCommandLine(
    base::CommandLine* command_line) {
  command_line->AppendSwitchASCII(switches::kProcessType,
                                  switches::kRendererProcess);

#if defined(OS_WIN)
  command_line->AppendArg(switches::kPrefetchArgumentRenderer);
#endif  // defined(OS_WIN)

  const base::CommandLine& browser_command_line =
      *base::CommandLine::ForCurrentProcess();
  PropagateBrowserCommandLineToRenderer(browser_command_line, command_line);

  const std::string locale =
      GetContentClient()->browser()->GetApplicationLocale();
  command_line->AppendSwitchASCII(switches::kLang, locale);

  if (!base::CommandLine::ForCurrentProcess()
           ->GetSwitchValueNative(switches::kRendererCmdPrefix)
           .empty()) {
    command_line->AppendSwitch(switches::kNoZygote);
  }

  GetContentClient()->browser()->AppendExtraCommandLineSwitches(command_line,
                                                                GetID());

#if defined(OS_WIN)
  command_line->AppendSwitchASCII(
      switches::kDeviceScaleFactor,
      base::NumberToString(display::win::GetDPIScale()));
#endif

  AppendCompositorCommandLineFlags(command_line);

  command_line->AppendSwitchASCII(switches::kServiceRequestChannelToken,
                                  child_connection_->service_token());
  command_line->AppendSwitchASCII(switches::kRendererClientId,
                                  std::to_string(GetID()));
}

Project: Chrome

void RenderProcessHostImpl::BindFrameSinkProvider(
    mojom::FrameSinkProviderRequest request) {
  frame_sink_provider_.Bind(std::move(request));
}

Project: Chrome

void RenderProcessHostImpl::BindInterface(
    const std::string& interface_name,
    mojo::ScopedMessagePipeHandle interface_pipe) {
  child_connection_->BindInterface(interface_name, std::move(interface_pipe));
}

Project: Chrome

void RenderProcessHostImpl::BindRouteProvider(
    mojom::RouteProviderAssociatedRequest request) {
  if (route_provider_binding_.is_bound())
    return;
  route_provider_binding_.Bind(std::move(request));
}

Project: Chrome

void RenderProcessHostImpl::BindSharedBitmapAllocationNotifier(
    viz::mojom::SharedBitmapAllocationNotifierRequest request) {
  shared_bitmap_allocation_notifier_impl_.Bind(std::move(request));
}

Project: Chrome

  void CallTask() {
    DCHECK_CURRENTLY_ON(BrowserThread::UI);
    if (render_process_host_->IsReady())
      std::move(task_).Run();

    delete this;
  }

Project: Chrome

void RenderProcessHostImpl::Cleanup() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  if (run_renderer_in_process())
    return;

  if (within_process_died_observer_) {
    delayed_cleanup_needed_ = true;
    return;
  }
  delayed_cleanup_needed_ = false;

  if (listeners_.IsEmpty() && keep_alive_ref_count_ > 0 &&
      keep_alive_start_time_.is_null()) {
    keep_alive_start_time_ = base::TimeTicks::Now();
  }

  if (!listeners_.IsEmpty() || keep_alive_ref_count_ != 0)
    return;

#if BUILDFLAG(ENABLE_WEBRTC)
  if (is_initialized_) {
    BrowserThread::PostTask(
        BrowserThread::IO, FROM_HERE,
        base::BindOnce(&WebRtcLog::ClearLogMessageCallback, GetID()));
  }
#endif

  if (!keep_alive_start_time_.is_null()) {
    UMA_HISTOGRAM_LONG_TIMES("BrowserRenderProcessHost.KeepAliveDuration",
                             base::TimeTicks::Now() - keep_alive_start_time_);
  }

  DCHECK(!deleting_soon_);

  DCHECK_EQ(0, pending_views_);

  if (HasConnection()) {
    for (auto& observer : observers_) {
      observer.RenderProcessExited(
          this, base::TERMINATION_STATUS_NORMAL_TERMINATION, 0);
    }
  }
  for (auto& observer : observers_)
    observer.RenderProcessHostDestroyed(this);
  NotificationService::current()->Notify(
      NOTIFICATION_RENDERER_PROCESS_TERMINATED,
      Source<RenderProcessHost>(this), NotificationService::NoDetails());

  if (connection_filter_id_ !=
        ServiceManagerConnection::kInvalidConnectionFilterId) {
    ServiceManagerConnection* service_manager_connection =
        BrowserContext::GetServiceManagerConnectionFor(browser_context_);
    connection_filter_controller_->DisableFilter();
    service_manager_connection->RemoveConnectionFilter(connection_filter_id_);
    connection_filter_id_ =
        ServiceManagerConnection::kInvalidConnectionFilterId;
  }

#ifndef NDEBUG
  is_self_deleted_ = true;
#endif
  base::ThreadTaskRunnerHandle::Get()->DeleteSoon(FROM_HERE, this);
  deleting_soon_ = true;

  ResetChannelProxy();

  DCHECK(!channel_);
  RemoveUserData(kSessionStorageHolderKey);

  UnregisterHost(GetID());

  instance_weak_factory_.reset(
      new base::WeakPtrFactory<RenderProcessHostImpl>(this));
}

Project: Chrome

  void CleanupSpareRenderProcessHost() {
    if (spare_render_process_host_) {
      spare_render_process_host_->Cleanup();
      DropSpareRenderProcessHost(spare_render_process_host_);
    }
  }

Project: Chrome

void RenderProcessHostImpl::CleanupSpareRenderProcessHost() {
  g_spare_render_process_host_manager.Get().CleanupSpareRenderProcessHost();
}

Project: Chrome

ChildProcessImportance RenderProcessHostImpl::ComputeEffectiveImportance() {
  ChildProcessImportance importance = ChildProcessImportance::NORMAL;
  for (size_t i = 0u; i < arraysize(widget_importance_counts_); ++i) {
    DCHECK_GE(widget_importance_counts_[i], 0);
    if (widget_importance_counts_[i]) {
      importance = static_cast<ChildProcessImportance>(i);
    }
  }
  return importance;
}

Project: Chrome

  ConnectionFilterImpl(
      const service_manager::Identity& child_identity,
      std::unique_ptr<service_manager::BinderRegistry> registry)
      : child_identity_(child_identity),
        registry_(std::move(registry)),
        controller_(new ConnectionFilterController(this)),
        weak_factory_(this) {
    thread_checker_.DetachFromThread();
  }

Project: Chrome

void CopyFeatureSwitch(const base::CommandLine& src,
                       base::CommandLine* dest,
                       const char* switch_name) {
  std::vector<std::string> features = FeaturesFromSwitch(src, switch_name);
  if (!features.empty())
    dest->AppendSwitchASCII(switch_name, base::JoinString(features, ","));
}

Project: Chrome

IPC::PlatformFileForTransit CreateFileForProcess(base::FilePath file_path) {
  base::File dump_file(file_path,
                       base::File::FLAG_OPEN_ALWAYS | base::File::FLAG_APPEND);
  if (!dump_file.IsValid()) {
    VLOG(1) << "Could not open AEC dump file, error="
            << dump_file.error_details();
    return IPC::InvalidPlatformFileForTransit();
  }
  return IPC::TakePlatformFileForTransit(std::move(dump_file));
}

Project: Chrome

void RenderProcessHostImpl::CreateMediaStreamDispatcherHost(
    MediaStreamManager* media_stream_manager,
    mojom::MediaStreamDispatcherHostRequest request) {
  DCHECK_CURRENTLY_ON(BrowserThread::IO);
  if (!media_stream_dispatcher_host_) {
    media_stream_dispatcher_host_.reset(
        new MediaStreamDispatcherHost(GetID(), media_stream_manager));
  }
  media_stream_dispatcher_host_->BindRequest(std::move(request));
}

Project: Chrome

void RenderProcessHostImpl::CreateMessageFilters() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  AddFilter(new ResourceSchedulerFilter(GetID()));
  MediaInternals* media_internals = MediaInternals::GetInstance();
  scoped_refptr<BrowserPluginMessageFilter> bp_message_filter(
      new BrowserPluginMessageFilter(GetID()));
  AddFilter(bp_message_filter.get());

  scoped_refptr<net::URLRequestContextGetter> request_context(
      storage_partition_impl_->GetURLRequestContext());
  scoped_refptr<RenderMessageFilter> render_message_filter(
      new RenderMessageFilter(
          GetID(), GetBrowserContext(), request_context.get(),
          widget_helper_.get(), media_internals,
          storage_partition_impl_->GetDOMStorageContext(),
          storage_partition_impl_->GetCacheStorageContext()));
  AddFilter(render_message_filter.get());

  render_frame_message_filter_ = new RenderFrameMessageFilter(
      GetID(),
#if BUILDFLAG(ENABLE_PLUGINS)
      PluginServiceImpl::GetInstance(),
#else
      nullptr,
#endif
      GetBrowserContext(),
      request_context.get(),
      widget_helper_.get());
  AddFilter(render_frame_message_filter_.get());

  BrowserContext* browser_context = GetBrowserContext();
  ResourceContext* resource_context = browser_context->GetResourceContext();

  scoped_refptr<net::URLRequestContextGetter> media_request_context(
      GetStoragePartition()->GetMediaURLRequestContext());

  ResourceMessageFilter::GetContextsCallback get_contexts_callback(base::Bind(
      &GetContexts, resource_context, request_context, media_request_context));

  scoped_refptr<ChromeBlobStorageContext> blob_storage_context =
      ChromeBlobStorageContext::GetFor(browser_context);

  resource_message_filter_ = new ResourceMessageFilter(
      GetID(), storage_partition_impl_->GetAppCacheService(),
      blob_storage_context.get(),
      storage_partition_impl_->GetFileSystemContext(),
      storage_partition_impl_->GetServiceWorkerContext(), get_contexts_callback,
      BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));

  AddFilter(resource_message_filter_.get());

  media::AudioManager* audio_manager =
      BrowserMainLoop::GetInstance()->audio_manager();
  MediaStreamManager* media_stream_manager =
      BrowserMainLoop::GetInstance()->media_stream_manager();
  if (!RenderFrameAudioInputStreamFactory::UseMojoFactories()) {
    AddFilter(base::MakeRefCounted<AudioInputRendererHost>(
                  GetID(), audio_manager, media_stream_manager,
                  AudioMirroringManager::GetInstance(),
                  BrowserMainLoop::GetInstance()->user_input_monitor())
                  .get());
  }
  if (!RendererAudioOutputStreamFactoryContextImpl::UseMojoFactories()) {
    AddFilter(base::MakeRefCounted<AudioRendererHost>(
                  GetID(), audio_manager,
                  BrowserMainLoop::GetInstance()->audio_system(),
                  AudioMirroringManager::GetInstance(), media_stream_manager)
                  .get());
  }
  AddFilter(
      new MidiHost(GetID(), BrowserMainLoop::GetInstance()->midi_service()));
  AddFilter(new DOMStorageMessageFilter(
      storage_partition_impl_->GetDOMStorageContext()));

#if BUILDFLAG(ENABLE_WEBRTC)
  peer_connection_tracker_host_ = new PeerConnectionTrackerHost(GetID());
  AddFilter(peer_connection_tracker_host_.get());
  AddFilter(new MediaStreamTrackMetricsHost());
#endif
#if BUILDFLAG(ENABLE_PLUGINS)
  AddFilter(new PepperRendererConnection(GetID()));
#endif
  AddFilter(new SpeechRecognitionDispatcherHost(
      GetID(), storage_partition_impl_->GetURLRequestContext()));
  AddFilter(new FileAPIMessageFilter(
      GetID(), storage_partition_impl_->GetURLRequestContext(),
      storage_partition_impl_->GetFileSystemContext(),
      blob_storage_context.get()));
  AddFilter(new BlobDispatcherHost(GetID(), blob_storage_context));
#if defined(OS_MACOSX)
  AddFilter(new TextInputClientMessageFilter());
#endif

  scoped_refptr<CacheStorageDispatcherHost> cache_storage_filter =
      new CacheStorageDispatcherHost();
  cache_storage_filter->Init(storage_partition_impl_->GetCacheStorageContext());
  AddFilter(cache_storage_filter.get());

  scoped_refptr<ServiceWorkerDispatcherHost> service_worker_filter =
      new ServiceWorkerDispatcherHost(GetID(), resource_context);
  service_worker_filter->Init(
      storage_partition_impl_->GetServiceWorkerContext());
  AddFilter(service_worker_filter.get());

#if BUILDFLAG(ENABLE_WEBRTC)
  p2p_socket_dispatcher_host_ = new P2PSocketDispatcherHost(
      resource_context, request_context.get());
  AddFilter(p2p_socket_dispatcher_host_.get());
#endif

  AddFilter(new TraceMessageFilter(GetID()));
  AddFilter(new ResolveProxyMsgHelper(request_context.get()));

  scoped_refptr<ServiceWorkerContextWrapper> service_worker_context(
      static_cast<ServiceWorkerContextWrapper*>(
          storage_partition_impl_->GetServiceWorkerContext()));
  notification_message_filter_ = new NotificationMessageFilter(
      GetID(), storage_partition_impl_->GetPlatformNotificationContext(),
      resource_context, service_worker_context, browser_context);
  AddFilter(notification_message_filter_.get());

#if defined(OS_ANDROID)
  synchronous_compositor_filter_ =
      new SynchronousCompositorBrowserFilter(GetID());
  AddFilter(synchronous_compositor_filter_.get());
#endif
}

Project: Chrome

RenderProcessHost* RenderProcessHostImpl::CreateOrUseSpareRenderProcessHost(
    BrowserContext* browser_context,
    StoragePartitionImpl* storage_partition_impl,
    SiteInstance* site_instance,
    bool is_for_guests_only) {
  RenderProcessHost* render_process_host =
      g_spare_render_process_host_manager.Get().MaybeTakeSpareRenderProcessHost(
          browser_context, storage_partition_impl, site_instance,
          is_for_guests_only);

  if (!render_process_host) {
    render_process_host =
        CreateRenderProcessHost(browser_context, storage_partition_impl,
                                site_instance, is_for_guests_only);
  }

  DCHECK(render_process_host);
  return render_process_host;
}

Project: Chrome

void CreateProcessResourceCoordinator(
    RenderProcessHostImpl* render_process_host,
    resource_coordinator::mojom::ProcessCoordinationUnitRequest request) {
  render_process_host->GetProcessResourceCoordinator()->AddBinding(
      std::move(request));
}

Project: Chrome

RenderProcessHost* RenderProcessHostImpl::CreateRenderProcessHost(
    BrowserContext* browser_context,
    StoragePartitionImpl* storage_partition_impl,
    SiteInstance* site_instance,
    bool is_for_guests_only) {
  if (g_render_process_host_factory_) {
    return g_render_process_host_factory_->CreateRenderProcessHost(
        browser_context, site_instance);
  }

  if (!storage_partition_impl) {
    storage_partition_impl = static_cast<StoragePartitionImpl*>(
        BrowserContext::GetStoragePartition(browser_context, site_instance));
  }
  if (is_for_guests_only && site_instance &&
      storage_partition_impl->site_for_service_worker().is_empty()) {
    storage_partition_impl->set_site_for_service_worker(
        site_instance->GetSiteURL());
  }

  return new RenderProcessHostImpl(browser_context, storage_partition_impl,
                                   is_for_guests_only);
}

Project: Chrome

void RenderProcessHostImpl::CreateRendererHost(
    mojom::RendererHostAssociatedRequest request) {
  renderer_host_binding_.Bind(std::move(request));
}

Project: Chrome

void RenderProcessHostImpl::CreateStoragePartitionService(
    mojom::StoragePartitionServiceRequest request) {
  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableMojoLocalStorage)) {
    if (g_create_storage_partition) {
      g_create_storage_partition(this, std::move(request));
      return;
    }

    storage_partition_impl_->Bind(id_, std::move(request));
  }
}

Project: Chrome

void RenderProcessHostImpl::CreateURLLoaderFactory(
    network::mojom::URLLoaderFactoryRequest request) {
  if (!base::FeatureList::IsEnabled(features::kNetworkService)) {
    NOTREACHED();
    return;
  }
  storage_partition_impl_->GetNetworkContext()->CreateURLLoaderFactory(
      std::move(request), id_);
}

Project: Chrome

void RenderProcessHostImpl::DecrementKeepAliveRefCount() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DCHECK(!is_keep_alive_ref_count_disabled_);
  DCHECK_GT(keep_alive_ref_count_, 0U);
  --keep_alive_ref_count_;
  if (keep_alive_ref_count_ == 0)
    Cleanup();
}

Project: Chrome

  void DecrementSiteProcessCount(const GURL& site_url,
                                 int render_process_host_id) {
    auto result = map_.find(site_url);
    DCHECK(result != map_.end());
    std::map<ProcessID, Count>& counts_per_process = result->second;

    --counts_per_process[render_process_host_id];
    DCHECK(counts_per_process[render_process_host_id] >= 0);

    if (counts_per_process[render_process_host_id] == 0)
      counts_per_process.erase(render_process_host_id);

    if (counts_per_process.empty())
      map_.erase(site_url);
  }

Project: Chrome

  explicit DefaultSubframeProcessHostHolder(BrowserContext* browser_context)
      : browser_context_(browser_context) {}

Project: Chrome

void RenderProcessHostImpl::DisableAudioDebugRecordings() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  GetAecDumpFileTaskRunner().PostTaskAndReply(
      FROM_HERE, base::BindOnce(&base::DoNothing),
      base::BindOnce(&RenderProcessHostImpl::SendDisableAecDumpToRenderer,
                     weak_factory_.GetWeakPtr()));
}

Project: Chrome

void RenderProcessHostImpl::DisableKeepAliveRefCount() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DCHECK(!is_keep_alive_ref_count_disabled_);
  is_keep_alive_ref_count_disabled_ = true;
  if (!keep_alive_ref_count_)
    return;
  keep_alive_ref_count_ = 0;
  Cleanup();
}

Project: Chrome

  void DropSpareOnProcessCreation(RenderProcessHost* new_host) {
    if (spare_render_process_host_ == new_host) {
      DropSpareRenderProcessHost(new_host);
    } else {
      CleanupSpareRenderProcessHost();
    }
  }

Project: Chrome

  void DropSpareRenderProcessHost(RenderProcessHost* host) {
    if (spare_render_process_host_ && spare_render_process_host_ == host) {
      spare_render_process_host_->RemoveObserver(this);
      spare_render_process_host_ = nullptr;
    }
  }

Project: Chrome

void RenderProcessHostImpl::EnableAecDumpForId(const base::FilePath& file,
                                               int id) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  base::PostTaskAndReplyWithResult(
      &GetAecDumpFileTaskRunner(), FROM_HERE,
      base::Bind(&CreateFileForProcess, file.AddExtension(IntToStringType(id))),
      base::Bind(&RenderProcessHostImpl::SendAecDumpFileToRenderer,
                 weak_factory_.GetWeakPtr(), id));
}

Project: Chrome

void RenderProcessHostImpl::EnableAudioDebugRecordings(
    const base::FilePath& file) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  base::FilePath file_with_extensions = GetAecDumpFilePathWithExtensions(file);
  for (int id : aec_dump_consumers_) {
    EnableAecDumpForId(file_with_extensions, id);
  }
}

Project: Chrome

  RenderProcessHost* FindFreshestProcessForSite(const GURL& site_url) const {
    for (const auto& site_process_pair : base::Reversed(site_process_set_)) {
      if (site_process_pair.first == site_url)
        return RenderProcessHost::FromID(site_process_pair.second);
    }
    return nullptr;
  }

Project: Chrome

  RenderProcessHost* FindProcess(const std::string& site) {
    SiteToProcessMap::iterator i = map_.find(site);
    if (i != map_.end())
      return i->second;
    return nullptr;
  }

Project: Chrome

  void FindRenderProcessesForSite(
      const GURL& site_url,
      std::set<RenderProcessHost*>* foreground_processes,
      std::set<RenderProcessHost*>* background_processes) {
    auto result = map_.find(site_url);
    if (result == map_.end())
      return;

    std::map<ProcessID, Count>& counts_per_process = result->second;
    for (auto iter : counts_per_process) {
      RenderProcessHost* host = RenderProcessHost::FromID(iter.first);
      if (!host) {
        NOTREACHED();
        continue;
      }

      if (!host->MayReuseHost() ||
          !RenderProcessHostImpl::IsSuitableHost(
              host, host->GetBrowserContext(), site_url))
        continue;

      if (host->VisibleWidgetCount())
        foreground_processes->insert(host);
      else
        background_processes->insert(host);
    }
  }

Project: Chrome

RenderProcessHost* RenderProcessHostImpl::FindReusableProcessHostForSite(
    BrowserContext* browser_context,
    const GURL& site_url) {
  if (!ShouldFindReusableProcessHostForSite(browser_context, site_url))
    return nullptr;

  std::set<RenderProcessHost*> eligible_foreground_hosts;
  std::set<RenderProcessHost*> eligible_background_hosts;

  SiteProcessCountTracker* pending_tracker =
      static_cast<SiteProcessCountTracker*>(
          browser_context->GetUserData(kPendingSiteProcessCountTrackerKey));
  if (pending_tracker) {
    pending_tracker->FindRenderProcessesForSite(
        site_url, &eligible_foreground_hosts, &eligible_background_hosts);
  }

  if (eligible_foreground_hosts.empty()) {
    SiteProcessCountTracker* committed_tracker =
        static_cast<SiteProcessCountTracker*>(
            browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey));
    if (committed_tracker) {
      committed_tracker->FindRenderProcessesForSite(
          site_url, &eligible_foreground_hosts, &eligible_background_hosts);
    }
  }

  if (!eligible_foreground_hosts.empty()) {
    int index = base::RandInt(0, eligible_foreground_hosts.size() - 1);
    auto iterator = eligible_foreground_hosts.begin();
    for (int i = 0; i < index; ++i)
      ++iterator;
    return (*iterator);
  }

  if (!eligible_background_hosts.empty()) {
    int index = base::RandInt(0, eligible_background_hosts.size() - 1);
    auto iterator = eligible_background_hosts.begin();
    for (int i = 0; i < index; ++i)
      ++iterator;
    return (*iterator);
  }

  return nullptr;
}

Project: Chrome

void ForwardRequest(const char* service_name,
                    mojo::InterfaceRequest<Interface> request) {
  service_manager::Connector* connector =
      ServiceManagerConnection::GetForProcess()->GetConnector();
  connector->BindInterface(service_name, std::move(request));
}

Project: Chrome

RenderProcessHost* RenderProcessHost::FromRendererIdentity(
    const service_manager::Identity& identity) {
  for (content::RenderProcessHost::iterator i(
           content::RenderProcessHost::AllHostsIterator());
       !i.IsAtEnd(); i.Advance()) {
    content::RenderProcessHost* process = i.GetCurrentValue();
    if (process->GetChildIdentity() == identity)
      return process;
  }
  return nullptr;
}

Project: Chrome

void RenderProcessHostImpl::GetBlobURLLoaderFactory(
    network::mojom::URLLoaderFactoryRequest request) {
  if (!base::FeatureList::IsEnabled(features::kNetworkService)) {
    NOTREACHED();
    return;
  }
  storage_partition_impl_->GetBlobURLLoaderFactory()->HandleRequest(
      std::move(request));
}

Project: Chrome

const service_manager::Identity& RenderProcessHostImpl::GetChildIdentity()
    const {
  return child_connection_->child_identity();
}

Project: Chrome

RenderProcessHost* RenderProcessHostImpl::GetDefaultSubframeProcessHost(
    BrowserContext* browser_context,
    SiteInstanceImpl* site_instance,
    bool is_for_guests_only) {
  DefaultSubframeProcessHostHolder* holder =
      static_cast<DefaultSubframeProcessHostHolder*>(
          browser_context->GetUserData(&kDefaultSubframeProcessHostHolderKey));
  if (!holder) {
    holder = new DefaultSubframeProcessHostHolder(browser_context);
    browser_context->SetUserData(kDefaultSubframeProcessHostHolderKey,
                                 base::WrapUnique(holder));
  }

  return holder->GetProcessHost(site_instance, is_for_guests_only);
}

Project: Chrome

RenderProcessHost* RenderProcessHost::GetExistingProcessHost(
    BrowserContext* browser_context,
    const GURL& site_url) {
  std::vector<RenderProcessHost*> suitable_renderers;
  suitable_renderers.reserve(g_all_hosts.Get().size());

  iterator iter(AllHostsIterator());
  while (!iter.IsAtEnd()) {
    if (iter.GetCurrentValue()->MayReuseHost() &&
        RenderProcessHostImpl::IsSuitableHost(iter.GetCurrentValue(),
                                              browser_context, site_url)) {
      suitable_renderers.push_back(iter.GetCurrentValue());
    }
    iter.Advance();
  }

  if (!suitable_renderers.empty()) {
    int suitable_count = static_cast<int>(suitable_renderers.size());
    int random_index = base::RandInt(0, suitable_count - 1);
    g_spare_render_process_host_manager.Get().DropSpareOnProcessCreation(
        suitable_renderers[random_index]);
    return suitable_renderers[random_index];
  }

  return nullptr;
}

Project: Chrome

size_t RenderProcessHost::GetMaxRendererProcessCount() {
  if (g_max_renderer_count_override)
    return g_max_renderer_count_override;

#if defined(OS_ANDROID)
  static const size_t kNumRendererSlots =
      ChildProcessLauncher::GetNumberOfRendererSlots();
  return kNumRendererSlots;
#endif
#if defined(OS_CHROMEOS)
  return 100;
#endif


  static size_t max_count = 0;
  if (!max_count) {
    const size_t kEstimatedWebContentsMemoryUsage =
#if defined(ARCH_CPU_64_BITS)
        60;  // In MB
#else
        40;  // In MB
#endif
    max_count = base::SysInfo::AmountOfPhysicalMemoryMB() / 2;
    max_count /= kEstimatedWebContentsMemoryUsage;

    const size_t kMinRendererProcessCount = 3;
    max_count = std::max(max_count, kMinRendererProcessCount);
    max_count = std::min(max_count, kMaxRendererProcessCount);
  }
  return max_count;
}

Project: Chrome

  RenderProcessHost* GetProcessHost(SiteInstance* site_instance,
                                    bool is_for_guests_only) {
    StoragePartitionImpl* default_partition =
        static_cast<StoragePartitionImpl*>(
            BrowserContext::GetDefaultStoragePartition(browser_context_));
    StoragePartitionImpl* partition = static_cast<StoragePartitionImpl*>(
        BrowserContext::GetStoragePartition(browser_context_, site_instance));

    if (partition != default_partition || is_for_guests_only) {
      RenderProcessHost* host = RenderProcessHostImpl::CreateRenderProcessHost(
          browser_context_, partition, site_instance, is_for_guests_only);
      host->SetIsNeverSuitableForReuse();
      return host;
    }

    if (host_)
      return host_;

    host_ = RenderProcessHostImpl::CreateOrUseSpareRenderProcessHost(
        browser_context_, partition, site_instance,
        false /* is for guests only */);
    host_->SetIsNeverSuitableForReuse();
    host_->AddObserver(this);

    return host_;
  }

Project: Chrome

RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSite(
    BrowserContext* browser_context,
    const GURL& url) {
  SiteProcessMap* map = GetSiteProcessMapForBrowserContext(browser_context);

  GURL site_url = SiteInstance::GetSiteForURL(browser_context, url);
  RenderProcessHost* host = map->FindProcess(site_url.possibly_invalid_spec());
  if (host && (!host->MayReuseHost() ||
               !IsSuitableHost(host, browser_context, site_url))) {
    RecordAction(
        base::UserMetricsAction("BindingsMismatch_GetProcessHostPerSite"));
    map->RemoveProcess(host);
    host = nullptr;
  }

  return host;
}

Project: Chrome

RenderProcessHost* RenderProcessHostImpl::GetProcessHostForSiteInstance(
    BrowserContext* browser_context,
    SiteInstanceImpl* site_instance) {
  const GURL site_url = site_instance->GetSiteURL();
  SiteInstanceImpl::ProcessReusePolicy process_reuse_policy =
      site_instance->process_reuse_policy();
  bool is_for_guests_only = site_url.SchemeIs(kGuestScheme);
  RenderProcessHost* render_process_host = nullptr;

  bool is_unmatched_service_worker = site_instance->is_for_service_worker();

  switch (process_reuse_policy) {
    case SiteInstanceImpl::ProcessReusePolicy::PROCESS_PER_SITE:
      render_process_host = GetProcessHostForSite(browser_context, site_url);
      break;
    case SiteInstanceImpl::ProcessReusePolicy::USE_DEFAULT_SUBFRAME_PROCESS:
      DCHECK(SiteIsolationPolicy::IsTopDocumentIsolationEnabled());
      DCHECK(!site_instance->is_for_service_worker());
      render_process_host = GetDefaultSubframeProcessHost(
          browser_context, site_instance, is_for_guests_only);
      break;
    case SiteInstanceImpl::ProcessReusePolicy::REUSE_PENDING_OR_COMMITTED_SITE:
      render_process_host =
          FindReusableProcessHostForSite(browser_context, site_url);
      UMA_HISTOGRAM_BOOLEAN(
          "SiteIsolation.ReusePendingOrCommittedSite.CouldReuse",
          render_process_host != nullptr);
      if (render_process_host)
        is_unmatched_service_worker = false;
      break;
    default:
      break;
  }

  if (!render_process_host &&
      !(process_reuse_policy == SiteInstanceImpl::ProcessReusePolicy::DEFAULT &&
        site_instance->is_for_service_worker())) {
    render_process_host = UnmatchedServiceWorkerProcessTracker::MatchWithSite(
        browser_context, site_url);
  }

  if (!render_process_host &&
      ShouldTryToUseExistingProcessHost(browser_context, site_url)) {
    render_process_host = GetExistingProcessHost(browser_context, site_url);
  }

  if (render_process_host &&
      !RenderProcessHostImpl::IsSuitableHost(render_process_host,
                                             browser_context, site_url)) {
    ChildProcessSecurityPolicyImpl* policy =
        ChildProcessSecurityPolicyImpl::GetInstance();
    base::debug::SetCrashKeyString(bad_message::GetRequestedSiteURLKey(),
                                   site_url.spec());
    base::debug::SetCrashKeyString(
        bad_message::GetKilledProcessOriginLockKey(),
        policy->GetOriginLock(render_process_host->GetID()).spec());
    CHECK(false) << "Unsuitable process reused for site " << site_url;
  }

  if (!render_process_host) {
    render_process_host = CreateOrUseSpareRenderProcessHost(
        browser_context, nullptr, site_instance, is_for_guests_only);
  }

  if (is_unmatched_service_worker) {
    UnmatchedServiceWorkerProcessTracker::Register(
        browser_context, render_process_host, site_url);
  }

  CHECK(render_process_host->InSameStoragePartition(
      BrowserContext::GetStoragePartition(browser_context, site_instance,
                                          false /* can_create */)));

  return render_process_host;
}

Project: Chrome

RenderProcessHostImpl::GetProcessResourceCoordinator() {
  if (process_resource_coordinator_)
    return process_resource_coordinator_.get();

  if (!resource_coordinator::IsResourceCoordinatorEnabled()) {
    process_resource_coordinator_ =
        std::make_unique<resource_coordinator::ProcessResourceCoordinator>(
            nullptr);
  } else {
    auto* connection = ServiceManagerConnection::GetForProcess();
    process_resource_coordinator_ =
        std::make_unique<resource_coordinator::ProcessResourceCoordinator>(
            connection ? connection->GetConnector() : nullptr);
  }
  return process_resource_coordinator_.get();
}

Project: Chrome

RenderProcessHostImpl::GetRendererAudioOutputStreamFactoryContext() {
  if (!audio_output_stream_factory_context_) {
    media::AudioManager* audio_manager =
        BrowserMainLoop::GetInstance()->audio_manager();
    MediaStreamManager* media_stream_manager =
        BrowserMainLoop::GetInstance()->media_stream_manager();
    media::AudioSystem* audio_system =
        BrowserMainLoop::GetInstance()->audio_system();
    audio_output_stream_factory_context_.reset(
        new RendererAudioOutputStreamFactoryContextImpl(
            GetID(), audio_system, audio_manager, media_stream_manager));
  }
  return audio_output_stream_factory_context_.get();
}

Project: Chrome

RenderProcessHostImpl::GetSharedBitmapAllocationNotifier() {
  return &shared_bitmap_allocation_notifier_impl_;
}

Project: Chrome

SiteProcessMap* GetSiteProcessMapForBrowserContext(BrowserContext* context) {
  DCHECK(context);
  SiteProcessMap* map = static_cast<SiteProcessMap*>(
      context->GetUserData(kSiteProcessMapKeyName));
  if (!map) {
    map = new SiteProcessMap();
    context->SetUserData(kSiteProcessMapKeyName, base::WrapUnique(map));
  }
  return map;
}

Project: Chrome

RenderProcessHostImpl::GetSpareRenderProcessHostForTesting() {
  return g_spare_render_process_host_manager.Get().spare_render_process_host();
}

Project: Chrome

  bool HasProcess(RenderProcessHost* process) {
    for (auto iter : map_) {
      std::map<ProcessID, Count>& counts_per_process = iter.second;
      for (auto iter_process : counts_per_process) {
        if (iter_process.first == process->GetID())
          return true;
      }
    }
    return false;
  }

Project: Chrome

  bool HasProcess(RenderProcessHost* host) const {
    int process_id = host->GetID();
    for (const auto& site_process_id : site_process_set_) {
      if (site_process_id.second == process_id)
        return true;
    }
    return false;
  }

Project: Chrome

bool RenderProcessHostImpl::HostHasNotBeenUsed() {
  return IsUnused() && listeners_.IsEmpty() && keep_alive_ref_count_ == 0 &&
         pending_views_ == 0;
}

Project: Chrome

void RenderProcessHostImpl::IncrementKeepAliveRefCount() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DCHECK(!is_keep_alive_ref_count_disabled_);
  ++keep_alive_ref_count_;
}

Project: Chrome

  void IncrementSiteProcessCount(const GURL& site_url,
                                 int render_process_host_id) {
    std::map<ProcessID, Count>& counts_per_process = map_[site_url];
    ++counts_per_process[render_process_host_id];

#ifndef NDEBUG
    RenderProcessHost* host = RenderProcessHost::FromID(render_process_host_id);
    if (!HasProcess(host))
      host->AddObserver(this);
#endif
  }

Project: Chrome

bool RenderProcessHostImpl::Init() {
  if (HasConnection())
    return true;

  is_dead_ = false;

  base::CommandLine::StringType renderer_prefix;
  const base::CommandLine& browser_command_line =
      *base::CommandLine::ForCurrentProcess();
  renderer_prefix =
      browser_command_line.GetSwitchValueNative(switches::kRendererCmdPrefix);

#if defined(OS_LINUX)
  int flags = renderer_prefix.empty() ? ChildProcessHost::CHILD_ALLOW_SELF
                                      : ChildProcessHost::CHILD_NORMAL;
#else
  int flags = ChildProcessHost::CHILD_NORMAL;
#endif

  base::FilePath renderer_path = ChildProcessHost::GetChildPath(flags);
  if (renderer_path.empty())
    return false;

  if (gpu_client_)
    gpu_client_->PreEstablishGpuChannel();

  sent_render_process_ready_ = false;

  if (!channel_)
    InitializeChannelProxy();
  DCHECK(broker_client_invitation_);

  channel_->Unpause(false /* flush */);

  GetContentClient()->browser()->RenderProcessWillLaunch(this);

#if !defined(OS_MACOSX)
  media::AudioManager::StartHangMonitorIfNeeded(
      BrowserThread::GetTaskRunnerForThread(BrowserThread::IO));
#endif  // !defined(OS_MACOSX)

#if defined(OS_ANDROID)
  static_cast<media::AudioManagerAndroid*>(media::AudioManager::Get())->
      InitializeIfNeeded();
#endif  // defined(OS_ANDROID)

  CreateMessageFilters();
  RegisterMojoInterfaces();

  if (run_renderer_in_process()) {
    DCHECK(g_renderer_main_thread_factory);
    in_process_renderer_.reset(
        g_renderer_main_thread_factory(InProcessChildThreadParams(
            BrowserThread::GetTaskRunnerForThread(BrowserThread::IO),
            broker_client_invitation_.get(),
            child_connection_->service_token())));

    base::Thread::Options options;
#if defined(OS_WIN) && !defined(OS_MACOSX)
    options.message_loop_type = base::MessageLoop::TYPE_UI;
#else
    options.message_loop_type = base::MessageLoop::TYPE_DEFAULT;
#endif
    OnProcessLaunched();  // Fake a callback that the process is ready.

    in_process_renderer_->StartWithOptions(options);

    g_in_process_thread = in_process_renderer_->message_loop();

    channel_->Flush();
  } else {
    std::unique_ptr<base::CommandLine> cmd_line =
        std::make_unique<base::CommandLine>(renderer_path);
    if (!renderer_prefix.empty())
      cmd_line->PrependWrapper(renderer_prefix);
    AppendRendererCommandLine(cmd_line.get());

    child_process_launcher_.reset(new ChildProcessLauncher(
        std::make_unique<RendererSandboxedProcessLauncherDelegate>(),
        std::move(cmd_line), GetID(), this,
        std::move(broker_client_invitation_),
        base::Bind(&RenderProcessHostImpl::OnMojoError, id_)));
    channel_->Pause();

    fast_shutdown_started_ = false;
  }

  if (!gpu_observer_registered_) {
    gpu_observer_registered_ = true;
    ui::GpuSwitchingManager::GetInstance()->AddObserver(this);
  }

  is_initialized_ = true;
  init_time_ = base::TimeTicks::Now();
  return true;
}

Project: Chrome

void RenderProcessHostImpl::InitializeChannelProxy() {
  scoped_refptr<base::SingleThreadTaskRunner> io_task_runner =
      BrowserThread::GetTaskRunnerForThread(BrowserThread::IO);

  service_manager::Connector* connector =
      BrowserContext::GetConnectorFor(browser_context_);
  if (!connector) {
    if (!ServiceManagerConnection::GetForProcess()) {
      ServiceManagerConnection::SetForProcess(ServiceManagerConnection::Create(
          mojo::MakeRequest(&test_service_), io_task_runner));
    }
    connector = ServiceManagerConnection::GetForProcess()->GetConnector();
  }

  broker_client_invitation_ =
      std::make_unique<mojo::edk::OutgoingBrokerClientInvitation>();
  service_manager::Identity child_identity(
      mojom::kRendererServiceName,
      BrowserContext::GetServiceUserIdFor(GetBrowserContext()),
      base::StringPrintf("%d_%d", id_, instance_id_++));
  child_connection_.reset(new ChildConnection(child_identity,
                                              broker_client_invitation_.get(),
                                              connector, io_task_runner));

  mojo::MessagePipe pipe;
  BindInterface(IPC::mojom::ChannelBootstrap::Name_, std::move(pipe.handle1));
  std::unique_ptr<IPC::ChannelFactory> channel_factory =
      IPC::ChannelMojo::CreateServerFactory(
          std::move(pipe.handle0), io_task_runner,
          base::ThreadTaskRunnerHandle::Get());

  content::BindInterface(this, &child_control_interface_);

  ResetChannelProxy();

#if defined(OS_ANDROID)
  if (GetContentClient()->UsingSynchronousCompositing()) {
    channel_ = IPC::SyncChannel::Create(this, io_task_runner.get(),
                                        base::ThreadTaskRunnerHandle::Get(),
                                        &never_signaled_);
  }
#endif  // OS_ANDROID
  if (!channel_)
    channel_.reset(new IPC::ChannelProxy(this, io_task_runner.get(),
                                         base::ThreadTaskRunnerHandle::Get()));
  channel_->Init(std::move(channel_factory), true /* create_pipe_now */);

  channel_->GetRemoteAssociatedInterface(&remote_route_provider_);
  channel_->GetRemoteAssociatedInterface(&renderer_interface_);

  channel_->Pause();
}

Project: Chrome

bool RenderProcessHostImpl::IsKeepAliveRefCountDisabled() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  return is_keep_alive_ref_count_disabled_;
}

Project: Chrome

bool RenderProcessHostImpl::IsProcessBackgrounded() const {
  return priority_.background;
}

Project: Chrome

bool RenderProcessHostImpl::IsSuitableHost(RenderProcessHost* host,
                                           BrowserContext* browser_context,
                                           const GURL& site_url) {
  if (run_renderer_in_process()) {
    DCHECK_EQ(host->GetBrowserContext(), browser_context)
        << " Single-process mode does not support multiple browser contexts.";
    return true;
  }

  if (host->GetBrowserContext() != browser_context)
    return false;

  if (host->IsForGuestsOnly())
    return false;

  StoragePartition* dest_partition =
      BrowserContext::GetStoragePartitionForSite(browser_context, site_url);
  if (!host->InSameStoragePartition(dest_partition))
    return false;

  auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
  if (policy->HasWebUIBindings(host->GetID()) !=
      WebUIControllerFactoryRegistry::GetInstance()->UseWebUIBindingsForURL(
          browser_context, site_url)) {
    return false;
  }

  auto lock_state = policy->CheckOriginLock(host->GetID(), site_url);
  if (lock_state !=
      ChildProcessSecurityPolicyImpl::CheckOriginLockResult::NO_LOCK) {
    if (lock_state !=
        ChildProcessSecurityPolicyImpl::CheckOriginLockResult::HAS_EQUAL_LOCK)
      return false;
  } else if (!host->IsUnused() && SiteInstanceImpl::ShouldLockToOrigin(
                                      browser_context, host, site_url)) {
    return false;
  }

  return GetContentClient()->browser()->IsSuitableHost(host, site_url);
}

Project: Chrome

bool RenderProcessHostImpl::IsUnused() {
  return is_unused_;
}

Project: Chrome

  static RenderProcessHost* MatchWithSite(BrowserContext* browser_context,
                                          const GURL& site_url) {
    if (!ShouldFindReusableProcessHostForSite(browser_context, site_url))
      return nullptr;

    UnmatchedServiceWorkerProcessTracker* tracker =
        static_cast<UnmatchedServiceWorkerProcessTracker*>(
            browser_context->GetUserData(
                kUnmatchedServiceWorkerProcessTrackerKey));
    if (!tracker)
      return nullptr;
    return tracker->TakeFreshestProcessForSite(site_url);
  }

Project: Chrome

  RenderProcessHost* MaybeTakeSpareRenderProcessHost(
      BrowserContext* browser_context,
      StoragePartition* partition,
      SiteInstance* site_instance,
      bool is_for_guests_only) {
    if (spare_render_process_host_ &&
        browser_context == matching_browser_context_ && !is_for_guests_only &&
        !partition) {
      partition =
          BrowserContext::GetStoragePartition(browser_context, site_instance);
    }

    if (!spare_render_process_host_ ||
        browser_context != matching_browser_context_ ||
        partition != matching_storage_partition_ || is_for_guests_only) {
      CleanupSpareRenderProcessHost();
      return nullptr;
    }

    CHECK(spare_render_process_host_->HostHasNotBeenUsed());
    RenderProcessHost* rph = spare_render_process_host_;
    DropSpareRenderProcessHost(spare_render_process_host_);
    return rph;
  }

Project: Chrome

void RenderProcessHostImpl::OnAec3Enabled() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);

  if (!aec3_set_callback_.is_null())
    std::move(aec3_set_callback_).Run(true, std::string());
}

Project: Chrome

void RenderProcessHostImpl::OnAssociatedInterfaceRequest(
    const std::string& interface_name,
    mojo::ScopedInterfaceEndpointHandle handle) {
  if (associated_interfaces_ &&
      associated_interfaces_->CanBindRequest(interface_name)) {
    associated_interfaces_->BindRequest(interface_name, std::move(handle));
  } else {
    LOG(ERROR) << "Request for unknown Channel-associated interface: "
               << interface_name;
  }
}

Project: Chrome

void RenderProcessHostImpl::OnChannelConnected(int32_t peer_pid) {
  channel_connected_ = true;
  if (IsReady()) {
    DCHECK(!sent_render_process_ready_);
    sent_render_process_ready_ = true;
    for (auto& observer : observers_)
      observer.RenderProcessReady(this);
  }

#if BUILDFLAG(IPC_MESSAGE_LOG_ENABLED)
  child_control_interface_->SetIPCLoggingEnabled(
      IPC::Logging::GetInstance()->Enabled());
#endif
}

Project: Chrome

void RenderProcessHostImpl::OnMediaStreamAdded() {
  ++media_stream_count_;
  UpdateProcessPriority();
}

Project: Chrome

void RenderProcessHostImpl::OnMediaStreamRemoved() {
  DCHECK_GT(media_stream_count_, 0);
  --media_stream_count_;
  UpdateProcessPriority();
}

Project: Chrome

void RenderProcessHostImpl::OnMojoError(int render_process_id,
                                        const std::string& error) {
  LOG(ERROR) << "Terminating render process for bad Mojo message: " << error;

  base::debug::ScopedCrashKeyString error_key_value(
      bad_message::GetMojoErrorCrashKey(), error);
  bad_message::ReceivedBadMessage(render_process_id,
                                  bad_message::RPH_MOJO_PROCESS_ERROR);
}

Project: Chrome

void RenderProcessHostImpl::OnRegisterAecDumpConsumer(int id) {
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::BindOnce(&RenderProcessHostImpl::RegisterAecDumpConsumerOnUIThread,
                     weak_factory_.GetWeakPtr(), id));
}

Project: Chrome

void RenderProcessHostImpl::OnUnregisterAecDumpConsumer(int id) {
  BrowserThread::PostTask(
      BrowserThread::UI, FROM_HERE,
      base::BindOnce(
          &RenderProcessHostImpl::UnregisterAecDumpConsumerOnUIThread,
          weak_factory_.GetWeakPtr(), id));
}

Project: Chrome

  void PostTask() {
    BrowserThread::PostTask(
        BrowserThread::UI, FROM_HERE,
        base::BindOnce(&RenderProcessHostIsReadyObserver::CallTask,
                       weak_factory_.GetWeakPtr()));
  }

Project: Chrome

void RenderProcessHost::PostTaskWhenProcessIsReady(base::OnceClosure task) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DCHECK(!task.is_null());
  new RenderProcessHostIsReadyObserver(this, std::move(task));
}

Project: Chrome

 void RenderProcessHostImpl::ProcessDied(bool already_dead,
                                        RendererClosedDetails* known_details) {

  DCHECK(!within_process_died_observer_);

  DCHECK(!deleting_soon_);

  base::TerminationStatus status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
  int exit_code = 0;
  if (known_details) {
    status = known_details->status;
    exit_code = known_details->exit_code;
  } else if (child_process_launcher_.get()) {
    status = child_process_launcher_->GetChildTerminationStatus(already_dead,
                                                                &exit_code);
    if (already_dead && status == base::TERMINATION_STATUS_STILL_RUNNING) {
      status = base::TERMINATION_STATUS_PROCESS_CRASHED;
    }
  }

  RendererClosedDetails details(status, exit_code);

  child_process_launcher_.reset();
  is_dead_ = true;
  if (route_provider_binding_.is_bound())
    route_provider_binding_.Close();
  associated_interfaces_.reset();
  process_resource_coordinator_.reset();
  ResetChannelProxy();

  UpdateProcessPriority();

  within_process_died_observer_ = true;
  NotificationService::current()->Notify(
      NOTIFICATION_RENDERER_PROCESS_CLOSED, Source<RenderProcessHost>(this),
      Details<RendererClosedDetails>(&details));
  for (auto& observer : observers_)
    observer.RenderProcessExited(this, status, exit_code);
  within_process_died_observer_ = false;

  RemoveUserData(kSessionStorageHolderKey);

  base::IDMap<IPC::Listener*>::iterator iter(&listeners_);
  while (!iter.IsAtEnd()) {
    iter.GetCurrentValue()->OnMessageReceived(FrameHostMsg_RenderProcessGone(
        iter.GetCurrentKey(), static_cast<int>(status), exit_code));
    iter.Advance();
  }

  EnableSendQueue();

  if (delayed_cleanup_needed_)
    Cleanup();

  frame_sink_provider_.Unbind();
  if (renderer_host_binding_.is_bound())
    renderer_host_binding_.Unbind();

  compositing_mode_reporter_.reset();

  shared_bitmap_allocation_notifier_impl_.ChildDied();

  HistogramController::GetInstance()->NotifyChildDied<RenderProcessHost>(this);
}

Project: Chrome

void RenderProcessHostImpl::PropagateBrowserCommandLineToRenderer(
    const base::CommandLine& browser_cmd,
    base::CommandLine* renderer_cmd) {
  static const char* const kSwitchNames[] = {
    service_manager::switches::kDisableInProcessStackTraces,
    service_manager::switches::kDisableSeccompFilterSandbox,
    switches::kAgcStartupMinVolume,
    switches::kAecRefinedAdaptiveFilter,
    switches::kAllowLoopbackInPeerConnection,
    switches::kAndroidFontsPath,
    switches::kAudioBufferSize,
    switches::kAutoplayPolicy,
    switches::kBlinkSettings,
    switches::kDefaultTileWidth,
    switches::kDefaultTileHeight,
    switches::kDisable2dCanvasImageChromium,
    switches::kDisableAcceleratedJpegDecoding,
    switches::kDisableAcceleratedVideoDecode,
    switches::kDisableBackgroundTimerThrottling,
    switches::kDisableBreakpad,
    switches::kDisableCompositorUkmForTests,
    switches::kDisablePreferCompositingToLCDText,
    switches::kDisableDatabases,
    switches::kDisableDistanceFieldText,
    switches::kDisableFileSystem,
    switches::kDisableGpuMemoryBufferVideoFrames,
    switches::kDisableGpuVsync,
    switches::kDisableLowResTiling,
    switches::kDisableHistogramCustomizer,
    switches::kDisableLCDText,
    switches::kDisableLogging,
    switches::kDisableMediaSuspend,
    switches::kDisableNotifications,
    switches::kDisableOriginTrialControlledBlinkFeatures,
    switches::kDisablePepper3DImageChromium,
    switches::kDisablePermissionsAPI,
    switches::kDisablePresentationAPI,
    switches::kDisableRGBA4444Textures,
    switches::kDisableRTCSmoothnessAlgorithm,
    switches::kDisableSharedWorkers,
    switches::kDisableSkiaRuntimeOpts,
    switches::kDisableSpeechAPI,
    switches::kDisableThreadedCompositing,
    switches::kDisableThreadedScrolling,
    switches::kDisableTouchAdjustment,
    switches::kDisableTouchDragDrop,
    switches::kDisableV8IdleTasks,
    switches::kDisableWebGLImageChromium,
    switches::kDomAutomationController,
    switches::kEnableAutomation,
    switches::kEnableDistanceFieldText,
    switches::kEnableExperimentalCanvasFeatures,
    switches::kEnableExperimentalWebPlatformFeatures,
    switches::kEnableHeapProfiling,
    switches::kEnableGPUClientLogging,
    switches::kEnableGpuClientTracing,
    switches::kEnableGpuMemoryBufferVideoFrames,
    switches::kEnableGPUServiceLogging,
    switches::kEnableLowResTiling,
    switches::kEnableMediaSuspend,
    switches::kEnableInbandTextTracks,
    switches::kEnableLCDText,
    switches::kEnableLogging,
    switches::kEnableNetworkInformationDownlinkMax,
    switches::kEnableOOPRasterization,
    switches::kEnablePluginPlaceholderTesting,
    switches::kEnablePreciseMemoryInfo,
    switches::kEnablePrintBrowser,
    switches::kEnablePreferCompositingToLCDText,
    switches::kEnableRGBA4444Textures,
    switches::kEnableSkiaBenchmarking,
    switches::kEnableSlimmingPaintV175,
    switches::kEnableSlimmingPaintV2,
    switches::kEnableThreadedCompositing,
    switches::kEnableTouchDragDrop,
    switches::kEnableUseZoomForDSF,
    switches::kEnableViewport,
    switches::kEnableVtune,
    switches::kEnableWebGLDraftExtensions,
    switches::kEnableWebGLImageChromium,
    switches::kEnableWebVR,
    switches::kExplicitlyAllowedPorts,
    switches::kForceColorProfile,
    switches::kForceDeviceScaleFactor,
    switches::kForceGpuMemAvailableMb,
    switches::kForceGpuRasterization,
    switches::kForceOverlayFullscreenVideo,
    switches::kForceVideoOverlays,
    switches::kFullMemoryCrashReport,
    switches::kIPCConnectionTimeout,
    switches::kJavaScriptFlags,
    switches::kLoggingLevel,
    switches::kMaxUntiledLayerWidth,
    switches::kMaxUntiledLayerHeight,
    switches::kDisableMojoLocalStorage,
    switches::kMSEAudioBufferSizeLimit,
    switches::kMSEVideoBufferSizeLimit,
    switches::kNoReferrers,
    switches::kNoSandbox,
    switches::kNoZygote,
    switches::kOverridePluginPowerSaverForTesting,
    switches::kPassiveListenersDefault,
    switches::kPpapiInProcess,
    switches::kReducedReferrerGranularity,
    switches::kRegisterPepperPlugins,
    switches::kRendererStartupDialog,
    switches::kRootLayerScrolls,
    switches::kShowPaintRects,
    switches::kStatsCollectionController,
    switches::kTestType,
    switches::kTouchEventFeatureDetection,
    switches::kTouchTextSelectionStrategy,
    switches::kTraceConfigFile,
    switches::kTraceToConsole,
    switches::kUseFakeUIForMediaStream,
    switches::kUseGL,
    switches::kUseGpuInTests,
    switches::kUseMobileUserAgent,
    switches::kV,
    switches::kVideoThreads,
    switches::kVideoUnderflowThresholdMs,
    switches::kVModule,
    cc::switches::kDisableCompositedAntialiasing,
    cc::switches::kDisableThreadedAnimation,
    cc::switches::kEnableGpuBenchmarking,
    cc::switches::kEnableLayerLists,
    cc::switches::kEnableTileCompression,
    cc::switches::kShowCompositedLayerBorders,
    cc::switches::kShowFPSCounter,
    cc::switches::kShowLayerAnimationBounds,
    cc::switches::kShowPropertyChangedRects,
    cc::switches::kShowScreenSpaceRects,
    cc::switches::kShowSurfaceDamageRects,
    cc::switches::kSlowDownRasterScaleFactor,
    cc::switches::kBrowserControlsHideThreshold,
    cc::switches::kBrowserControlsShowThreshold,
    cc::switches::kRunAllCompositorStagesBeforeDraw,
    switches::kDisableSurfaceReferences,
    switches::kEnableSurfaceSynchronization,

#if BUILDFLAG(ENABLE_PLUGINS)
    switches::kEnablePepperTesting,
#endif
#if BUILDFLAG(ENABLE_RUNTIME_MEDIA_RENDERER_SELECTION)
    switches::kDisableMojoRenderer,
#endif
#if BUILDFLAG(ENABLE_WEBRTC)
    switches::kDisableWebRtcHWDecoding,
    switches::kDisableWebRtcHWEncoding,
    switches::kEnableWebRtcSrtpAesGcm,
    switches::kEnableWebRtcSrtpEncryptedHeaders,
    switches::kEnableWebRtcStunOrigin,
    switches::kEnforceWebRtcIPPermissionCheck,
    switches::kWebRtcMaxCaptureFramerate,
#endif
    switches::kEnableLowEndDeviceMode,
    switches::kDisableLowEndDeviceMode,
    switches::kDisallowNonExactResourceReuse,
#if defined(OS_ANDROID)
    switches::kDisableMediaSessionAPI,
    switches::kMadviseRandomExecutableCode,
    switches::kRendererWaitForJavaDebugger,
#endif
#if defined(OS_MACOSX)
    switches::kEnableSandboxLogging,
#endif
#if defined(OS_WIN)
    service_manager::switches::kDisableWin32kLockDown,
    switches::kEnableWin7WebRtcHWH264Decoding,
    switches::kTrySupportedChannelLayouts,
    switches::kTraceExportEventsToETW,
#endif
#if defined(USE_OZONE)
    switches::kOzonePlatform,
#endif
#if defined(ENABLE_IPC_FUZZER)
    switches::kIpcDumpDirectory,
    switches::kIpcFuzzerTestcase,
#endif
#if BUILDFLAG(ENABLE_MUS)
    switches::kMus,
    switches::kMusHostingViz,
#endif
  };
  renderer_cmd->CopySwitchesFrom(browser_cmd, kSwitchNames,
                                 arraysize(kSwitchNames));

  BrowserChildProcessHostImpl::CopyFeatureAndFieldTrialFlags(renderer_cmd);

  if (browser_cmd.HasSwitch(switches::kTraceStartup) &&
      BrowserMainLoop::GetInstance()->is_tracing_startup_for_duration()) {
    renderer_cmd->AppendSwitchASCII(
        switches::kTraceStartup,
        browser_cmd.GetSwitchValueASCII(switches::kTraceStartup));
  }

#if BUILDFLAG(ENABLE_WEBRTC)
  if (!has_done_stun_trials &&
      browser_cmd.HasSwitch(switches::kWebRtcStunProbeTrialParameter)) {
    has_done_stun_trials = true;
    renderer_cmd->AppendSwitchASCII(
        switches::kWebRtcStunProbeTrialParameter,
        browser_cmd.GetSwitchValueASCII(
            switches::kWebRtcStunProbeTrialParameter));
  }
#endif

  if (GetBrowserContext()->IsOffTheRecord() &&
      !browser_cmd.HasSwitch(switches::kDisableDatabases)) {
    renderer_cmd->AppendSwitch(switches::kDisableDatabases);
  }

#if !defined(OS_ANDROID) && !defined(OS_CHROMEOS)
#if !BUILDFLAG(ENABLE_MUS)
  if (ImageTransportFactory::GetInstance()->IsGpuCompositingDisabled())
    renderer_cmd->AppendSwitch(switches::kDisableGpuCompositing);
#else
#endif
#endif

  if (browser_cmd.HasSwitch(switches::kWaitForDebuggerChildren)) {
    std::string value =
        browser_cmd.GetSwitchValueASCII(switches::kWaitForDebuggerChildren);
    if (value.empty() || value == switches::kRendererProcess) {
      renderer_cmd->AppendSwitch(switches::kWaitForDebugger);
    }
  }

  DCHECK(child_connection_);
  renderer_cmd->AppendSwitchASCII(service_manager::switches::kServicePipeToken,
                                  child_connection_->service_token());

#if defined(OS_WIN) && !defined(OFFICIAL_BUILD)
  if (renderer_cmd->HasSwitch(switches::kRendererStartupDialog) &&
      !renderer_cmd->HasSwitch(switches::kNoSandbox)) {
    renderer_cmd->AppendSwitch(switches::kNoSandbox);
  }
#endif

  CopyFeatureSwitch(browser_cmd, renderer_cmd, switches::kEnableBlinkFeatures);
  CopyFeatureSwitch(browser_cmd, renderer_cmd, switches::kDisableBlinkFeatures);
}

Project: Chrome

void RenderProcessHostImpl::PurgeAndSuspend() {
  GetRendererInterface()->ProcessPurgeAndSuspend();
}

Project: Chrome

  static void Register(BrowserContext* browser_context,
                       RenderProcessHost* render_process_host,
                       const GURL& site_url) {
    DCHECK(!site_url.is_empty());
    if (!ShouldTrackProcessForSite(browser_context, render_process_host,
                                   site_url))
      return;

    UnmatchedServiceWorkerProcessTracker* tracker =
        static_cast<UnmatchedServiceWorkerProcessTracker*>(
            browser_context->GetUserData(
                kUnmatchedServiceWorkerProcessTrackerKey));
    if (!tracker) {
      tracker = new UnmatchedServiceWorkerProcessTracker();
      browser_context->SetUserData(kUnmatchedServiceWorkerProcessTrackerKey,
                                   base::WrapUnique(tracker));
    }
    tracker->RegisterProcessForSite(render_process_host, site_url);
  }

Project: Chrome

void RenderProcessHostImpl::RegisterAecDumpConsumerOnUIThread(int id) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  aec_dump_consumers_.push_back(id);

  WebRTCInternals* webrtc_internals = WebRTCInternals::GetInstance();
  if (webrtc_internals->IsAudioDebugRecordingsEnabled()) {
    base::FilePath file_with_extensions = GetAecDumpFilePathWithExtensions(
        webrtc_internals->GetAudioDebugRecordingsFilePath());
    EnableAecDumpForId(file_with_extensions, id);
  }
}

Project: Chrome

  void RegisterProcess(const std::string& site, RenderProcessHost* process) {
    SiteToProcessMap::iterator i = map_.find(site);
    if (i == map_.end())
      map_[site] = process;
  }

Project: Chrome

  void RegisterProcessForSite(RenderProcessHost* host, const GURL& site_url) {
    if (!HasProcess(host))
      host->AddObserver(this);
    site_process_set_.insert(SiteProcessIDPair(site_url, host->GetID()));
  }

Project: Chrome

void RenderProcessHostImpl::ReleaseOnCloseACK(
    RenderProcessHost* host,
    const SessionStorageNamespaceMap& sessions,
    int view_route_id) {
  DCHECK(host);
  if (sessions.empty())
    return;
  SessionStorageHolder* holder = static_cast<SessionStorageHolder*>(
      host->GetUserData(kSessionStorageHolderKey));
  if (!holder) {
    holder = new SessionStorageHolder();
    host->SetUserData(kSessionStorageHolderKey, base::WrapUnique(holder));
  }
  holder->Hold(sessions, view_route_id);
}

Project: Chrome

void RenderProcessHostImpl::RemoveExpectedNavigationToSite(
    BrowserContext* browser_context,
    RenderProcessHost* render_process_host,
    const GURL& site_url) {
  if (!ShouldTrackProcessForSite(browser_context, render_process_host,
                                 site_url))
    return;

  SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>(
      browser_context->GetUserData(kPendingSiteProcessCountTrackerKey));
  if (!tracker) {
    tracker = new SiteProcessCountTracker();
    browser_context->SetUserData(kPendingSiteProcessCountTrackerKey,
                                 base::WrapUnique(tracker));
  }
  tracker->DecrementSiteProcessCount(site_url, render_process_host->GetID());
}

Project: Chrome

void RenderProcessHostImpl::RemoveFrameWithSite(
    BrowserContext* browser_context,
    RenderProcessHost* render_process_host,
    const GURL& site_url) {
  if (!ShouldTrackProcessForSite(browser_context, render_process_host,
                                 site_url))
    return;

  SiteProcessCountTracker* tracker = static_cast<SiteProcessCountTracker*>(
      browser_context->GetUserData(kCommittedSiteProcessCountTrackerKey));
  if (!tracker) {
    tracker = new SiteProcessCountTracker();
    browser_context->SetUserData(kCommittedSiteProcessCountTrackerKey,
                                 base::WrapUnique(tracker));
  }
  tracker->DecrementSiteProcessCount(site_url, render_process_host->GetID());
}

Project: Chrome

void RenderProcessHostImpl::RemovePendingView() {
  DCHECK(pending_views_);
  pending_views_--;
  UpdateProcessPriority();
}

Project: Chrome

void RenderProcessHostImpl::RemoveWidget(RenderWidgetHost* widget) {
  RenderWidgetHostImpl* widget_impl =
      static_cast<RenderWidgetHostImpl*>(widget);
  widgets_.erase(widget_impl);

#if defined(OS_ANDROID)
  ChildProcessImportance importance = widget_impl->importance();
  DCHECK(widget_importance_counts_[static_cast<size_t>(importance)]);
  widget_importance_counts_[static_cast<size_t>(importance)]--;
  UpdateProcessPriority();
#endif
}

Project: Chrome

RenderProcessHostImpl::RenderProcessHostImpl(
    BrowserContext* browser_context,
    StoragePartitionImpl* storage_partition_impl,
    bool is_for_guests_only)
    : fast_shutdown_started_(false),
      deleting_soon_(false),
#ifndef NDEBUG
      is_self_deleted_(false),
#endif
      pending_views_(0),
      keep_alive_ref_count_(0),
      is_keep_alive_ref_count_disabled_(false),
      route_provider_binding_(this),
      visible_widgets_(0),
      priority_({
            kLaunchingProcessIsBackgrounded,
            kLaunchingProcessIsBoostedForPendingView,
#if defined(OS_ANDROID)
            ChildProcessImportance::NORMAL,
#endif
      }),

Project: Chrome

  RenderProcessHostIsReadyObserver(RenderProcessHost* render_process_host,
                                   base::OnceClosure task)
      : render_process_host_(render_process_host),
        task_(std::move(task)),
        weak_factory_(this) {
    render_process_host_->AddObserver(this);
    if (render_process_host_->IsReady())
      PostTask();
  }

Project: Chrome

void RenderProcessHostImpl::Resume() {}

Project: Chrome

void RenderProcessHostImpl::SetCreateStoragePartitionServiceFunction(
    CreateStoragePartitionServiceFunction function) {
  g_create_storage_partition = function;
}

Project: Chrome

void RenderProcessHostImpl::SetEchoCanceller3(
    bool enable,
    base::OnceCallback<void(bool, const std::string&)> callback) {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
  DCHECK(!callback.is_null());

  if (!aec3_set_callback_.is_null()) {
    MediaStreamManager::SendMessageToNativeLog("RPHI: Failed to set AEC3");
    BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
                            base::BindOnce(std::move(callback), false,
                                           "Operation already in progress"));
    return;
  }

  aec3_set_callback_ = std::move(callback);
  Send(new AudioProcessingMsg_EnableAec3(enable));
}

Project: Chrome

void RenderProcessHostImpl::SetIgnoreInputEvents(bool ignore_input_events) {
  if (ignore_input_events == ignore_input_events_)
    return;

  ignore_input_events_ = ignore_input_events;
  for (auto* widget : widgets_) {
    widget->ProcessIgnoreInputEventsChanged(ignore_input_events);
  }
}

Project: Chrome

void RenderProcessHostImpl::SetIsUsed() {
  is_unused_ = false;
}

Project: Chrome

bool ShouldTrackProcessForSite(BrowserContext* browser_context,
                               RenderProcessHost* render_process_host,
                               const GURL& site_url) {
  if (site_url.is_empty())
    return false;

  return ShouldUseSiteProcessTracking(
      browser_context, render_process_host->GetStoragePartition(), site_url);
}

Project: Chrome

bool RenderProcessHost::ShouldTryToUseExistingProcessHost(
    BrowserContext* browser_context,
    const GURL& url) {
  if (run_renderer_in_process())
    return true;

  if (g_all_hosts.Get().size() >= GetMaxRendererProcessCount())
    return true;

  return GetContentClient()->browser()->ShouldTryToUseExistingProcessHost(
      browser_context, url);
}

Project: Chrome

bool ShouldUseSiteProcessTracking(BrowserContext* browser_context,
                                  StoragePartition* dest_partition,
                                  const GURL& site_url) {
  StoragePartition* default_partition =
      BrowserContext::GetDefaultStoragePartition(browser_context);
  if (dest_partition != default_partition)
    return false;

  return true;
}

Project: Chrome

void RenderProcessHostImpl::ShutdownForBadMessage(
    CrashReportMode crash_report_mode) {
  base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
  if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
    return;

  if (run_renderer_in_process()) {
    CHECK(false);
  }

  Shutdown(RESULT_CODE_KILLED_BAD_MESSAGE, false);

  if (crash_report_mode == CrashReportMode::GENERATE_CRASH_DUMP) {
    auto* policy = ChildProcessSecurityPolicyImpl::GetInstance();
    base::debug::SetCrashKeyString(bad_message::GetKilledProcessOriginLockKey(),
                                   policy->GetOriginLock(GetID()).spec());

    std::string site_isolation_mode;
    if (SiteIsolationPolicy::UseDedicatedProcessesForAllSites())
      site_isolation_mode += "spp ";
    if (SiteIsolationPolicy::IsTopDocumentIsolationEnabled())
      site_isolation_mode += "tdi ";
    if (SiteIsolationPolicy::AreIsolatedOriginsEnabled())
      site_isolation_mode += "io ";

    static auto* isolation_mode_key = base::debug::AllocateCrashKeyString(
        "site_isolation_mode", base::debug::CrashKeySize::Size32);
    base::debug::SetCrashKeyString(isolation_mode_key, site_isolation_mode);

    base::debug::DumpWithoutCrashing();
  }

  BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
      PROCESS_TYPE_RENDERER);
}

Project: Chrome

void RenderProcessHostImpl::ShutdownRequest() {
  for (auto& observer : observers_) {
    observer.RenderProcessShutdownRequested(this);
  }

  if (pending_views_ || run_renderer_in_process() || GetActiveViewCount() > 0) {
    return;
  }

  for (auto& observer : observers_) {
    observer.RenderProcessWillExit(this);
  }
  child_control_interface_->ProcessShutdown();
}

Project: Chrome

  SiteProcessCountTracker() {}

Project: Chrome

  SpareRenderProcessHostManager() {}

Project: Chrome

  RenderProcessHost* TakeFreshestProcessForSite(const GURL& site_url) {
    RenderProcessHost* host = FindFreshestProcessForSite(site_url);
    if (!host)
      return nullptr;

    if (!host->MayReuseHost() || !RenderProcessHostImpl::IsSuitableHost(
                                     host, host->GetBrowserContext(), site_url))
      return nullptr;

    site_process_set_.erase(SiteProcessIDPair(site_url, host->GetID()));
    if (!HasProcess(host))
      host->RemoveObserver(this);
    return host;
  }

Project: Chrome

  UnmatchedServiceWorkerProcessTracker() {}

Project: Chrome

void RenderProcessHostImpl::UpdateProcessPriority() {
  if (!run_renderer_in_process() && (!child_process_launcher_.get() ||
                                     child_process_launcher_->IsStarting())) {
    priority_.background = kLaunchingProcessIsBackgrounded;
    priority_.boost_for_pending_views =
        kLaunchingProcessIsBoostedForPendingView;
    return;
  }

  const ChildProcessLauncherPriority priority = {
    visible_widgets_ == 0 && media_stream_count_ == 0 &&
        !base::CommandLine::ForCurrentProcess()->HasSwitch(
            switches::kDisableRendererBackgrounding),
    !!pending_views_,
#if defined(OS_ANDROID)
    ComputeEffectiveImportance(),
#endif
  };

  const bool should_background_changed =
      priority_.background != priority.background;
  if (priority_ == priority)
    return;

  TRACE_EVENT2("renderer_host", "RenderProcessHostImpl::UpdateProcessPriority",
               "should_background", priority.background, "has_pending_views",
               priority.boost_for_pending_views);
  priority_ = priority;

#if defined(OS_WIN)
  if (GetModuleHandle(L"cbstext.dll"))
    return;
#endif  // OS_WIN

  if (!run_renderer_in_process()) {
    DCHECK(child_process_launcher_.get());
    DCHECK(!child_process_launcher_->IsStarting());
    child_process_launcher_->SetProcessPriority(priority_);
  }

  if (should_background_changed) {
    GetRendererInterface()->SetProcessBackgrounded(priority.background);
  }
}

Project: Chrome

void RenderProcessHostImpl::UpdateWidgetImportance(
    ChildProcessImportance old_value,
    ChildProcessImportance new_value) {
  DCHECK_NE(old_value, new_value);
  DCHECK(widget_importance_counts_[static_cast<size_t>(old_value)]);
  widget_importance_counts_[static_cast<size_t>(old_value)]--;
  widget_importance_counts_[static_cast<size_t>(new_value)]++;
  UpdateProcessPriority();
}

Project: Chrome

  void WarmupSpareRenderProcessHost(BrowserContext* browser_context) {
    StoragePartitionImpl* current_partition =
        static_cast<StoragePartitionImpl*>(
            BrowserContext::GetStoragePartition(browser_context, nullptr));

    if (spare_render_process_host_ &&
        matching_browser_context_ == browser_context &&
        matching_storage_partition_ == current_partition)
      return;  // Nothing to warm up.

    CleanupSpareRenderProcessHost();

    if (RenderProcessHost::run_renderer_in_process() ||
        g_all_hosts.Get().size() >=
            RenderProcessHostImpl::GetMaxRendererProcessCount())
      return;

    matching_browser_context_ = browser_context;
    matching_storage_partition_ = current_partition;

    spare_render_process_host_ = RenderProcessHostImpl::CreateRenderProcessHost(
        browser_context, current_partition, nullptr,
        false /* is_for_guests_only */);
    spare_render_process_host_->AddObserver(this);
    spare_render_process_host_->Init();
  }

Project: Chrome

void RenderProcessHost::WarmupSpareRenderProcessHost(
    content::BrowserContext* browser_context) {
  g_spare_render_process_host_manager.Get().WarmupSpareRenderProcessHost(
      browser_context);
}

Project: Chrome

void RenderProcessHostImpl::WidgetHidden() {
  if (visible_widgets_ == 0)
    return;

  --visible_widgets_;
  if (visible_widgets_ == 0) {
    UpdateProcessPriority();
  }
}

Project: Chrome

void RenderProcessHostImpl::WidgetRestored() {
  visible_widgets_++;
  UpdateProcessPriority();
}

Project: Chrome

void RenderProcessHostImpl::set_render_process_host_factory(
    const RenderProcessHostFactory* rph_factory) {
  g_render_process_host_factory_ = rph_factory;
}

Project: Chrome

  RenderProcessHost* spare_render_process_host() {
    return spare_render_process_host_;
  }

Project: Chrome

RenderProcessHostImpl::~RenderProcessHostImpl() {
  DCHECK_CURRENTLY_ON(BrowserThread::UI);
#ifndef NDEBUG
  DCHECK(is_self_deleted_)
      << "RenderProcessHostImpl is destroyed by something other than itself";
#endif

  in_process_renderer_.reset();

  ChildProcessSecurityPolicyImpl::GetInstance()->Remove(GetID());

  if (gpu_observer_registered_) {
    ui::GpuSwitchingManager::GetInstance()->RemoveObserver(this);
    gpu_observer_registered_ = false;
  }

  is_dead_ = true;

  UnregisterHost(GetID());

  if (!base::CommandLine::ForCurrentProcess()->HasSwitch(
          switches::kDisableGpuShaderDiskCache)) {
    BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
                            base::BindOnce(&RemoveShaderInfo, GetID()));
  }
}

Project: Chrome

void MojoAudioInputIPC::CloseStream() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  delegate_ = nullptr;
  if (factory_client_binding_.is_bound())
    factory_client_binding_.Unbind();
  if (stream_client_binding_.is_bound())
    stream_client_binding_.Unbind();
  stream_.reset();
}

Project: Chrome

MojoAudioInputIPC::MojoAudioInputIPC(StreamCreatorCB stream_creator)
    : stream_creator_(std::move(stream_creator)),
      stream_client_binding_(this),
      factory_client_binding_(this),
      weak_factory_(this) {
  DETACH_FROM_SEQUENCE(sequence_checker_);
  DCHECK(stream_creator_);
}

Project: Chrome

void MojoAudioInputIPC::OnError() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(delegate_);
  delegate_->OnError();
}

Project: Chrome

void MojoAudioInputIPC::RecordStream() {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(stream_.is_bound());
  stream_->Record();
}

Project: Chrome

void MojoAudioInputIPC::SetVolume(double volume) {
  DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  DCHECK(stream_.is_bound());
  stream_->SetVolume(volume);
}

Project: Chrome

bool MojoAudioOutputIPC::AuthorizationRequested() {
  return stream_provider_.is_bound();
}

Project: Chrome

void MojoAudioOutputIPC::CloseStream() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  stream_provider_.reset();
  stream_.reset();
  binding_.Close();
  delegate_ = nullptr;

  weak_factory_.InvalidateWeakPtrs();
}

Project: Chrome

void MojoAudioOutputIPC::CreateStream(media::AudioOutputIPCDelegate* delegate,
                                      const media::AudioParameters& params) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(delegate);
  DCHECK(!StreamCreationRequested());
  if (!AuthorizationRequested()) {
    DCHECK(!delegate_);
    delegate_ = delegate;
    if (!DoRequestDeviceAuthorization(
            0, media::AudioDeviceDescription::kDefaultDeviceId,
            base::BindOnce(&TrivialAuthorizedCallback))) {
      return;
    }
  }

  DCHECK_EQ(delegate_, delegate);
  media::mojom::AudioOutputStreamClientPtr client_ptr;
  binding_.Bind(mojo::MakeRequest(&client_ptr));
  stream_provider_->Acquire(mojo::MakeRequest(&stream_), std::move(client_ptr),
                            params,
                            base::BindOnce(&MojoAudioOutputIPC::StreamCreated,
                                           base::Unretained(this)));

}

Project: Chrome

bool MojoAudioOutputIPC::DoRequestDeviceAuthorization(
    int session_id,
    const std::string& device_id,
    AuthorizationCB callback) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  auto* factory = factory_accessor_.Run();
  if (!factory) {
    LOG(ERROR) << "MojoAudioOutputIPC failed to acquire factory";

    callback.Reset();
    return false;
  }

  static_assert(sizeof(int) == sizeof(int32_t),
                "sizeof(int) == sizeof(int32_t)");
  factory->RequestDeviceAuthorization(MakeProviderRequest(), session_id,
                                      device_id, std::move(callback));
  return true;
}

Project: Chrome

MojoAudioOutputIPC::MakeProviderRequest() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(!AuthorizationRequested());
  media::mojom::AudioOutputStreamProviderRequest request =
      mojo::MakeRequest(&stream_provider_);

  return request;
}

Project: Chrome

MojoAudioOutputIPC::MojoAudioOutputIPC(FactoryAccessorCB factory_accessor)
    : factory_accessor_(std::move(factory_accessor)),
      binding_(this),
      weak_factory_(this) {
  DETACH_FROM_THREAD(thread_checker_);
}

Project: Chrome

void MojoAudioOutputIPC::OnError() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(delegate_);
  delegate_->OnError();
}

Project: Chrome

void MojoAudioOutputIPC::PauseStream() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(stream_.is_bound());
  stream_->Pause();
}

Project: Chrome

void MojoAudioOutputIPC::PlayStream() {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(stream_.is_bound());
  stream_->Play();
}

Project: Chrome

void MojoAudioOutputIPC::ReceivedDeviceAuthorization(
    media::OutputDeviceStatus status,
    const media::AudioParameters& params,
    const std::string& device_id) const {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(delegate_);
  delegate_->OnDeviceAuthorized(status, params, device_id);
}

Project: Chrome

void MojoAudioOutputIPC::RequestDeviceAuthorization(
    media::AudioOutputIPCDelegate* delegate,
    int session_id,
    const std::string& device_id,
    const url::Origin& security_origin) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(delegate);
  DCHECK(!delegate_);
  DCHECK(!AuthorizationRequested());
  DCHECK(!StreamCreationRequested());
  delegate_ = delegate;

  DoRequestDeviceAuthorization(
      session_id, device_id,
      mojo::WrapCallbackWithDefaultInvokeIfNotRun(
          base::BindOnce(&MojoAudioOutputIPC::ReceivedDeviceAuthorization,
                         weak_factory_.GetWeakPtr()),
          media::OutputDeviceStatus::OUTPUT_DEVICE_STATUS_ERROR_INTERNAL,
          media::AudioParameters::UnavailableDeviceParams(), std::string()));
}

Project: Chrome

void MojoAudioOutputIPC::SetVolume(double volume) {
  DCHECK_CALLED_ON_VALID_THREAD(thread_checker_);
  DCHECK(stream_.is_bound());
  stream_->SetVolume(volume);
}

Project: Chrome

bool MojoAudioOutputIPC::StreamCreationRequested() {
  return stream_.is_bound();
}

Project: Chrome

void TrivialAuthorizedCallback(media::OutputDeviceStatus,
                               const media::AudioParameters&,
                               const std::string&) {}

Project: Chrome

MojoAudioOutputIPC::~MojoAudioOutputIPC() {
  DCHECK(!AuthorizationRequested() && !StreamCreationRequested())
      << "CloseStream must be called before destructing the AudioOutputIPC";
}

Project: Chrome

  ClientBuffer(std::unique_ptr<base::SharedMemory> buffer, size_t buffer_size)
      : buffer_(std::move(buffer)), buffer_size_(buffer_size) {}

Project: Chrome

void VideoCaptureImpl::DidFinishConsumingFrame(
    const media::VideoFrameMetadata* metadata,
    BufferFinishedCallback callback_to_io_thread) {
  double consumer_resource_utilization = -1.0;
  if (!metadata->GetDouble(media::VideoFrameMetadata::RESOURCE_UTILIZATION,
                           &consumer_resource_utilization)) {
    consumer_resource_utilization = -1.0;
  }
  std::move(callback_to_io_thread).Run(consumer_resource_utilization);
}

Project: Chrome

mojom::VideoCaptureHost* VideoCaptureImpl::GetVideoCaptureHost() {
  DCHECK(io_thread_checker_.CalledOnValidThread());
  if (video_capture_host_for_testing_)
    return video_capture_host_for_testing_;

  if (!video_capture_host_.get())
    video_capture_host_.Bind(std::move(video_capture_host_info_));
  return video_capture_host_.get();
};

Project: Chrome

void VideoCaptureImpl::OnBufferDestroyed(int32_t buffer_id) {
  DCHECK(io_thread_checker_.CalledOnValidThread());

  const auto& cb_iter = client_buffers_.find(buffer_id);
  if (cb_iter != client_buffers_.end()) {
    DCHECK(!cb_iter->second.get() || cb_iter->second->HasOneRef())
        << "Instructed to delete buffer we are still using.";
    client_buffers_.erase(cb_iter);
  }
}

Project: Chrome

void VideoCaptureImpl::OnBufferReady(int32_t buffer_id,
                                     media::mojom::VideoFrameInfoPtr info) {
  DVLOG(1) << __func__ << " buffer_id: " << buffer_id;
  DCHECK(io_thread_checker_.CalledOnValidThread());

  bool consume_buffer = state_ == VIDEO_CAPTURE_STATE_STARTED;
  if ((info->pixel_format != media::PIXEL_FORMAT_I420 &&
       info->pixel_format != media::PIXEL_FORMAT_Y16) ||
      info->storage_type != media::VideoPixelStorage::CPU) {
    consume_buffer = false;
    LOG(DFATAL) << "Wrong pixel format or storage, got pixel format:"
                << VideoPixelFormatToString(info->pixel_format)
                << ", storage:" << static_cast<int>(info->storage_type);
  }
  if (!consume_buffer) {
    GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id, -1.0);
    return;
  }

  base::TimeTicks reference_time;
  media::VideoFrameMetadata frame_metadata;
  frame_metadata.MergeInternalValuesFrom(*info->metadata);
  const bool success = frame_metadata.GetTimeTicks(
      media::VideoFrameMetadata::REFERENCE_TIME, &reference_time);
  DCHECK(success);

  if (first_frame_ref_time_.is_null())
    first_frame_ref_time_ = reference_time;

  if (info->timestamp.is_zero())
    info->timestamp = reference_time - first_frame_ref_time_;

  TRACE_EVENT_INSTANT2("cast_perf_test", "OnBufferReceived",
                       TRACE_EVENT_SCOPE_THREAD, "timestamp",
                       (reference_time - base::TimeTicks()).InMicroseconds(),
                       "time_delta", info->timestamp.InMicroseconds());

  const auto& iter = client_buffers_.find(buffer_id);
  DCHECK(iter != client_buffers_.end());
  scoped_refptr<ClientBuffer> buffer = iter->second;
  scoped_refptr<media::VideoFrame> frame =
      media::VideoFrame::WrapExternalSharedMemory(
          static_cast<media::VideoPixelFormat>(info->pixel_format),
          info->coded_size, info->visible_rect, info->visible_rect.size(),
          reinterpret_cast<uint8_t*>(buffer->buffer()->memory()),
          buffer->buffer_size(), buffer->buffer()->handle(),
          0 /* shared_memory_offset */, info->timestamp);
  if (!frame) {
    GetVideoCaptureHost()->ReleaseBuffer(device_id_, buffer_id, -1.0);
    return;
  }

  frame->AddDestructionObserver(base::BindOnce(
      &VideoCaptureImpl::DidFinishConsumingFrame, frame->metadata(),
      media::BindToCurrentLoop(base::BindOnce(
          &VideoCaptureImpl::OnClientBufferFinished, weak_factory_.GetWeakPtr(),
          buffer_id, std::move(buffer)))));

  frame->metadata()->MergeInternalValuesFrom(*info->metadata);

  for (const auto& client : clients_)
    client.second.deliver_frame_cb.Run(frame, reference_time);
}

Project: Chrome

void VideoCaptureImpl::OnClientBufferFinished(
    int buffer_id,
    scoped_refptr<ClientBuffer> buffer,
    double consumer_resource_utilization) {
  DCHECK(io_thread_checker_.CalledOnValidThread());

#if DCHECK_IS_ON()
  DCHECK(!buffer->HasOneRef());
  ClientBuffer* const buffer_raw_ptr = buffer.get();
  buffer = nullptr;
  DCHECK(buffer_raw_ptr->HasOneRef());
#else
  buffer = nullptr;
#endif

  GetVideoCaptureHost()->ReleaseBuffer(
      device_id_, buffer_id, consumer_resource_utilization);
}

Project: Chrome

void VideoCaptureImpl::OnDeviceSupportedFormats(
    const VideoCaptureDeviceFormatsCB& callback,
    const media::VideoCaptureFormats& supported_formats) {
  DCHECK(io_thread_checker_.CalledOnValidThread());
  callback.Run(supported_formats);
}

Project: Chrome

void VideoCaptureImpl::OnStateChanged(mojom::VideoCaptureState state) {
  DVLOG(1) << __func__ << " state: " << state;
  DCHECK(io_thread_checker_.CalledOnValidThread());

  switch (state) {
    case mojom::VideoCaptureState::STARTED:
      state_ = VIDEO_CAPTURE_STATE_STARTED;
      for (const auto& client : clients_)
        client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STARTED);
      RequestRefreshFrame();
      break;
    case mojom::VideoCaptureState::STOPPED:
      state_ = VIDEO_CAPTURE_STATE_STOPPED;
      client_buffers_.clear();
      weak_factory_.InvalidateWeakPtrs();
      if (!clients_.empty() || !clients_pending_on_restart_.empty())
        RestartCapture();
      break;
    case mojom::VideoCaptureState::PAUSED:
      for (const auto& client : clients_)
        client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_PAUSED);
      break;
    case mojom::VideoCaptureState::RESUMED:
      for (const auto& client : clients_)
        client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_RESUMED);
      break;
    case mojom::VideoCaptureState::FAILED:
      for (const auto& client : clients_)
        client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR);
      clients_.clear();
      state_ = VIDEO_CAPTURE_STATE_ERROR;
      break;
    case mojom::VideoCaptureState::ENDED:
      for (const auto& client : clients_)
        client.second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED);
      clients_.clear();
      state_ = VIDEO_CAPTURE_STATE_ENDED;
      break;
  }
}

Project: Chrome

bool VideoCaptureImpl::RemoveClient(int client_id, ClientInfoMap* clients) {
  DCHECK(io_thread_checker_.CalledOnValidThread());

  const ClientInfoMap::iterator it = clients->find(client_id);
  if (it == clients->end())
    return false;

  it->second.state_update_cb.Run(VIDEO_CAPTURE_STATE_STOPPED);
  clients->erase(it);
  return true;
}

Project: Chrome

void VideoCaptureImpl::RequestRefreshFrame() {
  DCHECK(io_thread_checker_.CalledOnValidThread());
  GetVideoCaptureHost()->RequestRefreshFrame(device_id_);
}

Project: Chrome

void VideoCaptureImpl::RestartCapture() {
  DCHECK(io_thread_checker_.CalledOnValidThread());
  DCHECK_EQ(state_, VIDEO_CAPTURE_STATE_STOPPED);

  int width = 0;
  int height = 0;
  clients_.insert(clients_pending_on_restart_.begin(),
                  clients_pending_on_restart_.end());
  clients_pending_on_restart_.clear();
  for (const auto& client : clients_) {
    width = std::max(width,
                     client.second.params.requested_format.frame_size.width());
    height = std::max(
        height, client.second.params.requested_format.frame_size.height());
  }
  params_.requested_format.frame_size.SetSize(width, height);
  DVLOG(1) << __func__ << " " << params_.requested_format.frame_size.ToString();
  StartCaptureInternal();
}

Project: Chrome

void VideoCaptureImpl::StartCapture(
    int client_id,
    const media::VideoCaptureParams& params,
    const VideoCaptureStateUpdateCB& state_update_cb,
    const VideoCaptureDeliverFrameCB& deliver_frame_cb) {
  DVLOG(1) << __func__ << " |device_id_| = " << device_id_;
  DCHECK(io_thread_checker_.CalledOnValidThread());
  ClientInfo client_info;
  client_info.params = params;
  client_info.state_update_cb = state_update_cb;
  client_info.deliver_frame_cb = deliver_frame_cb;

  switch (state_) {
    case VIDEO_CAPTURE_STATE_STARTING:
    case VIDEO_CAPTURE_STATE_STARTED:
      clients_[client_id] = client_info;
      DCHECK_EQ(params_.resolution_change_policy,
                params.resolution_change_policy);
      return;
    case VIDEO_CAPTURE_STATE_STOPPING:
      clients_pending_on_restart_[client_id] = client_info;
      DVLOG(1) << __func__ << " Got new resolution while stopping: "
               << params.requested_format.frame_size.ToString();
      return;
    case VIDEO_CAPTURE_STATE_STOPPED:
    case VIDEO_CAPTURE_STATE_ENDED:
      clients_[client_id] = client_info;
      params_ = params;
      params_.requested_format.frame_rate =
          std::min(params_.requested_format.frame_rate,
                   static_cast<float>(media::limits::kMaxFramesPerSecond));

      DVLOG(1) << "StartCapture: starting with first resolution "
               << params_.requested_format.frame_size.ToString();
      StartCaptureInternal();
      return;
    case VIDEO_CAPTURE_STATE_ERROR:
      state_update_cb.Run(VIDEO_CAPTURE_STATE_ERROR);
      return;
    case VIDEO_CAPTURE_STATE_PAUSED:
    case VIDEO_CAPTURE_STATE_RESUMED:
      NOTREACHED();
      return;
  }
}

Project: Chrome

void VideoCaptureImpl::StartCaptureInternal() {
  DCHECK(io_thread_checker_.CalledOnValidThread());
  state_ = VIDEO_CAPTURE_STATE_STARTING;

  mojom::VideoCaptureObserverPtr observer;
  observer_binding_.Bind(mojo::MakeRequest(&observer));
  GetVideoCaptureHost()->Start(device_id_, session_id_, params_,
                               std::move(observer));
}

Project: Chrome

void VideoCaptureImpl::StopCapture(int client_id) {
  DCHECK(io_thread_checker_.CalledOnValidThread());
  if (!RemoveClient(client_id, &clients_pending_on_restart_)) {
    RemoveClient(client_id, &clients_);
  }

  if (!clients_.empty())
    return;
  DVLOG(1) << "StopCapture: No more client, stopping ...";
  StopDevice();
  client_buffers_.clear();
  weak_factory_.InvalidateWeakPtrs();
}

Project: Chrome

void VideoCaptureImpl::StopDevice() {
  DCHECK(io_thread_checker_.CalledOnValidThread());
  if (state_ != VIDEO_CAPTURE_STATE_STARTING &&
      state_ != VIDEO_CAPTURE_STATE_STARTED)
    return;
  state_ = VIDEO_CAPTURE_STATE_STOPPING;
  GetVideoCaptureHost()->Stop(device_id_);
  params_.requested_format.frame_size.SetSize(0, 0);
}

Project: Chrome

VideoCaptureImpl::VideoCaptureImpl(media::VideoCaptureSessionId session_id)
    : device_id_(session_id),
      session_id_(session_id),
      video_capture_host_for_testing_(nullptr),
      observer_binding_(this),
      state_(VIDEO_CAPTURE_STATE_STOPPED),
      weak_factory_(this) {
  io_thread_checker_.DetachFromThread();

  if (ChildThread::Get()) {  // This will be null in unit tests.
    mojom::VideoCaptureHostPtr temp_video_capture_host;
    ChildThread::Get()->GetConnector()->BindInterface(
        mojom::kBrowserServiceName,
        mojo::MakeRequest(&temp_video_capture_host));
    video_capture_host_info_ = temp_video_capture_host.PassInterface();
  }
}

Project: Chrome

  size_t buffer_size() const { return buffer_size_; }

Project: Chrome

  virtual ~ClientBuffer() {}

Project: Chrome

VideoCaptureImpl::~VideoCaptureImpl() {
  DCHECK(io_thread_checker_.CalledOnValidThread());
  if ((state_ == VIDEO_CAPTURE_STATE_STARTING ||
       state_ == VIDEO_CAPTURE_STATE_STARTED) &&
      GetVideoCaptureHost())
    GetVideoCaptureHost()->Stop(device_id_);
}

Project: Chrome

ACTION(DoNothing) {}

Project: Chrome

  void GetDeviceFormatsInUse() {
    const base::Callback<void(const media::VideoCaptureFormats&)>
        callback = base::Bind(
            &VideoCaptureImplTest::OnDeviceFormatsInUse,
            base::Unretained(this));
    video_capture_impl_->GetDeviceFormatsInUse(callback);
  }

Project: Chrome

  void GetDeviceSupportedFormats() {
    const base::Callback<void(const media::VideoCaptureFormats&)>
        callback = base::Bind(
            &VideoCaptureImplTest::OnDeviceSupportedFormats,
            base::Unretained(this));
    video_capture_impl_->GetDeviceSupportedFormats(callback);
  }

Project: Chrome

  MockMojoVideoCaptureHost() : released_buffer_count_(0) {
    ON_CALL(*this, GetDeviceSupportedFormatsMock(_, _, _))
        .WillByDefault(WithArgs<2>(Invoke(RunEmptyFormatsCallback)));
    ON_CALL(*this, GetDeviceFormatsInUseMock(_, _, _))
        .WillByDefault(WithArgs<2>(Invoke(RunEmptyFormatsCallback)));
    ON_CALL(*this, ReleaseBuffer(_, _, _))
        .WillByDefault(InvokeWithoutArgs(
            this, &MockMojoVideoCaptureHost::increase_released_buffer_count));
  }

Project: Chrome

void RunEmptyFormatsCallback(
    mojom::VideoCaptureHost::GetDeviceSupportedFormatsCallback& callback) {
  media::VideoCaptureFormats formats;
  std::move(callback).Run(formats);
}

Project: Chrome

  void SimulateBufferDestroyed(int buffer_id) {
    video_capture_impl_->OnBufferDestroyed(buffer_id);
  }

Project: Chrome

   void SimulateBufferReceived(int buffer_id, const gfx::Size& size) {
    media::mojom::VideoFrameInfoPtr info = media::mojom::VideoFrameInfo::New();

    const base::TimeTicks now = base::TimeTicks::Now();
    media::VideoFrameMetadata frame_metadata;
    frame_metadata.SetTimeTicks(media::VideoFrameMetadata::REFERENCE_TIME, now);
    info->metadata = frame_metadata.CopyInternalValues();

    info->timestamp = now - base::TimeTicks();
    info->pixel_format = media::PIXEL_FORMAT_I420;
    info->storage_type = media::VideoPixelStorage::CPU;
    info->coded_size = size;
    info->visible_rect = gfx::Rect(size);

    video_capture_impl_->OnBufferReady(buffer_id, std::move(info));
  }

Project: Chrome

  void StartCapture(int client_id, const media::VideoCaptureParams& params) {
    const auto state_update_callback = base::Bind(
        &VideoCaptureImplTest::OnStateUpdate, base::Unretained(this));
    const auto frame_ready_callback =
        base::Bind(&VideoCaptureImplTest::OnFrameReady, base::Unretained(this));

    video_capture_impl_->StartCapture(client_id, params, state_update_callback,
                                      frame_ready_callback);
  }

Project: Chrome

  void StopCapture(int client_id) {
     video_capture_impl_->StopCapture(client_id);
   }

Project: Chrome

  VideoCaptureImplTest()
      : video_capture_impl_(new VideoCaptureImpl(kSessionId)) {
    params_small_.requested_format = media::VideoCaptureFormat(
        gfx::Size(176, 144), 30, media::PIXEL_FORMAT_I420);
    params_large_.requested_format = media::VideoCaptureFormat(
        gfx::Size(320, 240), 30, media::PIXEL_FORMAT_I420);

    video_capture_impl_->SetVideoCaptureHostForTesting(
        &mock_video_capture_host_);

    ON_CALL(mock_video_capture_host_, DoStart(_, _, _))
        .WillByDefault(InvokeWithoutArgs([this]() {
          video_capture_impl_->OnStateChanged(
              mojom::VideoCaptureState::STARTED);
        }));
  }

Project: Chrome

  void increase_released_buffer_count() { released_buffer_count_++; }

Project: Chrome

  int released_buffer_count() const { return released_buffer_count_; }

Project: Chrome

void GamepadProvider::AddGamepadDataFetcher(
    std::unique_ptr<GamepadDataFetcher> fetcher) {
  polling_thread_->task_runner()->PostTask(
      FROM_HERE, base::Bind(&GamepadProvider::DoAddGamepadDataFetcher,
                            base::Unretained(this), base::Passed(&fetcher)));
}

Project: Chrome

void GamepadProvider::CheckForUserGesture() {
  base::AutoLock lock(user_gesture_lock_);
  if (user_gesture_observers_.empty() && ever_had_user_gesture_)
    return;

  const Gamepads* pads = gamepad_shared_buffer_->buffer();
  if (GamepadsHaveUserGesture(*pads)) {
    ever_had_user_gesture_ = true;
    for (size_t i = 0; i < user_gesture_observers_.size(); i++) {
      user_gesture_observers_[i].task_runner->PostTask(
          FROM_HERE, user_gesture_observers_[i].closure);
    }
    user_gesture_observers_.clear();
  }
}

Project: Chrome

void GamepadProvider::DoAddGamepadDataFetcher(
    std::unique_ptr<GamepadDataFetcher> fetcher) {
  DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());

  if (!fetcher)
    return;

  InitializeDataFetcher(fetcher.get());
  data_fetchers_.push_back(std::move(fetcher));
}

Project: Chrome

void GamepadProvider::DoPoll() {
  DCHECK(polling_thread_->task_runner()->BelongsToCurrentThread());
  DCHECK(have_scheduled_do_poll_);
  have_scheduled_do_poll_ = false;

  bool changed;

  ANNOTATE_BENIGN_RACE_SIZED(gamepad_shared_buffer_->buffer(), sizeof(Gamepads),
                             "Racey reads are discarded");

  {
    base::AutoLock lock(devices_changed_lock_);
    changed = devices_changed_;
    devices_changed_ = false;
  }

  for (const auto& it : data_fetchers_) {
    it->GetGamepadData(changed);
  }

  Gamepads* buffer = gamepad_shared_buffer_->buffer();

  if (ever_had_user_gesture_) {
    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i) {
      PadState& state = pad_states_.get()[i];

      if (!state.active_state && state.source != GAMEPAD_SOURCE_NONE) {
        auto pad = buffer->items[i];
        pad.connected = false;
        OnGamepadConnectionChange(false, i, pad);
        ClearPadState(state);
      }
    }
  }

  {
    base::AutoLock lock(shared_memory_lock_);

    gamepad_shared_buffer_->WriteBegin();
    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i) {
      PadState& state = pad_states_.get()[i];
      MapAndSanitizeGamepadData(&state, &buffer->items[i], sanitize_);
    }
    gamepad_shared_buffer_->WriteEnd();
  }

  if (ever_had_user_gesture_) {
    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i) {
      PadState& state = pad_states_.get()[i];

      if (state.active_state) {
        if (state.active_state == GAMEPAD_NEWLY_ACTIVE &&
            buffer->items[i].connected) {
          OnGamepadConnectionChange(true, i, buffer->items[i]);
        }
      }
    }
  }

  CheckForUserGesture();

  if (ever_had_user_gesture_) {
    for (unsigned i = 0; i < Gamepads::kItemsLengthCap; ++i)
      pad_states_.get()[i].active_state = GAMEPAD_INACTIVE;
  }

  ScheduleDoPoll();
}

Project: Chrome

base::SharedMemoryHandle GamepadProvider::DuplicateSharedMemoryHandle() {
  return gamepad_shared_buffer_->shared_memory()->handle().Duplicate();
}

Project: Chrome

GamepadProvider::GamepadProvider(
    GamepadConnectionChangeClient* connection_change_client)
    : is_paused_(true),
      have_scheduled_do_poll_(false),
      devices_changed_(true),
      ever_had_user_gesture_(false),
      sanitize_(true),
      gamepad_shared_buffer_(new GamepadSharedBuffer()),
      connection_change_client_(connection_change_client) {
  Initialize(std::unique_ptr<GamepadDataFetcher>());
}

Project: Chrome

GamepadProvider::GamepadProvider(
    GamepadConnectionChangeClient* connection_change_client,
    std::unique_ptr<GamepadDataFetcher> fetcher)
    : is_paused_(true),
      have_scheduled_do_poll_(false),
      devices_changed_(true),
      ever_had_user_gesture_(false),
      sanitize_(true),
      gamepad_shared_buffer_(new GamepadSharedBuffer()),
      connection_change_client_(connection_change_client) {
  Initialize(std::move(fetcher));
}

Project: Chrome

 void GamepadProvider::GetCurrentGamepadData(Gamepads* data) {
  const Gamepads* pads = gamepad_shared_buffer_->buffer();
  base::AutoLock lock(shared_memory_lock_);
  *data = *pads;
}

Project: Chrome

GamepadDataFetcher* GamepadProvider::GetSourceGamepadDataFetcher(
    GamepadSource source) {
  for (GamepadFetcherVector::iterator it = data_fetchers_.begin();
       it != data_fetchers_.end();) {
    if ((*it)->source() == source) {
      return it->get();
    } else {
      ++it;
    }
  }
  return nullptr;
}