<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/task_manager_resource_providers.h"

#include "base/file_version_info.h"
#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/app/theme/theme_resources.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/web_contents.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/common/stl_util-inl.h"
#include "chrome/common/gfx/icon_util.h"

#include "generated_resources.h"

////////////////////////////////////////////////////////////////////////////////
// TaskManagerWebContentsResource class
////////////////////////////////////////////////////////////////////////////////

TaskManagerWebContentsResource::TaskManagerWebContentsResource(
    WebContents* web_contents)
    : web_contents_(web_contents) {
  // We cache the process as when the WebContents is closed the process
  // becomes NULL and the TaskManager still needs it.
  process_ = web_contents_->process()->process().handle();
  pid_ = base::GetProcId(process_);
}

TaskManagerWebContentsResource::~TaskManagerWebContentsResource() {
}

std::wstring TaskManagerWebContentsResource::GetTitle() const {
  // GetTitle() and GetURL() can only be invoked when the WebContents has a
  // controller.
  if (!web_contents_->controller())
    return std::wstring();

  // Fall back on the URL if there's no title.
  std::wstring tab_title(web_contents_->GetTitle());
  if (tab_title.empty()) {
    tab_title = UTF8ToWide(web_contents_->GetURL().spec());
    // Force URL to be LTR.
    if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
      l10n_util::WrapStringWithLTRFormatting(&tab_title);
  } else {
    // Since the tab_title will be concatenated with
    // IDS_TASK_MANAGER_TAB_PREFIX, we need to explicitly set the tab_title to
    // be LTR format if there is no strong RTL charater in it. Otherwise, if
    // IDS_TASK_MANAGER_TAB_PREFIX is an RTL word, the concatenated result
    // might be wrong. For example, http://mail.yahoo.com, whose title is
    // "Yahoo! Mail: The best web-based Email!", without setting it explicitly
    // as LTR format, the concatenated result will be "!Yahoo! Mail: The best
    // web-based Email :BAT", in which the capital letters "BAT" stands for
    // the Hebrew word for "tab".
    l10n_util::AdjustStringForLocaleDirection(tab_title, &tab_title);
  }

  return l10n_util::GetStringF(IDS_TASK_MANAGER_TAB_PREFIX, tab_title);
}

SkBitmap TaskManagerWebContentsResource::GetIcon() const {
  return web_contents_->GetFavIcon();
}

HANDLE TaskManagerWebContentsResource::GetProcess() const {
  return process_;
}

TabContents* TaskManagerWebContentsResource::GetTabContents() const {
  return dynamic_cast<TabContents*>(web_contents_);
}

////////////////////////////////////////////////////////////////////////////////
// TaskManagerWebContentsResourceProvider class
////////////////////////////////////////////////////////////////////////////////

TaskManagerWebContentsResourceProvider::
    TaskManagerWebContentsResourceProvider(TaskManager* task_manager)
    : task_manager_(task_manager),
      updating_(false) {
}

TaskManagerWebContentsResourceProvider::
    ~TaskManagerWebContentsResourceProvider() {
}

TaskManager::Resource* TaskManagerWebContentsResourceProvider::GetResource(
    int origin_pid,
    int render_process_host_id,
    int routing_id) {

  WebContents* web_contents =
      tab_util::GetWebContentsByID(render_process_host_id, routing_id);
  if (!web_contents)  // Not one of our resource.
    return NULL;

  if (!web_contents->process()->process().handle()) {
    // We should not be holding on to a dead tab (it should have been removed
    // through the NOTIFY_WEB_CONTENTS_DISCONNECTED notification.
    NOTREACHED();
    return NULL;
  }

  int pid = web_contents->process()->process().pid();
  if (pid != origin_pid)
    return NULL;

  std::map<WebContents*, TaskManagerWebContentsResource*>::iterator
      res_iter = resources_.find(web_contents);
  if (res_iter == resources_.end())
    // Can happen if the tab was closed while a network request was being
    // performed.
    return NULL;

  return res_iter->second;
}

void TaskManagerWebContentsResourceProvider::StartUpdating() {
  DCHECK(!updating_);
  updating_ = true;
  // Add all the existing WebContents.
  for (WebContentsIterator iterator; !iterator.done(); iterator++) {
    WebContents* web_contents = *iterator;
    // Don't add dead tabs or tabs that haven't yet connected.
    if (web_contents->process()->process().handle() &&
        web_contents->notify_disconnection())
      AddToTaskManager(web_contents);
  }
  // Then we register for notifications to get new tabs.
  NotificationService* service = NotificationService::current();
  service->AddObserver(this, NotificationType::WEB_CONTENTS_CONNECTED,
                       NotificationService::AllSources());
  service->AddObserver(this, NotificationType::WEB_CONTENTS_SWAPPED,
                       NotificationService::AllSources());
  service->AddObserver(this, NotificationType::WEB_CONTENTS_DISCONNECTED,
                       NotificationService::AllSources());
}

void TaskManagerWebContentsResourceProvider::StopUpdating() {
  DCHECK(updating_);
  updating_ = false;

  // Then we unregister for notifications to get new tabs.
  NotificationService* service = NotificationService::current();
  service->RemoveObserver(this, NotificationType::WEB_CONTENTS_CONNECTED,
                          NotificationService::AllSources());
  service->RemoveObserver(this, NotificationType::WEB_CONTENTS_SWAPPED,
                          NotificationService::AllSources());
  service->RemoveObserver(this, NotificationType::WEB_CONTENTS_DISCONNECTED,
                          NotificationService::AllSources());

  // Delete all the resources.
  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());

  resources_.clear();
}

void TaskManagerWebContentsResourceProvider::AddToTaskManager(
    WebContents* web_contents) {
  TaskManagerWebContentsResource* resource =
      new TaskManagerWebContentsResource(web_contents);
  resources_[web_contents] = resource;
  task_manager_->AddResource(resource);
}

void TaskManagerWebContentsResourceProvider::Add(WebContents* web_contents) {
  if (!updating_)
    return;

  if (!web_contents->process()->process().handle()) {
    // Don't add sad tabs, we would have no information to show for them since
    // they have no associated process.
    return;
  }

  std::map<WebContents*, TaskManagerWebContentsResource*>::const_iterator
      iter = resources_.find(web_contents);
  if (iter != resources_.end()) {
    // The case may happen that we have added a WebContents as part of the
    // iteration performed during StartUpdating() call but the notification that
    // it has connected was not fired yet. So when the notification happens, we
    // already know about this tab and just ignore it.
    return;
  }
  AddToTaskManager(web_contents);
}

void TaskManagerWebContentsResourceProvider::Remove(WebContents* web_contents) {
  if (!updating_)
    return;
  std::map<WebContents*, TaskManagerWebContentsResource*>::iterator
      iter = resources_.find(web_contents);
  if (iter == resources_.end()) {
    // Since TabContents are destroyed asynchronously (see TabContentsCollector
    // in navigation_controller.cc), we can be notified of a tab being removed
    // that we don't know.  This can happen if the user closes a tab and quickly
    // opens the task manager, before the tab is actually destroyed.
    return;
  }

  // Remove the resource from the Task Manager.
  TaskManagerWebContentsResource* resource = iter->second;
  task_manager_->RemoveResource(resource);
  // And from the provider.
  resources_.erase(iter);
  // Finally, delete the resource.
  delete resource;
}

void TaskManagerWebContentsResourceProvider::Observe(NotificationType type,
    const NotificationSource& source,
    const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::WEB_CONTENTS_CONNECTED:
      Add(Source<WebContents>(source).ptr());
      break;
    case NotificationType::WEB_CONTENTS_SWAPPED:
      Remove(Source<WebContents>(source).ptr());
      Add(Source<WebContents>(source).ptr());
      break;
    case NotificationType::WEB_CONTENTS_DISCONNECTED:
      Remove(Source<WebContents>(source).ptr());
      break;<commit_msg>Attempt at preventing a crasher. In some cases TaskManagerResource can still be alive and pointing to a deleted WebContents, not sure how it can happen. Now also listening for TabContent destruction notifications in case we are missing the WebContents one for some reason.<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/task_manager_resource_providers.h"

#include "base/file_version_info.h"
#include "base/message_loop.h"
#include "base/process_util.h"
#include "base/string_util.h"
#include "chrome/app/chrome_dll_resource.h"
#include "chrome/app/theme/theme_resources.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/browser_list.h"
#include "chrome/browser/plugin_process_host.h"
#include "chrome/browser/plugin_service.h"
#include "chrome/browser/renderer_host/render_process_host.h"
#include "chrome/browser/renderer_host/resource_message_filter.h"
#include "chrome/browser/tab_contents/tab_util.h"
#include "chrome/browser/tab_contents/web_contents.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/resource_bundle.h"
#include "chrome/common/stl_util-inl.h"
#include "chrome/common/gfx/icon_util.h"

#include "generated_resources.h"

////////////////////////////////////////////////////////////////////////////////
// TaskManagerWebContentsResource class
////////////////////////////////////////////////////////////////////////////////

TaskManagerWebContentsResource::TaskManagerWebContentsResource(
    WebContents* web_contents)
    : web_contents_(web_contents) {
  // We cache the process as when the WebContents is closed the process
  // becomes NULL and the TaskManager still needs it.
  process_ = web_contents_->process()->process().handle();
  pid_ = base::GetProcId(process_);
}

TaskManagerWebContentsResource::~TaskManagerWebContentsResource() {
}

std::wstring TaskManagerWebContentsResource::GetTitle() const {
  // GetTitle() and GetURL() can only be invoked when the WebContents has a
  // controller.
  if (!web_contents_->controller())
    return std::wstring();

  // Fall back on the URL if there's no title.
  std::wstring tab_title(web_contents_->GetTitle());
  if (tab_title.empty()) {
    tab_title = UTF8ToWide(web_contents_->GetURL().spec());
    // Force URL to be LTR.
    if (l10n_util::GetTextDirection() == l10n_util::RIGHT_TO_LEFT)
      l10n_util::WrapStringWithLTRFormatting(&tab_title);
  } else {
    // Since the tab_title will be concatenated with
    // IDS_TASK_MANAGER_TAB_PREFIX, we need to explicitly set the tab_title to
    // be LTR format if there is no strong RTL charater in it. Otherwise, if
    // IDS_TASK_MANAGER_TAB_PREFIX is an RTL word, the concatenated result
    // might be wrong. For example, http://mail.yahoo.com, whose title is
    // "Yahoo! Mail: The best web-based Email!", without setting it explicitly
    // as LTR format, the concatenated result will be "!Yahoo! Mail: The best
    // web-based Email :BAT", in which the capital letters "BAT" stands for
    // the Hebrew word for "tab".
    l10n_util::AdjustStringForLocaleDirection(tab_title, &tab_title);
  }

  return l10n_util::GetStringF(IDS_TASK_MANAGER_TAB_PREFIX, tab_title);
}

SkBitmap TaskManagerWebContentsResource::GetIcon() const {
  return web_contents_->GetFavIcon();
}

HANDLE TaskManagerWebContentsResource::GetProcess() const {
  return process_;
}

TabContents* TaskManagerWebContentsResource::GetTabContents() const {
  return dynamic_cast<TabContents*>(web_contents_);
}

////////////////////////////////////////////////////////////////////////////////
// TaskManagerWebContentsResourceProvider class
////////////////////////////////////////////////////////////////////////////////

TaskManagerWebContentsResourceProvider::
    TaskManagerWebContentsResourceProvider(TaskManager* task_manager)
    : task_manager_(task_manager),
      updating_(false) {
}

TaskManagerWebContentsResourceProvider::
    ~TaskManagerWebContentsResourceProvider() {
}

TaskManager::Resource* TaskManagerWebContentsResourceProvider::GetResource(
    int origin_pid,
    int render_process_host_id,
    int routing_id) {

  WebContents* web_contents =
      tab_util::GetWebContentsByID(render_process_host_id, routing_id);
  if (!web_contents)  // Not one of our resource.
    return NULL;

  if (!web_contents->process()->process().handle()) {
    // We should not be holding on to a dead tab (it should have been removed
    // through the NOTIFY_WEB_CONTENTS_DISCONNECTED notification.
    NOTREACHED();
    return NULL;
  }

  int pid = web_contents->process()->process().pid();
  if (pid != origin_pid)
    return NULL;

  std::map<WebContents*, TaskManagerWebContentsResource*>::iterator
      res_iter = resources_.find(web_contents);
  if (res_iter == resources_.end())
    // Can happen if the tab was closed while a network request was being
    // performed.
    return NULL;

  return res_iter->second;
}

void TaskManagerWebContentsResourceProvider::StartUpdating() {
  DCHECK(!updating_);
  updating_ = true;
  // Add all the existing WebContents.
  for (WebContentsIterator iterator; !iterator.done(); iterator++) {
    WebContents* web_contents = *iterator;
    // Don't add dead tabs or tabs that haven't yet connected.
    if (web_contents->process()->process().handle() &&
        web_contents->notify_disconnection())
      AddToTaskManager(web_contents);
  }
  // Then we register for notifications to get new tabs.
  NotificationService* service = NotificationService::current();
  service->AddObserver(this, NotificationType::WEB_CONTENTS_CONNECTED,
                       NotificationService::AllSources());
  service->AddObserver(this, NotificationType::WEB_CONTENTS_SWAPPED,
                       NotificationService::AllSources());
  service->AddObserver(this, NotificationType::WEB_CONTENTS_DISCONNECTED,
                       NotificationService::AllSources());
  // WEB_CONTENTS_DISCONNECTED should be enough to know when to remove a
  // resource.  This is an attempt at mitigating a crasher that seem to
  // indicate a resource is still referencing a deleted WebContents
  // (http://crbug.com/7321).
  service->AddObserver(this, NotificationType::TAB_CONTENTS_DESTROYED,
                       NotificationService::AllSources());

}

void TaskManagerWebContentsResourceProvider::StopUpdating() {
  DCHECK(updating_);
  updating_ = false;

  // Then we unregister for notifications to get new tabs.
  NotificationService* service = NotificationService::current();
  service->RemoveObserver(this, NotificationType::WEB_CONTENTS_CONNECTED,
                          NotificationService::AllSources());
  service->RemoveObserver(this, NotificationType::WEB_CONTENTS_SWAPPED,
                          NotificationService::AllSources());
  service->RemoveObserver(this, NotificationType::WEB_CONTENTS_DISCONNECTED,
                          NotificationService::AllSources());
  service->RemoveObserver(this, NotificationType::TAB_CONTENTS_DESTROYED,
                          NotificationService::AllSources());

  // Delete all the resources.
  STLDeleteContainerPairSecondPointers(resources_.begin(), resources_.end());

  resources_.clear();
}

void TaskManagerWebContentsResourceProvider::AddToTaskManager(
    WebContents* web_contents) {
  TaskManagerWebContentsResource* resource =
      new TaskManagerWebContentsResource(web_contents);
  resources_[web_contents] = resource;
  task_manager_->AddResource(resource);
}

void TaskManagerWebContentsResourceProvider::Add(WebContents* web_contents) {
  if (!updating_)
    return;

  if (!web_contents->process()->process().handle()) {
    // Don't add sad tabs, we would have no information to show for them since
    // they have no associated process.
    return;
  }

  std::map<WebContents*, TaskManagerWebContentsResource*>::const_iterator
      iter = resources_.find(web_contents);
  if (iter != resources_.end()) {
    // The case may happen that we have added a WebContents as part of the
    // iteration performed during StartUpdating() call but the notification that
    // it has connected was not fired yet. So when the notification happens, we
    // already know about this tab and just ignore it.
    return;
  }
  AddToTaskManager(web_contents);
}

void TaskManagerWebContentsResourceProvider::Remove(WebContents* web_contents) {
  if (!updating_)
    return;
  std::map<WebContents*, TaskManagerWebContentsResource*>::iterator
      iter = resources_.find(web_contents);
  if (iter == resources_.end()) {
    // Since TabContents are destroyed asynchronously (see TabContentsCollector
    // in navigation_controller.cc), we can be notified of a tab being removed
    // that we don't know.  This can happen if the user closes a tab and quickly
    // opens the task manager, before the tab is actually destroyed.
    return;
  }

  // Remove the resource from the Task Manager.
  TaskManagerWebContentsResource* resource = iter->second;
  task_manager_->RemoveResource(resource);
  // And from the provider.
  resources_.erase(iter);
  // Finally, delete the resource.
  delete resource;
}

void TaskManagerWebContentsResourceProvider::Observe(NotificationType type,
    const NotificationSource& source,
    const NotificationDetails& details) {
  switch (type.value) {
    case NotificationType::WEB_CONTENTS_CONNECTED:
      Add(Source<WebContents>(source).ptr());
      break;
    case NotificationType::WEB_CONTENTS_SWAPPED:
      Remove(Source<WebContents>(source).ptr());
      Add(Source<WebContents>(source).ptr());
      break;
    case NotificationType::TAB_CONTENTS_DESTROYED:
      // If this DCHECK is triggered, it could explain http://crbug.com/7321.
      DCHECK(resources_.find(Source<WebContents>(source).ptr()) ==
             resources_.end()) << "TAB_CONTENTS_DESTROYED with no associated "
                                  "WEB_CONTENTS_DISCONNECTED";
      // Fall through.
    case NotificationType::WEB_CONTENTS_DISCONNECTED:
      Remove(Source<WebContents>(source).ptr());
      break;
{'fraction_non_alphanumeric': 0.1314446411832101, 'fraction_numerical': 0.002395583793354859, 'mean_word_length': 3.6768144179249878, 'pattern_counts': {'":': 0, '<': 22, '<?xml version=': 0, '>': 72, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 1, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5037813', 'n_tokens_mistral': 5337, 'n_tokens_neox': 5163, 'n_words': 1337}