| // Copyright (c) 2011 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/extensions/extension_processes_api.h" |
| |
| #include "base/callback.h" |
| #include "base/json/json_writer.h" |
| #include "base/message_loop.h" |
| #include "base/string_number_conversions.h" |
| #include "base/task.h" |
| #include "base/utf_string_conversions.h" |
| #include "base/values.h" |
| |
| #include "chrome/browser/extensions/extension_event_router.h" |
| #include "chrome/browser/extensions/extension_processes_api_constants.h" |
| #include "chrome/browser/extensions/extension_tabs_module.h" |
| #include "chrome/browser/extensions/extension_tabs_module_constants.h" |
| #include "chrome/browser/profiles/profile.h" |
| #include "chrome/browser/task_manager/task_manager.h" |
| #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |
| #include "chrome/common/extensions/extension_error_utils.h" |
| #include "content/browser/renderer_host/render_process_host.h" |
| #include "content/browser/tab_contents/tab_contents.h" |
| #include "content/common/notification_type.h" |
| |
| namespace keys = extension_processes_api_constants; |
| |
| DictionaryValue* CreateProcessValue(int process_id, |
| const std::string& type, |
| double cpu, |
| int64 net, |
| int64 pr_mem, |
| int64 sh_mem) { |
| DictionaryValue* result = new DictionaryValue(); |
| result->SetInteger(keys::kIdKey, process_id); |
| result->SetString(keys::kTypeKey, type); |
| result->SetDouble(keys::kCpuKey, cpu); |
| result->SetDouble(keys::kNetworkKey, static_cast<double>(net)); |
| result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem)); |
| result->SetDouble(keys::kSharedMemoryKey, static_cast<double>(sh_mem)); |
| return result; |
| } |
| |
| ExtensionProcessesEventRouter* ExtensionProcessesEventRouter::GetInstance() { |
| return Singleton<ExtensionProcessesEventRouter>::get(); |
| } |
| |
| ExtensionProcessesEventRouter::ExtensionProcessesEventRouter() { |
| model_ = TaskManager::GetInstance()->model(); |
| model_->AddObserver(this); |
| } |
| |
| ExtensionProcessesEventRouter::~ExtensionProcessesEventRouter() { |
| model_->RemoveObserver(this); |
| } |
| |
| void ExtensionProcessesEventRouter::ObserveProfile(Profile* profile) { |
| profiles_.insert(profile); |
| } |
| |
| void ExtensionProcessesEventRouter::ListenerAdded() { |
| model_->StartUpdating(); |
| } |
| |
| void ExtensionProcessesEventRouter::ListenerRemoved() { |
| model_->StopUpdating(); |
| } |
| |
| void ExtensionProcessesEventRouter::OnItemsChanged(int start, int length) { |
| if (model_) { |
| ListValue args; |
| DictionaryValue* processes = new DictionaryValue(); |
| for (int i = start; i < start + length; i++) { |
| if (model_->IsResourceFirstInGroup(i)) { |
| int id = model_->GetProcessId(i); |
| |
| // Determine process type |
| std::string type = keys::kProcessTypeOther; |
| TaskManager::Resource::Type resource_type = model_->GetResourceType(i); |
| switch (resource_type) { |
| case TaskManager::Resource::BROWSER: |
| type = keys::kProcessTypeBrowser; |
| break; |
| case TaskManager::Resource::RENDERER: |
| type = keys::kProcessTypeRenderer; |
| break; |
| case TaskManager::Resource::EXTENSION: |
| type = keys::kProcessTypeExtension; |
| break; |
| case TaskManager::Resource::NOTIFICATION: |
| type = keys::kProcessTypeNotification; |
| break; |
| case TaskManager::Resource::PLUGIN: |
| type = keys::kProcessTypePlugin; |
| break; |
| case TaskManager::Resource::WORKER: |
| type = keys::kProcessTypeWorker; |
| break; |
| case TaskManager::Resource::NACL: |
| type = keys::kProcessTypeNacl; |
| break; |
| case TaskManager::Resource::UTILITY: |
| type = keys::kProcessTypeUtility; |
| break; |
| case TaskManager::Resource::GPU: |
| type = keys::kProcessTypeGPU; |
| break; |
| case TaskManager::Resource::PROFILE_IMPORT: |
| case TaskManager::Resource::ZYGOTE: |
| case TaskManager::Resource::SANDBOX_HELPER: |
| case TaskManager::Resource::UNKNOWN: |
| type = keys::kProcessTypeOther; |
| break; |
| default: |
| NOTREACHED() << "Unknown resource type."; |
| } |
| |
| // Get process metrics as numbers |
| double cpu = model_->GetCPUUsage(i); |
| |
| // TODO(creis): Network is actually reported per-resource (tab), |
| // not per-process. We should aggregate it here. |
| int64 net = model_->GetNetworkUsage(i); |
| size_t mem; |
| int64 pr_mem = model_->GetPrivateMemory(i, &mem) ? |
| static_cast<int64>(mem) : -1; |
| int64 sh_mem = model_->GetSharedMemory(i, &mem) ? |
| static_cast<int64>(mem) : -1; |
| |
| // Store each process indexed by the string version of its id |
| processes->Set(base::IntToString(id), |
| CreateProcessValue(id, type, cpu, net, pr_mem, sh_mem)); |
| } |
| } |
| args.Append(processes); |
| |
| std::string json_args; |
| base::JSONWriter::Write(&args, false, &json_args); |
| |
| // Notify each profile that is interested. |
| for (ProfileSet::iterator it = profiles_.begin(); |
| it != profiles_.end(); it++) { |
| Profile* profile = *it; |
| DispatchEvent(profile, keys::kOnUpdated, json_args); |
| } |
| } |
| } |
| |
| void ExtensionProcessesEventRouter::DispatchEvent(Profile* profile, |
| const char* event_name, |
| const std::string& json_args) { |
| if (profile && profile->GetExtensionEventRouter()) { |
| profile->GetExtensionEventRouter()->DispatchEventToRenderers( |
| event_name, json_args, NULL, GURL()); |
| } |
| } |
| |
| bool GetProcessIdForTabFunction::RunImpl() { |
| int tab_id; |
| EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id)); |
| |
| TabContentsWrapper* contents = NULL; |
| int tab_index = -1; |
| if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), |
| NULL, NULL, &contents, &tab_index)) { |
| error_ = ExtensionErrorUtils::FormatErrorMessage( |
| extension_tabs_module_constants::kTabNotFoundError, |
| base::IntToString(tab_id)); |
| return false; |
| } |
| |
| // Return the process ID of the tab as an integer. |
| int id = base::GetProcId(contents->tab_contents()-> |
| GetRenderProcessHost()->GetHandle()); |
| result_.reset(Value::CreateIntegerValue(id)); |
| return true; |
| } |