1// Copyright (c) 2012 The Chromium Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#include "components/nacl/browser/nacl_broker_service_win.h"
6
7#include "components/nacl/browser/nacl_process_host.h"
8#include "components/nacl/common/nacl_process_type.h"
9#include "content/public/browser/browser_child_process_host_iterator.h"
10
11using content::BrowserChildProcessHostIterator;
12
13namespace nacl {
14
15NaClBrokerService* NaClBrokerService::GetInstance() {
16  return Singleton<NaClBrokerService>::get();
17}
18
19NaClBrokerService::NaClBrokerService()
20    : loaders_running_(0) {
21}
22
23bool NaClBrokerService::StartBroker() {
24  NaClBrokerHost* broker_host = new NaClBrokerHost;
25  if (!broker_host->Init()) {
26    delete broker_host;
27    return false;
28  }
29  return true;
30}
31
32bool NaClBrokerService::LaunchLoader(
33    base::WeakPtr<nacl::NaClProcessHost> nacl_process_host,
34    const std::string& loader_channel_id) {
35  // Add task to the list
36  pending_launches_[loader_channel_id] = nacl_process_host;
37  NaClBrokerHost* broker_host = GetBrokerHost();
38
39  if (!broker_host) {
40    if (!StartBroker())
41      return false;
42    broker_host = GetBrokerHost();
43  }
44  broker_host->LaunchLoader(loader_channel_id);
45
46  return true;
47}
48
49void NaClBrokerService::OnLoaderLaunched(const std::string& channel_id,
50                                         base::ProcessHandle handle) {
51  PendingLaunchesMap::iterator it = pending_launches_.find(channel_id);
52  if (pending_launches_.end() == it)
53    NOTREACHED();
54
55  NaClProcessHost* client = it->second.get();
56  if (client)
57    client->OnProcessLaunchedByBroker(handle);
58  pending_launches_.erase(it);
59  ++loaders_running_;
60}
61
62void NaClBrokerService::OnLoaderDied() {
63  DCHECK(loaders_running_ > 0);
64  --loaders_running_;
65  // Stop the broker only if there are no loaders running or being launched.
66  NaClBrokerHost* broker_host = GetBrokerHost();
67  if (loaders_running_ + pending_launches_.size() == 0 && broker_host != NULL) {
68    broker_host->StopBroker();
69  }
70}
71
72bool NaClBrokerService::LaunchDebugExceptionHandler(
73    base::WeakPtr<NaClProcessHost> nacl_process_host, int32 pid,
74    base::ProcessHandle process_handle, const std::string& startup_info) {
75  pending_debuggers_[pid] = nacl_process_host;
76  NaClBrokerHost* broker_host = GetBrokerHost();
77  if (!broker_host)
78    return false;
79  return broker_host->LaunchDebugExceptionHandler(pid, process_handle,
80                                                  startup_info);
81}
82
83void NaClBrokerService::OnDebugExceptionHandlerLaunched(int32 pid,
84                                                        bool success) {
85  PendingDebugExceptionHandlersMap::iterator it = pending_debuggers_.find(pid);
86  if (pending_debuggers_.end() == it)
87    NOTREACHED();
88
89  NaClProcessHost* client = it->second.get();
90  if (client)
91    client->OnDebugExceptionHandlerLaunchedByBroker(success);
92  pending_debuggers_.erase(it);
93}
94
95NaClBrokerHost* NaClBrokerService::GetBrokerHost() {
96  BrowserChildProcessHostIterator iter(PROCESS_TYPE_NACL_BROKER);
97  while (!iter.Done()) {
98    NaClBrokerHost* host = static_cast<NaClBrokerHost*>(iter.GetDelegate());
99    if (!host->IsTerminating())
100      return host;
101    ++iter;
102  }
103  return NULL;
104}
105
106}  // namespace nacl
107