blob: 8beda8aad21fa35b03128218c863c0e9239f57ce [file] [log] [blame]
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "chrome/browser/ash/arc/idle_manager/arc_idle_manager.h"
#include "ash/components/arc/arc_browser_context_keyed_service_factory_base.h"
#include "ash/components/arc/arc_features.h"
#include "ash/components/arc/mojom/power.mojom.h"
#include "ash/components/arc/power/arc_power_bridge.h"
#include "ash/components/arc/session/arc_bridge_service.h"
#include "base/logging.h"
#include "chrome/browser/ash/arc/idle_manager/arc_background_service_observer.h"
#include "chrome/browser/ash/arc/idle_manager/arc_cpu_throttle_observer.h"
#include "chrome/browser/ash/arc/idle_manager/arc_display_power_observer.h"
#include "chrome/browser/ash/arc/idle_manager/arc_on_battery_observer.h"
#include "chrome/browser/ash/arc/idle_manager/arc_window_observer.h"
namespace arc {
namespace {
class DefaultDelegateImpl : public ArcIdleManager::Delegate {
public:
DefaultDelegateImpl() = default;
DefaultDelegateImpl(const DefaultDelegateImpl&) = delete;
DefaultDelegateImpl& operator=(const DefaultDelegateImpl&) = delete;
~DefaultDelegateImpl() override = default;
// ArcIdleManager::Delegate:
void SetInteractiveMode(ArcBridgeService* bridge, bool enable) override {
auto* const power =
ARC_GET_INSTANCE_FOR_METHOD(bridge->power(), SetInteractive);
if (!power)
return;
// When enable=false,
// the code below is equivalent to pressing the power button on
// a smartphone, which turns its screen off and kicks off a gradual
// power state transition, ultimately leading to doze mode.
power->SetInteractive(enable);
}
};
// Singleton factory for ArcIdleManager.
class ArcIdleManagerFactory
: public internal::ArcBrowserContextKeyedServiceFactoryBase<
ArcIdleManager,
ArcIdleManagerFactory> {
public:
static constexpr const char* kName = "ArcIdleManagerFactory";
static ArcIdleManagerFactory* GetInstance() {
static base::NoDestructor<ArcIdleManagerFactory> instance;
return instance.get();
}
private:
friend class base::NoDestructor<ArcIdleManagerFactory>;
ArcIdleManagerFactory() = default;
~ArcIdleManagerFactory() override = default;
};
} // namespace
// static
ArcIdleManager* ArcIdleManager::GetForBrowserContext(
content::BrowserContext* context) {
return ArcIdleManagerFactory::GetForBrowserContext(context);
}
// static
ArcIdleManager* ArcIdleManager::GetForBrowserContextForTesting(
content::BrowserContext* context) {
return ArcIdleManagerFactory::GetForBrowserContextForTesting(context);
}
ArcIdleManager::ArcIdleManager(content::BrowserContext* context,
ArcBridgeService* bridge)
: ThrottleService(context),
delegate_(std::make_unique<DefaultDelegateImpl>()),
bridge_(bridge) {
AddObserver(std::make_unique<ArcCpuThrottleObserver>());
AddObserver(std::make_unique<ArcBackgroundServiceObserver>());
AddObserver(std::make_unique<ArcWindowObserver>());
if (kEnableArcIdleManagerIgnoreBatteryForPLT.Get()) {
LOG(WARNING) << "Doze will be enabled regardless of battery status";
} else {
AddObserver(std::make_unique<ArcOnBatteryObserver>());
}
AddObserver(std::make_unique<ArcDisplayPowerObserver>());
auto* const power_bridge = ArcPowerBridge::GetForBrowserContext(context);
// This may be null in unit tests.
if (power_bridge)
power_bridge->DisableAndroidIdleControl();
DCHECK(bridge_);
bridge_->power()->AddObserver(this);
DETACH_FROM_SEQUENCE(sequence_checker_);
}
// Destructor is empty because this is a KeyedService, which must
// cleanup in Shutdown();
ArcIdleManager::~ArcIdleManager() = default;
void ArcIdleManager::Shutdown() {
// After this is done, we will no longer get connection notifications.
bridge_->power()->RemoveObserver(this);
// Safeguard against resource leak by observers.
OnConnectionClosed();
}
void ArcIdleManager::OnConnectionReady() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (is_connected_)
return;
StartObservers();
delegate_->SetInteractiveMode(bridge_, !should_throttle());
is_connected_ = true;
}
void ArcIdleManager::OnConnectionClosed() {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (!is_connected_)
return;
StopObservers();
is_connected_ = false;
}
void ArcIdleManager::ThrottleInstance(bool should_throttle) {
delegate_->SetInteractiveMode(bridge_, !should_throttle);
}
} // namespace arc