Commit a37cf3b6 authored by Willie Koomson's avatar Willie Koomson Committed by Commit Bot

Add Crostini throttling service

This change adds a throttling service for Crostini, CrostiniThrottle.
This class is a KeyedService that holds observers and throttles the
VM on a change in observer state. Currently the class it is inactive
since it holds no observers and is not instantiated anywhere.

Bug: 997397
Test: Run CrostiniThrottleTest unit test
Change-Id: I344075908abc6c86f311e2c25f5c7ebead25fa42
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1836086
Commit-Queue: Nicholas Verne <nverne@chromium.org>
Reviewed-by: default avatarNicholas Verne <nverne@chromium.org>
Reviewed-by: default avatarYusuke Sato <yusukes@chromium.org>
Reviewed-by: default avatarXiyuan Xia <xiyuan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#703505}
parent 36ced796
......@@ -806,6 +806,8 @@ source_set("chromeos") {
"crostini/crosvm_process_list.h",
"crostini/fake_crostini_installer_ui_delegate.cc",
"crostini/fake_crostini_installer_ui_delegate.h",
"crostini/throttle/crostini_throttle.cc",
"crostini/throttle/crostini_throttle.h",
"cryptauth/client_app_metadata_provider_service.cc",
"cryptauth/client_app_metadata_provider_service.h",
"cryptauth/client_app_metadata_provider_service_factory.cc",
......@@ -2527,6 +2529,7 @@ source_set("unit_tests") {
"crostini/crostini_unsupported_action_notifier_unittest.cc",
"crostini/crosvm_metrics_unittest.cc",
"crostini/crosvm_process_list_unittest.cc",
"crostini/throttle/crostini_throttle_unittest.cc",
"cryptauth/client_app_metadata_provider_service_unittest.cc",
"customization/customization_document_unittest.cc",
"dbus/proxy_resolution_service_provider_unittest.cc",
......
......@@ -59,10 +59,6 @@ class ArcInstanceThrottle : public KeyedService,
delegate_ = std::move(delegate);
}
void set_level_for_testing(chromeos::ThrottleObserver::PriorityLevel level) {
SetLevel(level);
}
private:
// chromeos::ThrottleService:
void ThrottleInstance(
......
// Copyright 2019 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.
#include "chrome/browser/chromeos/crostini/throttle/crostini_throttle.h"
#include "base/no_destructor.h"
#include "chrome/browser/chromeos/concierge_helper_service.h"
#include "chrome/browser/chromeos/crostini/crostini_util.h"
#include "chrome/browser/profiles/profile.h"
#include "components/keyed_service/content/browser_context_dependency_manager.h"
#include "components/keyed_service/content/browser_context_keyed_service_factory.h"
#include "content/public/browser/browser_context.h"
namespace crostini {
namespace {
class DefaultDelegateImpl : public CrostiniThrottle::Delegate {
public:
explicit DefaultDelegateImpl(content::BrowserContext* context)
: context_(context) {}
~DefaultDelegateImpl() override = default;
void SetCpuRestriction(bool do_restrict) override {
chromeos::ConciergeHelperService::GetForBrowserContext(context_)
->SetTerminaVmCpuRestriction(do_restrict);
}
private:
content::BrowserContext* context_;
DISALLOW_COPY_AND_ASSIGN(DefaultDelegateImpl);
};
class CrostiniThrottleFactory : public BrowserContextKeyedServiceFactory {
public:
static CrostiniThrottleFactory* GetInstance() {
static base::NoDestructor<CrostiniThrottleFactory> instance;
return instance.get();
}
static CrostiniThrottle* GetForBrowserContext(
content::BrowserContext* context) {
return static_cast<CrostiniThrottle*>(
CrostiniThrottleFactory::GetInstance()->GetServiceForBrowserContext(
context, true /* create */));
}
private:
friend class base::NoDestructor<CrostiniThrottleFactory>;
CrostiniThrottleFactory()
: BrowserContextKeyedServiceFactory(
"CrostiniThrottleFactory",
BrowserContextDependencyManager::GetInstance()) {}
~CrostiniThrottleFactory() override = default;
// BrowserContextKeyedServiceFactory:
KeyedService* BuildServiceInstanceFor(
content::BrowserContext* context) const override {
if (context->IsOffTheRecord())
return nullptr;
return new CrostiniThrottle(context);
}
DISALLOW_COPY_AND_ASSIGN(CrostiniThrottleFactory);
};
} // namespace
// static
CrostiniThrottle* CrostiniThrottle::GetForBrowserContext(
content::BrowserContext* context) {
return CrostiniThrottleFactory::GetForBrowserContext(context);
}
CrostiniThrottle::CrostiniThrottle(content::BrowserContext* context)
: ThrottleService(context),
delegate_(std::make_unique<DefaultDelegateImpl>(context)) {
StartObservers();
}
CrostiniThrottle::~CrostiniThrottle() = default;
void CrostiniThrottle::Shutdown() {
StopObservers();
}
void CrostiniThrottle::ThrottleInstance(
chromeos::ThrottleObserver::PriorityLevel level) {
switch (level) {
case chromeos::ThrottleObserver::PriorityLevel::CRITICAL:
case chromeos::ThrottleObserver::PriorityLevel::IMPORTANT:
case chromeos::ThrottleObserver::PriorityLevel::NORMAL:
delegate_->SetCpuRestriction(false);
break;
case chromeos::ThrottleObserver::PriorityLevel::LOW:
case chromeos::ThrottleObserver::PriorityLevel::UNKNOWN:
delegate_->SetCpuRestriction(true);
break;
}
}
} // namespace crostini
// Copyright 2019 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_CHROMEOS_CROSTINI_THROTTLE_CROSTINI_THROTTLE_H_
#define CHROME_BROWSER_CHROMEOS_CROSTINI_THROTTLE_CROSTINI_THROTTLE_H_
#include <memory>
#include <string>
#include <utility>
#include "base/macros.h"
#include "chrome/browser/chromeos/throttle_service.h"
#include "components/keyed_service/core/keyed_service.h"
namespace content {
class BrowserContext;
}
namespace crostini {
// This class holds a number observers which watch for conditions and adjust the
// throttle state of the Crostini VM on a change in conditions.
class CrostiniThrottle : public KeyedService, public chromeos::ThrottleService {
public:
class Delegate {
public:
Delegate() = default;
virtual ~Delegate() = default;
virtual void SetCpuRestriction(bool) = 0;
private:
DISALLOW_COPY_AND_ASSIGN(Delegate);
};
// Returns singleton instance for the given BrowserContext, or nullptr if
// the browser |context| is not allowed to use Crostini.
static CrostiniThrottle* GetForBrowserContext(
content::BrowserContext* context);
explicit CrostiniThrottle(content::BrowserContext* context);
~CrostiniThrottle() override;
// KeyedService:
void Shutdown() override;
void set_delegate_for_testing(std::unique_ptr<Delegate> delegate) {
delegate_ = std::move(delegate);
}
private:
// chromeos::ThrottleService:
void ThrottleInstance(
chromeos::ThrottleObserver::PriorityLevel level) override;
void RecordCpuRestrictionDisabledUMA(const std::string& observer_name,
base::TimeDelta delta) override {}
std::unique_ptr<Delegate> delegate_;
DISALLOW_COPY_AND_ASSIGN(CrostiniThrottle);
};
} // namespace crostini
#endif // CHROME_BROWSER_CHROMEOS_CROSTINI_THROTTLE_CROSTINI_THROTTLE_H_
// Copyright 2019 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.
#include "chrome/browser/chromeos/crostini/throttle/crostini_throttle.h"
#include <memory>
#include "base/macros.h"
#include "chrome/browser/chromeos/crostini/crostini_test_helper.h"
#include "chrome/test/base/testing_profile.h"
#include "chromeos/dbus/dbus_thread_manager.h"
#include "content/public/test/browser_task_environment.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace crostini {
class CrostiniThrottleTest : public testing::Test {
public:
CrostiniThrottleTest()
: crostini_helper_(&profile_), crostini_throttle_(&profile_) {
crostini_throttle_.set_delegate_for_testing(
std::make_unique<TestDelegateImpl>(this));
}
protected:
CrostiniThrottle* crostini_throttle() { return &crostini_throttle_; }
size_t disable_cpu_restriction_counter() const {
return disable_cpu_restriction_counter_;
}
size_t enable_cpu_restriction_counter() const {
return enable_cpu_restriction_counter_;
}
private:
class TestDelegateImpl : public CrostiniThrottle::Delegate {
public:
explicit TestDelegateImpl(CrostiniThrottleTest* test) : test_(test) {}
~TestDelegateImpl() override = default;
void SetCpuRestriction(bool restrict) override {
if (restrict)
++(test_->enable_cpu_restriction_counter_);
else
++(test_->disable_cpu_restriction_counter_);
}
CrostiniThrottleTest* test_;
DISALLOW_COPY_AND_ASSIGN(TestDelegateImpl);
};
content::BrowserTaskEnvironment task_environment_;
TestingProfile profile_;
CrostiniTestHelper crostini_helper_;
CrostiniThrottle crostini_throttle_;
size_t disable_cpu_restriction_counter_{0};
size_t enable_cpu_restriction_counter_{0};
DISALLOW_COPY_AND_ASSIGN(CrostiniThrottleTest);
};
// Tests that CrostiniThrottle can be constructed and destructed.
TEST_F(CrostiniThrottleTest, TestConstructDestruct) {}
// Tests that CrostiniThrottle adjusts CPU restriction
// when ThrottleInstance is called.
TEST_F(CrostiniThrottleTest, TestThrottleInstance) {
crostini_throttle()->set_level_for_testing(
chromeos::ThrottleObserver::PriorityLevel::LOW);
EXPECT_EQ(1U, enable_cpu_restriction_counter());
EXPECT_EQ(0U, disable_cpu_restriction_counter());
// CrostiniThrottle level is already LOW, expect no change
crostini_throttle()->set_level_for_testing(
chromeos::ThrottleObserver::PriorityLevel::LOW);
EXPECT_EQ(1U, enable_cpu_restriction_counter());
EXPECT_EQ(0U, disable_cpu_restriction_counter());
crostini_throttle()->set_level_for_testing(
chromeos::ThrottleObserver::PriorityLevel::CRITICAL);
EXPECT_EQ(1U, enable_cpu_restriction_counter());
EXPECT_EQ(1U, disable_cpu_restriction_counter());
crostini_throttle()->set_level_for_testing(
chromeos::ThrottleObserver::PriorityLevel::LOW);
EXPECT_EQ(2U, enable_cpu_restriction_counter());
EXPECT_EQ(1U, disable_cpu_restriction_counter());
}
} // namespace crostini
......@@ -26,6 +26,11 @@ void ThrottleService::SetObserversForTesting(
StartObservers();
}
void ThrottleService::set_level_for_testing(
ThrottleObserver::PriorityLevel level) {
SetLevel(level);
}
void ThrottleService::AddObserver(std::unique_ptr<ThrottleObserver> observer) {
observers_.push_back(std::move(observer));
}
......
......@@ -33,6 +33,7 @@ class ThrottleService {
void NotifyObserverStateChangedForTesting();
void SetObserversForTesting(
std::vector<std::unique_ptr<ThrottleObserver>> observers);
void set_level_for_testing(ThrottleObserver::PriorityLevel level);
protected:
void AddObserver(std::unique_ptr<ThrottleObserver> observer);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment