1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.companion.virtual;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.companion.virtual.IVirtualDevice;
22 import android.companion.virtual.sensor.IVirtualSensorCallback;
23 import android.companion.virtual.sensor.VirtualSensor;
24 import android.companion.virtual.sensor.VirtualSensorConfig;
25 import android.companion.virtual.sensor.VirtualSensorEvent;
26 import android.content.AttributionSource;
27 import android.hardware.SensorDirectChannel;
28 import android.os.Binder;
29 import android.os.IBinder;
30 import android.os.ParcelFileDescriptor;
31 import android.os.RemoteException;
32 import android.os.SharedMemory;
33 import android.util.ArrayMap;
34 import android.util.Slog;
35 import android.util.SparseArray;
36 
37 import com.android.internal.annotations.GuardedBy;
38 import com.android.internal.annotations.VisibleForTesting;
39 import com.android.modules.expresslog.Counter;
40 import com.android.server.LocalServices;
41 import com.android.server.sensors.SensorManagerInternal;
42 
43 import java.io.PrintWriter;
44 import java.util.ArrayList;
45 import java.util.Collections;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Objects;
49 import java.util.concurrent.atomic.AtomicInteger;
50 
51 /** Controls virtual sensors, including their lifecycle and sensor event dispatch. */
52 public class SensorController {
53 
54     private static final String TAG = "SensorController";
55 
56     // See system/core/libutils/include/utils/Errors.h
57     private static final int OK = 0;
58     private static final int UNKNOWN_ERROR = (-2147483647 - 1); // INT32_MIN value
59     private static final int BAD_VALUE = -22;
60 
61     private static AtomicInteger sNextDirectChannelHandle = new AtomicInteger(1);
62 
63     private final Object mLock = new Object();
64     private final int mVirtualDeviceId;
65 
66     @GuardedBy("mLock")
67     private final ArrayMap<IBinder, SensorDescriptor> mSensorDescriptors = new ArrayMap<>();
68 
69     // This device's sensors, keyed by sensor handle.
70     @GuardedBy("mLock")
71     private SparseArray<VirtualSensor> mVirtualSensors = new SparseArray<>();
72     @GuardedBy("mLock")
73     private List<VirtualSensor> mVirtualSensorList = null;
74 
75     @NonNull
76     private final AttributionSource mAttributionSource;
77     @NonNull
78     private final SensorManagerInternal.RuntimeSensorCallback mRuntimeSensorCallback;
79     private final SensorManagerInternal mSensorManagerInternal;
80     private final VirtualDeviceManagerInternal mVdmInternal;
81 
SensorController(@onNull IVirtualDevice virtualDevice, int virtualDeviceId, @NonNull AttributionSource attributionSource, @Nullable IVirtualSensorCallback virtualSensorCallback, @NonNull List<VirtualSensorConfig> sensors)82     public SensorController(@NonNull IVirtualDevice virtualDevice, int virtualDeviceId,
83             @NonNull AttributionSource attributionSource,
84             @Nullable IVirtualSensorCallback virtualSensorCallback,
85             @NonNull List<VirtualSensorConfig> sensors) {
86         mVirtualDeviceId = virtualDeviceId;
87         mAttributionSource = attributionSource;
88         mRuntimeSensorCallback = new RuntimeSensorCallbackWrapper(virtualSensorCallback);
89         mSensorManagerInternal = LocalServices.getService(SensorManagerInternal.class);
90         mVdmInternal = LocalServices.getService(VirtualDeviceManagerInternal.class);
91         createSensors(virtualDevice, sensors);
92     }
93 
close()94     void close() {
95         synchronized (mLock) {
96             mSensorDescriptors.values().forEach(
97                     descriptor -> mSensorManagerInternal.removeRuntimeSensor(descriptor.mHandle));
98             mSensorDescriptors.clear();
99             mVirtualSensors.clear();
100             mVirtualSensorList = null;
101         }
102     }
103 
createSensors(@onNull IVirtualDevice virtualDevice, @NonNull List<VirtualSensorConfig> configs)104     private void createSensors(@NonNull IVirtualDevice virtualDevice,
105             @NonNull List<VirtualSensorConfig> configs) {
106         Objects.requireNonNull(virtualDevice);
107         final long token = Binder.clearCallingIdentity();
108         try {
109             for (VirtualSensorConfig config : configs) {
110                 createSensorInternal(virtualDevice, config);
111             }
112         } catch (SensorCreationException e) {
113             throw new RuntimeException("Failed to create virtual sensor", e);
114         } finally {
115             Binder.restoreCallingIdentity(token);
116         }
117     }
118 
createSensorInternal(@onNull IVirtualDevice virtualDevice, @NonNull VirtualSensorConfig config)119     private void createSensorInternal(@NonNull IVirtualDevice virtualDevice,
120             @NonNull VirtualSensorConfig config)
121             throws SensorCreationException {
122         Objects.requireNonNull(config);
123         if (config.getType() <= 0) {
124             throw new SensorCreationException(
125                     "Received an invalid virtual sensor type (config name '" + config.getName()
126                             + "').");
127         }
128         final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
129                 config.getType(), config.getName(),
130                 config.getVendor() == null ? "" : config.getVendor(), config.getMaximumRange(),
131                 config.getResolution(), config.getPower(), config.getMinDelay(),
132                 config.getMaxDelay(), config.getFlags(), mRuntimeSensorCallback);
133         if (handle <= 0) {
134             throw new SensorCreationException(
135                     "Received an invalid virtual sensor handle '" + config.getName() + "'.");
136         }
137 
138         SensorDescriptor sensorDescriptor = new SensorDescriptor(
139                 handle, config.getType(), config.getName());
140         final IBinder sensorToken =
141                 new Binder("android.hardware.sensor.VirtualSensor:" + config.getName());
142         VirtualSensor sensor = new VirtualSensor(handle, config.getType(), config.getName(),
143                 virtualDevice, sensorToken);
144         synchronized (mLock) {
145             mSensorDescriptors.put(sensorToken, sensorDescriptor);
146             mVirtualSensors.put(handle, sensor);
147         }
148         if (android.companion.virtualdevice.flags.Flags.metricsCollection()) {
149             Counter.logIncrementWithUid(
150                     "virtual_devices.value_virtual_sensors_created_count",
151                     mAttributionSource.getUid());
152         }
153     }
154 
sendSensorEvent(@onNull IBinder token, @NonNull VirtualSensorEvent event)155     boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
156         Objects.requireNonNull(token);
157         Objects.requireNonNull(event);
158         synchronized (mLock) {
159             final SensorDescriptor sensorDescriptor = mSensorDescriptors.get(token);
160             if (sensorDescriptor == null) {
161                 throw new IllegalArgumentException("Could not send sensor event for given token");
162             }
163             return mSensorManagerInternal.sendSensorEvent(
164                     sensorDescriptor.getHandle(), sensorDescriptor.getType(),
165                     event.getTimestampNanos(), event.getValues());
166         }
167     }
168 
169     @Nullable
getSensorByHandle(int handle)170     VirtualSensor getSensorByHandle(int handle) {
171         synchronized (mLock) {
172             return mVirtualSensors.get(handle);
173         }
174     }
175 
getSensorList()176     List<VirtualSensor> getSensorList() {
177         synchronized (mLock) {
178             if (mVirtualSensorList == null) {
179                 mVirtualSensorList = new ArrayList<>(mVirtualSensors.size());
180                 for (int i = 0; i < mVirtualSensors.size(); ++i) {
181                     mVirtualSensorList.add(mVirtualSensors.valueAt(i));
182                 }
183                 mVirtualSensorList = Collections.unmodifiableList(mVirtualSensorList);
184             }
185             return mVirtualSensorList;
186         }
187     }
188 
dump(@onNull PrintWriter fout)189     void dump(@NonNull PrintWriter fout) {
190         fout.println("    SensorController: ");
191         synchronized (mLock) {
192             fout.println("      Active descriptors: ");
193             for (SensorDescriptor sensorDescriptor : mSensorDescriptors.values()) {
194                 fout.println("        handle: " + sensorDescriptor.getHandle());
195                 fout.println("          type: " + sensorDescriptor.getType());
196                 fout.println("          name: " + sensorDescriptor.getName());
197             }
198         }
199     }
200 
201     @VisibleForTesting
addSensorForTesting(IBinder deviceToken, int handle, int type, String name)202     void addSensorForTesting(IBinder deviceToken, int handle, int type, String name) {
203         synchronized (mLock) {
204             mSensorDescriptors.put(deviceToken,
205                     new SensorDescriptor(handle, type, name));
206         }
207     }
208 
209     @VisibleForTesting
getSensorDescriptors()210     Map<IBinder, SensorDescriptor> getSensorDescriptors() {
211         synchronized (mLock) {
212             return new ArrayMap<>(mSensorDescriptors);
213         }
214     }
215 
216     private final class RuntimeSensorCallbackWrapper
217             implements SensorManagerInternal.RuntimeSensorCallback {
218         @Nullable
219         private IVirtualSensorCallback mCallback;
220 
RuntimeSensorCallbackWrapper(@ullable IVirtualSensorCallback callback)221         RuntimeSensorCallbackWrapper(@Nullable IVirtualSensorCallback callback) {
222             mCallback = callback;
223         }
224 
225         @Override
onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros, int batchReportLatencyMicros)226         public int onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros,
227                 int batchReportLatencyMicros) {
228             if (mCallback == null) {
229                 Slog.e(TAG, "No sensor callback configured for sensor handle " + handle);
230                 return BAD_VALUE;
231             }
232             VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, handle);
233             if (sensor == null) {
234                 Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
235                         + " and sensor handle=" + handle);
236                 return BAD_VALUE;
237             }
238             try {
239                 mCallback.onConfigurationChanged(sensor, enabled, samplingPeriodMicros,
240                         batchReportLatencyMicros);
241             } catch (RemoteException e) {
242                 Slog.e(TAG, "Failed to call sensor callback: " + e);
243                 return UNKNOWN_ERROR;
244             }
245             return OK;
246         }
247 
248         @Override
onDirectChannelCreated(ParcelFileDescriptor fd)249         public int onDirectChannelCreated(ParcelFileDescriptor fd) {
250             if (mCallback == null) {
251                 Slog.e(TAG, "No sensor callback for virtual deviceId " + mVirtualDeviceId);
252                 return BAD_VALUE;
253             } else if (fd == null) {
254                 Slog.e(TAG, "Received invalid ParcelFileDescriptor");
255                 return BAD_VALUE;
256             }
257             final int channelHandle = sNextDirectChannelHandle.getAndIncrement();
258             SharedMemory sharedMemory = SharedMemory.fromFileDescriptor(fd);
259             try {
260                 mCallback.onDirectChannelCreated(channelHandle, sharedMemory);
261             } catch (RemoteException e) {
262                 Slog.e(TAG, "Failed to call sensor callback: " + e);
263                 return UNKNOWN_ERROR;
264             }
265             return channelHandle;
266         }
267 
268         @Override
onDirectChannelDestroyed(int channelHandle)269         public void onDirectChannelDestroyed(int channelHandle) {
270             if (mCallback == null) {
271                 Slog.e(TAG, "No sensor callback for virtual deviceId " + mVirtualDeviceId);
272                 return;
273             }
274             try {
275                 mCallback.onDirectChannelDestroyed(channelHandle);
276             } catch (RemoteException e) {
277                 Slog.e(TAG, "Failed to call sensor callback: " + e);
278             }
279         }
280 
281         @Override
onDirectChannelConfigured(int channelHandle, int sensorHandle, @SensorDirectChannel.RateLevel int rateLevel)282         public int onDirectChannelConfigured(int channelHandle, int sensorHandle,
283                 @SensorDirectChannel.RateLevel int rateLevel) {
284             if (mCallback == null) {
285                 Slog.e(TAG, "No runtime sensor callback configured.");
286                 return BAD_VALUE;
287             }
288             VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, sensorHandle);
289             if (sensor == null) {
290                 Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
291                         + " and sensor handle=" + sensorHandle);
292                 return BAD_VALUE;
293             }
294             try {
295                 mCallback.onDirectChannelConfigured(channelHandle, sensor, rateLevel, sensorHandle);
296             } catch (RemoteException e) {
297                 Slog.e(TAG, "Failed to call sensor callback: " + e);
298                 return UNKNOWN_ERROR;
299             }
300             if (rateLevel == SensorDirectChannel.RATE_STOP) {
301                 return OK;
302             } else {
303                 // Use the sensor handle as a report token, i.e. a unique identifier of the sensor.
304                 return sensorHandle;
305             }
306         }
307     }
308 
309     @VisibleForTesting
310     static final class SensorDescriptor {
311 
312         private final int mHandle;
313         private final int mType;
314         private final String mName;
315 
SensorDescriptor(int handle, int type, String name)316         SensorDescriptor(int handle, int type, String name) {
317             mHandle = handle;
318             mType = type;
319             mName = name;
320         }
getHandle()321         public int getHandle() {
322             return mHandle;
323         }
getType()324         public int getType() {
325             return mType;
326         }
getName()327         public String getName() {
328             return mName;
329         }
330     }
331 
332     /** An internal exception that is thrown to indicate an error when opening a virtual sensor. */
333     private static class SensorCreationException extends Exception {
SensorCreationException(String message)334         SensorCreationException(String message) {
335             super(message);
336         }
337     }
338 }
339