summaryrefslogtreecommitdiffstats
path: root/chrome/browser/mach_broker_mac.cc
blob: 39f3fcedd19c0f8f0a9426a07d30e72286aa71d6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
// Copyright (c) 2009 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/mach_broker_mac.h"

#include "base/logging.h"
#include "chrome/browser/chrome_thread.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/common/child_process_info.h"
#include "chrome/common/notification_service.h"

// Required because notifications happen on the UI thread.
class RegisterNotificationTask : public Task {
 public:
  RegisterNotificationTask(
      MachBroker* broker)
      : broker_(broker) { }

  virtual void Run() {
    broker_->registrar_.Add(broker_,
        NotificationType::RENDERER_PROCESS_CLOSED,
        NotificationService::AllSources());
    broker_->registrar_.Add(broker_,
        NotificationType::RENDERER_PROCESS_TERMINATED,
        NotificationService::AllSources());
    broker_->registrar_.Add(broker_,
        NotificationType::CHILD_PROCESS_CRASHED,
        NotificationService::AllSources());
    broker_->registrar_.Add(broker_,
        NotificationType::CHILD_PROCESS_HOST_DISCONNECTED,
        NotificationService::AllSources());
    broker_->registrar_.Add(broker_,
        NotificationType::EXTENSION_PROCESS_TERMINATED,
        NotificationService::AllSources());
  }

 private:
  MachBroker* broker_;
};

MachBroker::MachBroker() {
  ChromeThread::PostTask(
      ChromeThread::UI, FROM_HERE, new RegisterNotificationTask(this));
}

// Returns the global MachBroker.
MachBroker* MachBroker::instance() {
  return Singleton<MachBroker>::get();
}

// Adds mach info for a given pid.
void MachBroker::RegisterPid(
    base::ProcessHandle pid, const MachInfo& mach_info) {
  AutoLock lock(lock_);
  DCHECK_EQ(0u, mach_map_.count(pid));
  mach_map_[pid] = mach_info;
}

// Removes all mappings belonging to |pid| from the broker.
void MachBroker::Invalidate(base::ProcessHandle pid) {
  AutoLock lock(lock_);
  MachBroker::MachMap::iterator it = mach_map_.find(pid);
  if (it == mach_map_.end())
    return;

  kern_return_t kr = mach_port_deallocate(mach_task_self(),
                                          it->second.mach_task_);
  LOG_IF(WARNING, kr != KERN_SUCCESS)
     << "Failed to mach_port_deallocate mach task " << it->second.mach_task_
     << ", error " << kr;
  mach_map_.erase(it);
}

// Returns the mach task belonging to |pid|.
mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const {
  AutoLock lock(lock_);
  MachBroker::MachMap::const_iterator it = mach_map_.find(pid);
  if (it == mach_map_.end())
    return MACH_PORT_NULL;
  return it->second.mach_task_;
}

void MachBroker::Observe(NotificationType type,
                         const NotificationSource& source,
                         const NotificationDetails& details) {
  base::ProcessHandle handle = 0;
  switch (type.value) {
    case NotificationType::RENDERER_PROCESS_CLOSED:
    case NotificationType::RENDERER_PROCESS_TERMINATED:
      handle = Source<RenderProcessHost>(source)->GetHandle();
      break;
    case NotificationType::EXTENSION_PROCESS_TERMINATED:
      handle =
          Details<ExtensionHost>(details)->render_process_host()->GetHandle();
      break;
    case NotificationType::CHILD_PROCESS_CRASHED:
    case NotificationType::CHILD_PROCESS_HOST_DISCONNECTED:
      handle = Details<ChildProcessInfo>(details)->handle();
      break;
    default:
      NOTREACHED() << "Unexpected notification";
      break;
  }
  Invalidate(handle);
}