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 "content/browser/histogram_controller.h"
6
7#include "base/bind.h"
8#include "base/metrics/histogram.h"
9#include "base/process/process_handle.h"
10#include "content/browser/histogram_subscriber.h"
11#include "content/common/child_process_messages.h"
12#include "content/public/browser/browser_child_process_host_iterator.h"
13#include "content/public/browser/browser_thread.h"
14#include "content/public/browser/child_process_data.h"
15#include "content/public/browser/render_process_host.h"
16#include "content/public/common/process_type.h"
17
18namespace content {
19
20HistogramController* HistogramController::GetInstance() {
21  return Singleton<HistogramController>::get();
22}
23
24HistogramController::HistogramController() : subscriber_(NULL) {
25}
26
27HistogramController::~HistogramController() {
28}
29
30void HistogramController::OnPendingProcesses(int sequence_number,
31                                             int pending_processes,
32                                             bool end) {
33  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
34  if (subscriber_)
35    subscriber_->OnPendingProcesses(sequence_number, pending_processes, end);
36}
37
38void HistogramController::OnHistogramDataCollected(
39    int sequence_number,
40    const std::vector<std::string>& pickled_histograms) {
41  if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
42    BrowserThread::PostTask(
43        BrowserThread::UI, FROM_HERE,
44        base::Bind(&HistogramController::OnHistogramDataCollected,
45                   base::Unretained(this),
46                   sequence_number,
47                   pickled_histograms));
48    return;
49  }
50
51  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
52  if (subscriber_) {
53    subscriber_->OnHistogramDataCollected(sequence_number,
54                                          pickled_histograms);
55  }
56}
57
58void HistogramController::Register(HistogramSubscriber* subscriber) {
59  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
60  DCHECK(!subscriber_);
61  subscriber_ = subscriber;
62}
63
64void HistogramController::Unregister(
65    const HistogramSubscriber* subscriber) {
66  DCHECK_EQ(subscriber_, subscriber);
67  subscriber_ = NULL;
68}
69
70void HistogramController::GetHistogramDataFromChildProcesses(
71    int sequence_number) {
72  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
73
74  int pending_processes = 0;
75  for (BrowserChildProcessHostIterator iter; !iter.Done(); ++iter) {
76    const ChildProcessData& data = iter.GetData();
77    int type = data.process_type;
78    if (type != PROCESS_TYPE_PLUGIN &&
79        type != PROCESS_TYPE_GPU &&
80        type != PROCESS_TYPE_PPAPI_PLUGIN &&
81        type != PROCESS_TYPE_PPAPI_BROKER) {
82      continue;
83    }
84
85    // In some cases, there may be no child process of the given type (for
86    // example, the GPU process may not exist and there may instead just be a
87    // GPU thread in the browser process). If that's the case, then the process
88    // handle will be base::kNullProcessHandle and we shouldn't ask it for data.
89    if (data.handle == base::kNullProcessHandle)
90      continue;
91
92    ++pending_processes;
93    if (!iter.Send(new ChildProcessMsg_GetChildHistogramData(sequence_number)))
94      --pending_processes;
95  }
96
97  BrowserThread::PostTask(
98      BrowserThread::UI,
99      FROM_HERE,
100      base::Bind(
101          &HistogramController::OnPendingProcesses,
102          base::Unretained(this),
103          sequence_number,
104          pending_processes,
105          true));
106}
107
108void HistogramController::GetHistogramData(int sequence_number) {
109  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
110
111  int pending_processes = 0;
112  for (RenderProcessHost::iterator it(RenderProcessHost::AllHostsIterator());
113       !it.IsAtEnd(); it.Advance()) {
114    ++pending_processes;
115    if (!it.GetCurrentValue()->Send(
116            new ChildProcessMsg_GetChildHistogramData(sequence_number))) {
117      --pending_processes;
118    }
119  }
120  OnPendingProcesses(sequence_number, pending_processes, false);
121
122  BrowserThread::PostTask(
123      BrowserThread::IO,
124      FROM_HERE,
125      base::Bind(&HistogramController::GetHistogramDataFromChildProcesses,
126                 base::Unretained(this),
127                 sequence_number));
128}
129
130}  // namespace content
131