Skip to content

Commit

Permalink
[freezing] Track Hid and Serial port connections in Performance Manager.
Browse files Browse the repository at this point in the history
This is needed to implement a freezing opt-out as described at
go/tab-freezing-on-energy-saver-prd.


Implementation details:

- WebContentsObserver::OnIsConnectedToUsbDeviceChanged() and
  WebContentsObserver::OnIsConnectedToBluetoothDeviceChanged() are
  replaced with
  WebContentsObserver::OnDeviceConnectionTypesChanged(), which is
  invoked when the connection types used by a WebContents change
  (USB, Bluetooth, HID and serial). This avoids an explosion of the
  number of observer methods as more device connection types need
  to be tracked by performance policies.

- Hid Device and Serial Port usage are tracked in
  PageLiveStateDecorator, alongside USB Device and Bluetooth device
  usage.

- In a separate CL, we'll use the new properties as Page Freezing
  opt-outs.

Bug: 325954772
Change-Id: I5d9df041f7cb45309f3eb69cb9b6ad59f35d64b7
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/5847688
Reviewed-by: Matt Reynolds <[email protected]>
Reviewed-by: Patrick Monette <[email protected]>
Commit-Queue: Francois Pierre Doray <[email protected]>
Reviewed-by: Avi Drissman <[email protected]>
Cr-Commit-Position: refs/heads/main@{#1356468}
  • Loading branch information
fdoray authored and Chromium LUCI CQ committed Sep 17, 2024
1 parent 4c8e831 commit e753bf9
Show file tree
Hide file tree
Showing 15 changed files with 388 additions and 137 deletions.
50 changes: 24 additions & 26 deletions chrome/browser/bluetooth/web_bluetooth_browsertest.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1059,40 +1059,38 @@ class TestWebContentsObserver : public content::WebContentsObserver {
TestWebContentsObserver& operator=(const TestWebContentsObserver&) = delete;
~TestWebContentsObserver() override = default;

void OnIsConnectedToBluetoothDeviceChanged(
bool is_connected_to_bluetooth_device) override {
++num_is_connected_to_bluetooth_device_changed_;
last_is_connected_to_bluetooth_device_ = is_connected_to_bluetooth_device;
if (quit_closure_ && expected_updating_count_ ==
num_is_connected_to_bluetooth_device_changed_) {
void OnDeviceConnectionTypesChanged(DeviceConnectionType connection_type,
bool used) override {
EXPECT_EQ(connection_type, DeviceConnectionType::kBluetooth);
++num_device_connection_types_changed_;
last_device_used_ = used;
if (quit_closure_ &&
expected_updating_count_ == num_device_connection_types_changed_) {
std::move(quit_closure_).Run();
}
}

int num_is_connected_to_bluetooth_device_changed() {
return num_is_connected_to_bluetooth_device_changed_;
int num_device_connection_types_changed() {
return num_device_connection_types_changed_;
}

const std::optional<bool>& last_is_connected_to_bluetooth_device() {
return last_is_connected_to_bluetooth_device_;
}
const std::optional<bool>& last_device_used() { return last_device_used_; }

void clear_last_is_connected_to_bluetooth_device() {
last_is_connected_to_bluetooth_device_.reset();
}
void clear_last_device_used() { last_device_used_.reset(); }

void WaitUntilConnectionIsUpdated(int expected_count) {
if (num_is_connected_to_bluetooth_device_changed_ == expected_count)
if (num_device_connection_types_changed_ == expected_count) {
return;
}
expected_updating_count_ = expected_count;
base::RunLoop run_loop;
quit_closure_ = run_loop.QuitClosure();
run_loop.Run();
}

private:
int num_is_connected_to_bluetooth_device_changed_ = 0;
std::optional<bool> last_is_connected_to_bluetooth_device_;
int num_device_connection_types_changed_ = 0;
std::optional<bool> last_device_used_;
int expected_updating_count_;
base::OnceClosure quit_closure_;
};
Expand Down Expand Up @@ -1120,10 +1118,10 @@ IN_PROC_BROWSER_TEST_F(

observer.WaitUntilConnectionIsUpdated(1);
// In the active main frame, the connection of Web Bluetooth works.
EXPECT_EQ(observer.num_is_connected_to_bluetooth_device_changed(), 1);
EXPECT_TRUE(observer.last_is_connected_to_bluetooth_device().has_value());
EXPECT_TRUE(observer.last_is_connected_to_bluetooth_device().value());
observer.clear_last_is_connected_to_bluetooth_device();
EXPECT_EQ(observer.num_device_connection_types_changed(), 1);
EXPECT_TRUE(observer.last_device_used().has_value());
EXPECT_TRUE(observer.last_device_used().value());
observer.clear_last_device_used();

// Loads a page in the prerender.
auto prerender_url = embedded_test_server()->GetURL("/simple.html");
Expand All @@ -1146,8 +1144,8 @@ IN_PROC_BROWSER_TEST_F(

// In the prerendering, the connection of Web Bluetooth is deferred and
// `observer` doesn't have any update.
EXPECT_EQ(observer.num_is_connected_to_bluetooth_device_changed(), 1);
EXPECT_FALSE(observer.last_is_connected_to_bluetooth_device().has_value());
EXPECT_EQ(observer.num_device_connection_types_changed(), 1);
EXPECT_FALSE(observer.last_device_used().has_value());

content::RenderFrameDeletedObserver rfh_observer(
GetWebContents()->GetPrimaryMainFrame());
Expand All @@ -1163,9 +1161,9 @@ IN_PROC_BROWSER_TEST_F(
// During prerendering activation, the connection from the previous
// RenderFrameHost to Web Bluetooth is closed, while the connection attempt
// from the prerendering RenderFrameHost was refused.
EXPECT_EQ(observer.num_is_connected_to_bluetooth_device_changed(), 2);
EXPECT_TRUE(observer.last_is_connected_to_bluetooth_device().has_value());
EXPECT_FALSE(observer.last_is_connected_to_bluetooth_device().value());
EXPECT_EQ(observer.num_device_connection_types_changed(), 2);
EXPECT_TRUE(observer.last_device_used().has_value());
EXPECT_FALSE(observer.last_device_used().value());
}

} // namespace
Original file line number Diff line number Diff line change
Expand Up @@ -121,18 +121,11 @@ class PageLiveStateDecoratorHelper::WebContentsObserver
}

// content::WebContentsObserver:
void OnIsConnectedToBluetoothDeviceChanged(
bool is_connected_to_bluetooth_device) override {
void OnDeviceConnectionTypesChanged(DeviceConnectionType connection_type,
bool used) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PageLiveStateDecorator::OnIsConnectedToBluetoothDeviceChanged(
web_contents(), is_connected_to_bluetooth_device);
}

void OnIsConnectedToUsbDeviceChanged(
bool is_connected_to_usb_device) override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
PageLiveStateDecorator::OnIsConnectedToUSBDeviceChanged(
web_contents(), is_connected_to_usb_device);
PageLiveStateDecorator::OnDeviceConnectionTypesChanged(
web_contents(), connection_type, used);
}

void WebContentsDestroyed() override {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@ class FrameVisibilityDecorator : public GraphOwnedDefaultImpl,
void OnIsConnectedToUSBDeviceChanged(const PageNode* page_node) override {}
void OnIsConnectedToBluetoothDeviceChanged(
const PageNode* page_node) override {}
void OnIsConnectedToHidDeviceChanged(const PageNode* page_node) override {}
void OnIsConnectedToSerialPortChanged(const PageNode* page_node) override {}
void OnIsCapturingVideoChanged(const PageNode* page_node) override {}
void OnIsCapturingAudioChanged(const PageNode* page_node) override {}
void OnIsCapturingWindowChanged(const PageNode* page_node) override {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,14 @@ class PageLiveStateDataImpl
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return is_connected_to_bluetooth_device_;
}
bool IsConnectedToHidDevice() const override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return is_connected_to_hid_device_;
}
bool IsConnectedToSerialPort() const override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return is_connected_to_serial_port_;
}
bool IsCapturingVideo() const override {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
return is_capturing_video_;
Expand Down Expand Up @@ -154,6 +162,26 @@ class PageLiveStateDataImpl
for (auto& obs : observers_)
obs.OnIsConnectedToBluetoothDeviceChanged(page_node_);
}
void set_is_connected_to_hid_device(bool is_connected_to_hid_device) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (is_connected_to_hid_device_ == is_connected_to_hid_device) {
return;
}
is_connected_to_hid_device_ = is_connected_to_hid_device;
for (auto& obs : observers_) {
obs.OnIsConnectedToHidDeviceChanged(page_node_);
}
}
void set_is_connected_to_serial_port(bool is_connected_to_serial_port) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (is_connected_to_serial_port_ == is_connected_to_serial_port) {
return;
}
is_connected_to_serial_port_ = is_connected_to_serial_port;
for (auto& obs : observers_) {
obs.OnIsConnectedToSerialPortChanged(page_node_);
}
}
void set_is_capturing_video(bool is_capturing_video) {
DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
if (is_capturing_video_ == is_capturing_video)
Expand Down Expand Up @@ -258,6 +286,10 @@ class PageLiveStateDataImpl
false;
bool is_connected_to_bluetooth_device_ GUARDED_BY_CONTEXT(sequence_checker_) =
false;
bool is_connected_to_hid_device_ GUARDED_BY_CONTEXT(sequence_checker_) =
false;
bool is_connected_to_serial_port_ GUARDED_BY_CONTEXT(sequence_checker_) =
false;
bool is_capturing_video_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
bool is_capturing_audio_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
bool is_being_mirrored_ GUARDED_BY_CONTEXT(sequence_checker_) = false;
Expand All @@ -283,21 +315,34 @@ PageLiveStateDecorator::PageLiveStateDecorator() = default;
PageLiveStateDecorator::~PageLiveStateDecorator() = default;

// static
void PageLiveStateDecorator::OnIsConnectedToUSBDeviceChanged(
content::WebContents* contents,
bool is_connected_to_usb_device) {
SetPropertyForWebContentsPageNode(
contents, &PageLiveStateDataImpl::set_is_connected_to_usb_device,
is_connected_to_usb_device);
}

// static
void PageLiveStateDecorator::OnIsConnectedToBluetoothDeviceChanged(
void PageLiveStateDecorator::OnDeviceConnectionTypesChanged(
content::WebContents* contents,
bool is_connected_to_bluetooth_device) {
SetPropertyForWebContentsPageNode(
contents, &PageLiveStateDataImpl::set_is_connected_to_bluetooth_device,
is_connected_to_bluetooth_device);
content::WebContentsObserver::DeviceConnectionType connection_type,
bool used) {
DCHECK_CURRENTLY_ON(content::BrowserThread::UI);

switch (connection_type) {
case content::WebContentsObserver::DeviceConnectionType::kUSB:
SetPropertyForWebContentsPageNode(
contents, &PageLiveStateDataImpl::set_is_connected_to_usb_device,
used);
break;
case content::WebContentsObserver::DeviceConnectionType::kBluetooth:
SetPropertyForWebContentsPageNode(
contents,
&PageLiveStateDataImpl::set_is_connected_to_bluetooth_device, used);
break;
case content::WebContentsObserver::DeviceConnectionType::kHID:
SetPropertyForWebContentsPageNode(
contents, &PageLiveStateDataImpl::set_is_connected_to_hid_device,
used);
break;
case content::WebContentsObserver::DeviceConnectionType::kSerial:
SetPropertyForWebContentsPageNode(
contents, &PageLiveStateDataImpl::set_is_connected_to_serial_port,
used);
break;
}
}

// static
Expand Down Expand Up @@ -412,6 +457,8 @@ base::Value::Dict PageLiveStateDecorator::DescribePageNodeData(
base::Value::Dict ret;
ret.Set("IsConnectedToUSBDevice", data->IsConnectedToUSBDevice());
ret.Set("IsConnectedToBluetoothDevice", data->IsConnectedToBluetoothDevice());
ret.Set("IsConnectedToHidDevice", data->IsConnectedToHidDevice());
ret.Set("IsConnectedToSerialPort", data->IsConnectedToSerialPort());
ret.Set("IsCapturingVideo", data->IsCapturingVideo());
ret.Set("IsCapturingAudio", data->IsCapturingAudio());
ret.Set("IsBeingMirrored", data->IsBeingMirrored());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "content/public/browser/browser_task_traits.h"
#include "content/public/browser/browser_thread.h"
#include "content/public/browser/web_contents.h"
#include "content/public/browser/web_contents_observer.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/accessibility/ax_mode.h"

Expand All @@ -45,6 +46,8 @@ class TestPageLiveStateObserver : public PageLiveStateObserver {
kNone,
kOnIsConnectedToUSBDeviceChanged,
kOnIsConnectedToBluetoothDeviceChanged,
kOnIsConnectedToHidDeviceChanged,
kOnIsConnectedToSerialPortChanged,
kOnIsCapturingVideoChanged,
kOnIsCapturingAudioChanged,
kOnIsBeingMirroredChanged,
Expand All @@ -69,6 +72,16 @@ class TestPageLiveStateObserver : public PageLiveStateObserver {
ObserverFunction::kOnIsConnectedToBluetoothDeviceChanged;
page_node_passed_ = page_node;
}
void OnIsConnectedToHidDeviceChanged(const PageNode* page_node) override {
latest_function_called_ =
ObserverFunction::kOnIsConnectedToHidDeviceChanged;
page_node_passed_ = page_node;
}
void OnIsConnectedToSerialPortChanged(const PageNode* page_node) override {
latest_function_called_ =
ObserverFunction::kOnIsConnectedToSerialPortChanged;
page_node_passed_ = page_node;
}
void OnIsCapturingVideoChanged(const PageNode* page_node) override {
latest_function_called_ = ObserverFunction::kOnIsCapturingVideoChanged;
page_node_passed_ = page_node;
Expand Down Expand Up @@ -213,26 +226,62 @@ class PageLiveStateDecoratorTest : public PerformanceManagerTestHarness {
std::unique_ptr<TestPageLiveStateObserver> observer_;
};

TEST_F(PageLiveStateDecoratorTest, OnIsConnectedToUSBDeviceChanged) {
TEST_F(PageLiveStateDecoratorTest, Usb) {
auto setter = [](content::WebContents* contents, bool value) {
PageLiveStateDecorator::OnDeviceConnectionTypesChanged(
contents, content::WebContentsObserver::DeviceConnectionType::kUSB,
value);
};
testing::EndToEndBooleanPropertyTest(
web_contents(), &PageLiveStateDecorator::Data::GetOrCreateForPageNode,
&PageLiveStateDecorator::Data::IsConnectedToUSBDevice,
&PageLiveStateDecorator::OnIsConnectedToUSBDeviceChanged);
&PageLiveStateDecorator::Data::IsConnectedToUSBDevice, setter);
VerifyObserverExpectationOnPMSequence(
TestPageLiveStateObserver::ObserverFunction::
kOnIsConnectedToUSBDeviceChanged);
}

TEST_F(PageLiveStateDecoratorTest, OnIsConnectedToBluetoothDeviceChanged) {
TEST_F(PageLiveStateDecoratorTest, Bluetooth) {
auto setter = [](content::WebContents* contents, bool value) {
PageLiveStateDecorator::OnDeviceConnectionTypesChanged(
contents,
content::WebContentsObserver::DeviceConnectionType::kBluetooth, value);
};
testing::EndToEndBooleanPropertyTest(
web_contents(), &PageLiveStateDecorator::Data::GetOrCreateForPageNode,
&PageLiveStateDecorator::Data::IsConnectedToBluetoothDevice,
&PageLiveStateDecorator::OnIsConnectedToBluetoothDeviceChanged);
&PageLiveStateDecorator::Data::IsConnectedToBluetoothDevice, setter);
VerifyObserverExpectationOnPMSequence(
TestPageLiveStateObserver::ObserverFunction::
kOnIsConnectedToBluetoothDeviceChanged);
}

TEST_F(PageLiveStateDecoratorTest, Hid) {
auto setter = [](content::WebContents* contents, bool value) {
PageLiveStateDecorator::OnDeviceConnectionTypesChanged(
contents, content::WebContentsObserver::DeviceConnectionType::kHID,
value);
};
testing::EndToEndBooleanPropertyTest(
web_contents(), &PageLiveStateDecorator::Data::GetOrCreateForPageNode,
&PageLiveStateDecorator::Data::IsConnectedToHidDevice, setter);
VerifyObserverExpectationOnPMSequence(
TestPageLiveStateObserver::ObserverFunction::
kOnIsConnectedToHidDeviceChanged);
}

TEST_F(PageLiveStateDecoratorTest, Serial) {
auto setter = [](content::WebContents* contents, bool value) {
PageLiveStateDecorator::OnDeviceConnectionTypesChanged(
contents, content::WebContentsObserver::DeviceConnectionType::kSerial,
value);
};
testing::EndToEndBooleanPropertyTest(
web_contents(), &PageLiveStateDecorator::Data::GetOrCreateForPageNode,
&PageLiveStateDecorator::Data::IsConnectedToSerialPort, setter);
VerifyObserverExpectationOnPMSequence(
TestPageLiveStateObserver::ObserverFunction::
kOnIsConnectedToSerialPortChanged);
}

TEST_F(PageLiveStateDecoratorTest, OnIsCapturingVideoChanged) {
testing::EndToEndBooleanPropertyTest(
web_contents(), &PageLiveStateDecorator::Data::GetOrCreateForPageNode,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "components/performance_manager/public/graph/graph.h"
#include "components/performance_manager/public/graph/node_data_describer.h"
#include "components/performance_manager/public/graph/page_node.h"
#include "content/public/browser/web_contents_observer.h"
#include "ui/accessibility/ax_mode.h"
#include "url/gurl.h"

Expand Down Expand Up @@ -39,14 +40,11 @@ class PageLiveStateDecorator : public GraphOwnedDefaultImpl,
PageLiveStateDecorator(const PageLiveStateDecorator& other) = delete;
PageLiveStateDecorator& operator=(const PageLiveStateDecorator&) = delete;

// Must be called when the connected to USB device state changes.
static void OnIsConnectedToUSBDeviceChanged(content::WebContents* contents,
bool is_connected_to_usb_device);

// Must be called when the connected to Bluetooth device state changes.
static void OnIsConnectedToBluetoothDeviceChanged(
// Must be called when the device connection types used by `contents` change.
static void OnDeviceConnectionTypesChanged(
content::WebContents* contents,
bool is_connected_to_bluetooth_device);
content::WebContentsObserver::DeviceConnectionType connection_type,
bool used);

// Functions that should be called by a MediaStreamCaptureIndicator::Observer.
static void OnIsCapturingVideoChanged(content::WebContents* contents,
Expand Down Expand Up @@ -109,6 +107,8 @@ class PageLiveStateDecorator::Data {

virtual bool IsConnectedToUSBDevice() const = 0;
virtual bool IsConnectedToBluetoothDevice() const = 0;
virtual bool IsConnectedToHidDevice() const = 0;
virtual bool IsConnectedToSerialPort() const = 0;
virtual bool IsCapturingVideo() const = 0;
virtual bool IsCapturingAudio() const = 0;
virtual bool IsBeingMirrored() const = 0;
Expand Down Expand Up @@ -160,6 +160,8 @@ class PageLiveStateObserver : public base::CheckedObserver {
virtual void OnIsConnectedToUSBDeviceChanged(const PageNode* page_node) = 0;
virtual void OnIsConnectedToBluetoothDeviceChanged(
const PageNode* page_node) = 0;
virtual void OnIsConnectedToHidDeviceChanged(const PageNode* page_node) = 0;
virtual void OnIsConnectedToSerialPortChanged(const PageNode* page_node) = 0;
virtual void OnIsCapturingVideoChanged(const PageNode* page_node) = 0;
virtual void OnIsCapturingAudioChanged(const PageNode* page_node) = 0;
virtual void OnIsBeingMirroredChanged(const PageNode* page_node) = 0;
Expand All @@ -186,6 +188,8 @@ class PageLiveStateObserverDefaultImpl : public PageLiveStateObserver {
void OnIsConnectedToUSBDeviceChanged(const PageNode* page_node) override {}
void OnIsConnectedToBluetoothDeviceChanged(
const PageNode* page_node) override {}
void OnIsConnectedToHidDeviceChanged(const PageNode* page_node) override {}
void OnIsConnectedToSerialPortChanged(const PageNode* page_node) override {}
void OnIsCapturingVideoChanged(const PageNode* page_node) override {}
void OnIsCapturingAudioChanged(const PageNode* page_node) override {}
void OnIsBeingMirroredChanged(const PageNode* page_node) override {}
Expand Down
Loading

0 comments on commit e753bf9

Please sign in to comment.