1// Copyright (c) 2011 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 "chrome/browser/extensions/extension_processes_api.h"
6
7#include "base/callback.h"
8#include "base/json/json_writer.h"
9#include "base/message_loop.h"
10#include "base/string_number_conversions.h"
11#include "base/task.h"
12#include "base/utf_string_conversions.h"
13#include "base/values.h"
14
15#include "chrome/browser/extensions/extension_event_router.h"
16#include "chrome/browser/extensions/extension_processes_api_constants.h"
17#include "chrome/browser/extensions/extension_tabs_module.h"
18#include "chrome/browser/extensions/extension_tabs_module_constants.h"
19#include "chrome/browser/profiles/profile.h"
20#include "chrome/browser/task_manager/task_manager.h"
21#include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h"
22#include "chrome/common/extensions/extension_error_utils.h"
23#include "content/browser/renderer_host/render_process_host.h"
24#include "content/browser/tab_contents/tab_contents.h"
25#include "content/common/notification_type.h"
26
27namespace keys = extension_processes_api_constants;
28
29DictionaryValue* CreateProcessValue(int process_id,
30                                    const std::string& type,
31                                    double cpu,
32                                    int64 net,
33                                    int64 pr_mem,
34                                    int64 sh_mem) {
35  DictionaryValue* result = new DictionaryValue();
36  result->SetInteger(keys::kIdKey, process_id);
37  result->SetString(keys::kTypeKey, type);
38  result->SetDouble(keys::kCpuKey, cpu);
39  result->SetDouble(keys::kNetworkKey, static_cast<double>(net));
40  result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem));
41  result->SetDouble(keys::kSharedMemoryKey, static_cast<double>(sh_mem));
42  return result;
43}
44
45ExtensionProcessesEventRouter* ExtensionProcessesEventRouter::GetInstance() {
46  return Singleton<ExtensionProcessesEventRouter>::get();
47}
48
49ExtensionProcessesEventRouter::ExtensionProcessesEventRouter() {
50  model_ = TaskManager::GetInstance()->model();
51  model_->AddObserver(this);
52}
53
54ExtensionProcessesEventRouter::~ExtensionProcessesEventRouter() {
55  model_->RemoveObserver(this);
56}
57
58void ExtensionProcessesEventRouter::ObserveProfile(Profile* profile) {
59  profiles_.insert(profile);
60}
61
62void ExtensionProcessesEventRouter::ListenerAdded() {
63  model_->StartUpdating();
64}
65
66void ExtensionProcessesEventRouter::ListenerRemoved() {
67  model_->StopUpdating();
68}
69
70void ExtensionProcessesEventRouter::OnItemsChanged(int start, int length) {
71  if (model_) {
72    ListValue args;
73    DictionaryValue* processes = new DictionaryValue();
74    for (int i = start; i < start + length; i++) {
75      if (model_->IsResourceFirstInGroup(i)) {
76        int id = model_->GetProcessId(i);
77
78        // Determine process type
79        std::string type = keys::kProcessTypeOther;
80        TaskManager::Resource::Type resource_type = model_->GetResourceType(i);
81        switch (resource_type) {
82          case TaskManager::Resource::BROWSER:
83            type = keys::kProcessTypeBrowser;
84            break;
85          case TaskManager::Resource::RENDERER:
86            type = keys::kProcessTypeRenderer;
87            break;
88          case TaskManager::Resource::EXTENSION:
89            type = keys::kProcessTypeExtension;
90            break;
91          case TaskManager::Resource::NOTIFICATION:
92            type = keys::kProcessTypeNotification;
93            break;
94          case TaskManager::Resource::PLUGIN:
95            type = keys::kProcessTypePlugin;
96            break;
97          case TaskManager::Resource::WORKER:
98            type = keys::kProcessTypeWorker;
99            break;
100          case TaskManager::Resource::NACL:
101            type = keys::kProcessTypeNacl;
102            break;
103          case TaskManager::Resource::UTILITY:
104            type = keys::kProcessTypeUtility;
105            break;
106          case TaskManager::Resource::GPU:
107            type = keys::kProcessTypeGPU;
108            break;
109          case TaskManager::Resource::PROFILE_IMPORT:
110          case TaskManager::Resource::ZYGOTE:
111          case TaskManager::Resource::SANDBOX_HELPER:
112          case TaskManager::Resource::UNKNOWN:
113            type = keys::kProcessTypeOther;
114            break;
115          default:
116            NOTREACHED() << "Unknown resource type.";
117        }
118
119        // Get process metrics as numbers
120        double cpu = model_->GetCPUUsage(i);
121
122        // TODO(creis): Network is actually reported per-resource (tab),
123        // not per-process.  We should aggregate it here.
124        int64 net = model_->GetNetworkUsage(i);
125        size_t mem;
126        int64 pr_mem = model_->GetPrivateMemory(i, &mem) ?
127            static_cast<int64>(mem) : -1;
128        int64 sh_mem = model_->GetSharedMemory(i, &mem) ?
129            static_cast<int64>(mem) : -1;
130
131        // Store each process indexed by the string version of its id
132        processes->Set(base::IntToString(id),
133                       CreateProcessValue(id, type, cpu, net, pr_mem, sh_mem));
134      }
135    }
136    args.Append(processes);
137
138    std::string json_args;
139    base::JSONWriter::Write(&args, false, &json_args);
140
141    // Notify each profile that is interested.
142    for (ProfileSet::iterator it = profiles_.begin();
143         it != profiles_.end(); it++) {
144      Profile* profile = *it;
145      DispatchEvent(profile, keys::kOnUpdated, json_args);
146    }
147  }
148}
149
150void ExtensionProcessesEventRouter::DispatchEvent(Profile* profile,
151    const char* event_name,
152    const std::string& json_args) {
153  if (profile && profile->GetExtensionEventRouter()) {
154    profile->GetExtensionEventRouter()->DispatchEventToRenderers(
155        event_name, json_args, NULL, GURL());
156  }
157}
158
159bool GetProcessIdForTabFunction::RunImpl() {
160  int tab_id;
161  EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id));
162
163  TabContentsWrapper* contents = NULL;
164  int tab_index = -1;
165  if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(),
166                                    NULL, NULL, &contents, &tab_index)) {
167    error_ = ExtensionErrorUtils::FormatErrorMessage(
168        extension_tabs_module_constants::kTabNotFoundError,
169        base::IntToString(tab_id));
170    return false;
171  }
172
173  // Return the process ID of the tab as an integer.
174  int id = base::GetProcId(contents->tab_contents()->
175      GetRenderProcessHost()->GetHandle());
176  result_.reset(Value::CreateIntegerValue(id));
177  return true;
178}
179