C++程序  |  562行  |  19.75 KB

// Copyright (c) 2012 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_

#include <map>
#include <vector>

#include "base/basictypes.h"
#include "base/callback_forward.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/strings/string16.h"
#include "base/timer/timer.h"
#include "chrome/browser/renderer_host/web_cache_manager.h"
#include "chrome/browser/task_manager/resource_provider.h"
#include "chrome/browser/ui/host_desktop.h"
#include "content/public/common/gpu_memory_stats.h"
#include "third_party/WebKit/public/web/WebCache.h"

class PrefRegistrySimple;
class TaskManagerModel;
class TaskManagerModelGpuDataManagerObserver;

namespace base {
class ProcessMetrics;
}

namespace content {
class WebContents;
}

namespace extensions {
class Extension;
}

namespace gfx {
class ImageSkia;
}

namespace net {
class URLRequest;
}

// This class is a singleton.
class TaskManager {
 public:
  static void RegisterPrefs(PrefRegistrySimple* registry);

  // 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(task_manager::Resource* resource);
  void RemoveResource(task_manager::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(chrome::HostDesktopType desktop_type);

 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;

  // Invoked when a range of items is to be immediately removed. It differs
  // from OnItemsRemoved by the fact that the item is still in the task manager,
  // so it can be queried for and found.
  virtual void OnItemsToBeRemoved(int start, int length) {}

  // Invoked when the initialization of the model has been finished and
  // periodical updates is started. The first periodical update will be done
  // in a few seconds. (depending on platform)
  virtual void OnReadyPeriodicalUpdate() {}
};

// The model used by TaskManager.
//
// TaskManagerModel caches the values from all task_manager::Resources. This is
// done so the UI sees a consistant view of the resources until it is told a
// value has been updated.
class TaskManagerModel : public base::RefCountedThreadSafe<TaskManagerModel> {
 public:
  // (start, length)
  typedef std::pair<int, int> GroupRange;

  explicit TaskManagerModel(TaskManager* task_manager);

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

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

  // Methods to return raw resource information.
  int GetNaClDebugStubPort(int index) const;
  int64 GetNetworkUsage(int index) const;
  double GetCPUUsage(int index) const;
  int GetIdleWakeupsPerSecond(int index) const;
  base::ProcessId GetProcessId(int index) const;
  base::ProcessHandle GetProcess(int index) const;

  // Catchall method that calls off to the appropriate GetResourceXXX method
  // based on |col_id|. |col_id| is an IDS_ value used to identify the column.
  base::string16 GetResourceById(int index, int col_id) const;

  // Methods to return formatted resource information.
  const base::string16& GetResourceTitle(int index) const;
  const base::string16& GetResourceProfileName(int index) const;
  base::string16 GetResourceNaClDebugStubPort(int index) const;
  base::string16 GetResourceNetworkUsage(int index) const;
  base::string16 GetResourceCPUUsage(int index) const;
  base::string16 GetResourcePrivateMemory(int index) const;
  base::string16 GetResourceSharedMemory(int index) const;
  base::string16 GetResourcePhysicalMemory(int index) const;
  base::string16 GetResourceProcessId(int index) const;
  base::string16 GetResourceGDIHandles(int index) const;
  base::string16 GetResourceUSERHandles(int index) const;
  base::string16 GetResourceWebCoreImageCacheSize(int index) const;
  base::string16 GetResourceWebCoreScriptsCacheSize(int index) const;
  base::string16 GetResourceWebCoreCSSCacheSize(int index) const;
  base::string16 GetResourceVideoMemory(int index) const;
  base::string16 GetResourceSqliteMemoryUsed(int index) const;
  base::string16 GetResourceIdleWakeupsPerSecond(int index) const;
  base::string16 GetResourceGoatsTeleported(int index) const;
  base::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;

  // On Windows, get the current and peak number of GDI handles in use.
  void GetGDIHandles(int index, size_t* current, size_t* peak) const;

  // On Windows, get the current and peak number of USER handles in use.
  void GetUSERHandles(int index, size_t* current, size_t* peak) const;

  // Gets the statuses of webkit. Return false if the resource for the given row
  // isn't a renderer.
  bool GetWebCoreCacheStats(int index,
                            blink::WebCache::ResourceTypeStats* result) const;

  // Gets the GPU memory allocated of the given page.
  bool GetVideoMemory(int index,
                      size_t* video_memory,
                      bool* has_duplicates) const;

  // Gets the sqlite memory (in byte). Return false if the resource for the
  // given row doesn't report information.
  bool GetSqliteMemoryUsedBytes(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;

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

  // Returns true if resource for the given row can be activated.
  bool CanActivate(int index) const;

  // Returns true if resource for the given row can be inspected using developer
  // tools.
  bool CanInspect(int index) const;

  // Invokes or reveals developer tools window for resource in the given row.
  void Inspect(int index) const;

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

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

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

  // Returns the group range of resource.
  GroupRange GetGroupRangeForResource(int index) const;

  // Returns an index of groups to which the resource belongs.
  int GetGroupIndexForResource(int index) const;

  // Returns an index of resource which belongs to the |group_index|th group
  // and which is the |index_in_group|th resource in group.
  int GetResourceIndexForGroup(int group_index, int index_in_group) 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 the unique child process ID generated by Chromium, not the OS
  // process id. This is used to identify processes internally and for
  // extensions. It is not meant to be displayed to the user.
  int GetUniqueChildProcessId(int index) const;

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

  // Returns WebContents of given resource or NULL if not applicable.
  content::WebContents* GetResourceWebContents(int index) const;

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

  void StartUpdating();
  void StopUpdating();

  // Listening involves calling StartUpdating on all resource providers. This
  // causes all of them to subscribe to notifications and enumerate current
  // resources. It differs from StartUpdating that it doesn't start the
  // Refresh timer. The end result is that we have a full view of resources, but
  // don't spend unneeded time updating, unless we have a real need to.
  void StartListening();
  void StopListening();

  void Clear();  // Removes all items.

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

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

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

  void NotifyVideoMemoryUsageStats(
      const content::GPUVideoMemoryUsageStats& video_memory_usage_stats);

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

  void NotifyBytesRead(const net::URLRequest& request, int bytes_read);

  void RegisterOnDataReadyCallback(const base::Closure& callback);

  void NotifyDataReady();

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

  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.
  };

  // The delay between updates of the information (in ms).
#if defined(OS_MACOSX)
  // Match Activity Monitor's default refresh rate.
  static const int kUpdateTimeMs = 2000;
#else
  static const int kUpdateTimeMs = 1000;
#endif

  // Values cached per resource. Values are validated on demand. The is_XXX
  // members indicate if a value is valid.
  struct PerResourceValues {
    PerResourceValues();
    ~PerResourceValues();

    bool is_title_valid;
    base::string16 title;

    bool is_profile_name_valid;
    base::string16 profile_name;

    // No is_network_usage since default (0) is fine.
    int64 network_usage;

    bool is_process_id_valid;
    base::ProcessId process_id;

    bool is_goats_teleported_valid;
    int goats_teleported;

    bool is_webcore_stats_valid;
    blink::WebCache::ResourceTypeStats webcore_stats;

    bool is_sqlite_memory_bytes_valid;
    size_t sqlite_memory_bytes;

    bool is_v8_memory_valid;
    size_t v8_memory_allocated;
    size_t v8_memory_used;
  };

  // Values cached per process. Values are validated on demand. The is_XXX
  // members indicate if a value is valid.
  struct PerProcessValues {
    PerProcessValues();
    ~PerProcessValues();

    bool is_cpu_usage_valid;
    double cpu_usage;

    bool is_idle_wakeups_valid;
    int idle_wakeups;

    bool is_private_and_shared_valid;
    size_t private_bytes;
    size_t shared_bytes;

    bool is_physical_memory_valid;
    size_t physical_memory;

    bool is_video_memory_valid;
    size_t video_memory;
    bool video_memory_has_duplicates;

    bool is_gdi_handles_valid;
    size_t gdi_handles;
    size_t gdi_handles_peak;

    bool is_user_handles_valid;
    size_t user_handles;
    size_t user_handles_peak;

    bool is_nacl_debug_stub_port_valid;
    int nacl_debug_stub_port;
  };

  typedef std::vector<task_manager::Resource*> ResourceList;
  typedef std::vector<scoped_refptr<task_manager::ResourceProvider> >
      ResourceProviderList;
  typedef std::map<base::ProcessHandle, ResourceList> GroupMap;
  typedef std::map<base::ProcessHandle, base::ProcessMetrics*> MetricsMap;
  typedef std::map<task_manager::Resource*, int64> ResourceValueMap;
  typedef std::map<task_manager::Resource*,
                   PerResourceValues> PerResourceCache;
  typedef std::map<base::ProcessHandle, PerProcessValues> PerProcessCache;

  // This struct is used to exchange information between the io and ui threads.
  struct BytesReadParam {
    BytesReadParam(int origin_pid,
                   int child_id,
                   int route_id,
                   int byte_count)
        : origin_pid(origin_pid),
          child_id(child_id),
          route_id(route_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 process this request was routed through.
    int child_id;

    int route_id;
    int byte_count;
  };

  ~TaskManagerModel();

  // Callback from the timer to refresh. Invokes Refresh() as appropriate.
  void RefreshCallback();

  void RefreshVideoMemoryUsageStats();

  // 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(task_manager::Resource* resource) const;

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

  void MultipleBytesRead(const std::vector<BytesReadParam>* params);

  // Notifies the UI thread about all the bytes read. Allows for coalescing
  // multiple bytes read into a single task for the UI thread. This is important
  // for when downloading a lot of data on the IO thread, since posting a Task
  // for each one is expensive.
  void NotifyMultipleBytesRead();

  // 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(task_manager::Resource* resource) const;

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

  // Returns the idle wakeups that should be displayed for the passed
  // |resource|.
  int GetIdleWakeupsPerSecond(task_manager::Resource* resource) const;

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

  // Verifies the private and shared memory for |handle| is valid in
  // |per_process_cache_|. Returns true if the data in |per_process_cache_| is
  // valid.
  bool CachePrivateAndSharedMemory(base::ProcessHandle handle) const;

  // Verifies |webcore_stats| in |per_resource_cache_|, returning true on
  // success.
  bool CacheWebCoreStats(int index) const;

  // Verifies |v8_memory_allocated| and |v8_memory_used| in
  // |per_resource_cache_|. Returns true if valid, false if not valid.
  bool CacheV8Memory(int index) const;

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

  // Returns the PerResourceValues for the specified index.
  PerResourceValues& GetPerResourceValues(int index) const;

  // Returns the Resource for the specified index.
  task_manager::Resource* GetResource(int index) const;

  // 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 video memory usage for a process
  content::GPUVideoMemoryUsageStats video_memory_usage_stats_;

  // Set to true when we've requested video stats and false once we get them.
  bool pending_video_memory_usage_stats_update_;

  // An observer waiting for video memory usage stats updates from the GPU
  // process
  scoped_ptr<TaskManagerModelGpuDataManagerObserver>
      video_memory_usage_stats_observer_;

  ObserverList<TaskManagerModelObserver> observer_list_;

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

  // How many calls to StartListening have been made without matching calls to
  // StopListening.
  int listen_requests_;

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

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

  // Buffer for coalescing BytesReadParam so we don't have to post a task on
  // each NotifyBytesRead() call.
  std::vector<BytesReadParam> bytes_read_buffer_;

  std::vector<base::Closure> on_data_ready_callbacks_;

  // All per-Resource values are stored here.
  mutable PerResourceCache per_resource_cache_;

  // All per-Process values are stored here.
  mutable PerProcessCache per_process_cache_;

  DISALLOW_COPY_AND_ASSIGN(TaskManagerModel);
};

#endif  // CHROME_BROWSER_TASK_MANAGER_TASK_MANAGER_H_