chromium/chrome/browser/ash/power/extension_event_observer.h

// Copyright 2015 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CHROME_BROWSER_ASH_POWER_EXTENSION_EVENT_OBSERVER_H_
#define CHROME_BROWSER_ASH_POWER_EXTENSION_EVENT_OBSERVER_H_

#include <stdint.h>

#include <memory>
#include <set>
#include <string>
#include <unordered_map>

#include "base/cancelable_callback.h"
#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_multi_source_observation.h"
#include "base/time/time.h"
#include "base/unguessable_token.h"
#include "chrome/browser/profiles/profile_manager_observer.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "extensions/browser/extension_host_observer.h"
#include "extensions/browser/process_manager.h"
#include "extensions/browser/process_manager_observer.h"

class Profile;

namespace extensions {
class ExtensionHost;
}  // namespace extensions

namespace ash {

// This class listens for extension events that should potentially keep the
// system awake while they are being processed.  Examples include push messages
// that arrive from Google's GCM servers and network requests initiated by
// extensions while processing the push messages.  This class is owned by
// WakeOnWifiManager.
class ExtensionEventObserver : public ProfileManagerObserver,
                               public extensions::ProcessManagerObserver,
                               public extensions::ExtensionHostObserver,
                               public chromeos::PowerManagerClient::Observer {
 public:
  class TestApi {
   public:
    TestApi(const TestApi&) = delete;
    TestApi& operator=(const TestApi&) = delete;

    ~TestApi();

    // Runs |suspend_readiness_callback_| if it is non-null and then resets it.
    // Returns true iff it actually ran the callback.
    bool MaybeRunSuspendReadinessCallback();

    // Returns true if the ExtensionEventObserver will delay suspend attempts
    // for |host| if host has pending push messages or network requests.
    bool WillDelaySuspendForExtensionHost(extensions::ExtensionHost* host);

   private:
    friend class ExtensionEventObserver;

    explicit TestApi(base::WeakPtr<ExtensionEventObserver> parent);

    base::WeakPtr<ExtensionEventObserver> parent_;
  };

  ExtensionEventObserver();

  ExtensionEventObserver(const ExtensionEventObserver&) = delete;
  ExtensionEventObserver& operator=(const ExtensionEventObserver&) = delete;

  ~ExtensionEventObserver() override;

  std::unique_ptr<TestApi> CreateTestApi();

  // Called by the WakeOnWifiManager to control whether the
  // ExtensionEventObserver should or should not delay the system suspend.
  void SetShouldDelaySuspend(bool should_delay);

  // ProfileManagerObserver:
  void OnProfileAdded(Profile* profile) override;

  // extensions::ProcessManagerObserver:
  void OnBackgroundHostCreated(extensions::ExtensionHost* host) override;
  void OnProcessManagerShutdown(extensions::ProcessManager* manager) override;

  // extensions::ExtensionHostObserver:
  void OnExtensionHostDestroyed(extensions::ExtensionHost* host) override;
  void OnBackgroundEventDispatched(const extensions::ExtensionHost* host,
                                   const std::string& event_name,
                                   int event_id) override;
  void OnBackgroundEventAcked(const extensions::ExtensionHost* host,
                              int event_id) override;
  void OnNetworkRequestStarted(const extensions::ExtensionHost* host,
                               uint64_t request_id) override;
  void OnNetworkRequestDone(const extensions::ExtensionHost* host,
                            uint64_t request_id) override;

  // PowerManagerClient::Observer:
  void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
  void DarkSuspendImminent() override;
  void SuspendDone(base::TimeDelta duration) override;

 private:
  friend class TestApi;

  // Called when the system is about to perform a regular suspend or a dark
  // suspend.
  void OnSuspendImminent(bool dark_suspend);

  // Reports readiness to suspend to the PowerManagerClient if a suspend is
  // pending and there are no outstanding events keeping the system awake.
  void MaybeReportSuspendReadiness();

  struct KeepaliveSources;
  std::unordered_map<const extensions::ExtensionHost*,
                     std::unique_ptr<KeepaliveSources>>
      keepalive_sources_;

  base::ScopedMultiSourceObservation<extensions::ProcessManager,
                                     extensions::ProcessManagerObserver>
      process_manager_observers_{this};

  bool should_delay_suspend_ = true;
  int suspend_keepalive_count_ = 0;

  // |this| blocks Power Manager suspend with this token. When the token is
  // empty, |this| isn't blocking suspend.
  base::UnguessableToken block_suspend_token_;

  base::CancelableOnceClosure suspend_readiness_callback_;

  base::WeakPtrFactory<ExtensionEventObserver> weak_factory_{this};
};

}  // namespace ash

#endif  // CHROME_BROWSER_ASH_POWER_EXTENSION_EVENT_OBSERVER_H_