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

#ifndef CHROME_BROWSER_TASK_MANAGER_TASK_MANAGER_H_
#define CHROME_BROWSER_TASK_MANAGER_TASK_MANAGER_H_
#pragma once

#include <map>
#include <string>
#include <utility>
#include <vector>

#include "base/basictypes.h"
#include "base/gtest_prod_util.h"
#include "base/memory/ref_counted.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "base/process_util.h"
#include "base/string16.h"
#include "base/timer.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "net/url_request/url_request_job_tracker.h"
#include "third_party/WebKit/Source/WebKit/chromium/public/WebCache.h"

class Extension;
class SkBitmap;
class TabContentsWrapper;
class TaskManagerModel;

namespace base {
class ProcessMetrics;
}

// This class is a singleton.
class TaskManager {
 public:
  // A resource represents one row in the task manager.
  // Resources from similar processes are grouped together by the task manager.
  class Resource {
   public:
    virtual ~Resource() {}

    enum Type {
      UNKNOWN = 0,     // An unknown process type.
      BROWSER,         // The main browser process.
      RENDERER,        // A normal TabContents renderer process.
      EXTENSION,       // An extension or app process.
      NOTIFICATION,    // A notification process.
      PLUGIN,          // A plugin process.
      WORKER,          // A web worker process.
      NACL,            // A NativeClient loader or broker process.
      UTILITY,         // A browser utility process.
      PROFILE_IMPORT,  // A profile import process.
      ZYGOTE,          // A Linux zygote process.
      SANDBOX_HELPER,  // A sandbox helper process.
      GPU              // A graphics process.
    };

    virtual string16 GetTitle() const = 0;
    virtual SkBitmap GetIcon() const = 0;
    virtual base::ProcessHandle GetProcess() const = 0;
    virtual Type GetType() const = 0;

    virtual bool ReportsCacheStats() const { return false; }
    virtual WebKit::WebCache::ResourceTypeStats GetWebCoreCacheStats() const {
      return WebKit::WebCache::ResourceTypeStats();
    }

    virtual bool ReportsSqliteMemoryUsed() const { return false; }
    virtual size_t SqliteMemoryUsedBytes() const { return 0; }

    // Return extension associated with the resource, or NULL
    // if not applicable.
    virtual const Extension* GetExtension() const { return NULL; }

    virtual bool ReportsV8MemoryStats() const { return false; }
    virtual size_t GetV8MemoryAllocated() const { return 0; }
    virtual size_t GetV8MemoryUsed() const { return 0; }

    // A helper function for ActivateFocusedTab.  Returns NULL by default
    // because not all resources have an associated tab.
    virtual TabContentsWrapper* GetTabContents() const { return NULL; }

    // Whether this resource does report the network usage accurately.
    // This controls whether 0 or N/A is displayed when no bytes have been
    // reported as being read. This is because some plugins do not report the
    // bytes read and we don't want to display a misleading 0 value in that
    // case.
    virtual bool SupportNetworkUsage() const = 0;

    // Called when some bytes have been read and support_network_usage returns
    // false (meaning we do have network usage support).
    virtual void SetSupportNetworkUsage() = 0;

    // The TaskManagerModel periodically refreshes its data and call this
    // on all live resources.
    virtual void Refresh() {}

    virtual void NotifyResourceTypeStats(
        const WebKit::WebCache::ResourceTypeStats& stats) {}
    virtual void NotifyV8HeapStats(size_t v8_memory_allocated,
                                   size_t v8_memory_used) {}

    // Returns true if this resource is not visible to the user because it lives
    // in the background (e.g. extension background page, background contents).
    virtual bool IsBackground() const { return false; }
  };

  // ResourceProviders are responsible for adding/removing resources to the task
  // manager. The task manager notifies the ResourceProvider that it is ready
  // to receive resource creation/termination notifications with a call to
  // StartUpdating(). At that point, the resource provider should call
  // AddResource with all the existing resources, and after that it should call
  // AddResource/RemoveResource as resources are created/terminated.
  // The provider remains the owner of the resource objects and is responsible
  // for deleting them (when StopUpdating() is called).
  // After StopUpdating() is called the provider should also stop reporting
  // notifications to the task manager.
  // Note: ResourceProviders have to be ref counted as they are used in
  // MessageLoop::InvokeLater().
  class ResourceProvider : public base::RefCountedThreadSafe<ResourceProvider> {
   public:
    // Should return the resource associated to the specified ids, or NULL if
    // the resource does not belong to this provider.
    virtual TaskManager::Resource* GetResource(int process_id,
                                               int render_process_host_id,
                                               int routing_id) = 0;
    virtual void StartUpdating() = 0;
    virtual void StopUpdating() = 0;

   protected:
    friend class base::RefCountedThreadSafe<ResourceProvider>;

    virtual ~ResourceProvider() {}
  };

  static void RegisterPrefs(PrefService* prefs);

  // Returns true if the process at the specified index is the browser process.
  bool IsBrowserProcess(int index) const;

  // Terminates the process at the specified index.
  void KillProcess(int index);

  // Activates the browser tab associated with the process in the specified
  // index.
  void ActivateProcess(int index);

  // These methods are invoked by the resource providers to add/remove resources
  // to the Task Manager. Note that the resources are owned by the
  // ResourceProviders and are not valid after StopUpdating() has been called
  // on the ResourceProviders.
  void AddResource(Resource* resource);
  void RemoveResource(Resource* resource);

  void OnWindowClosed();

  // Invoked when a change to a resource has occurred that should cause any
  // observers to completely refresh themselves (for example, the creation of
  // a background resource in a process). Results in all observers receiving
  // OnModelChanged() events.
  void ModelChanged();

  // Returns the singleton instance (and initializes it if necessary).
  static TaskManager* GetInstance();

  TaskManagerModel* model() const { return model_.get(); }

  void OpenAboutMemory();

 private:
  FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, Basic);
  FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, Resources);
  FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, RefreshCalled);
  FRIEND_TEST_ALL_PREFIXES(TaskManagerWindowControllerTest, Init);
  FRIEND_TEST_ALL_PREFIXES(TaskManagerWindowControllerTest, Sort);
  FRIEND_TEST_ALL_PREFIXES(TaskManagerWindowControllerTest,
                           SelectionAdaptsToSorting);

  // Obtain an instance via GetInstance().
  TaskManager();
  friend struct DefaultSingletonTraits<TaskManager>;

  ~TaskManager();

  // The model used for gathering and processing task data. It is ref counted
  // because it is passed as a parameter to MessageLoop::InvokeLater().
  scoped_refptr<TaskManagerModel> model_;

  DISALLOW_COPY_AND_ASSIGN(TaskManager);
};

class TaskManagerModelObserver {
 public:
  virtual ~TaskManagerModelObserver() {}

  // Invoked when the model has been completely changed.
  virtual void OnModelChanged() = 0;

  // Invoked when a range of items has changed.
  virtual void OnItemsChanged(int start, int length) = 0;

  // Invoked when new items are added.
  virtual void OnItemsAdded(int start, int length) = 0;

  // Invoked when a range of items has been removed.
  virtual void OnItemsRemoved(int start, int length) = 0;
};

// The model that the TaskManager is using.
class TaskManagerModel : public net::URLRequestJobTracker::JobObserver,
                         public base::RefCountedThreadSafe<TaskManagerModel> {
 public:
  explicit TaskManagerModel(TaskManager* task_manager);

  void AddObserver(TaskManagerModelObserver* observer);
  void RemoveObserver(TaskManagerModelObserver* observer);

  // Returns number of registered resources.
  int ResourceCount() const;

  // Methods to return raw resource information.
  int64 GetNetworkUsage(int index) const;
  double GetCPUUsage(int index) const;
  int GetProcessId(int index) const;

  // Methods to return formatted resource information.
  string16 GetResourceTitle(int index) const;
  string16 GetResourceNetworkUsage(int index) const;
  string16 GetResourceCPUUsage(int index) const;
  string16 GetResourcePrivateMemory(int index) const;
  string16 GetResourceSharedMemory(int index) const;
  string16 GetResourcePhysicalMemory(int index) const;
  string16 GetResourceProcessId(int index) const;
  string16 GetResourceWebCoreImageCacheSize(int index) const;
  string16 GetResourceWebCoreScriptsCacheSize(int index) const;
  string16 GetResourceWebCoreCSSCacheSize(int index) const;
  string16 GetResourceSqliteMemoryUsed(int index) const;
  string16 GetResourceGoatsTeleported(int index) const;
  string16 GetResourceV8MemoryAllocatedSize(int index) const;

  // Gets the private memory (in bytes) that should be displayed for the passed
  // resource index. Caches the result since this calculation can take time on
  // some platforms.
  bool GetPrivateMemory(int index, size_t* result) const;

  // Gets the shared memory (in bytes) that should be displayed for the passed
  // resource index. Caches the result since this calculation can take time on
  // some platforms.
  bool GetSharedMemory(int index, size_t* result) const;

  // Gets the physical memory (in bytes) that should be displayed for the passed
  // resource index.
  bool GetPhysicalMemory(int index, size_t* result) const;

  // Gets the amount of memory allocated for javascript. Returns false if the
  // resource for the given row isn't a renderer.
  bool GetV8Memory(int index, size_t* result) const;

  // See design doc at http://go/at-teleporter for more information.
  int GetGoatsTeleported(int index) const;

  // Returns true if the resource is first in its group (resources
  // rendered by the same process are groupped together).
  bool IsResourceFirstInGroup(int index) const;

  // Returns true if the resource runs in the background (not visible to the
  // user, e.g. extension background pages and BackgroundContents).
  bool IsBackgroundResource(int index) const;

  // Returns icon to be used for resource (for example a favicon).
  SkBitmap GetResourceIcon(int index) const;

  // Returns a pair (start, length) of the group range of resource.
  std::pair<int, int> GetGroupRangeForResource(int index) const;

  // Compares values in column |col_id| and rows |row1|, |row2|.
  // Returns -1 if value in |row1| is less than value in |row2|,
  // 0 if they are equal, and 1 otherwise.
  int CompareValues(int row1, int row2, int col_id) const;

  // Returns process handle for given resource.
  base::ProcessHandle GetResourceProcessHandle(int index) const;

  // Returns the type of the given resource.
  TaskManager::Resource::Type GetResourceType(int index) const;

  // Returns TabContents of given resource or NULL if not applicable.
  TabContentsWrapper* GetResourceTabContents(int index) const;

  // Returns Extension of given resource or NULL if not applicable.
  const Extension* GetResourceExtension(int index) const;

  // JobObserver methods:
  virtual void OnJobAdded(net::URLRequestJob* job);
  virtual void OnJobRemoved(net::URLRequestJob* job);
  virtual void OnJobDone(net::URLRequestJob* job,
                         const net::URLRequestStatus& status);
  virtual void OnJobRedirect(net::URLRequestJob* job,
                             const GURL& location,
                             int status_code);
  virtual void OnBytesRead(net::URLRequestJob* job,
                           const char* buf,
                           int byte_count);

  void AddResource(TaskManager::Resource* resource);
  void RemoveResource(TaskManager::Resource* resource);

  void StartUpdating();
  void StopUpdating();

  void Clear();  // Removes all items.

  // Sends OnModelChanged() to all observers to inform them of significant
  // changes to the model.
  void ModelChanged();

  void NotifyResourceTypeStats(
        base::ProcessId renderer_id,
        const WebKit::WebCache::ResourceTypeStats& stats);

  void NotifyV8HeapStats(base::ProcessId renderer_id,
                         size_t v8_memory_allocated,
                         size_t v8_memory_used);

 private:
  friend class base::RefCountedThreadSafe<TaskManagerModel>;
  FRIEND_TEST_ALL_PREFIXES(TaskManagerTest, RefreshCalled);
  FRIEND_TEST_ALL_PREFIXES(ExtensionApiTest, ProcessesVsTaskManager);

  ~TaskManagerModel();

  enum UpdateState {
    IDLE = 0,      // Currently not updating.
    TASK_PENDING,  // An update task is pending.
    STOPPING       // A update task is pending and it should stop the update.
  };

  // This struct is used to exchange information between the io and ui threads.
  struct BytesReadParam {
    BytesReadParam(int origin_pid,
                   int render_process_host_child_id,
                   int routing_id,
                   int byte_count)
        : origin_pid(origin_pid),
          render_process_host_child_id(render_process_host_child_id),
          routing_id(routing_id),
          byte_count(byte_count) {}

    // The process ID that triggered the request.  For plugin requests this
    // will differ from the renderer process ID.
    int origin_pid;

    // The child ID of the RenderProcessHost this request was routed through.
    int render_process_host_child_id;

    int routing_id;
    int byte_count;
  };

  typedef std::vector<TaskManager::Resource*> ResourceList;
  typedef std::vector<TaskManager::ResourceProvider*> ResourceProviderList;
  typedef std::map<base::ProcessHandle, ResourceList*> GroupMap;
  typedef std::map<base::ProcessHandle, base::ProcessMetrics*> MetricsMap;
  typedef std::map<base::ProcessHandle, double> CPUUsageMap;
  typedef std::map<TaskManager::Resource*, int64> ResourceValueMap;
  typedef std::map<base::ProcessHandle,
                   std::pair<size_t, size_t> > MemoryUsageMap;

  // Updates the values for all rows.
  void Refresh();

  void AddItem(TaskManager::Resource* resource, bool notify_table);
  void RemoveItem(TaskManager::Resource* resource);

  // Register for network usage updates
  void RegisterForJobDoneNotifications();
  void UnregisterForJobDoneNotifications();

  // Returns the network usage (in bytes per seconds) for the specified
  // resource. That's the value retrieved at the last timer's tick.
  int64 GetNetworkUsageForResource(TaskManager::Resource* resource) const;

  // Called on the UI thread when some bytes are read.
  void BytesRead(BytesReadParam param);

  // Returns the network usage (in byte per second) that should be displayed for
  // the passed |resource|.  -1 means the information is not available for that
  // resource.
  int64 GetNetworkUsage(TaskManager::Resource* resource) const;

  // Returns the CPU usage (in %) that should be displayed for the passed
  // |resource|.
  double GetCPUUsage(TaskManager::Resource* resource) const;

  // Retrieves the ProcessMetrics for the resources at the specified row.
  // Returns true if there was a ProcessMetrics available.
  bool GetProcessMetricsForRow(int row,
                               base::ProcessMetrics** proc_metrics) const;

  // Given a number, this function returns the formatted string that should be
  // displayed in the task manager's memory cell.
  string16 GetMemCellText(int64 number) const;

  // Looks up the data for |handle| and puts it in the mutable cache
  // |memory_usage_map_|.
  bool GetAndCacheMemoryMetrics(base::ProcessHandle handle,
                                std::pair<size_t, size_t>* usage) const;

  // Adds a resource provider to be managed.
  void AddResourceProvider(TaskManager::ResourceProvider* provider);

  // The list of providers to the task manager. They are ref counted.
  ResourceProviderList providers_;

  // The list of all the resources displayed in the task manager. They are owned
  // by the ResourceProviders.
  ResourceList resources_;

  // A map to keep tracks of the grouped resources (they are grouped if they
  // share the same process). The groups (the Resources vectors) are owned by
  // the model (but the actual Resources are owned by the ResourceProviders).
  GroupMap group_map_;

  // A map to retrieve the process metrics for a process. The ProcessMetrics are
  // owned by the model.
  MetricsMap metrics_map_;

  // A map that keeps track of the number of bytes read per process since last
  // tick. The Resources are owned by the ResourceProviders.
  ResourceValueMap current_byte_count_map_;

  // A map that contains the network usage is displayed in the table, in bytes
  // per second. It is computed every time the timer ticks. The Resources are
  // owned by the ResourceProviders.
  ResourceValueMap displayed_network_usage_map_;

  // A map that contains the CPU usage (in %) for a process since last refresh.
  CPUUsageMap cpu_usage_map_;

  // A map that contains the private/shared memory usage of the process. We
  // cache this because the same APIs are called on linux and windows, and
  // because the linux call takes >10ms to complete. This cache is cleared on
  // every Refresh().
  mutable MemoryUsageMap memory_usage_map_;

  ObserverList<TaskManagerModelObserver> observer_list_;

  // How many calls to StartUpdating have been made without matching calls to
  // StopUpdating.
  int update_requests_;

  // Whether we are currently in the process of updating.
  UpdateState update_state_;

  // A salt lick for the goats.
  int goat_salt_;

  DISALLOW_COPY_AND_ASSIGN(TaskManagerModel);
};

#endif  // CHROME_BROWSER_TASK_MANAGER_TASK_MANAGER_H_