| OLD | NEW | 
|    1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |    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 |    2 // Use of this source code is governed by a BSD-style license that can be | 
|    3 // found in the LICENSE file. |    3 // found in the LICENSE file. | 
|    4  |    4  | 
|    5 #include "chrome/browser/extensions/extension_processes_api.h" |    5 #include "chrome/browser/extensions/extension_processes_api.h" | 
|    6  |    6  | 
|    7 #include "base/callback.h" |    7 #include "base/callback.h" | 
|    8 #include "base/json/json_writer.h" |    8 #include "base/json/json_writer.h" | 
|    9 #include "base/message_loop.h" |    9 #include "base/message_loop.h" | 
 |   10 #include "base/metrics/histogram.h" | 
|   10 #include "base/string_number_conversions.h" |   11 #include "base/string_number_conversions.h" | 
|   11 #include "base/utf_string_conversions.h" |   12 #include "base/utf_string_conversions.h" | 
|   12 #include "base/values.h" |   13 #include "base/values.h" | 
|   13  |   14  | 
|   14 #include "chrome/browser/extensions/extension_event_router.h" |   15 #include "chrome/browser/extensions/extension_event_router.h" | 
 |   16 #include "chrome/browser/extensions/extension_function_util.h" | 
|   15 #include "chrome/browser/extensions/extension_processes_api_constants.h" |   17 #include "chrome/browser/extensions/extension_processes_api_constants.h" | 
 |   18 #include "chrome/browser/extensions/extension_service.h" | 
|   16 #include "chrome/browser/extensions/extension_tab_util.h" |   19 #include "chrome/browser/extensions/extension_tab_util.h" | 
|   17 #include "chrome/browser/extensions/extension_tabs_module_constants.h" |   20 #include "chrome/browser/extensions/extension_tabs_module_constants.h" | 
|   18 #include "chrome/browser/profiles/profile.h" |   21 #include "chrome/browser/profiles/profile.h" | 
|   19 #include "chrome/browser/task_manager/task_manager.h" |   22 #include "chrome/browser/task_manager/task_manager.h" | 
|   20 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" |   23 #include "chrome/browser/ui/tab_contents/tab_contents_wrapper.h" | 
 |   24 #include "chrome/common/chrome_notification_types.h" | 
|   21 #include "chrome/common/extensions/extension_error_utils.h" |   25 #include "chrome/common/extensions/extension_error_utils.h" | 
 |   26 #include "content/public/browser/browser_thread.h" | 
 |   27 #include "content/public/browser/notification_details.h" | 
 |   28 #include "content/public/browser/notification_service.h" | 
 |   29 #include "content/public/browser/notification_source.h" | 
|   22 #include "content/public/browser/notification_types.h" |   30 #include "content/public/browser/notification_types.h" | 
|   23 #include "content/public/browser/render_process_host.h" |   31 #include "content/public/browser/render_process_host.h" | 
 |   32 #include "content/public/browser/render_view_host.h" | 
 |   33 #include "content/public/browser/render_view_host_delegate.h" | 
 |   34 #include "content/public/browser/render_widget_host.h" | 
|   24 #include "content/public/browser/web_contents.h" |   35 #include "content/public/browser/web_contents.h" | 
 |   36 #include "content/public/common/result_codes.h" | 
|   25  |   37  | 
|   26 namespace keys = extension_processes_api_constants; |   38 namespace keys = extension_processes_api_constants; | 
|   27  |   39 namespace errors = extension_processes_api_constants; | 
|   28 DictionaryValue* CreateProcessValue(int process_id, |   40  | 
|   29                                     const std::string& type, |   41 namespace { | 
|   30                                     double cpu, |   42  | 
|   31                                     int64 net, |   43 #if defined(ENABLE_TASK_MANAGER) | 
|   32                                     int64 pr_mem, |   44  | 
|   33                                     int64 sh_mem) { |   45 DictionaryValue* CreateCacheData( | 
 |   46     const WebKit::WebCache::ResourceTypeStat& stat) { | 
 |   47  | 
 |   48   DictionaryValue* cache = new DictionaryValue(); | 
 |   49   cache->SetDouble(keys::kCacheSize, static_cast<double>(stat.size)); | 
 |   50   cache->SetDouble(keys::kCacheLiveSize, static_cast<double>(stat.liveSize)); | 
 |   51   return cache; | 
 |   52 } | 
 |   53  | 
 |   54 void SetProcessType(DictionaryValue* result, | 
 |   55                     TaskManagerModel* model, | 
 |   56                     int index) { | 
 |   57   // Determine process type. | 
 |   58   std::string type = keys::kProcessTypeOther; | 
 |   59   TaskManager::Resource::Type resource_type = model->GetResourceType(index); | 
 |   60   switch (resource_type) { | 
 |   61     case TaskManager::Resource::BROWSER: | 
 |   62       type = keys::kProcessTypeBrowser; | 
 |   63       break; | 
 |   64     case TaskManager::Resource::RENDERER: | 
 |   65       type = keys::kProcessTypeRenderer; | 
 |   66       break; | 
 |   67     case TaskManager::Resource::EXTENSION: | 
 |   68       type = keys::kProcessTypeExtension; | 
 |   69       break; | 
 |   70     case TaskManager::Resource::NOTIFICATION: | 
 |   71       type = keys::kProcessTypeNotification; | 
 |   72       break; | 
 |   73     case TaskManager::Resource::PLUGIN: | 
 |   74       type = keys::kProcessTypePlugin; | 
 |   75       break; | 
 |   76     case TaskManager::Resource::WORKER: | 
 |   77       type = keys::kProcessTypeWorker; | 
 |   78       break; | 
 |   79     case TaskManager::Resource::NACL: | 
 |   80       type = keys::kProcessTypeNacl; | 
 |   81       break; | 
 |   82     case TaskManager::Resource::UTILITY: | 
 |   83       type = keys::kProcessTypeUtility; | 
 |   84       break; | 
 |   85     case TaskManager::Resource::GPU: | 
 |   86       type = keys::kProcessTypeGPU; | 
 |   87       break; | 
 |   88     case TaskManager::Resource::PROFILE_IMPORT: | 
 |   89     case TaskManager::Resource::ZYGOTE: | 
 |   90     case TaskManager::Resource::SANDBOX_HELPER: | 
 |   91     case TaskManager::Resource::UNKNOWN: | 
 |   92       type = keys::kProcessTypeOther; | 
 |   93       break; | 
 |   94     default: | 
 |   95       NOTREACHED() << "Unknown resource type."; | 
 |   96   } | 
 |   97   result->SetString(keys::kTypeKey, type); | 
 |   98 } | 
 |   99  | 
 |  100 ListValue* GetTabsForProcess(int process_id) { | 
 |  101   ListValue* tabs_list = new ListValue(); | 
 |  102  | 
 |  103   // The tabs list only makes sense for render processes, so if we don't find | 
 |  104   // one, just return the empty list. | 
 |  105   content::RenderProcessHost* rph = | 
 |  106       content::RenderProcessHost::FromID(process_id); | 
 |  107   if (rph == NULL) | 
 |  108     return tabs_list; | 
 |  109  | 
 |  110   int tab_id = -1; | 
 |  111   // We need to loop through all the RVHs to ensure we collect the set of all | 
 |  112   // tabs using this renderer process. | 
 |  113   content::RenderProcessHost::RenderWidgetHostsIterator iter( | 
 |  114       rph->GetRenderWidgetHostsIterator()); | 
 |  115   for (; !iter.IsAtEnd(); iter.Advance()) { | 
 |  116     const content::RenderWidgetHost* widget = iter.GetCurrentValue(); | 
 |  117     DCHECK(widget); | 
 |  118     if (!widget || !widget->IsRenderView()) | 
 |  119       continue; | 
 |  120  | 
 |  121     content::RenderViewHost* host = content::RenderViewHost::From( | 
 |  122         const_cast<content::RenderWidgetHost*>(widget)); | 
 |  123     content::RenderViewHostDelegate* host_delegate = host->GetDelegate(); | 
 |  124     content::WebContents* contents = host_delegate->GetAsWebContents(); | 
 |  125     if (contents != NULL) { | 
 |  126       tab_id = ExtensionTabUtil::GetTabId(contents); | 
 |  127       if (tab_id != -1) | 
 |  128         tabs_list->Append(Value::CreateIntegerValue(tab_id)); | 
 |  129     } | 
 |  130   } | 
 |  131  | 
 |  132   return tabs_list; | 
 |  133 } | 
 |  134  | 
 |  135 // This function creates a Process object to be returned to the extensions | 
 |  136 // using these APIs. For memory details, which are not added by this function, | 
 |  137 // the callers need to use AddMemoryDetails. | 
 |  138 DictionaryValue* CreateProcessFromModel(int process_id, | 
 |  139                                         TaskManagerModel* model, | 
 |  140                                         int index, | 
 |  141                                         bool include_optional) { | 
|   34   DictionaryValue* result = new DictionaryValue(); |  142   DictionaryValue* result = new DictionaryValue(); | 
 |  143   size_t mem; | 
 |  144  | 
|   35   result->SetInteger(keys::kIdKey, process_id); |  145   result->SetInteger(keys::kIdKey, process_id); | 
|   36   result->SetString(keys::kTypeKey, type); |  146   result->SetInteger(keys::kOsProcessIdKey, model->GetProcessId(index)); | 
|   37   result->SetDouble(keys::kCpuKey, cpu); |  147   SetProcessType(result, model, index); | 
 |  148   result->SetString(keys::kProfileKey, | 
 |  149       model->GetResourceProfileName(index)); | 
 |  150  | 
 |  151   result->Set(keys::kTabsListKey, GetTabsForProcess(process_id)); | 
 |  152  | 
 |  153   // If we don't need to include the optional properties, just return now. | 
 |  154   if (!include_optional) | 
 |  155     return result; | 
 |  156  | 
 |  157   result->SetDouble(keys::kCpuKey, model->GetCPUUsage(index)); | 
 |  158  | 
 |  159   if (model->GetV8Memory(index, &mem)) | 
 |  160     result->SetDouble(keys::kJsMemoryAllocatedKey, | 
 |  161         static_cast<double>(mem)); | 
 |  162  | 
 |  163   if (model->GetV8MemoryUsed(index, &mem)) | 
 |  164     result->SetDouble(keys::kJsMemoryUsedKey, | 
 |  165         static_cast<double>(mem)); | 
 |  166  | 
 |  167   if (model->GetSqliteMemoryUsedBytes(index, &mem)) | 
 |  168     result->SetDouble(keys::kSqliteMemoryKey, | 
 |  169         static_cast<double>(mem)); | 
 |  170  | 
 |  171   WebKit::WebCache::ResourceTypeStats cache_stats; | 
 |  172   if (model->GetWebCoreCacheStats(index, &cache_stats)) { | 
 |  173     result->Set(keys::kImageCacheKey, | 
 |  174                 CreateCacheData(cache_stats.images)); | 
 |  175     result->Set(keys::kScriptCacheKey, | 
 |  176                 CreateCacheData(cache_stats.scripts)); | 
 |  177     result->Set(keys::kCssCacheKey, | 
 |  178                 CreateCacheData(cache_stats.cssStyleSheets)); | 
 |  179   } | 
 |  180  | 
 |  181   // Network and FPS are reported by the TaskManager per resource (tab), not | 
 |  182   // per process, therefore we need to iterate through the group of resources | 
 |  183   // and aggregate the data. | 
 |  184   float fps = 0, tmp = 0; | 
 |  185   int64 net = 0; | 
 |  186   int length = model->GetGroupRangeForResource(index).second; | 
 |  187   for (int i = 0; i < length; ++i) { | 
 |  188     net += model->GetNetworkUsage(index + i); | 
 |  189     if (model->GetFPS(index + i, &tmp)) | 
 |  190       fps += tmp; | 
 |  191   } | 
 |  192   result->SetDouble(keys::kFPSKey, static_cast<double>(fps)); | 
|   38   result->SetDouble(keys::kNetworkKey, static_cast<double>(net)); |  193   result->SetDouble(keys::kNetworkKey, static_cast<double>(net)); | 
 |  194  | 
 |  195   return result; | 
 |  196 } | 
 |  197  | 
 |  198 // Since memory details are expensive to gather, we don't do it by default. | 
 |  199 // This function is a helper to add memory details data to an existing | 
 |  200 // Process object representation. | 
 |  201 void AddMemoryDetails(DictionaryValue* result, | 
 |  202                       TaskManagerModel* model, | 
 |  203                       int index) { | 
 |  204   size_t mem; | 
 |  205   int64 pr_mem = model->GetPrivateMemory(index, &mem) ? | 
 |  206       static_cast<int64>(mem) : -1; | 
|   39   result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem)); |  207   result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem)); | 
|   40   result->SetDouble(keys::kSharedMemoryKey, static_cast<double>(sh_mem)); |  208 } | 
|   41   return result; |  209  | 
|   42 } |  210 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  211  | 
 |  212 } // local namespace | 
|   43  |  213  | 
|   44 ExtensionProcessesEventRouter* ExtensionProcessesEventRouter::GetInstance() { |  214 ExtensionProcessesEventRouter* ExtensionProcessesEventRouter::GetInstance() { | 
|   45   return Singleton<ExtensionProcessesEventRouter>::get(); |  215   return Singleton<ExtensionProcessesEventRouter>::get(); | 
|   46 } |  216 } | 
|   47  |  217  | 
|   48 ExtensionProcessesEventRouter::ExtensionProcessesEventRouter() { |  218 ExtensionProcessesEventRouter::ExtensionProcessesEventRouter() | 
 |  219     : listeners_(0), | 
 |  220       task_manager_listening_(false) { | 
|   49 #if defined(ENABLE_TASK_MANAGER) |  221 #if defined(ENABLE_TASK_MANAGER) | 
|   50   model_ = TaskManager::GetInstance()->model(); |  222   model_ = TaskManager::GetInstance()->model(); | 
|   51   model_->AddObserver(this); |  223   model_->AddObserver(this); | 
 |  224  | 
 |  225   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_HANG, | 
 |  226       content::NotificationService::AllSources()); | 
 |  227   registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | 
 |  228       content::NotificationService::AllSources()); | 
|   52 #endif  // defined(ENABLE_TASK_MANAGER) |  229 #endif  // defined(ENABLE_TASK_MANAGER) | 
|   53 } |  230 } | 
|   54  |  231  | 
|   55 ExtensionProcessesEventRouter::~ExtensionProcessesEventRouter() { |  232 ExtensionProcessesEventRouter::~ExtensionProcessesEventRouter() { | 
|   56 #if defined(ENABLE_TASK_MANAGER) |  233 #if defined(ENABLE_TASK_MANAGER) | 
 |  234   registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_HANG, | 
 |  235       content::NotificationService::AllSources()); | 
 |  236   registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, | 
 |  237       content::NotificationService::AllSources()); | 
 |  238  | 
 |  239   if (task_manager_listening_) | 
 |  240     model_->StopListening(); | 
 |  241  | 
|   57   model_->RemoveObserver(this); |  242   model_->RemoveObserver(this); | 
|   58 #endif  // defined(ENABLE_TASK_MANAGER) |  243 #endif  // defined(ENABLE_TASK_MANAGER) | 
|   59 } |  244 } | 
|   60  |  245  | 
|   61 void ExtensionProcessesEventRouter::ObserveProfile(Profile* profile) { |  246 void ExtensionProcessesEventRouter::ObserveProfile(Profile* profile) { | 
|   62   profiles_.insert(profile); |  247   profiles_.insert(profile); | 
|   63 } |  248 } | 
|   64  |  249  | 
|   65 void ExtensionProcessesEventRouter::ListenerAdded() { |  250 void ExtensionProcessesEventRouter::ListenerAdded() { | 
|   66 #if defined(ENABLE_TASK_MANAGER) |  251 #if defined(ENABLE_TASK_MANAGER) | 
 |  252   // The task manager has its own ref count to balance other callers of | 
 |  253   // StartUpdating/StopUpdating. | 
|   67   model_->StartUpdating(); |  254   model_->StartUpdating(); | 
|   68 #endif  // defined(ENABLE_TASK_MANAGER) |  255 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  256   ++listeners_; | 
|   69 } |  257 } | 
|   70  |  258  | 
|   71 void ExtensionProcessesEventRouter::ListenerRemoved() { |  259 void ExtensionProcessesEventRouter::ListenerRemoved() { | 
|   72 #if defined(ENABLE_TASK_MANAGER) |  260   DCHECK(listeners_ > 0); | 
 |  261   --listeners_; | 
 |  262 #if defined(ENABLE_TASK_MANAGER) | 
 |  263   // The task manager has its own ref count to balance other callers of | 
 |  264   // StartUpdating/StopUpdating. | 
|   73   model_->StopUpdating(); |  265   model_->StopUpdating(); | 
|   74 #endif  // defined(ENABLE_TASK_MANAGER) |  266 #endif  // defined(ENABLE_TASK_MANAGER) | 
|   75 } |  267 } | 
|   76  |  268  | 
 |  269 void ExtensionProcessesEventRouter::StartTaskManagerListening() { | 
 |  270 #if defined(ENABLE_TASK_MANAGER) | 
 |  271   if (!task_manager_listening_) { | 
 |  272     model_->StartListening(); | 
 |  273     task_manager_listening_ = true; | 
 |  274   } | 
 |  275 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  276 } | 
 |  277  | 
 |  278 void ExtensionProcessesEventRouter::Observe( | 
 |  279     int type, | 
 |  280     const content::NotificationSource& source, | 
 |  281     const content::NotificationDetails& details) { | 
 |  282  | 
 |  283   switch (type) { | 
 |  284     case content::NOTIFICATION_RENDERER_PROCESS_HANG: | 
 |  285       ProcessHangEvent( | 
 |  286           content::Source<content::RenderWidgetHost>(source).ptr()); | 
 |  287       break; | 
 |  288     case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: | 
 |  289       ProcessClosedEvent( | 
 |  290           content::Source<content::RenderProcessHost>(source).ptr(), | 
 |  291           content::Details<content::RenderProcessHost::RendererClosedDetails>( | 
 |  292               details).ptr()); | 
 |  293       break; | 
 |  294     default: | 
 |  295       NOTREACHED() << "Unexpected observe of type " << type; | 
 |  296   } | 
 |  297   return; | 
 |  298 } | 
 |  299  | 
 |  300 void ExtensionProcessesEventRouter::OnItemsAdded(int start, int length) { | 
 |  301 #if defined(ENABLE_TASK_MANAGER) | 
 |  302   DCHECK_EQ(length, 1); | 
 |  303   int index = start; | 
 |  304  | 
 |  305   std::string event(keys::kOnCreated); | 
 |  306   if (!HasEventListeners(event)) | 
 |  307     return; | 
 |  308  | 
 |  309   // If the item being added is not the first one in the group, find the base | 
 |  310   // index and use it for retrieving the process data. | 
 |  311   if (!model_->IsResourceFirstInGroup(start)) { | 
 |  312     index = model_->GetGroupIndexForResource(start); | 
 |  313   } | 
 |  314  | 
 |  315   ListValue args; | 
 |  316   DictionaryValue* process = CreateProcessFromModel( | 
 |  317       model_->GetUniqueChildProcessId(index), model_, index, false); | 
 |  318   DCHECK(process != NULL); | 
 |  319  | 
 |  320   if (process == NULL) | 
 |  321     return; | 
 |  322  | 
 |  323   args.Append(process); | 
 |  324  | 
 |  325   std::string json_args; | 
 |  326   base::JSONWriter::Write(&args, &json_args); | 
 |  327   NotifyProfiles(keys::kOnCreated, json_args); | 
 |  328 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  329 } | 
 |  330  | 
|   77 void ExtensionProcessesEventRouter::OnItemsChanged(int start, int length) { |  331 void ExtensionProcessesEventRouter::OnItemsChanged(int start, int length) { | 
|   78 #if defined(ENABLE_TASK_MANAGER) |  332 #if defined(ENABLE_TASK_MANAGER) | 
|   79   if (model_) { |  333   // If we don't have any listeners, return immediately. | 
 |  334   if (listeners_ == 0) | 
 |  335     return; | 
 |  336  | 
 |  337   if (!model_) | 
 |  338     return; | 
 |  339  | 
 |  340   // We need to know which type of onUpdated events to fire and whether to | 
 |  341   // collect memory or not. | 
 |  342   std::string updated_event(keys::kOnUpdated); | 
 |  343   std::string updated_event_memory(keys::kOnUpdatedWithMemory); | 
 |  344   bool updated = HasEventListeners(updated_event); | 
 |  345   bool updated_memory = HasEventListeners(updated_event_memory); | 
 |  346  | 
 |  347   DCHECK(updated || updated_memory); | 
 |  348  | 
 |  349   IDMap<DictionaryValue> processes_map; | 
 |  350   for (int i = start; i < start + length; i++) { | 
 |  351     if (model_->IsResourceFirstInGroup(i)) { | 
 |  352       int id = model_->GetUniqueChildProcessId(i); | 
 |  353       DictionaryValue* process = CreateProcessFromModel(id, model_, i, true); | 
 |  354       processes_map.AddWithID(process, i); | 
 |  355     } | 
 |  356   } | 
 |  357  | 
 |  358   int id; | 
 |  359   std::string idkey(keys::kIdKey); | 
 |  360   DictionaryValue* processes = new DictionaryValue(); | 
 |  361  | 
 |  362   if (updated) { | 
 |  363     IDMap<DictionaryValue>::iterator it(&processes_map); | 
 |  364     for (; !it.IsAtEnd(); it.Advance()) { | 
 |  365       if (!it.GetCurrentValue()->GetInteger(idkey, &id)) | 
 |  366         continue; | 
 |  367  | 
 |  368       // Store each process indexed by the string version of its id. | 
 |  369       processes->Set(base::IntToString(id), it.GetCurrentValue()); | 
 |  370     } | 
 |  371  | 
|   80     ListValue args; |  372     ListValue args; | 
|   81     DictionaryValue* processes = new DictionaryValue(); |  | 
|   82     for (int i = start; i < start + length; i++) { |  | 
|   83       if (model_->IsResourceFirstInGroup(i)) { |  | 
|   84         int id = model_->GetProcessId(i); |  | 
|   85  |  | 
|   86         // Determine process type |  | 
|   87         std::string type = keys::kProcessTypeOther; |  | 
|   88         TaskManager::Resource::Type resource_type = model_->GetResourceType(i); |  | 
|   89         switch (resource_type) { |  | 
|   90           case TaskManager::Resource::BROWSER: |  | 
|   91             type = keys::kProcessTypeBrowser; |  | 
|   92             break; |  | 
|   93           case TaskManager::Resource::RENDERER: |  | 
|   94             type = keys::kProcessTypeRenderer; |  | 
|   95             break; |  | 
|   96           case TaskManager::Resource::EXTENSION: |  | 
|   97             type = keys::kProcessTypeExtension; |  | 
|   98             break; |  | 
|   99           case TaskManager::Resource::NOTIFICATION: |  | 
|  100             type = keys::kProcessTypeNotification; |  | 
|  101             break; |  | 
|  102           case TaskManager::Resource::PLUGIN: |  | 
|  103             type = keys::kProcessTypePlugin; |  | 
|  104             break; |  | 
|  105           case TaskManager::Resource::WORKER: |  | 
|  106             type = keys::kProcessTypeWorker; |  | 
|  107             break; |  | 
|  108           case TaskManager::Resource::NACL: |  | 
|  109             type = keys::kProcessTypeNacl; |  | 
|  110             break; |  | 
|  111           case TaskManager::Resource::UTILITY: |  | 
|  112             type = keys::kProcessTypeUtility; |  | 
|  113             break; |  | 
|  114           case TaskManager::Resource::GPU: |  | 
|  115             type = keys::kProcessTypeGPU; |  | 
|  116             break; |  | 
|  117           case TaskManager::Resource::PROFILE_IMPORT: |  | 
|  118           case TaskManager::Resource::ZYGOTE: |  | 
|  119           case TaskManager::Resource::SANDBOX_HELPER: |  | 
|  120           case TaskManager::Resource::UNKNOWN: |  | 
|  121             type = keys::kProcessTypeOther; |  | 
|  122             break; |  | 
|  123           default: |  | 
|  124             NOTREACHED() << "Unknown resource type."; |  | 
|  125         } |  | 
|  126  |  | 
|  127         // Get process metrics as numbers |  | 
|  128         double cpu = model_->GetCPUUsage(i); |  | 
|  129  |  | 
|  130         // TODO(creis): Network is actually reported per-resource (tab), |  | 
|  131         // not per-process.  We should aggregate it here. |  | 
|  132         int64 net = model_->GetNetworkUsage(i); |  | 
|  133         size_t mem; |  | 
|  134         int64 pr_mem = model_->GetPrivateMemory(i, &mem) ? |  | 
|  135             static_cast<int64>(mem) : -1; |  | 
|  136         int64 sh_mem = model_->GetSharedMemory(i, &mem) ? |  | 
|  137             static_cast<int64>(mem) : -1; |  | 
|  138  |  | 
|  139         // Store each process indexed by the string version of its id |  | 
|  140         processes->Set(base::IntToString(id), |  | 
|  141                        CreateProcessValue(id, type, cpu, net, pr_mem, sh_mem)); |  | 
|  142       } |  | 
|  143     } |  | 
|  144     args.Append(processes); |  373     args.Append(processes); | 
|  145  |  | 
|  146     std::string json_args; |  374     std::string json_args; | 
|  147     base::JSONWriter::Write(&args, &json_args); |  375     base::JSONWriter::Write(&args, &json_args); | 
|  148  |  376     NotifyProfiles(keys::kOnUpdated, json_args); | 
|  149     // Notify each profile that is interested. |  377   } | 
|  150     for (ProfileSet::iterator it = profiles_.begin(); |  378  | 
|  151          it != profiles_.end(); it++) { |  379   if (updated_memory) { | 
|  152       Profile* profile = *it; |  380     IDMap<DictionaryValue>::iterator it(&processes_map); | 
|  153       DispatchEvent(profile, keys::kOnUpdated, json_args); |  381     for (; !it.IsAtEnd(); it.Advance()) { | 
|  154     } |  382       if (!it.GetCurrentValue()->GetInteger(idkey, &id)) | 
|  155   } |  383         continue; | 
|  156 #endif  // defined(ENABLE_TASK_MANAGER) |  384  | 
|  157 } |  385       AddMemoryDetails(it.GetCurrentValue(), model_, it.GetCurrentKey()); | 
|  158  |  386  | 
|  159 void ExtensionProcessesEventRouter::DispatchEvent(Profile* profile, |  387       // Store each process indexed by the string version of its id if we didn't | 
 |  388       // already insert it as part of the onUpdated processing above. | 
 |  389       if (!updated) | 
 |  390         processes->Set(base::IntToString(id), it.GetCurrentValue()); | 
 |  391     } | 
 |  392  | 
 |  393     ListValue args; | 
 |  394     args.Append(processes); | 
 |  395     std::string json_args; | 
 |  396     base::JSONWriter::Write(&args, &json_args); | 
 |  397     NotifyProfiles(keys::kOnUpdatedWithMemory, json_args); | 
 |  398   } | 
 |  399 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  400 } | 
 |  401  | 
 |  402 void ExtensionProcessesEventRouter::OnItemsToBeRemoved(int start, int length) { | 
 |  403 #if defined(ENABLE_TASK_MANAGER) | 
 |  404   DCHECK(length == 1); | 
 |  405  | 
 |  406   // Process exit for renderer processes has the data about exit code and | 
 |  407   // termination status, therefore we will rely on notifications and not on | 
 |  408   // the Task Manager data. We do use the rest of this method for non-renderer | 
 |  409   // processes. | 
 |  410   if (model_->GetResourceType(start) == TaskManager::Resource::RENDERER) | 
 |  411     return; | 
 |  412  | 
 |  413   // The callback function parameters. | 
 |  414   ListValue args; | 
 |  415  | 
 |  416   // First arg: The id of the process that was closed. | 
 |  417   args.Append(Value::CreateIntegerValue( | 
 |  418       model_->GetUniqueChildProcessId(start))); | 
 |  419  | 
 |  420   // Second arg: The exit type for the process. | 
 |  421   args.Append(Value::CreateIntegerValue(0)); | 
 |  422  | 
 |  423   // Third arg: The exit code for the process. | 
 |  424   args.Append(Value::CreateIntegerValue(0)); | 
 |  425  | 
 |  426   std::string json_args; | 
 |  427   base::JSONWriter::Write(&args, &json_args); | 
 |  428   NotifyProfiles(keys::kOnExited, json_args); | 
 |  429 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  430 } | 
 |  431  | 
 |  432 void ExtensionProcessesEventRouter::ProcessHangEvent( | 
 |  433     content::RenderWidgetHost* widget) { | 
 |  434 #if defined(ENABLE_TASK_MANAGER) | 
 |  435   std::string event(keys::kOnUnresponsive); | 
 |  436   if (!HasEventListeners(event)) | 
 |  437     return; | 
 |  438  | 
 |  439   DictionaryValue* process = NULL; | 
 |  440   int count = model_->ResourceCount(); | 
 |  441   int id = widget->GetProcess()->GetID(); | 
 |  442  | 
 |  443   for (int i = 0; i < count; ++i) { | 
 |  444     if (model_->IsResourceFirstInGroup(i)) { | 
 |  445       if (id == model_->GetUniqueChildProcessId(i)) { | 
 |  446         process = CreateProcessFromModel(id, model_, i, false); | 
 |  447         break; | 
 |  448       } | 
 |  449     } | 
 |  450   } | 
 |  451  | 
 |  452   DCHECK(process); | 
 |  453   if (process == NULL) | 
 |  454     return; | 
 |  455  | 
 |  456   ListValue args; | 
 |  457   args.Append(process); | 
 |  458  | 
 |  459   std::string json_args; | 
 |  460   base::JSONWriter::Write(&args, &json_args); | 
 |  461   NotifyProfiles(keys::kOnUnresponsive, json_args); | 
 |  462 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  463 } | 
 |  464  | 
 |  465 void ExtensionProcessesEventRouter::ProcessClosedEvent( | 
 |  466     content::RenderProcessHost* rph, | 
 |  467     content::RenderProcessHost::RendererClosedDetails* details) { | 
 |  468 #if defined(ENABLE_TASK_MANAGER) | 
 |  469   // The callback function parameters. | 
 |  470   ListValue args; | 
 |  471  | 
 |  472   // First arg: The id of the process that was closed. | 
 |  473   args.Append(Value::CreateIntegerValue(rph->GetID())); | 
 |  474  | 
 |  475   // Second arg: The exit type for the process. | 
 |  476   args.Append(Value::CreateIntegerValue(details->status)); | 
 |  477  | 
 |  478   // Third arg: The exit code for the process. | 
 |  479   args.Append(Value::CreateIntegerValue(details->exit_code)); | 
 |  480  | 
 |  481   std::string json_args; | 
 |  482   base::JSONWriter::Write(&args, &json_args); | 
 |  483   NotifyProfiles(keys::kOnExited, json_args); | 
 |  484 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  485 } | 
 |  486  | 
 |  487 void ExtensionProcessesEventRouter::DispatchEvent( | 
 |  488     Profile* profile, | 
|  160     const char* event_name, |  489     const char* event_name, | 
|  161     const std::string& json_args) { |  490     const std::string& json_args) { | 
|  162   if (profile && profile->GetExtensionEventRouter()) { |  491   if (profile && profile->GetExtensionEventRouter()) { | 
|  163     profile->GetExtensionEventRouter()->DispatchEventToRenderers( |  492     profile->GetExtensionEventRouter()->DispatchEventToRenderers( | 
|  164         event_name, json_args, NULL, GURL()); |  493         event_name, json_args, NULL, GURL()); | 
|  165   } |  494   } | 
|  166 } |  495 } | 
|  167  |  496  | 
 |  497 void ExtensionProcessesEventRouter::NotifyProfiles(const char* event_name, | 
 |  498                                                    std::string json_args) { | 
 |  499   for (ProfileSet::iterator it = profiles_.begin(); | 
 |  500        it != profiles_.end(); it++) { | 
 |  501     Profile* profile = *it; | 
 |  502     DispatchEvent(profile, event_name, json_args); | 
 |  503   } | 
 |  504 } | 
 |  505  | 
 |  506 // In order to determine whether there are any listeners for the event of | 
 |  507 // interest, we need to ask each profile whether it has one registered. | 
 |  508 // We only need to look for the profiles that have registered with the | 
 |  509 // this extension API. | 
 |  510 bool ExtensionProcessesEventRouter::HasEventListeners(std::string& event_name) { | 
 |  511   for (ProfileSet::iterator it = profiles_.begin(); | 
 |  512        it != profiles_.end(); it++) { | 
 |  513     Profile* profile = *it; | 
 |  514     ExtensionEventRouter* router = profile->GetExtensionEventRouter(); | 
 |  515     if (!router) | 
 |  516       continue; | 
 |  517  | 
 |  518     if (router->HasEventListener(event_name)) | 
 |  519       return true; | 
 |  520   } | 
 |  521   return false; | 
 |  522 } | 
 |  523  | 
|  168 bool GetProcessIdForTabFunction::RunImpl() { |  524 bool GetProcessIdForTabFunction::RunImpl() { | 
|  169   int tab_id; |  525 #if defined(ENABLE_TASK_MANAGER) | 
|  170   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id)); |  526   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id_)); | 
|  171  |  527  | 
 |  528   // Add a reference, which is balanced in GetProcessIdForTab to keep the object | 
 |  529   // around and allow for the callback to be invoked. | 
 |  530   AddRef(); | 
 |  531  | 
 |  532   // If the task manager is already listening, just post a task to execute | 
 |  533   // which will invoke the callback once we have returned from this function. | 
 |  534   // Otherwise, wait for the notification that the task manager is done with | 
 |  535   // the data gathering. | 
 |  536   if (ExtensionProcessesEventRouter::GetInstance()-> | 
 |  537           is_task_manager_listening()) { | 
 |  538     MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 
 |  539         &GetProcessIdForTabFunction::GetProcessIdForTab, this)); | 
 |  540   } else { | 
 |  541     registrar_.Add(this, | 
 |  542                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY, | 
 |  543                    content::NotificationService::AllSources()); | 
 |  544     ExtensionProcessesEventRouter::GetInstance()-> | 
 |  545         StartTaskManagerListening(); | 
 |  546   } | 
 |  547  | 
 |  548   return true; | 
 |  549 #else | 
 |  550   error_ = ExtensionErrorUtils::FormatErrorMessage( | 
 |  551       errors::kExtensionNotSupported); | 
 |  552   return false; | 
 |  553 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  554 } | 
 |  555  | 
 |  556 void GetProcessIdForTabFunction::Observe( | 
 |  557     int type, | 
 |  558     const content::NotificationSource& source, | 
 |  559     const content::NotificationDetails& details) { | 
 |  560   DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY); | 
 |  561   registrar_.RemoveAll(); | 
 |  562   GetProcessIdForTab(); | 
 |  563 } | 
 |  564  | 
 |  565 void GetProcessIdForTabFunction::GetProcessIdForTab() { | 
|  172   TabContentsWrapper* contents = NULL; |  566   TabContentsWrapper* contents = NULL; | 
|  173   int tab_index = -1; |  567   int tab_index = -1; | 
|  174   if (!ExtensionTabUtil::GetTabById(tab_id, profile(), include_incognito(), |  568   if (!ExtensionTabUtil::GetTabById(tab_id_, profile(), include_incognito(), | 
|  175                                     NULL, NULL, &contents, &tab_index)) { |  569                                     NULL, NULL, &contents, &tab_index)) { | 
|  176     error_ = ExtensionErrorUtils::FormatErrorMessage( |  570     error_ = ExtensionErrorUtils::FormatErrorMessage( | 
|  177         extension_tabs_module_constants::kTabNotFoundError, |  571         extension_tabs_module_constants::kTabNotFoundError, | 
|  178         base::IntToString(tab_id)); |  572         base::IntToString(tab_id_)); | 
|  179     return false; |  573     result_.reset(Value::CreateIntegerValue(-1)); | 
|  180   } |  574     SendResponse(false); | 
|  181  |  575   } else { | 
|  182   // Return the process ID of the tab as an integer. |  576     int process_id = contents->web_contents()->GetRenderProcessHost()->GetID(); | 
|  183   int id = base::GetProcId(contents->web_contents()-> |  577     result_.reset(Value::CreateIntegerValue(process_id)); | 
|  184       GetRenderProcessHost()->GetHandle()); |  578     SendResponse(true); | 
|  185   result_.reset(Value::CreateIntegerValue(id)); |  579   } | 
 |  580  | 
 |  581   // Balance the AddRef in the RunImpl. | 
 |  582   Release(); | 
 |  583 } | 
 |  584  | 
 |  585 bool TerminateFunction::RunImpl() { | 
 |  586 #if defined(ENABLE_TASK_MANAGER) | 
 |  587   EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &process_id_)); | 
 |  588  | 
 |  589   // Add a reference, which is balanced in TerminateProcess to keep the object | 
 |  590   // around and allow for the callback to be invoked. | 
 |  591   AddRef(); | 
 |  592  | 
 |  593   // If the task manager is already listening, just post a task to execute | 
 |  594   // which will invoke the callback once we have returned from this function. | 
 |  595   // Otherwise, wait for the notification that the task manager is done with | 
 |  596   // the data gathering. | 
 |  597   if (ExtensionProcessesEventRouter::GetInstance()-> | 
 |  598           is_task_manager_listening()) { | 
 |  599     MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 
 |  600         &TerminateFunction::TerminateProcess, this)); | 
 |  601   } else { | 
 |  602     registrar_.Add(this, | 
 |  603                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY, | 
 |  604                    content::NotificationService::AllSources()); | 
 |  605     ExtensionProcessesEventRouter::GetInstance()-> | 
 |  606         StartTaskManagerListening(); | 
 |  607   } | 
 |  608  | 
|  186   return true; |  609   return true; | 
|  187 } |  610 #else | 
 |  611   error_ = ExtensionErrorUtils::FormatErrorMessage( | 
 |  612       errors::kExtensionNotSupported); | 
 |  613   return false; | 
 |  614 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  615 } | 
 |  616  | 
 |  617 void TerminateFunction::Observe( | 
 |  618     int type, | 
 |  619     const content::NotificationSource& source, | 
 |  620     const content::NotificationDetails& details) { | 
 |  621   DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY); | 
 |  622   registrar_.RemoveAll(); | 
 |  623   TerminateProcess(); | 
 |  624 } | 
 |  625  | 
 |  626 void TerminateFunction::TerminateProcess() { | 
 |  627   TaskManagerModel* model = TaskManager::GetInstance()->model(); | 
 |  628  | 
 |  629   int count = model->ResourceCount(); | 
 |  630   bool killed = false; | 
 |  631   bool found = false; | 
 |  632  | 
 |  633   for (int i = 0; i < count; ++i) { | 
 |  634     if (model->IsResourceFirstInGroup(i)) { | 
 |  635       if (process_id_ == model->GetUniqueChildProcessId(i)) { | 
 |  636         found = true; | 
 |  637         killed = base::KillProcess(model->GetProcess(i), | 
 |  638             content::RESULT_CODE_KILLED, true); | 
 |  639         UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1); | 
 |  640         break; | 
 |  641       } | 
 |  642     } | 
 |  643   } | 
 |  644  | 
 |  645   if (!found) { | 
 |  646     error_ = ExtensionErrorUtils::FormatErrorMessage(errors::kProcessNotFound, | 
 |  647         base::IntToString(process_id_)); | 
 |  648     SendResponse(false); | 
 |  649   } else { | 
 |  650     result_.reset(Value::CreateBooleanValue(killed)); | 
 |  651     SendResponse(true); | 
 |  652   } | 
 |  653  | 
 |  654   // Balance the AddRef in the RunImpl. | 
 |  655   Release(); | 
 |  656 } | 
 |  657  | 
 |  658 GetProcessInfoFunction::GetProcessInfoFunction() { | 
 |  659 } | 
 |  660  | 
 |  661 GetProcessInfoFunction::~GetProcessInfoFunction() { | 
 |  662 } | 
 |  663  | 
 |  664 bool GetProcessInfoFunction::RunImpl() { | 
 |  665 #if defined(ENABLE_TASK_MANAGER) | 
 |  666   Value* processes = NULL; | 
 |  667  | 
 |  668   EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &processes)); | 
 |  669   EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &memory_)); | 
 |  670  | 
 |  671   EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers( | 
 |  672       processes, &process_ids_)); | 
 |  673  | 
 |  674   // Add a reference, which is balanced in GatherProcessInfo to keep the object | 
 |  675   // around and allow for the callback to be invoked. | 
 |  676   AddRef(); | 
 |  677  | 
 |  678   // If the task manager is already listening, just post a task to execute | 
 |  679   // which will invoke the callback once we have returned from this function. | 
 |  680   // Otherwise, wait for the notification that the task manager is done with | 
 |  681   // the data gathering. | 
 |  682   if (ExtensionProcessesEventRouter::GetInstance()-> | 
 |  683           is_task_manager_listening()) { | 
 |  684     MessageLoop::current()->PostTask(FROM_HERE, base::Bind( | 
 |  685         &GetProcessInfoFunction::GatherProcessInfo, this)); | 
 |  686   } else { | 
 |  687     registrar_.Add(this, | 
 |  688                    chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY, | 
 |  689                    content::NotificationService::AllSources()); | 
 |  690     ExtensionProcessesEventRouter::GetInstance()-> | 
 |  691         StartTaskManagerListening(); | 
 |  692   } | 
 |  693   return true; | 
 |  694  | 
 |  695 #else | 
 |  696   error_ = ExtensionErrorUtils::FormatErrorMessage( | 
 |  697       errors::kExtensionNotSupported); | 
 |  698   return false; | 
 |  699 #endif  // defined(ENABLE_TASK_MANAGER) | 
 |  700 } | 
 |  701  | 
 |  702 void GetProcessInfoFunction::Observe( | 
 |  703     int type, | 
 |  704     const content::NotificationSource& source, | 
 |  705     const content::NotificationDetails& details) { | 
 |  706   DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY); | 
 |  707   registrar_.RemoveAll(); | 
 |  708   GatherProcessInfo(); | 
 |  709 } | 
 |  710  | 
 |  711 void GetProcessInfoFunction::GatherProcessInfo() { | 
 |  712   TaskManagerModel* model = TaskManager::GetInstance()->model(); | 
 |  713   DictionaryValue* processes = new DictionaryValue(); | 
 |  714  | 
 |  715   // If there are no process IDs specified, it means we need to return all of | 
 |  716   // the ones we know of. | 
 |  717   if (process_ids_.size() == 0) { | 
 |  718     int resources = model->ResourceCount(); | 
 |  719     for (int i = 0; i < resources; ++i) { | 
 |  720       if (model->IsResourceFirstInGroup(i)) { | 
 |  721         int id = model->GetUniqueChildProcessId(i); | 
 |  722         DictionaryValue* d = CreateProcessFromModel(id, model, i, false); | 
 |  723         if (memory_) | 
 |  724           AddMemoryDetails(d, model, i); | 
 |  725         processes->Set(base::IntToString(id), d); | 
 |  726       } | 
 |  727     } | 
 |  728   } else { | 
 |  729     int resources = model->ResourceCount(); | 
 |  730     for (int i = 0; i < resources; ++i) { | 
 |  731       if (model->IsResourceFirstInGroup(i)) { | 
 |  732         int id = model->GetUniqueChildProcessId(i); | 
 |  733         std::vector<int>::iterator proc_id = std::find(process_ids_.begin(), | 
 |  734                                                        process_ids_.end(), id); | 
 |  735         if (proc_id != process_ids_.end()) { | 
 |  736           DictionaryValue* d = CreateProcessFromModel(id, model, i, false); | 
 |  737           if (memory_) | 
 |  738             AddMemoryDetails(d, model, i); | 
 |  739           processes->Set(base::IntToString(id), d); | 
 |  740  | 
 |  741           process_ids_.erase(proc_id); | 
 |  742           if (process_ids_.size() == 0) | 
 |  743             break; | 
 |  744         } | 
 |  745       } | 
 |  746     } | 
 |  747     DCHECK(process_ids_.size() == 0); | 
 |  748   } | 
 |  749  | 
 |  750   result_.reset(processes); | 
 |  751   SendResponse(true); | 
 |  752  | 
 |  753   // Balance the AddRef in the RunImpl. | 
 |  754   Release(); | 
 |  755 } | 
| OLD | NEW |