1 // Copyright 2017 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/browser/generic_sensor/sensor_provider_proxy_impl.h"
6
7 #include <algorithm>
8 #include <utility>
9 #include <vector>
10
11 #include "base/bind.h"
12 #include "base/no_destructor.h"
13 #include "content/browser/frame_host/render_frame_host_impl.h"
14 #include "content/browser/permissions/permission_controller_impl.h"
15 #include "content/public/browser/browser_context.h"
16 #include "content/public/browser/device_service.h"
17 #include "content/public/browser/permission_type.h"
18 #include "content/public/browser/render_frame_host.h"
19 #include "content/public/browser/web_contents.h"
20 #include "third_party/blink/public/mojom/feature_policy/feature_policy.mojom.h"
21
22 using device::mojom::SensorType;
23
24 using device::mojom::SensorCreationResult;
25
26 namespace content {
27
28 namespace {
29
GetBinderOverride()30 SensorProviderProxyImpl::SensorProviderBinder& GetBinderOverride() {
31 static base::NoDestructor<SensorProviderProxyImpl::SensorProviderBinder>
32 binder;
33 return *binder;
34 }
35
36 } // namespace
37
SensorProviderProxyImpl(PermissionControllerImpl * permission_controller,RenderFrameHost * render_frame_host)38 SensorProviderProxyImpl::SensorProviderProxyImpl(
39 PermissionControllerImpl* permission_controller,
40 RenderFrameHost* render_frame_host)
41 : permission_controller_(permission_controller),
42 render_frame_host_(render_frame_host) {
43 DCHECK(permission_controller);
44 DCHECK(render_frame_host);
45 }
46
47 SensorProviderProxyImpl::~SensorProviderProxyImpl() = default;
48
Bind(mojo::PendingReceiver<device::mojom::SensorProvider> receiver)49 void SensorProviderProxyImpl::Bind(
50 mojo::PendingReceiver<device::mojom::SensorProvider> receiver) {
51 receiver_set_.Add(this, std::move(receiver));
52 }
53
54 // static
OverrideSensorProviderBinderForTesting(SensorProviderBinder binder)55 void SensorProviderProxyImpl::OverrideSensorProviderBinderForTesting(
56 SensorProviderBinder binder) {
57 GetBinderOverride() = std::move(binder);
58 }
59
GetSensor(SensorType type,GetSensorCallback callback)60 void SensorProviderProxyImpl::GetSensor(SensorType type,
61 GetSensorCallback callback) {
62 if (!CheckFeaturePolicies(type)) {
63 std::move(callback).Run(SensorCreationResult::ERROR_NOT_ALLOWED, nullptr);
64 return;
65 }
66
67 if (!sensor_provider_) {
68 auto receiver = sensor_provider_.BindNewPipeAndPassReceiver();
69 sensor_provider_.set_disconnect_handler(base::BindOnce(
70 &SensorProviderProxyImpl::OnConnectionError, base::Unretained(this)));
71
72 const auto& binder = GetBinderOverride();
73 if (binder)
74 binder.Run(std::move(receiver));
75 else
76 GetDeviceService().BindSensorProvider(std::move(receiver));
77 }
78
79 // TODO(shalamov): base::BindOnce should be used (https://crbug.com/714018),
80 // however, PermissionController::RequestPermission enforces use of repeating
81 // callback.
82 permission_controller_->RequestPermission(
83 PermissionType::SENSORS, render_frame_host_,
84 render_frame_host_->GetLastCommittedURL().GetOrigin(), false,
85 base::BindRepeating(
86 &SensorProviderProxyImpl::OnPermissionRequestCompleted,
87 weak_factory_.GetWeakPtr(), type, base::Passed(std::move(callback))));
88 }
89
OnPermissionRequestCompleted(device::mojom::SensorType type,GetSensorCallback callback,blink::mojom::PermissionStatus status)90 void SensorProviderProxyImpl::OnPermissionRequestCompleted(
91 device::mojom::SensorType type,
92 GetSensorCallback callback,
93 blink::mojom::PermissionStatus status) {
94 if (status != blink::mojom::PermissionStatus::GRANTED || !sensor_provider_) {
95 std::move(callback).Run(SensorCreationResult::ERROR_NOT_ALLOWED, nullptr);
96 return;
97 }
98
99 // Unblock the orientation sensors as these are tested to play well with
100 // back-forward cache. This is conservative.
101 // TODO(crbug.com/1027985): Test and unblock all of the sensors to work with
102 // back-forward cache.
103 switch (type) {
104 case SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
105 case SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
106 case SensorType::RELATIVE_ORIENTATION_EULER_ANGLES:
107 case SensorType::RELATIVE_ORIENTATION_QUATERNION:
108 break;
109 default:
110 static_cast<RenderFrameHostImpl*>(render_frame_host_)
111 ->OnSchedulerTrackedFeatureUsed(
112 blink::scheduler::WebSchedulerTrackedFeature::
113 kRequestedBackForwardCacheBlockedSensors);
114 }
115 sensor_provider_->GetSensor(type, std::move(callback));
116 }
117
118 namespace {
119
120 std::vector<blink::mojom::FeaturePolicyFeature>
SensorTypeToFeaturePolicyFeatures(SensorType type)121 SensorTypeToFeaturePolicyFeatures(SensorType type) {
122 switch (type) {
123 case SensorType::AMBIENT_LIGHT:
124 return {blink::mojom::FeaturePolicyFeature::kAmbientLightSensor};
125 case SensorType::ACCELEROMETER:
126 case SensorType::LINEAR_ACCELERATION:
127 return {blink::mojom::FeaturePolicyFeature::kAccelerometer};
128 case SensorType::GYROSCOPE:
129 return {blink::mojom::FeaturePolicyFeature::kGyroscope};
130 case SensorType::MAGNETOMETER:
131 return {blink::mojom::FeaturePolicyFeature::kMagnetometer};
132 case SensorType::ABSOLUTE_ORIENTATION_EULER_ANGLES:
133 case SensorType::ABSOLUTE_ORIENTATION_QUATERNION:
134 return {blink::mojom::FeaturePolicyFeature::kAccelerometer,
135 blink::mojom::FeaturePolicyFeature::kGyroscope,
136 blink::mojom::FeaturePolicyFeature::kMagnetometer};
137 case SensorType::RELATIVE_ORIENTATION_EULER_ANGLES:
138 case SensorType::RELATIVE_ORIENTATION_QUATERNION:
139 return {blink::mojom::FeaturePolicyFeature::kAccelerometer,
140 blink::mojom::FeaturePolicyFeature::kGyroscope};
141 default:
142 NOTREACHED() << "Unknown sensor type " << type;
143 return {};
144 }
145 }
146
147 } // namespace
148
CheckFeaturePolicies(SensorType type) const149 bool SensorProviderProxyImpl::CheckFeaturePolicies(SensorType type) const {
150 const std::vector<blink::mojom::FeaturePolicyFeature>& features =
151 SensorTypeToFeaturePolicyFeatures(type);
152 return std::all_of(features.begin(), features.end(),
153 [this](blink::mojom::FeaturePolicyFeature feature) {
154 return render_frame_host_->IsFeatureEnabled(feature);
155 });
156 }
157
OnConnectionError()158 void SensorProviderProxyImpl::OnConnectionError() {
159 // Close all the bindings to notify them of this failure as the
160 // GetSensorCallbacks will never be called.
161 receiver_set_.Clear();
162 sensor_provider_.reset();
163 }
164
165 } // namespace content
166