Bluetooth Scanning API: Revoke granted permission when tab is switched to background
This CL implements revoking previously granted permission for Bluetooth Scanning API
when a tab is switched to background.
Design doc:
https://docs.google.com/document/d/1k4WM56Dx7sCu2k2MjvOdXArNz2Dy8BA1vt2VYHA6v7A/edit
Bug: 953075
Change-Id: I6690dcab7bfe8b41162cb3d1c98f8c18863955ba
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1614423
Commit-Queue: Jun Cai <juncai@chromium.org>
Reviewed-by: Reilly Grant <reillyg@chromium.org>
Cr-Commit-Position: refs/heads/master@{#666157}
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.cc b/content/browser/bluetooth/web_bluetooth_service_impl.cc
index 41d2063..ef01e844 100644
--- a/content/browser/bluetooth/web_bluetooth_service_impl.cc
+++ b/content/browser/bluetooth/web_bluetooth_service_impl.cc
@@ -410,6 +410,15 @@
}
}
+void WebBluetoothServiceImpl::OnVisibilityChanged(Visibility visibility) {
+ if (visibility == content::Visibility::HIDDEN ||
+ visibility == content::Visibility::OCCLUDED) {
+ allowed_scan_filters_.clear();
+ accept_all_advertisements_ = false;
+ scanning_clients_.clear();
+ }
+}
+
void WebBluetoothServiceImpl::AdapterPoweredChanged(
device::BluetoothAdapter* adapter,
bool powered) {
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl.h b/content/browser/bluetooth/web_bluetooth_service_impl.h
index 890b0cc..356c24f9 100644
--- a/content/browser/bluetooth/web_bluetooth_service_impl.h
+++ b/content/browser/bluetooth/web_bluetooth_service_impl.h
@@ -9,6 +9,7 @@
#include <string>
#include <vector>
+#include "base/gtest_prod_util.h"
#include "base/macros.h"
#include "base/optional.h"
#include "content/browser/bad_message.h"
@@ -81,7 +82,12 @@
BluetoothDeviceScanningPromptController* prompt_controller);
private:
+ FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
+ BluetoothScanningPermissionRevokedWhenTabHidden);
+ FRIEND_TEST_ALL_PREFIXES(WebBluetoothServiceImplTest,
+ BluetoothScanningPermissionRevokedWhenTabOccluded);
friend class FrameConnectedBluetoothDevicesTest;
+ friend class WebBluetoothServiceImplTest;
using PrimaryServicesRequestCallback =
base::OnceCallback<void(device::BluetoothDevice*)>;
using ScanFilters = std::vector<blink::mojom::WebBluetoothLeScanFilterPtr>;
@@ -133,6 +139,7 @@
// These functions should always check that the affected RenderFrameHost
// is this->render_frame_host_ and not some other frame in the same tab.
void DidFinishNavigation(NavigationHandle* navigation_handle) override;
+ void OnVisibilityChanged(Visibility visibility) override;
// BluetoothAdapter::Observer:
void AdapterPoweredChanged(device::BluetoothAdapter* adapter,
diff --git a/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc b/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc
new file mode 100644
index 0000000..d633a748
--- /dev/null
+++ b/content/browser/bluetooth/web_bluetooth_service_impl_unittest.cc
@@ -0,0 +1,150 @@
+// 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 "content/browser/bluetooth/web_bluetooth_service_impl.h"
+
+#include "base/macros.h"
+#include "base/test/bind_test_util.h"
+#include "content/public/browser/web_contents_delegate.h"
+#include "content/test/test_render_view_host.h"
+#include "content/test/test_web_contents.h"
+#include "device/bluetooth/bluetooth_adapter_factory_wrapper.h"
+#include "device/bluetooth/test/mock_bluetooth_adapter.h"
+#include "mojo/public/cpp/bindings/associated_interface_ptr.h"
+#include "testing/gtest/include/gtest/gtest.h"
+
+using testing::Return;
+
+namespace content {
+
+namespace {
+
+const char kBatteryServiceUUIDString[] = "0000180f-0000-1000-8000-00805f9b34fb";
+
+class FakeBluetoothScanningPrompt : public BluetoothScanningPrompt {
+ public:
+ explicit FakeBluetoothScanningPrompt(const EventHandler& event_handler) {
+ event_handler.Run(content::BluetoothScanningPrompt::Event::kAllow);
+ }
+ ~FakeBluetoothScanningPrompt() override = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FakeBluetoothScanningPrompt);
+};
+
+class FakeBluetoothAdapter : public device::MockBluetoothAdapter {
+ public:
+ FakeBluetoothAdapter() = default;
+
+ // device::BluetoothAdapter:
+ void StartScanWithFilter(
+ std::unique_ptr<device::BluetoothDiscoveryFilter> discovery_filter,
+ DiscoverySessionResultCallback callback) override {
+ std::move(callback).Run(
+ /*is_error=*/false,
+ device::UMABluetoothDiscoverySessionOutcome::SUCCESS);
+ }
+
+ protected:
+ ~FakeBluetoothAdapter() override = default;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FakeBluetoothAdapter);
+};
+
+class FakeWebContentsDelegate : public content::WebContentsDelegate {
+ public:
+ FakeWebContentsDelegate() = default;
+ ~FakeWebContentsDelegate() override = default;
+
+ std::unique_ptr<BluetoothScanningPrompt> ShowBluetoothScanningPrompt(
+ RenderFrameHost* frame,
+ const BluetoothScanningPrompt::EventHandler& event_handler) override {
+ return std::make_unique<FakeBluetoothScanningPrompt>(event_handler);
+ }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(FakeWebContentsDelegate);
+};
+
+} // namespace
+
+class WebBluetoothServiceImplTest : public RenderViewHostImplTestHarness {
+ public:
+ WebBluetoothServiceImplTest() = default;
+ ~WebBluetoothServiceImplTest() override = default;
+
+ void SetUp() override {
+ RenderViewHostImplTestHarness::SetUp();
+
+ // Set up an adapter.
+ scoped_refptr<FakeBluetoothAdapter> adapter(new FakeBluetoothAdapter());
+ EXPECT_CALL(*adapter, IsPresent()).WillRepeatedly(Return(true));
+ device::BluetoothAdapterFactoryWrapper::Get().SetBluetoothAdapterForTesting(
+ adapter);
+
+ contents()->GetMainFrame()->InitializeRenderFrameIfNeeded();
+ contents()->SetDelegate(&delegate_);
+
+ // Simulate a frame connected to a bluetooth service.
+ service_ =
+ contents()->GetMainFrame()->CreateWebBluetoothServiceForTesting();
+
+ blink::mojom::WebBluetoothScanClientAssociatedPtrInfo client_info;
+ mojo::MakeRequest(&client_info);
+ auto options = blink::mojom::WebBluetoothRequestLEScanOptions::New();
+ base::Optional<std::vector<device::BluetoothUUID>> services;
+ services.emplace();
+ services->push_back(device::BluetoothUUID(kBatteryServiceUUIDString));
+ auto filter =
+ blink::mojom::WebBluetoothLeScanFilter::New(services, "a", "b");
+ options->filters.emplace();
+ options->filters->push_back(filter.Clone());
+ filters_.emplace();
+ filters_->push_back(filter.Clone());
+ service_->RequestScanningStart(
+ std::move(client_info), std::move(options),
+ base::BindLambdaForTesting(
+ [&](blink::mojom::RequestScanningStartResultPtr p) {
+ loop_.Quit();
+ }));
+ loop_.Run();
+ }
+
+ void TearDown() override {
+ service_ = nullptr;
+ RenderViewHostImplTestHarness::TearDown();
+ }
+
+ protected:
+ WebBluetoothServiceImpl* service_;
+ base::Optional<WebBluetoothServiceImpl::ScanFilters> filters_;
+ FakeWebContentsDelegate delegate_;
+ base::RunLoop loop_;
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(WebBluetoothServiceImplTest);
+};
+
+TEST_F(WebBluetoothServiceImplTest,
+ BluetoothScanningPermissionRevokedWhenTabHidden) {
+ EXPECT_TRUE(service_->AreScanFiltersAllowed(filters_));
+
+ contents()->SetVisibility(content::Visibility::HIDDEN);
+
+ // The previously granted Bluetooth scanning permission should be revoked.
+ EXPECT_FALSE(service_->AreScanFiltersAllowed(filters_));
+}
+
+TEST_F(WebBluetoothServiceImplTest,
+ BluetoothScanningPermissionRevokedWhenTabOccluded) {
+ EXPECT_TRUE(service_->AreScanFiltersAllowed(filters_));
+
+ contents()->SetVisibility(content::Visibility::OCCLUDED);
+
+ // The previously granted Bluetooth scanning permission should be revoked.
+ EXPECT_FALSE(service_->AreScanFiltersAllowed(filters_));
+}
+
+} // namespace content
diff --git a/content/test/BUILD.gn b/content/test/BUILD.gn
index f14ca1b..318394f4 100644
--- a/content/test/BUILD.gn
+++ b/content/test/BUILD.gn
@@ -1441,6 +1441,7 @@
"../browser/bluetooth/bluetooth_device_chooser_controller_unittest.cc",
"../browser/bluetooth/bluetooth_util_unittest.cc",
"../browser/bluetooth/frame_connected_bluetooth_devices_unittest.cc",
+ "../browser/bluetooth/web_bluetooth_service_impl_unittest.cc",
"../browser/browser_associated_interface_unittest.cc",
"../browser/browser_main_loop_unittest.cc",
"../browser/browser_thread_unittest.cc",