Chromium Code Reviews| Index: chrome/browser/extensions/api/processes/processes_api.cc |
| diff --git a/chrome/browser/extensions/api/processes/processes_api.cc b/chrome/browser/extensions/api/processes/processes_api.cc |
| index ae43fd23870720bc227e4e58662776163e1a1c94..3d702a16d442b101356ab9716642d9d9ee8e7db3 100644 |
| --- a/chrome/browser/extensions/api/processes/processes_api.cc |
| +++ b/chrome/browser/extensions/api/processes/processes_api.cc |
| @@ -4,57 +4,58 @@ |
| #include "chrome/browser/extensions/api/processes/processes_api.h" |
| -#include <stddef.h> |
| #include <stdint.h> |
| #include <algorithm> |
| -#include <utility> |
| -#include "base/callback.h" |
| -#include "base/json/json_writer.h" |
| #include "base/lazy_instance.h" |
| -#include "base/location.h" |
| -#include "base/metrics/histogram.h" |
| -#include "base/single_thread_task_runner.h" |
| +#include "base/metrics/histogram_macros.h" |
| +#include "base/process/process.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/utf_string_conversions.h" |
| -#include "base/thread_task_runner_handle.h" |
| -#include "base/values.h" |
| -#include "chrome/browser/chrome_notification_types.h" |
| #include "chrome/browser/extensions/api/tabs/tabs_constants.h" |
| -#include "chrome/browser/extensions/extension_service.h" |
| #include "chrome/browser/extensions/extension_tab_util.h" |
| #include "chrome/browser/profiles/profile.h" |
| -#include "chrome/browser/task_manager/resource_provider.h" |
| -#include "chrome/browser/task_manager/task_manager.h" |
| +#include "chrome/browser/task_management/task_manager_interface.h" |
| #include "chrome/common/extensions/api/processes.h" |
| -#include "content/public/browser/browser_context.h" |
| -#include "content/public/browser/notification_details.h" |
| -#include "content/public/browser/notification_service.h" |
| -#include "content/public/browser/notification_source.h" |
| -#include "content/public/browser/notification_types.h" |
| +#include "content/public/browser/browser_child_process_host.h" |
| +#include "content/public/browser/child_process_data.h" |
| + |
|
ncarter (slow)
2016/03/10 21:01:04
Weird newline here.
afakhry
2016/03/11 03:38:11
Done.
|
| #include "content/public/browser/render_process_host.h" |
| -#include "content/public/browser/render_view_host.h" |
| -#include "content/public/browser/render_widget_host.h" |
| -#include "content/public/browser/render_widget_host_iterator.h" |
| #include "content/public/browser/web_contents.h" |
| +#include "content/public/common/child_process_host.h" |
| #include "content/public/common/result_codes.h" |
| -#include "extensions/browser/event_router.h" |
| -#include "extensions/browser/extension_function_registry.h" |
| -#include "extensions/browser/extension_function_util.h" |
| #include "extensions/common/error_utils.h" |
| +#include "third_party/WebKit/public/web/WebCache.h" |
| namespace extensions { |
| namespace errors { |
| const char kNotAllowedToTerminate[] = "Not allowed to terminate process: *."; |
| const char kProcessNotFound[] = "Process not found: *."; |
| -const char kInavlidArgument[] = "Invalid argument: *."; |
| +const char kInvalidArgument[] = "Invalid argument: *."; |
| } // namespace errors |
| namespace { |
| -#if defined(ENABLE_TASK_MANAGER) |
| +base::LazyInstance<BrowserContextKeyedAPIFactory<ProcessesAPI>> |
| + g_processes_api_factory = LAZY_INSTANCE_INITIALIZER; |
| + |
| +int64_t GetRefreshTypesFlagOnlyEssentialData() { |
| + // This is the only non-optional data in the Process as defined by the API in |
| + // processes.idl. |
| + return task_management::REFRESH_TYPE_NACL; |
| +} |
| + |
| +// This does not include memory. The memory refresh flag will only be added once |
| +// a listener to OnUpdatedWithMemory event is added. |
| +int64_t GetRefreshTypesForProcessOptionalData() { |
| + return task_management::REFRESH_TYPE_CPU | |
| + task_management::REFRESH_TYPE_NETWORK_USAGE | |
| + task_management::REFRESH_TYPE_SQLITE_MEMORY | |
| + task_management::REFRESH_TYPE_V8_MEMORY | |
| + task_management::REFRESH_TYPE_WEBCACHE_STATS; |
| +} |
| scoped_ptr<api::processes::Cache> CreateCacheData( |
| const blink::WebCache::ResourceTypeStat& stat) { |
| @@ -64,279 +65,232 @@ scoped_ptr<api::processes::Cache> CreateCacheData( |
| return cache; |
| } |
| -api::processes::ProcessType GetProcessType(TaskManagerModel* model, |
| - int index) { |
| - // Determine process type. |
| - task_manager::Resource::Type resource_type = model->GetResourceType(index); |
| - switch (resource_type) { |
| - case task_manager::Resource::BROWSER: |
| +api::processes::ProcessType GetProcessType( |
| + task_management::Task::Type task_type) { |
| + switch (task_type) { |
| + case task_management::Task::BROWSER: |
| return api::processes::PROCESS_TYPE_BROWSER; |
| - case task_manager::Resource::RENDERER: |
| + case task_management::Task::RENDERER: |
| return api::processes::PROCESS_TYPE_RENDERER; |
| - case task_manager::Resource::EXTENSION: |
| - case task_manager::Resource::GUEST: |
| + case task_management::Task::EXTENSION: |
| + case task_management::Task::GUEST: |
| return api::processes::PROCESS_TYPE_EXTENSION; |
| - case task_manager::Resource::NOTIFICATION: |
| - return api::processes::PROCESS_TYPE_NOTIFICATION; |
| - |
| - case task_manager::Resource::PLUGIN: |
| + case task_management::Task::PLUGIN: |
| return api::processes::PROCESS_TYPE_PLUGIN; |
| - case task_manager::Resource::WORKER: |
| + case task_management::Task::WORKER: |
| return api::processes::PROCESS_TYPE_WORKER; |
| - case task_manager::Resource::NACL: |
| + case task_management::Task::NACL: |
| return api::processes::PROCESS_TYPE_NACL; |
| - case task_manager::Resource::UTILITY: |
| + case task_management::Task::UTILITY: |
| return api::processes::PROCESS_TYPE_UTILITY; |
| - case task_manager::Resource::GPU: |
| + case task_management::Task::GPU: |
| return api::processes::PROCESS_TYPE_GPU; |
| - case task_manager::Resource::ZYGOTE: |
| - case task_manager::Resource::SANDBOX_HELPER: |
| - case task_manager::Resource::UNKNOWN: |
| + case task_management::Task::UNKNOWN: |
| + case task_management::Task::ARC: |
| + case task_management::Task::SANDBOX_HELPER: |
| + case task_management::Task::ZYGOTE: |
| return api::processes::PROCESS_TYPE_OTHER; |
| } |
| - NOTREACHED() << "Unknown resource type."; |
| + NOTREACHED() << "Unknown task type."; |
| return api::processes::PROCESS_TYPE_NONE; |
| } |
| -void FillTabsForProcess(int process_id, api::processes::Process* out_process) { |
| +// Fills |out_process| with the data of the process in which the task with |id| |
| +// is running. If |include_optional| is true, this function will fill the |
| +// optional fields in |api::processes::Process| except for |private_memory|, |
| +// which should be filled later if needed. |
| +void FillProcessData( |
| + task_management::TaskId id, |
| + task_management::TaskManagerInterface* task_manager, |
| + bool include_optional, |
| + api::processes::Process* out_process) { |
| DCHECK(out_process); |
| - // The tabs list only makes sense for render processes, so if we don't find |
| - // one, just return the empty list. |
| - content::RenderProcessHost* rph = |
| - content::RenderProcessHost::FromID(process_id); |
| - if (!rph) |
| - return; |
| - |
| - int tab_id = -1; |
| - // We need to loop through all the RVHs to ensure we collect the set of all |
| - // tabs using this renderer process. |
| - scoped_ptr<content::RenderWidgetHostIterator> widgets( |
| - content::RenderWidgetHost::GetRenderWidgetHosts()); |
| - while (content::RenderWidgetHost* widget = widgets->GetNextHost()) { |
| - if (widget->GetProcess()->GetID() != process_id) |
| - continue; |
| - |
| - content::RenderViewHost* host = content::RenderViewHost::From(widget); |
| - content::WebContents* contents = |
| - content::WebContents::FromRenderViewHost(host); |
| - if (contents) { |
| - tab_id = ExtensionTabUtil::GetTabId(contents); |
| - if (tab_id != -1) |
| - out_process->tabs.push_back(tab_id); |
| - } |
| + out_process->id = task_manager->GetChildProcessUniqueId(id); |
| + out_process->os_process_id = task_manager->GetProcessId(id); |
| + out_process->type = GetProcessType(task_manager->GetType(id)); |
| + out_process->profile = base::UTF16ToUTF8(task_manager->GetProfileName(id)); |
| + out_process->nacl_debug_port = task_manager->GetNaClDebugStubPort(id); |
| + |
| + // Collect the tab IDs of all the tasks sharing this renderer if any. |
| + const task_management::TaskIdList tasks_on_process = |
| + task_manager->GetIdsOfTasksSharingSameProcess(id); |
| + for (const auto& task_id : tasks_on_process) { |
| + linked_ptr<api::processes::TaskInfo> task_info( |
| + new api::processes::TaskInfo()); |
| + task_info->title = base::UTF16ToUTF8(task_manager->GetTitle(task_id)); |
| + const int tab_id = task_manager->GetTabId(task_id); |
| + if (tab_id != -1) |
| + task_info->tab_id.reset(new int(tab_id)); |
| + |
| + out_process->tasks.push_back(task_info); |
| } |
| -} |
| - |
| -// This function fills |out_process| with the data of the process with |
| -// |process_id|. For memory details, which are not added by this function, |
| -// the callers need to use AddMemoryDetails. |
| -void FillProcessData(int process_id, |
| - TaskManagerModel* model, |
| - int index, |
| - bool include_optional, |
| - api::processes::Process* out_process) { |
| - DCHECK(out_process); |
| - |
| - out_process->id = process_id; |
| - out_process->os_process_id = model->GetProcessId(index); |
| - out_process->type = GetProcessType(model, index); |
| - out_process->title = base::UTF16ToUTF8(model->GetResourceTitle(index)); |
| - out_process->profile = |
| - base::UTF16ToUTF8(model->GetResourceProfileName(index)); |
| - out_process->nacl_debug_port = model->GetNaClDebugStubPort(index); |
| - |
| - FillTabsForProcess(process_id, out_process); |
| // If we don't need to include the optional properties, just return now. |
| if (!include_optional) |
| return; |
| - out_process->cpu.reset(new double(model->GetCPUUsage(index))); |
| + out_process->cpu.reset(new double(task_manager->GetCpuUsage(id))); |
| + |
| + out_process->network.reset(new double(static_cast<double>( |
| + task_manager->GetProcessTotalNetworkUsage(id)))); |
| - size_t mem = 0; |
| - if (model->GetV8Memory(index, &mem)) { |
| + int64_t v8_allocated = 0; |
| + int64_t v8_used = 0; |
| + if (task_manager->GetV8Memory(id, &v8_allocated, &v8_used)) { |
| out_process->js_memory_allocated.reset(new double(static_cast<double>( |
| - mem))); |
| + v8_allocated))); |
| + out_process->js_memory_used.reset(new double(static_cast<double>(v8_used))); |
| } |
| - if (model->GetV8MemoryUsed(index, &mem)) |
| - out_process->js_memory_used.reset(new double(static_cast<double>(mem))); |
| - |
| - if (model->GetSqliteMemoryUsedBytes(index, &mem)) |
| - out_process->sqlite_memory.reset(new double(static_cast<double>(mem))); |
| + const int64_t sqlite_bytes = task_manager->GetSqliteMemoryUsed(id); |
| + if (sqlite_bytes != -1) { |
| + out_process->sqlite_memory.reset(new double(static_cast<double>( |
| + sqlite_bytes))); |
| + } |
| blink::WebCache::ResourceTypeStats cache_stats; |
| - if (model->GetWebCoreCacheStats(index, &cache_stats)) { |
| + if (task_manager->GetWebCacheStats(id, &cache_stats)) { |
| out_process->image_cache = CreateCacheData(cache_stats.images); |
| out_process->script_cache = CreateCacheData(cache_stats.scripts); |
| out_process->css_cache = CreateCacheData(cache_stats.cssStyleSheets); |
| } |
| - |
| - // Network is reported by the TaskManager per resource (tab), not per |
| - // process, therefore we need to iterate through the group of resources |
| - // and aggregate the data. |
| - int64_t net = 0; |
| - int length = model->GetGroupRangeForResource(index).second; |
| - for (int i = 0; i < length; ++i) |
| - net += model->GetNetworkUsage(index + i); |
| - out_process->network.reset(new double(static_cast<double>(net))); |
| -} |
| - |
| -// Since memory details are expensive to gather, we don't do it by default. |
| -// This function is a helper to add memory details data to an existing |
| -// Process object |out_process|. |
| -void AddMemoryDetails(TaskManagerModel* model, |
| - int index, |
| - api::processes::Process* out_process) { |
| - DCHECK(out_process); |
| - |
| - size_t mem; |
| - int64_t pr_mem = |
| - model->GetPrivateMemory(index, &mem) ? static_cast<int64_t>(mem) : -1; |
| - out_process->private_memory.reset(new double(static_cast<double>(pr_mem))); |
| } |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| - |
| } // namespace |
| -ProcessesEventRouter::ProcessesEventRouter(content::BrowserContext* context) |
| - : browser_context_(context), listeners_(0), task_manager_listening_(false) { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - model_ = TaskManager::GetInstance()->model(); |
| - model_->AddObserver(this); |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// ProcessesEventRouter: |
| +//////////////////////////////////////////////////////////////////////////////// |
| - registrar_.Add(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, |
| - content::NotificationService::AllSources()); |
| - registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| - content::NotificationService::AllSources()); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| +ProcessesEventRouter::ProcessesEventRouter(content::BrowserContext* context) |
| + : task_management::TaskManagerObserver(base::TimeDelta::FromSeconds(1), |
| + task_management::REFRESH_TYPE_NONE), |
| + browser_context_(context), |
| + listeners_(0) { |
| } |
| ProcessesEventRouter::~ProcessesEventRouter() { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - registrar_.Remove(this, content::NOTIFICATION_RENDER_WIDGET_HOST_HANG, |
| - content::NotificationService::AllSources()); |
| - registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, |
| - content::NotificationService::AllSources()); |
| - |
| - if (task_manager_listening_) |
| - model_->StopListening(); |
| - |
| - model_->RemoveObserver(this); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| } |
| void ProcessesEventRouter::ListenerAdded() { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - // The task manager has its own ref count to balance other callers of |
| - // StartUpdating/StopUpdating. |
| - model_->StartUpdating(); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| - ++listeners_; |
| + UpdateRefreshTypesFlagsBasedOnListeners(); |
| + |
| + if (listeners_++ == 0) { |
| + // The first listener to be added. |
| + task_management::TaskManagerInterface::GetTaskManager()->AddObserver(this); |
| + } |
| } |
| void ProcessesEventRouter::ListenerRemoved() { |
| - DCHECK_GT(listeners_, 0); |
| - --listeners_; |
| -#if defined(ENABLE_TASK_MANAGER) |
| - // The task manager has its own ref count to balance other callers of |
| - // StartUpdating/StopUpdating. |
| - model_->StopUpdating(); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| -} |
| - |
| -void ProcessesEventRouter::StartTaskManagerListening() { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - if (!task_manager_listening_) { |
| - model_->StartListening(); |
| - task_manager_listening_ = true; |
| - } |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| -} |
| - |
| -void ProcessesEventRouter::Observe( |
| - int type, |
| - const content::NotificationSource& source, |
| - const content::NotificationDetails& details) { |
| - |
| - switch (type) { |
| - case content::NOTIFICATION_RENDER_WIDGET_HOST_HANG: |
| - ProcessHangEvent( |
| - content::Source<content::RenderWidgetHost>(source).ptr()); |
| - break; |
| - case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: |
| - ProcessClosedEvent( |
| - content::Source<content::RenderProcessHost>(source).ptr(), |
| - content::Details<content::RenderProcessHost::RendererClosedDetails>( |
| - details).ptr()); |
| - break; |
| - default: |
| - NOTREACHED() << "Unexpected observe of type " << type; |
| + UpdateRefreshTypesFlagsBasedOnListeners(); |
| + |
| + if (--listeners_ == 0) { |
| + // Last listener to be removed. |
| + task_management::TaskManagerInterface::GetTaskManager()->RemoveObserver( |
| + this); |
| } |
| - return; |
| } |
| -void ProcessesEventRouter::OnItemsAdded(int start, int length) { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - DCHECK_EQ(length, 1); |
| +void ProcessesEventRouter::OnTaskAdded(task_management::TaskId id) { |
| if (!HasEventListeners(api::processes::OnCreated::kEventName)) |
| return; |
| - // If the item being added is not the first one in the group, find the base |
| - // index and use it for retrieving the process data. |
| - if (!model_->IsResourceFirstInGroup(start)) |
| - start = model_->GetGroupIndexForResource(start); |
| + int child_process_host_id = 0; |
| + if (!ShouldReportOnCreatedOrOnExited(id, &child_process_host_id)) |
| + return; |
| api::processes::Process process; |
| - FillProcessData(model_->GetUniqueChildProcessId(start), model_, start, |
| - false /* include_optional */, &process); |
| + FillProcessData(id, |
| + observed_task_manager(), |
| + false, // include_optional |
| + &process); |
| DispatchEvent(events::PROCESSES_ON_CREATED, |
| api::processes::OnCreated::kEventName, |
| api::processes::OnCreated::Create(process)); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| } |
| -void ProcessesEventRouter::OnItemsChanged(int start, int length) { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - // If we don't have any listeners, return immediately. |
| - if (listeners_ == 0) |
| +void ProcessesEventRouter::OnTaskToBeRemoved(task_management::TaskId id) { |
| + if (!HasEventListeners(api::processes::OnExited::kEventName)) |
| return; |
| - if (!model_) |
| + int child_process_host_id = 0; |
| + if (!ShouldReportOnCreatedOrOnExited(id, &child_process_host_id)) |
| return; |
| - // We need to know which type of onUpdated events to fire and whether to |
| - // collect memory or not. |
| - bool updated = HasEventListeners(api::processes::OnUpdated::kEventName); |
| - bool updated_memory = |
| + int exit_code = 0; |
| + base::TerminationStatus status = base::TERMINATION_STATUS_STILL_RUNNING; |
| + observed_task_manager()->GetTerminationStatus(id, &status, &exit_code); |
| + |
| + DispatchEvent(events::PROCESSES_ON_EXITED, |
| + api::processes::OnExited::kEventName, |
| + api::processes::OnExited::Create(child_process_host_id, |
| + status, |
| + exit_code)); |
| +} |
| + |
| +void ProcessesEventRouter::OnTasksRefreshedWithBackgroundCalculations( |
| + const task_management::TaskIdList& task_ids) { |
| + const bool has_on_updated_listeners = |
| + HasEventListeners(api::processes::OnUpdated::kEventName); |
| + const bool has_on_updated_with_memory_listeners = |
| HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName); |
| - if (!updated && !updated_memory) |
| + |
| + if (!has_on_updated_listeners && !has_on_updated_with_memory_listeners) |
| return; |
| + // Get the data of tasks sharing the same process only once. |
| + std::set<base::ProcessId> seen_processes; |
| base::DictionaryValue processes_dictionary; |
| - for (int i = start; i < start + length; ++i) { |
| - if (model_->IsResourceFirstInGroup(i)) { |
| - int id = model_->GetUniqueChildProcessId(i); |
| - api::processes::Process process; |
| - FillProcessData(id, model_, i, true /* include_optional */, &process); |
| - if (updated_memory) |
| - AddMemoryDetails(model_, i, &process); |
| - processes_dictionary.Set(base::IntToString(id), process.ToValue()); |
| + for (const auto& task_id : task_ids) { |
| + // We are not interested in tasks, but rather the processes on which they |
| + // run. |
| + const base::ProcessId proc_id = |
| + observed_task_manager()->GetProcessId(task_id); |
| + if (seen_processes.count(proc_id)) |
| + continue; |
| + |
| + const int child_process_host_id = |
| + observed_task_manager()->GetChildProcessUniqueId(task_id); |
| + // Ignore tasks that don't have a valid child process host ID like ARC |
| + // processes. We report the browser process info here though. |
| + if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID) |
| + continue; |
| + |
| + seen_processes.insert(proc_id); |
| + api::processes::Process process; |
| + FillProcessData(task_id, |
| + observed_task_manager(), |
| + true, // include_optional |
| + &process); |
| + |
| + if (has_on_updated_with_memory_listeners) { |
| + // Append the private memory usage to the process data. |
| + const int64_t private_memory = |
| + observed_task_manager()->GetPrivateMemoryUsage(task_id); |
| + process.private_memory.reset(new double(static_cast<double>( |
| + private_memory))); |
| } |
| + |
| + // Store each process indexed by the string version of its ChildProcessHost |
| + // ID. |
| + processes_dictionary.Set(base::IntToString(child_process_host_id), |
| + process.ToValue()); |
| } |
| - if (updated) { |
| + // Done with data collection. Now dispatch the appropriate events according to |
| + // the present listeners. |
| + DCHECK(has_on_updated_listeners || has_on_updated_with_memory_listeners); |
| + if (has_on_updated_listeners) { |
| api::processes::OnUpdated::Processes processes; |
| processes.additional_properties.MergeDictionary(&processes_dictionary); |
| // NOTE: If there are listeners to the updates with memory as well, |
| @@ -347,80 +301,33 @@ void ProcessesEventRouter::OnItemsChanged(int start, int length) { |
| api::processes::OnUpdated::Create(processes)); |
| } |
| - if (updated_memory) { |
| + if (has_on_updated_with_memory_listeners) { |
| api::processes::OnUpdatedWithMemory::Processes processes; |
| processes.additional_properties.MergeDictionary(&processes_dictionary); |
| DispatchEvent(events::PROCESSES_ON_UPDATED_WITH_MEMORY, |
| api::processes::OnUpdatedWithMemory::kEventName, |
| - api::processes::OnUpdatedWithMemory::Create(processes));} |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| -} |
| - |
| -void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - DCHECK_EQ(length, 1); |
| - |
| - if (!HasEventListeners(api::processes::OnExited::kEventName)) |
| - return; |
| - |
| - // Process exit for renderer processes has the data about exit code and |
| - // termination status, therefore we will rely on notifications and not on |
| - // the Task Manager data. We do use the rest of this method for non-renderer |
| - // processes. |
| - if (model_->GetResourceType(start) == task_manager::Resource::RENDERER) |
| - return; |
| - |
| - DispatchEvent(events::PROCESSES_ON_EXITED, |
| - api::processes::OnExited::kEventName, |
| - api::processes::OnExited::Create( |
| - model_->GetUniqueChildProcessId(start), |
| - 0 /* exit_type */, |
| - 0 /* exit_code */)); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| -} |
| - |
| -void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost* widget) { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - if (!HasEventListeners(api::processes::OnUnresponsive::kEventName)) |
| - return; |
| - |
| - int count = model_->ResourceCount(); |
| - int id = widget->GetProcess()->GetID(); |
| - |
| - for (int i = 0; i < count; ++i) { |
| - if (model_->IsResourceFirstInGroup(i)) { |
| - if (id == model_->GetUniqueChildProcessId(i)) { |
| - api::processes::Process process; |
| - FillProcessData(id, model_, i, false /* include_optional */, &process); |
| - DispatchEvent(events::PROCESSES_ON_UNRESPONSIVE, |
| - api::processes::OnUnresponsive::kEventName, |
| - api::processes::OnUnresponsive::Create(process)); |
| - return; |
| - } |
| - } |
| + api::processes::OnUpdatedWithMemory::Create(processes)); |
| } |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| } |
| -void ProcessesEventRouter::ProcessClosedEvent( |
| - content::RenderProcessHost* rph, |
| - content::RenderProcessHost::RendererClosedDetails* details) { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - if (!HasEventListeners(api::processes::OnExited::kEventName)) |
| +void ProcessesEventRouter::OnTaskUnresponsive(task_management::TaskId id) { |
| + if (!HasEventListeners(api::processes::OnUnresponsive::kEventName)) |
| return; |
| - DispatchEvent(events::PROCESSES_ON_EXITED, |
| - api::processes::OnExited::kEventName, |
| - api::processes::OnExited::Create(rph->GetID(), |
| - details->status, |
| - details->exit_code)); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| + api::processes::Process process; |
| + FillProcessData(id, |
| + observed_task_manager(), |
| + false, // include_optional |
| + &process); |
| + DispatchEvent(events::PROCESSES_ON_UNRESPONSIVE, |
| + api::processes::OnUnresponsive::kEventName, |
| + api::processes::OnUnresponsive::Create(process)); |
| } |
| void ProcessesEventRouter::DispatchEvent( |
| events::HistogramValue histogram_value, |
| const std::string& event_name, |
| - scoped_ptr<base::ListValue> event_args) { |
| + scoped_ptr<base::ListValue> event_args) const { |
| EventRouter* event_router = EventRouter::Get(browser_context_); |
| if (event_router) { |
| scoped_ptr<Event> event( |
| @@ -429,11 +336,53 @@ void ProcessesEventRouter::DispatchEvent( |
| } |
| } |
| -bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) { |
| +bool ProcessesEventRouter::HasEventListeners( |
| + const std::string& event_name) const { |
| EventRouter* event_router = EventRouter::Get(browser_context_); |
| return event_router && event_router->HasEventListener(event_name); |
| } |
| +bool ProcessesEventRouter::ShouldReportOnCreatedOrOnExited( |
| + task_management::TaskId id, |
| + int* out_child_process_host_id) const { |
| + // Is it the first task to be created or the last one to be removed? |
| + if (observed_task_manager()->GetNumberOfTasksOnSameProcess(id) != 1) |
| + return false; |
| + |
| + // Ignore tasks that don't have a valid child process host ID like ARC |
| + // processes, as well as the browser process (neither onCreated() nor |
| + // onExited() shouldn't report the browser process). |
| + *out_child_process_host_id = |
| + observed_task_manager()->GetChildProcessUniqueId(id); |
| + if (*out_child_process_host_id == |
| + content::ChildProcessHost::kInvalidUniqueID || |
| + *out_child_process_host_id == 0) { |
| + return false; |
| + } |
| + |
| + return true; |
| +} |
| + |
| +void ProcessesEventRouter::UpdateRefreshTypesFlagsBasedOnListeners() { |
| + int64_t refresh_types = task_management::REFRESH_TYPE_NONE; |
| + if (HasEventListeners(api::processes::OnCreated::kEventName) || |
| + HasEventListeners(api::processes::OnUnresponsive::kEventName)) { |
| + refresh_types |= GetRefreshTypesFlagOnlyEssentialData(); |
| + } |
| + |
| + if (HasEventListeners(api::processes::OnUpdated::kEventName)) |
| + refresh_types |= GetRefreshTypesForProcessOptionalData(); |
| + |
| + if (HasEventListeners(api::processes::OnUpdatedWithMemory::kEventName)) |
| + refresh_types |= task_management::REFRESH_TYPE_MEMORY; |
| + |
| + SetRefreshTypesFlags(refresh_types); |
| +} |
| + |
| +//////////////////////////////////////////////////////////////////////////////// |
| +// ProcessesAPI: |
| +//////////////////////////////////////////////////////////////////////////////// |
| + |
| ProcessesAPI::ProcessesAPI(content::BrowserContext* context) |
| : browser_context_(context) { |
| EventRouter* event_router = EventRouter::Get(browser_context_); |
| @@ -449,19 +398,13 @@ ProcessesAPI::ProcessesAPI(content::BrowserContext* context) |
| } |
| ProcessesAPI::~ProcessesAPI() { |
| + // This object has already been unregistered as an observer in Shutdown(). |
| } |
| -void ProcessesAPI::Shutdown() { |
| - EventRouter::Get(browser_context_)->UnregisterObserver(this); |
| -} |
| - |
| -static base::LazyInstance<BrowserContextKeyedAPIFactory<ProcessesAPI> > |
| - g_factory = LAZY_INSTANCE_INITIALIZER; |
| - |
| // static |
| BrowserContextKeyedAPIFactory<ProcessesAPI>* |
| ProcessesAPI::GetFactoryInstance() { |
| - return g_factory.Pointer(); |
| + return g_processes_api_factory.Pointer(); |
| } |
| // static |
| @@ -469,292 +412,280 @@ ProcessesAPI* ProcessesAPI::Get(content::BrowserContext* context) { |
| return BrowserContextKeyedAPIFactory<ProcessesAPI>::Get(context); |
| } |
| -ProcessesEventRouter* ProcessesAPI::processes_event_router() { |
| - if (!processes_event_router_) |
| - processes_event_router_.reset(new ProcessesEventRouter(browser_context_)); |
| - return processes_event_router_.get(); |
| +void ProcessesAPI::Shutdown() { |
| + EventRouter::Get(browser_context_)->UnregisterObserver(this); |
| } |
| void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) { |
| - // We lazily tell the TaskManager to start updating when listeners to the |
| - // processes.onUpdated or processes.onUpdatedWithMemory events arrive. |
| + // The ProcessesEventRouter will observe the TaskManager as long as there are |
| + // listeners for the processes.onUpdated/.onUpdatedWithMemory/.onCreated ... |
| + // etc. events. |
| processes_event_router()->ListenerAdded(); |
| } |
| void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) { |
| - // If a processes.onUpdated or processes.onUpdatedWithMemory event listener |
| - // is removed (or a process with one exits), then we let the extension API |
| - // know that it has one fewer listener. |
| + // If a processes.onUpdated/.onUpdatedWithMemory/.onCreated ... etc. event |
| + // listener is removed (or a process with one exits), then we let the |
| + // extension API know that it has one fewer listener. |
| processes_event_router()->ListenerRemoved(); |
| } |
| +ProcessesEventRouter* ProcessesAPI::processes_event_router() { |
| + if (!processes_event_router_.get()) |
| + processes_event_router_.reset(new ProcessesEventRouter(browser_context_)); |
| + return processes_event_router_.get(); |
| +} |
| + |
| //////////////////////////////////////////////////////////////////////////////// |
| // ProcessesGetProcessIdForTabFunction: |
| //////////////////////////////////////////////////////////////////////////////// |
| -ProcessesGetProcessIdForTabFunction::ProcessesGetProcessIdForTabFunction() |
| - : tab_id_(-1) { |
| -} |
| - |
| ExtensionFunction::ResponseAction ProcessesGetProcessIdForTabFunction::Run() { |
| -#if defined(ENABLE_TASK_MANAGER) |
| + // For this function, the task manager doesn't even need to be running. |
| scoped_ptr<api::processes::GetProcessIdForTab::Params> params( |
| - api::processes::GetProcessIdForTab::Params::Create(*args_)); |
| + api::processes::GetProcessIdForTab::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| - tab_id_ = params->tab_id; |
| - |
| - if (tab_id_ < 0) { |
| - return RespondNow(Error(errors::kInavlidArgument, |
| - base::IntToString(tab_id_))); |
| - } |
| - |
| - // Add a reference, which is balanced in GetProcessIdForTab to keep the object |
| - // around and allow for the callback to be invoked. |
| - AddRef(); |
| - |
| - // If the task manager is already listening, just post a task to execute |
| - // which will invoke the callback once we have returned from this function. |
| - // Otherwise, wait for the notification that the task manager is done with |
| - // the data gathering. |
| - if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) |
| - ->processes_event_router() |
| - ->is_task_manager_listening()) { |
| - base::ThreadTaskRunnerHandle::Get()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&ProcessesGetProcessIdForTabFunction::GetProcessIdForTab, |
| - this)); |
| - } else { |
| - TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback( |
| - base::Bind(&ProcessesGetProcessIdForTabFunction::GetProcessIdForTab, |
| - this)); |
| - |
| - ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) |
| - ->processes_event_router() |
| - ->StartTaskManagerListening(); |
| - } |
| - return RespondLater(); |
| -#else |
| - return RespondNow(Error(errors::kExtensionNotSupported)); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| -} |
| - |
| -void ProcessesGetProcessIdForTabFunction::GetProcessIdForTab() { |
| - content::WebContents* contents = NULL; |
| + const int tab_id = params->tab_id; |
| + content::WebContents* contents = nullptr; |
| int tab_index = -1; |
| if (!ExtensionTabUtil::GetTabById( |
| - tab_id_, |
| + tab_id, |
| Profile::FromBrowserContext(browser_context()), |
| include_incognito(), |
| nullptr, |
| nullptr, |
| &contents, |
| &tab_index)) { |
| - Respond(Error(tabs_constants::kTabNotFoundError, |
| - base::IntToString(tab_id_))); |
| - } else { |
| - int process_id = contents->GetRenderProcessHost()->GetID(); |
| - Respond(ArgumentList( |
| - api::processes::GetProcessIdForTab::Results::Create(process_id))); |
| + return RespondNow(Error(tabs_constants::kTabNotFoundError, |
| + base::IntToString(tab_id))); |
| } |
| - // Balance the AddRef in the Run. |
| - Release(); |
| + const int process_id = contents->GetRenderProcessHost()->GetID(); |
| + return RespondNow(ArgumentList( |
| + api::processes::GetProcessIdForTab::Results::Create(process_id))); |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| -// ProcessesTerminateFunction |
| +// ProcessesTerminateFunction: |
| //////////////////////////////////////////////////////////////////////////////// |
| -ProcessesTerminateFunction::ProcessesTerminateFunction() : process_id_(-1) { |
| -} |
| - |
| ExtensionFunction::ResponseAction ProcessesTerminateFunction::Run() { |
| -#if defined(ENABLE_TASK_MANAGER) |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| + |
| + // For this function, the task manager doesn't even need to be running. |
| scoped_ptr<api::processes::Terminate::Params> params( |
| api::processes::Terminate::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| - process_id_ = params->process_id; |
| - |
| - // Add a reference, which is balanced in TerminateProcess to keep the object |
| - // around and allow for the callback to be invoked. |
| - AddRef(); |
| - // If the task manager is already listening, just post a task to execute |
| - // which will invoke the callback once we have returned from this function. |
| - // Otherwise, wait for the notification that the task manager is done with |
| - // the data gathering. |
| - if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) |
| - ->processes_event_router() |
| - ->is_task_manager_listening()) { |
| - base::ThreadTaskRunnerHandle::Get()->PostTask( |
| - FROM_HERE, base::Bind(&ProcessesTerminateFunction::TerminateProcess, |
| - this)); |
| - } else { |
| - TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback( |
| - base::Bind(&ProcessesTerminateFunction::TerminateProcess, this)); |
| - |
| - ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) |
| - ->processes_event_router() |
| - ->StartTaskManagerListening(); |
| + child_process_host_id_ = params->process_id; |
| + if (child_process_host_id_ < 0) { |
| + return RespondNow(Error(errors::kInvalidArgument, |
| + base::IntToString(child_process_host_id_))); |
| + } else if (child_process_host_id_ == 0) { |
| + // Cannot kill the browser process. |
| + return RespondNow(Error(errors::kNotAllowedToTerminate, |
| + base::IntToString(child_process_host_id_))); |
| } |
| + // Check if it's a renderer. |
| + auto* render_process_host = |
| + content::RenderProcessHost::FromID(child_process_host_id_); |
| + if (render_process_host) |
| + return RespondNow(TerminateIfAllowed(render_process_host->GetHandle())); |
| + |
| + // This could be a non-renderer child process like a plugin or a nacl |
| + // process. Try to get its handle from the BrowserChildProcessHost on the |
| + // IO thread. |
| + content::BrowserThread::PostTaskAndReplyWithResult( |
| + content::BrowserThread::IO, |
| + FROM_HERE, |
| + base::Bind(&ProcessesTerminateFunction::GetProcessHandleOnIO, |
| + this, |
| + child_process_host_id_), |
| + base::Bind(&ProcessesTerminateFunction::OnProcessHandleOnUI, this)); |
| + |
| + // Promise to respond later. |
| return RespondLater(); |
| -#else |
| - return RespondNow(Error(errors::kExtensionNotSupported)); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| -} |
| - |
| -void ProcessesTerminateFunction::TerminateProcess() { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - TaskManagerModel* model = TaskManager::GetInstance()->model(); |
| - |
| - bool found = false; |
| - for (int i = 0, count = model->ResourceCount(); i < count; ++i) { |
| - if (model->IsResourceFirstInGroup(i) && |
| - process_id_ == model->GetUniqueChildProcessId(i)) { |
| - base::ProcessHandle process_handle = model->GetProcess(i); |
| - if (process_handle == base::GetCurrentProcessHandle()) { |
| - // Cannot kill the browser process. |
| - // TODO(kalman): Are there other sensitive processes? |
| - Respond(Error(errors::kNotAllowedToTerminate, |
| - base::IntToString(process_id_))); |
| - } else { |
| - base::Process process = |
| - base::Process::DeprecatedGetProcessFromHandle(process_handle); |
| - bool did_terminate = |
| - process.Terminate(content::RESULT_CODE_KILLED, true); |
| - if (did_terminate) |
| - UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1); |
| - |
| - Respond(ArgumentList( |
| - api::processes::Terminate::Results::Create(did_terminate))); |
| - } |
| - found = true; |
| - break; |
| - } |
| +} |
| + |
| +base::ProcessHandle ProcessesTerminateFunction::GetProcessHandleOnIO( |
| + int child_process_host_id) const { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::IO); |
| + |
| + auto* host = content::BrowserChildProcessHost::FromID(child_process_host_id); |
| + if (host) |
| + return host->GetData().handle; |
| + |
| + return base::kNullProcessHandle; |
| +} |
| + |
| +void ProcessesTerminateFunction::OnProcessHandleOnUI( |
| + base::ProcessHandle handle) { |
| + DCHECK_CURRENTLY_ON(content::BrowserThread::UI); |
| + |
| + Respond(TerminateIfAllowed(handle)); |
| +} |
| + |
| +ExtensionFunction::ResponseValue |
| +ProcessesTerminateFunction::TerminateIfAllowed(base::ProcessHandle handle) { |
| + if (handle == base::kNullProcessHandle) { |
| + return Error(errors::kProcessNotFound, |
| + base::IntToString(child_process_host_id_)); |
| } |
| - if (!found) |
| - Respond(Error(errors::kProcessNotFound, base::IntToString(process_id_))); |
| + if (handle == base::GetCurrentProcessHandle()) { |
| + // Cannot kill the browser process. |
| + return Error(errors::kNotAllowedToTerminate, |
| + base::IntToString(child_process_host_id_)); |
| + } |
| - // Balance the AddRef in the Run. |
| - Release(); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| + base::Process process = base::Process::Open(base::GetProcId(handle)); |
| + if (!process.IsValid()) { |
| + return Error(errors::kProcessNotFound, |
| + base::IntToString(child_process_host_id_)); |
| + } |
| + |
| + const bool did_terminate = |
| + process.Terminate(content::RESULT_CODE_KILLED, true /* wait */); |
| + if (did_terminate) |
| + UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1); |
| + |
| + return ArgumentList( |
| + api::processes::Terminate::Results::Create(did_terminate)); |
| } |
| //////////////////////////////////////////////////////////////////////////////// |
| -// ProcessesGetProcessInfoFunction |
| +// ProcessesGetProcessInfoFunction: |
| //////////////////////////////////////////////////////////////////////////////// |
| ProcessesGetProcessInfoFunction::ProcessesGetProcessInfoFunction() |
| -#if defined(ENABLE_TASK_MANAGER) |
| - : memory_(false) |
| -#endif |
| - { |
| + : task_management::TaskManagerObserver( |
| + base::TimeDelta::FromSeconds(1), |
| + GetRefreshTypesFlagOnlyEssentialData()) { |
| } |
| ExtensionFunction::ResponseAction ProcessesGetProcessInfoFunction::Run() { |
| -#if defined(ENABLE_TASK_MANAGER) |
| scoped_ptr<api::processes::GetProcessInfo::Params> params( |
| api::processes::GetProcessInfo::Params::Create(*args_)); |
| EXTENSION_FUNCTION_VALIDATE(params.get()); |
| if (params->process_ids.as_integer) |
| - process_ids_.push_back(*params->process_ids.as_integer); |
| + process_host_ids_.push_back(*params->process_ids.as_integer); |
| else |
| - process_ids_.swap(*params->process_ids.as_integers); |
| + process_host_ids_.swap(*params->process_ids.as_integers); |
| - memory_ = params->include_memory; |
| + include_memory_ = params->include_memory; |
| + if (include_memory_) |
| + AddRefreshType(task_management::REFRESH_TYPE_MEMORY); |
| - // Add a reference, which is balanced in GatherProcessInfo to keep the object |
| - // around and allow for the callback to be invoked. |
| + // Keep this object alive until the first of either OnTasksRefreshed() or |
| + // OnTasksRefreshedWithBackgroundCalculations() is received depending on |
| + // |include_memory_|. |
| AddRef(); |
| - // If the task manager is already listening, just post a task to execute |
| - // which will invoke the callback once we have returned from this function. |
| - // Otherwise, wait for the notification that the task manager is done with |
| - // the data gathering. |
| - if (ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) |
| - ->processes_event_router() |
| - ->is_task_manager_listening()) { |
| - base::ThreadTaskRunnerHandle::Get()->PostTask( |
| - FROM_HERE, |
| - base::Bind(&ProcessesGetProcessInfoFunction::GatherProcessInfo, this)); |
| - } else { |
| - TaskManager::GetInstance()->model()->RegisterOnDataReadyCallback( |
| - base::Bind(&ProcessesGetProcessInfoFunction::GatherProcessInfo, this)); |
| - |
| - ProcessesAPI::Get(Profile::FromBrowserContext(browser_context())) |
| - ->processes_event_router() |
| - ->StartTaskManagerListening(); |
| - } |
| + // The task manager needs to be enabled for this function. |
| + // Start observing the task manager and wait for the next refresh event. |
| + task_management::TaskManagerInterface::GetTaskManager()->AddObserver(this); |
| return RespondLater(); |
| -#else |
| - return RespondNow(Error(errors::kExtensionNotSupported)); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| } |
| -ProcessesGetProcessInfoFunction::~ProcessesGetProcessInfoFunction() { |
| +void ProcessesGetProcessInfoFunction::OnTasksRefreshed( |
| + const task_management::TaskIdList& task_ids) { |
| + // Memory is background calculated and will be ready when |
| + // OnTasksRefreshedWithBackgroundCalculations() is invoked. |
| + if (include_memory_) |
| + return; |
| + |
| + GatherDataAndRespond(task_ids); |
| } |
| -void ProcessesGetProcessInfoFunction::GatherProcessInfo() { |
| -#if defined(ENABLE_TASK_MANAGER) |
| - TaskManagerModel* model = TaskManager::GetInstance()->model(); |
| - api::processes::GetProcessInfo::Results::Processes processes; |
| +void |
| +ProcessesGetProcessInfoFunction::OnTasksRefreshedWithBackgroundCalculations( |
| + const task_management::TaskIdList& task_ids) { |
| + if (!include_memory_) |
| + return; |
| + GatherDataAndRespond(task_ids); |
| +} |
| + |
| +ProcessesGetProcessInfoFunction::~ProcessesGetProcessInfoFunction() {} |
| + |
| +void ProcessesGetProcessInfoFunction::GatherDataAndRespond( |
| + const task_management::TaskIdList& task_ids) { |
| // If there are no process IDs specified, it means we need to return all of |
| // the ones we know of. |
| - if (process_ids_.size() == 0) { |
| - int resources = model->ResourceCount(); |
| - for (int i = 0; i < resources; ++i) { |
| - if (model->IsResourceFirstInGroup(i)) { |
| - int id = model->GetUniqueChildProcessId(i); |
| - api::processes::Process process; |
| - FillProcessData(id, model, i, false, &process); |
| - if (memory_) |
| - AddMemoryDetails(model, i, &process); |
| - processes.additional_properties.Set(base::IntToString(id), |
| - process.ToValue()); |
| - } |
| - } |
| - } else { |
| - int resources = model->ResourceCount(); |
| - for (int i = 0; i < resources; ++i) { |
| - if (model->IsResourceFirstInGroup(i)) { |
| - int id = model->GetUniqueChildProcessId(i); |
| - std::vector<int>::iterator proc_id = std::find(process_ids_.begin(), |
| - process_ids_.end(), id); |
| - if (proc_id != process_ids_.end()) { |
| - api::processes::Process process; |
| - FillProcessData(id, model, i, false, &process); |
| - if (memory_) |
| - AddMemoryDetails(model, i, &process); |
| - processes.additional_properties.Set(base::IntToString(id), |
| - process.ToValue()); |
| - |
| - process_ids_.erase(proc_id); |
| - if (process_ids_.size() == 0) |
| - break; |
| - } |
| - } |
| + const bool specific_processes_requested = !process_host_ids_.empty(); |
| + std::set<base::ProcessId> seen_processes; |
| + // Create the results object as defined in the generated API from process.idl |
| + // and fill it with the processes info. |
| + api::processes::GetProcessInfo::Results::Processes processes; |
| + for (const auto& task_id : task_ids) { |
| + const base::ProcessId proc_id = |
| + observed_task_manager()->GetProcessId(task_id); |
| + if (seen_processes.count(proc_id)) |
| + continue; |
| + |
| + const int child_process_host_id = |
| + observed_task_manager()->GetChildProcessUniqueId(task_id); |
| + // Ignore tasks that don't have a valid child process host ID like ARC |
| + // processes. We report the browser process info here though. |
| + if (child_process_host_id == content::ChildProcessHost::kInvalidUniqueID) |
| + continue; |
| + |
| + if (specific_processes_requested) { |
| + // Note: we can't use |!process_host_ids_.empty()| directly in the above |
| + // condition as we will erase from |process_host_ids_| below. |
| + auto itr = std::find(process_host_ids_.begin(), |
| + process_host_ids_.end(), |
| + child_process_host_id); |
| + if (itr == process_host_ids_.end()) |
| + continue; |
| + |
| + // If found, we remove it from |process_host_ids|, so that at the end if |
| + // anything remains in |process_host_ids|, those were invalid arguments |
| + // that will be reported on the console. |
| + process_host_ids_.erase(itr); |
| } |
| - // If not all processes were found, log them to the extension's console to |
| - // help the developer, but don't fail the API call. |
| - for (int pid : process_ids_) { |
| - WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR, |
| - ErrorUtils::FormatErrorMessage(errors::kProcessNotFound, |
| - base::IntToString(pid))); |
| + |
| + seen_processes.insert(proc_id); |
| + |
| + // We do not include the optional data in this function results. |
| + api::processes::Process process; |
| + FillProcessData(task_id, |
| + observed_task_manager(), |
| + false, // include_optional |
| + &process); |
| + |
| + if (include_memory_) { |
| + // Append the private memory usage to the process data. |
| + const int64_t private_memory = |
| + observed_task_manager()->GetPrivateMemoryUsage(task_id); |
| + process.private_memory.reset(new double(static_cast<double>( |
| + private_memory))); |
| } |
| + |
| + // Store each process indexed by the string version of its |
| + // ChildProcessHost ID. |
| + processes.additional_properties.Set( |
| + base::IntToString(child_process_host_id), |
| + process.ToValue()); |
| + } |
| + |
| + // Report the invalid host ids sent in the arguments. |
| + for (const auto& host_id : process_host_ids_) { |
| + WriteToConsole(content::CONSOLE_MESSAGE_LEVEL_ERROR, |
| + ErrorUtils::FormatErrorMessage(errors::kProcessNotFound, |
| + base::IntToString(host_id))); |
| } |
| // Send the response. |
| Respond(ArgumentList( |
| api::processes::GetProcessInfo::Results::Create(processes))); |
| - // Balance the AddRef in the Run. |
| + // Stop observing the task manager, and balance the AddRef() in Run(). |
| + task_management::TaskManagerInterface::GetTaskManager()->RemoveObserver(this); |
| Release(); |
| -#endif // defined(ENABLE_TASK_MANAGER) |
| } |
| } // namespace extensions |