chromium/ash/components/arc/power/arc_power_bridge.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 ASH_COMPONENTS_ARC_POWER_ARC_POWER_BRIDGE_H_
#define ASH_COMPONENTS_ARC_POWER_ARC_POWER_BRIDGE_H_

#include <map>
#include <memory>
#include <optional>
#include <string>

#include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "ash/components/arc/mojom/anr.mojom.h"
#include "ash/components/arc/mojom/power.mojom.h"
#include "ash/components/arc/session/arc_service_manager.h"
#include "ash/components/arc/session/connection_observer.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/singleton.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "base/timer/timer.h"
#include "chromeos/ash/components/dbus/concierge/concierge_client.h"
#include "chromeos/dbus/power/power_manager_client.h"
#include "components/keyed_service/core/keyed_service.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "services/device/public/mojom/wake_lock.mojom.h"
#include "services/device/public/mojom/wake_lock_provider.mojom.h"
#include "ui/display/manager/display_configurator.h"

namespace content {
class BrowserContext;
}  // namespace content

namespace arc {

class ArcBridgeService;
class ArcPowerBridge;  // So we can declare the factory first.

// Singleton factory for ArcPowerBridge.
class ArcPowerBridgeFactory
    : public internal::ArcBrowserContextKeyedServiceFactoryBase<
          ArcPowerBridge,
          ArcPowerBridgeFactory> {
 public:
  // Factory name used by ArcBrowserContextKeyedServiceFactoryBase.
  static constexpr const char* kName = "ArcPowerBridgeFactory";

  static ArcPowerBridgeFactory* GetInstance();

 private:
  friend base::DefaultSingletonTraits<ArcPowerBridgeFactory>;
  ArcPowerBridgeFactory() = default;
  ~ArcPowerBridgeFactory() override = default;
};

// ARC Power Client sets power management policy based on requests from
// ARC instances.
class ArcPowerBridge : public KeyedService,
                       public ConnectionObserver<mojom::PowerInstance>,
                       public chromeos::PowerManagerClient::Observer,
                       public display::DisplayConfigurator::Observer,
                       public mojom::PowerHost {
 public:
  class Observer : public base::CheckedObserver {
   public:
    // Notifies that wakefulness mode is changed.
    virtual void OnWakefulnessChanged(mojom::WakefulnessMode mode) {}
    virtual void OnPreAnr(mojom::AnrType type) {}

    // Notifies about resume state of the underlying VM (ARCVM-exclusive).
    // ARC Container does not communicate with CrosVM, and it doesn't
    // instantiate services that care about this event.
    virtual void OnVmResumed() {}

    virtual void OnWillDestroyArcPowerBridge() {}
  };

  // Returns singleton instance for the given BrowserContext,
  // or nullptr if the browser |context| is not allowed to use ARC.
  static ArcPowerBridge* GetForBrowserContext(content::BrowserContext* context);
  static ArcPowerBridge* GetForBrowserContextForTesting(
      content::BrowserContext* context);

  ArcPowerBridge(content::BrowserContext* context,
                 ArcBridgeService* bridge_service);

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

  ~ArcPowerBridge() override;

  // Disables Android Idle Control logic locally.
  // This is necessary because we are in the process of moving this control
  // to a different class, and need to accommodate both cases.
  // TODO(b/259622742): remove this once the new control is default.
  void DisableAndroidIdleControl();

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

  void SetUserIdHash(const std::string& user_id_hash);

  // If |notify_brightness_timer_| is set, runs it and returns true. Returns
  // false otherwise.
  [[nodiscard]] bool TriggerNotifyBrightnessTimerForTesting();

  // Runs the message loop until replies have been received for all pending
  // device service requests in |wake_lock_requestors_|.
  void FlushWakeLocksForTesting();

  // ConnectionObserver<mojom::PowerInstance> overrides.
  void OnConnectionReady() override;
  void OnConnectionClosed() override;

  // chromeos::PowerManagerClient::Observer overrides.
  void SuspendImminent(power_manager::SuspendImminent::Reason reason) override;
  void SuspendDone(base::TimeDelta sleep_duration) override;
  void ScreenBrightnessChanged(
      const power_manager::BacklightBrightnessChange& change) override;
  void PowerChanged(const power_manager::PowerSupplyProperties& proto) override;
  void BatterySaverModeStateChanged(
      const power_manager::BatterySaverModeState& state) override;

  // DisplayConfigurator::Observer overrides.
  void OnPowerStateChanged(chromeos::DisplayPowerState power_state) override;

  // mojom::PowerHost overrides.
  void OnAcquireDisplayWakeLock(mojom::DisplayWakeLockType type) override;
  void OnReleaseDisplayWakeLock(mojom::DisplayWakeLockType type) override;
  void IsDisplayOn(IsDisplayOnCallback callback) override;
  void OnScreenBrightnessUpdateRequest(double percent) override;
  void OnWakefulnessChanged(mojom::WakefulnessMode mode) override;
  void OnPreAnr(mojom::AnrType type) override;
  void OnAnrRecoveryFailed(::arc::mojom::AnrType type) override;
  void GetBatterySaverModeState(
      GetBatterySaverModeStateCallback callback) override;

  void SetWakeLockProviderForTesting(
      mojo::Remote<device::mojom::WakeLockProvider> provider) {
    wake_lock_provider_ = std::move(provider);
  }

  static void EnsureFactoryBuilt();

  // Notify ARC and patchpanel about change in power state, notification to
  // patchpanel is used to decide whether to start/stop forwarding multicast
  // traffic to ARC.
  void NotifyAndroidIdleState(ArcBridgeService* bridge,
                              ::arc::mojom::IdleState enabled);

 private:
  class WakeLockRequestor;

  // Returns the WakeLockRequestor for |type|, creating one if needed.
  WakeLockRequestor* GetWakeLockRequestor(device::mojom::WakeLockType type);

  // Called on PowerManagerClient::GetScreenBrightnessPercent() completion.
  void OnGetScreenBrightnessPercent(std::optional<double> percent);

  // Called by Android when ready to suspend.
  void OnAndroidSuspendReady(base::UnguessableToken token);

  // Called by ConciergeClient when a response has been receive for the
  // SuspendVm D-Bus call.
  void OnConciergeSuspendVmResponse(
      base::UnguessableToken token,
      std::optional<vm_tools::concierge::SuspendVmResponse> reply);

  // Called by ConciergeClient when a response has been receive for the
  // ResumeVm D-Bus call.
  void OnConciergeResumeVmResponse(
      std::optional<vm_tools::concierge::ResumeVmResponse> reply);

  // Called on PowerManagerClient::GetBatterySaverModeState() completion.
  void OnBatterySaverModeStateReceived(
      GetBatterySaverModeStateCallback callback,
      std::optional<power_manager::BatterySaverModeState> state);

  // Sends a PowerInstance::UpdateScreenBrightnessSettings mojo call to Android.
  void UpdateAndroidScreenBrightness(double percent);

  // Sends a PowerInstance::Resume mojo call to Android.
  void DispatchAndroidResume();

  const raw_ptr<ArcBridgeService>
      arc_bridge_service_;  // Owned by ArcServiceManager.

  std::string user_id_hash_;

  mojo::Remote<device::mojom::WakeLockProvider> wake_lock_provider_;

  // Used to track Android wake lock requests and acquire and release device
  // service wake locks as needed.
  std::map<device::mojom::WakeLockType, std::unique_ptr<WakeLockRequestor>>
      wake_lock_requestors_;

  // Last time that the power manager notified about a brightness change.
  base::TimeTicks last_brightness_changed_time_;
  // Timer used to run UpdateAndroidScreenBrightness() to notify Android
  // about brightness changes.
  base::OneShotTimer notify_brightness_timer_;

  // List of observers.
  base::ObserverList<Observer> observer_list_;

  // Represents whether a device suspend is currently underway, ie. a
  // SuspendImminent event has been observed, but a SuspendDone event has not
  // yet been observed.
  bool is_suspending_ = false;

  // Controls whether or not we switch Android's idle state upon events.
  bool android_idle_control_disabled_ = false;

  base::WeakPtrFactory<ArcPowerBridge> weak_ptr_factory_{this};
};

}  // namespace arc

#endif  // ASH_COMPONENTS_ARC_POWER_ARC_POWER_BRIDGE_H_