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