1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/extensions/api/processes/processes_api.h" 6 7 #include "base/callback.h" 8 #include "base/json/json_writer.h" 9 #include "base/lazy_instance.h" 10 #include "base/message_loop/message_loop.h" 11 #include "base/metrics/histogram.h" 12 #include "base/strings/string_number_conversions.h" 13 #include "base/strings/utf_string_conversions.h" 14 #include "base/values.h" 15 #include "chrome/browser/chrome_notification_types.h" 16 #include "chrome/browser/extensions/api/processes/processes_api_constants.h" 17 #include "chrome/browser/extensions/api/tabs/tabs_constants.h" 18 #include "chrome/browser/extensions/event_router.h" 19 #include "chrome/browser/extensions/extension_function_registry.h" 20 #include "chrome/browser/extensions/extension_function_util.h" 21 #include "chrome/browser/extensions/extension_service.h" 22 #include "chrome/browser/extensions/extension_system.h" 23 #include "chrome/browser/extensions/extension_tab_util.h" 24 #include "chrome/browser/profiles/profile.h" 25 #include "chrome/browser/task_manager/resource_provider.h" 26 #include "chrome/browser/task_manager/task_manager.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" 30 #include "content/public/browser/notification_types.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_widget_host.h" 34 #include "content/public/browser/web_contents.h" 35 #include "content/public/common/result_codes.h" 36 #include "extensions/common/error_utils.h" 37 38 namespace extensions { 39 40 namespace keys = processes_api_constants; 41 namespace errors = processes_api_constants; 42 43 namespace { 44 45 #if defined(ENABLE_TASK_MANAGER) 46 47 base::DictionaryValue* CreateCacheData( 48 const WebKit::WebCache::ResourceTypeStat& stat) { 49 50 base::DictionaryValue* cache = new base::DictionaryValue(); 51 cache->SetDouble(keys::kCacheSize, static_cast<double>(stat.size)); 52 cache->SetDouble(keys::kCacheLiveSize, static_cast<double>(stat.liveSize)); 53 return cache; 54 } 55 56 void SetProcessType(base::DictionaryValue* result, 57 TaskManagerModel* model, 58 int index) { 59 // Determine process type. 60 std::string type = keys::kProcessTypeOther; 61 task_manager::Resource::Type resource_type = model->GetResourceType(index); 62 switch (resource_type) { 63 case task_manager::Resource::BROWSER: 64 type = keys::kProcessTypeBrowser; 65 break; 66 case task_manager::Resource::RENDERER: 67 type = keys::kProcessTypeRenderer; 68 break; 69 case task_manager::Resource::EXTENSION: 70 type = keys::kProcessTypeExtension; 71 break; 72 case task_manager::Resource::NOTIFICATION: 73 type = keys::kProcessTypeNotification; 74 break; 75 case task_manager::Resource::PLUGIN: 76 type = keys::kProcessTypePlugin; 77 break; 78 case task_manager::Resource::WORKER: 79 type = keys::kProcessTypeWorker; 80 break; 81 case task_manager::Resource::NACL: 82 type = keys::kProcessTypeNacl; 83 break; 84 case task_manager::Resource::UTILITY: 85 type = keys::kProcessTypeUtility; 86 break; 87 case task_manager::Resource::GPU: 88 type = keys::kProcessTypeGPU; 89 break; 90 case task_manager::Resource::ZYGOTE: 91 case task_manager::Resource::SANDBOX_HELPER: 92 case task_manager::Resource::UNKNOWN: 93 type = keys::kProcessTypeOther; 94 break; 95 default: 96 NOTREACHED() << "Unknown resource type."; 97 } 98 result->SetString(keys::kTypeKey, type); 99 } 100 101 base::ListValue* GetTabsForProcess(int process_id) { 102 base::ListValue* tabs_list = new base::ListValue(); 103 104 // The tabs list only makes sense for render processes, so if we don't find 105 // one, just return the empty list. 106 content::RenderProcessHost* rph = 107 content::RenderProcessHost::FromID(process_id); 108 if (rph == NULL) 109 return tabs_list; 110 111 int tab_id = -1; 112 // We need to loop through all the RVHs to ensure we collect the set of all 113 // tabs using this renderer process. 114 content::RenderWidgetHost::List widgets = 115 content::RenderWidgetHost::GetRenderWidgetHosts(); 116 for (size_t i = 0; i < widgets.size(); ++i) { 117 if (widgets[i]->GetProcess()->GetID() != process_id) 118 continue; 119 if (!widgets[i]->IsRenderView()) 120 continue; 121 122 content::RenderViewHost* host = content::RenderViewHost::From(widgets[i]); 123 content::WebContents* contents = 124 content::WebContents::FromRenderViewHost(host); 125 if (contents) { 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 base::DictionaryValue* CreateProcessFromModel(int process_id, 139 TaskManagerModel* model, 140 int index, 141 bool include_optional) { 142 base::DictionaryValue* result = new base::DictionaryValue(); 143 size_t mem; 144 145 result->SetInteger(keys::kIdKey, process_id); 146 result->SetInteger(keys::kOsProcessIdKey, model->GetProcessId(index)); 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)); 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(base::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; 207 result->SetDouble(keys::kPrivateMemoryKey, static_cast<double>(pr_mem)); 208 } 209 210 #endif // defined(ENABLE_TASK_MANAGER) 211 212 } // namespace 213 214 ProcessesEventRouter::ProcessesEventRouter(Profile* profile) 215 : profile_(profile), 216 listeners_(0), 217 task_manager_listening_(false) { 218 #if defined(ENABLE_TASK_MANAGER) 219 model_ = TaskManager::GetInstance()->model(); 220 model_->AddObserver(this); 221 222 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_HANG, 223 content::NotificationService::AllSources()); 224 registrar_.Add(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 225 content::NotificationService::AllSources()); 226 #endif // defined(ENABLE_TASK_MANAGER) 227 } 228 229 ProcessesEventRouter::~ProcessesEventRouter() { 230 #if defined(ENABLE_TASK_MANAGER) 231 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_HANG, 232 content::NotificationService::AllSources()); 233 registrar_.Remove(this, content::NOTIFICATION_RENDERER_PROCESS_CLOSED, 234 content::NotificationService::AllSources()); 235 236 if (task_manager_listening_) 237 model_->StopListening(); 238 239 model_->RemoveObserver(this); 240 #endif // defined(ENABLE_TASK_MANAGER) 241 } 242 243 void ProcessesEventRouter::ListenerAdded() { 244 #if defined(ENABLE_TASK_MANAGER) 245 // The task manager has its own ref count to balance other callers of 246 // StartUpdating/StopUpdating. 247 model_->StartUpdating(); 248 #endif // defined(ENABLE_TASK_MANAGER) 249 ++listeners_; 250 } 251 252 void ProcessesEventRouter::ListenerRemoved() { 253 DCHECK_GT(listeners_, 0); 254 --listeners_; 255 #if defined(ENABLE_TASK_MANAGER) 256 // The task manager has its own ref count to balance other callers of 257 // StartUpdating/StopUpdating. 258 model_->StopUpdating(); 259 #endif // defined(ENABLE_TASK_MANAGER) 260 } 261 262 void ProcessesEventRouter::StartTaskManagerListening() { 263 #if defined(ENABLE_TASK_MANAGER) 264 if (!task_manager_listening_) { 265 model_->StartListening(); 266 task_manager_listening_ = true; 267 } 268 #endif // defined(ENABLE_TASK_MANAGER) 269 } 270 271 void ProcessesEventRouter::Observe( 272 int type, 273 const content::NotificationSource& source, 274 const content::NotificationDetails& details) { 275 276 switch (type) { 277 case content::NOTIFICATION_RENDERER_PROCESS_HANG: 278 ProcessHangEvent( 279 content::Source<content::RenderWidgetHost>(source).ptr()); 280 break; 281 case content::NOTIFICATION_RENDERER_PROCESS_CLOSED: 282 ProcessClosedEvent( 283 content::Source<content::RenderProcessHost>(source).ptr(), 284 content::Details<content::RenderProcessHost::RendererClosedDetails>( 285 details).ptr()); 286 break; 287 default: 288 NOTREACHED() << "Unexpected observe of type " << type; 289 } 290 return; 291 } 292 293 void ProcessesEventRouter::OnItemsAdded(int start, int length) { 294 #if defined(ENABLE_TASK_MANAGER) 295 DCHECK_EQ(length, 1); 296 int index = start; 297 298 std::string event(keys::kOnCreated); 299 if (!HasEventListeners(event)) 300 return; 301 302 // If the item being added is not the first one in the group, find the base 303 // index and use it for retrieving the process data. 304 if (!model_->IsResourceFirstInGroup(start)) { 305 index = model_->GetGroupIndexForResource(start); 306 } 307 308 scoped_ptr<base::ListValue> args(new base::ListValue()); 309 base::DictionaryValue* process = CreateProcessFromModel( 310 model_->GetUniqueChildProcessId(index), model_, index, false); 311 DCHECK(process != NULL); 312 313 if (process == NULL) 314 return; 315 316 args->Append(process); 317 318 DispatchEvent(keys::kOnCreated, args.Pass()); 319 #endif // defined(ENABLE_TASK_MANAGER) 320 } 321 322 void ProcessesEventRouter::OnItemsChanged(int start, int length) { 323 #if defined(ENABLE_TASK_MANAGER) 324 // If we don't have any listeners, return immediately. 325 if (listeners_ == 0) 326 return; 327 328 if (!model_) 329 return; 330 331 // We need to know which type of onUpdated events to fire and whether to 332 // collect memory or not. 333 std::string updated_event(keys::kOnUpdated); 334 std::string updated_event_memory(keys::kOnUpdatedWithMemory); 335 bool updated = HasEventListeners(updated_event); 336 bool updated_memory = HasEventListeners(updated_event_memory); 337 338 DCHECK(updated || updated_memory); 339 340 IDMap<base::DictionaryValue> processes_map; 341 for (int i = start; i < start + length; i++) { 342 if (model_->IsResourceFirstInGroup(i)) { 343 int id = model_->GetUniqueChildProcessId(i); 344 base::DictionaryValue* process = CreateProcessFromModel(id, model_, i, true); 345 processes_map.AddWithID(process, i); 346 } 347 } 348 349 int id; 350 std::string idkey(keys::kIdKey); 351 base::DictionaryValue* processes = new base::DictionaryValue(); 352 353 if (updated) { 354 IDMap<base::DictionaryValue>::iterator it(&processes_map); 355 for (; !it.IsAtEnd(); it.Advance()) { 356 if (!it.GetCurrentValue()->GetInteger(idkey, &id)) 357 continue; 358 359 // Store each process indexed by the string version of its id. 360 processes->Set(base::IntToString(id), it.GetCurrentValue()); 361 } 362 363 scoped_ptr<base::ListValue> args(new base::ListValue()); 364 args->Append(processes); 365 DispatchEvent(keys::kOnUpdated, args.Pass()); 366 } 367 368 if (updated_memory) { 369 IDMap<base::DictionaryValue>::iterator it(&processes_map); 370 for (; !it.IsAtEnd(); it.Advance()) { 371 if (!it.GetCurrentValue()->GetInteger(idkey, &id)) 372 continue; 373 374 AddMemoryDetails(it.GetCurrentValue(), model_, it.GetCurrentKey()); 375 376 // Store each process indexed by the string version of its id if we didn't 377 // already insert it as part of the onUpdated processing above. 378 if (!updated) 379 processes->Set(base::IntToString(id), it.GetCurrentValue()); 380 } 381 382 scoped_ptr<base::ListValue> args(new base::ListValue()); 383 args->Append(processes); 384 DispatchEvent(keys::kOnUpdatedWithMemory, args.Pass()); 385 } 386 #endif // defined(ENABLE_TASK_MANAGER) 387 } 388 389 void ProcessesEventRouter::OnItemsToBeRemoved(int start, int length) { 390 #if defined(ENABLE_TASK_MANAGER) 391 DCHECK_EQ(length, 1); 392 393 // Process exit for renderer processes has the data about exit code and 394 // termination status, therefore we will rely on notifications and not on 395 // the Task Manager data. We do use the rest of this method for non-renderer 396 // processes. 397 if (model_->GetResourceType(start) == task_manager::Resource::RENDERER) 398 return; 399 400 // The callback function parameters. 401 scoped_ptr<base::ListValue> args(new base::ListValue()); 402 403 // First arg: The id of the process that was closed. 404 args->Append(Value::CreateIntegerValue( 405 model_->GetUniqueChildProcessId(start))); 406 407 // Second arg: The exit type for the process. 408 args->Append(Value::CreateIntegerValue(0)); 409 410 // Third arg: The exit code for the process. 411 args->Append(Value::CreateIntegerValue(0)); 412 413 DispatchEvent(keys::kOnExited, args.Pass()); 414 #endif // defined(ENABLE_TASK_MANAGER) 415 } 416 417 void ProcessesEventRouter::ProcessHangEvent(content::RenderWidgetHost* widget) { 418 #if defined(ENABLE_TASK_MANAGER) 419 std::string event(keys::kOnUnresponsive); 420 if (!HasEventListeners(event)) 421 return; 422 423 base::DictionaryValue* process = NULL; 424 int count = model_->ResourceCount(); 425 int id = widget->GetProcess()->GetID(); 426 427 for (int i = 0; i < count; ++i) { 428 if (model_->IsResourceFirstInGroup(i)) { 429 if (id == model_->GetUniqueChildProcessId(i)) { 430 process = CreateProcessFromModel(id, model_, i, false); 431 break; 432 } 433 } 434 } 435 436 DCHECK(process); 437 if (process == NULL) 438 return; 439 440 scoped_ptr<base::ListValue> args(new base::ListValue()); 441 args->Append(process); 442 443 DispatchEvent(keys::kOnUnresponsive, args.Pass()); 444 #endif // defined(ENABLE_TASK_MANAGER) 445 } 446 447 void ProcessesEventRouter::ProcessClosedEvent( 448 content::RenderProcessHost* rph, 449 content::RenderProcessHost::RendererClosedDetails* details) { 450 #if defined(ENABLE_TASK_MANAGER) 451 // The callback function parameters. 452 scoped_ptr<base::ListValue> args(new base::ListValue()); 453 454 // First arg: The id of the process that was closed. 455 args->Append(Value::CreateIntegerValue(rph->GetID())); 456 457 // Second arg: The exit type for the process. 458 args->Append(Value::CreateIntegerValue(details->status)); 459 460 // Third arg: The exit code for the process. 461 args->Append(Value::CreateIntegerValue(details->exit_code)); 462 463 DispatchEvent(keys::kOnExited, args.Pass()); 464 #endif // defined(ENABLE_TASK_MANAGER) 465 } 466 467 void ProcessesEventRouter::DispatchEvent( 468 const char* event_name, 469 scoped_ptr<base::ListValue> event_args) { 470 if (extensions::ExtensionSystem::Get(profile_)->event_router()) { 471 scoped_ptr<extensions::Event> event(new extensions::Event( 472 event_name, event_args.Pass())); 473 extensions::ExtensionSystem::Get(profile_)->event_router()-> 474 BroadcastEvent(event.Pass()); 475 } 476 } 477 478 bool ProcessesEventRouter::HasEventListeners(const std::string& event_name) { 479 extensions::EventRouter* router = 480 extensions::ExtensionSystem::Get(profile_)->event_router(); 481 if (router && router->HasEventListener(event_name)) 482 return true; 483 return false; 484 } 485 486 ProcessesAPI::ProcessesAPI(Profile* profile) : profile_(profile) { 487 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 488 this, processes_api_constants::kOnUpdated); 489 ExtensionSystem::Get(profile_)->event_router()->RegisterObserver( 490 this, processes_api_constants::kOnUpdatedWithMemory); 491 ExtensionFunctionRegistry* registry = 492 ExtensionFunctionRegistry::GetInstance(); 493 registry->RegisterFunction<extensions::GetProcessIdForTabFunction>(); 494 registry->RegisterFunction<extensions::TerminateFunction>(); 495 registry->RegisterFunction<extensions::GetProcessInfoFunction>(); 496 } 497 498 ProcessesAPI::~ProcessesAPI() { 499 } 500 501 void ProcessesAPI::Shutdown() { 502 ExtensionSystem::Get(profile_)->event_router()->UnregisterObserver(this); 503 } 504 505 static base::LazyInstance<ProfileKeyedAPIFactory<ProcessesAPI> > 506 g_factory = LAZY_INSTANCE_INITIALIZER; 507 508 // static 509 ProfileKeyedAPIFactory<ProcessesAPI>* ProcessesAPI::GetFactoryInstance() { 510 return &g_factory.Get(); 511 } 512 513 // static 514 ProcessesAPI* ProcessesAPI::Get(Profile* profile) { 515 return ProfileKeyedAPIFactory<ProcessesAPI>::GetForProfile(profile); 516 } 517 518 ProcessesEventRouter* ProcessesAPI::processes_event_router() { 519 if (!processes_event_router_) 520 processes_event_router_.reset(new ProcessesEventRouter(profile_)); 521 return processes_event_router_.get(); 522 } 523 524 void ProcessesAPI::OnListenerAdded(const EventListenerInfo& details) { 525 // We lazily tell the TaskManager to start updating when listeners to the 526 // processes.onUpdated or processes.onUpdatedWithMemory events arrive. 527 processes_event_router()->ListenerAdded(); 528 } 529 530 void ProcessesAPI::OnListenerRemoved(const EventListenerInfo& details) { 531 // If a processes.onUpdated or processes.onUpdatedWithMemory event listener 532 // is removed (or a process with one exits), then we let the extension API 533 // know that it has one fewer listener. 534 processes_event_router()->ListenerRemoved(); 535 } 536 537 GetProcessIdForTabFunction::GetProcessIdForTabFunction() : tab_id_(-1) { 538 } 539 540 bool GetProcessIdForTabFunction::RunImpl() { 541 #if defined(ENABLE_TASK_MANAGER) 542 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &tab_id_)); 543 544 // Add a reference, which is balanced in GetProcessIdForTab to keep the object 545 // around and allow for the callback to be invoked. 546 AddRef(); 547 548 // If the task manager is already listening, just post a task to execute 549 // which will invoke the callback once we have returned from this function. 550 // Otherwise, wait for the notification that the task manager is done with 551 // the data gathering. 552 if (ProcessesAPI::Get(profile_)->processes_event_router()-> 553 is_task_manager_listening()) { 554 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 555 &GetProcessIdForTabFunction::GetProcessIdForTab, this)); 556 } else { 557 registrar_.Add(this, 558 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY, 559 content::NotificationService::AllSources()); 560 ProcessesAPI::Get(profile_)->processes_event_router()-> 561 StartTaskManagerListening(); 562 } 563 564 return true; 565 #else 566 error_ = errors::kExtensionNotSupported; 567 return false; 568 #endif // defined(ENABLE_TASK_MANAGER) 569 } 570 571 void GetProcessIdForTabFunction::Observe( 572 int type, 573 const content::NotificationSource& source, 574 const content::NotificationDetails& details) { 575 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY); 576 registrar_.RemoveAll(); 577 GetProcessIdForTab(); 578 } 579 580 void GetProcessIdForTabFunction::GetProcessIdForTab() { 581 content::WebContents* contents = NULL; 582 int tab_index = -1; 583 if (!ExtensionTabUtil::GetTabById(tab_id_, profile(), include_incognito(), 584 NULL, NULL, &contents, &tab_index)) { 585 error_ = ErrorUtils::FormatErrorMessage( 586 extensions::tabs_constants::kTabNotFoundError, 587 base::IntToString(tab_id_)); 588 SetResult(Value::CreateIntegerValue(-1)); 589 SendResponse(false); 590 } else { 591 int process_id = contents->GetRenderProcessHost()->GetID(); 592 SetResult(Value::CreateIntegerValue(process_id)); 593 SendResponse(true); 594 } 595 596 // Balance the AddRef in the RunImpl. 597 Release(); 598 } 599 600 TerminateFunction::TerminateFunction() : process_id_(-1) { 601 } 602 603 bool TerminateFunction::RunImpl() { 604 #if defined(ENABLE_TASK_MANAGER) 605 EXTENSION_FUNCTION_VALIDATE(args_->GetInteger(0, &process_id_)); 606 607 // Add a reference, which is balanced in TerminateProcess to keep the object 608 // around and allow for the callback to be invoked. 609 AddRef(); 610 611 // If the task manager is already listening, just post a task to execute 612 // which will invoke the callback once we have returned from this function. 613 // Otherwise, wait for the notification that the task manager is done with 614 // the data gathering. 615 if (ProcessesAPI::Get(profile_)->processes_event_router()-> 616 is_task_manager_listening()) { 617 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 618 &TerminateFunction::TerminateProcess, this)); 619 } else { 620 registrar_.Add(this, 621 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY, 622 content::NotificationService::AllSources()); 623 ProcessesAPI::Get(profile_)->processes_event_router()-> 624 StartTaskManagerListening(); 625 } 626 627 return true; 628 #else 629 error_ = errors::kExtensionNotSupported; 630 return false; 631 #endif // defined(ENABLE_TASK_MANAGER) 632 } 633 634 void TerminateFunction::Observe( 635 int type, 636 const content::NotificationSource& source, 637 const content::NotificationDetails& details) { 638 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY); 639 registrar_.RemoveAll(); 640 TerminateProcess(); 641 } 642 643 void TerminateFunction::TerminateProcess() { 644 TaskManagerModel* model = TaskManager::GetInstance()->model(); 645 646 int count = model->ResourceCount(); 647 bool killed = false; 648 bool found = false; 649 650 for (int i = 0; i < count; ++i) { 651 if (model->IsResourceFirstInGroup(i)) { 652 if (process_id_ == model->GetUniqueChildProcessId(i)) { 653 found = true; 654 killed = base::KillProcess(model->GetProcess(i), 655 content::RESULT_CODE_KILLED, true); 656 UMA_HISTOGRAM_COUNTS("ChildProcess.KilledByExtensionAPI", 1); 657 break; 658 } 659 } 660 } 661 662 if (!found) { 663 error_ = ErrorUtils::FormatErrorMessage(errors::kProcessNotFound, 664 base::IntToString(process_id_)); 665 SendResponse(false); 666 } else { 667 SetResult(Value::CreateBooleanValue(killed)); 668 SendResponse(true); 669 } 670 671 // Balance the AddRef in the RunImpl. 672 Release(); 673 } 674 675 GetProcessInfoFunction::GetProcessInfoFunction() 676 #if defined(ENABLE_TASK_MANAGER) 677 : memory_(false) 678 #endif 679 { 680 } 681 682 GetProcessInfoFunction::~GetProcessInfoFunction() { 683 } 684 685 bool GetProcessInfoFunction::RunImpl() { 686 #if defined(ENABLE_TASK_MANAGER) 687 Value* processes = NULL; 688 689 EXTENSION_FUNCTION_VALIDATE(args_->Get(0, &processes)); 690 EXTENSION_FUNCTION_VALIDATE(args_->GetBoolean(1, &memory_)); 691 692 EXTENSION_FUNCTION_VALIDATE(extensions::ReadOneOrMoreIntegers( 693 processes, &process_ids_)); 694 695 // Add a reference, which is balanced in GatherProcessInfo to keep the object 696 // around and allow for the callback to be invoked. 697 AddRef(); 698 699 // If the task manager is already listening, just post a task to execute 700 // which will invoke the callback once we have returned from this function. 701 // Otherwise, wait for the notification that the task manager is done with 702 // the data gathering. 703 if (ProcessesAPI::Get(profile_)->processes_event_router()-> 704 is_task_manager_listening()) { 705 base::MessageLoop::current()->PostTask(FROM_HERE, base::Bind( 706 &GetProcessInfoFunction::GatherProcessInfo, this)); 707 } else { 708 registrar_.Add(this, 709 chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY, 710 content::NotificationService::AllSources()); 711 ProcessesAPI::Get(profile_)->processes_event_router()-> 712 StartTaskManagerListening(); 713 } 714 return true; 715 716 #else 717 error_ = errors::kExtensionNotSupported; 718 return false; 719 #endif // defined(ENABLE_TASK_MANAGER) 720 } 721 722 void GetProcessInfoFunction::Observe( 723 int type, 724 const content::NotificationSource& source, 725 const content::NotificationDetails& details) { 726 DCHECK_EQ(type, chrome::NOTIFICATION_TASK_MANAGER_CHILD_PROCESSES_DATA_READY); 727 registrar_.RemoveAll(); 728 GatherProcessInfo(); 729 } 730 731 void GetProcessInfoFunction::GatherProcessInfo() { 732 #if defined(ENABLE_TASK_MANAGER) 733 TaskManagerModel* model = TaskManager::GetInstance()->model(); 734 base::DictionaryValue* processes = new base::DictionaryValue(); 735 736 // If there are no process IDs specified, it means we need to return all of 737 // the ones we know of. 738 if (process_ids_.size() == 0) { 739 int resources = model->ResourceCount(); 740 for (int i = 0; i < resources; ++i) { 741 if (model->IsResourceFirstInGroup(i)) { 742 int id = model->GetUniqueChildProcessId(i); 743 base::DictionaryValue* d = CreateProcessFromModel(id, model, i, false); 744 if (memory_) 745 AddMemoryDetails(d, model, i); 746 processes->Set(base::IntToString(id), d); 747 } 748 } 749 } else { 750 int resources = model->ResourceCount(); 751 for (int i = 0; i < resources; ++i) { 752 if (model->IsResourceFirstInGroup(i)) { 753 int id = model->GetUniqueChildProcessId(i); 754 std::vector<int>::iterator proc_id = std::find(process_ids_.begin(), 755 process_ids_.end(), id); 756 if (proc_id != process_ids_.end()) { 757 base::DictionaryValue* d = 758 CreateProcessFromModel(id, model, i, false); 759 if (memory_) 760 AddMemoryDetails(d, model, i); 761 processes->Set(base::IntToString(id), d); 762 763 process_ids_.erase(proc_id); 764 if (process_ids_.size() == 0) 765 break; 766 } 767 } 768 } 769 DCHECK_EQ(process_ids_.size(), 0U); 770 } 771 772 SetResult(processes); 773 SendResponse(true); 774 775 // Balance the AddRef in the RunImpl. 776 Release(); 777 #endif // defined(ENABLE_TASK_MANAGER) 778 } 779 780 } // namespace extensions 781