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.sensor.IVirtualSensorCallback;
22 import android.companion.virtual.sensor.VirtualSensor;
23 import android.companion.virtual.sensor.VirtualSensorConfig;
24 import android.companion.virtual.sensor.VirtualSensorEvent;
25 import android.hardware.SensorDirectChannel;
26 import android.os.IBinder;
27 import android.os.ParcelFileDescriptor;
28 import android.os.RemoteException;
29 import android.os.SharedMemory;
30 import android.util.ArrayMap;
31 import android.util.Slog;
32 
33 import com.android.internal.annotations.GuardedBy;
34 import com.android.internal.annotations.VisibleForTesting;
35 import com.android.server.LocalServices;
36 import com.android.server.sensors.SensorManagerInternal;
37 
38 import java.io.PrintWriter;
39 import java.util.Map;
40 import java.util.Objects;
41 import java.util.concurrent.atomic.AtomicInteger;
42 
43 /** Controls virtual sensors, including their lifecycle and sensor event dispatch. */
44 public class SensorController {
45 
46     private static final String TAG = "SensorController";
47 
48     // See system/core/libutils/include/utils/Errors.h
49     private static final int OK = 0;
50     private static final int UNKNOWN_ERROR = (-2147483647 - 1); // INT32_MIN value
51     private static final int BAD_VALUE = -22;
52 
53     private static AtomicInteger sNextDirectChannelHandle = new AtomicInteger(1);
54 
55     private final Object mLock = new Object();
56     private final int mVirtualDeviceId;
57     @GuardedBy("mLock")
58     private final ArrayMap<IBinder, SensorDescriptor> mSensorDescriptors = new ArrayMap<>();
59 
60     @NonNull
61     private final SensorManagerInternal.RuntimeSensorCallback mRuntimeSensorCallback;
62     private final SensorManagerInternal mSensorManagerInternal;
63     private final VirtualDeviceManagerInternal mVdmInternal;
64 
SensorController(int virtualDeviceId, @Nullable IVirtualSensorCallback virtualSensorCallback)65     public SensorController(int virtualDeviceId,
66             @Nullable IVirtualSensorCallback virtualSensorCallback) {
67         mVirtualDeviceId = virtualDeviceId;
68         mRuntimeSensorCallback = new RuntimeSensorCallbackWrapper(virtualSensorCallback);
69         mSensorManagerInternal = LocalServices.getService(SensorManagerInternal.class);
70         mVdmInternal = LocalServices.getService(VirtualDeviceManagerInternal.class);
71     }
72 
close()73     void close() {
74         synchronized (mLock) {
75             mSensorDescriptors.values().forEach(
76                     descriptor -> mSensorManagerInternal.removeRuntimeSensor(
77                             descriptor.getHandle()));
78             mSensorDescriptors.clear();
79         }
80     }
81 
createSensor(@onNull IBinder sensorToken, @NonNull VirtualSensorConfig config)82     int createSensor(@NonNull IBinder sensorToken, @NonNull VirtualSensorConfig config) {
83         Objects.requireNonNull(sensorToken);
84         Objects.requireNonNull(config);
85         try {
86             return createSensorInternal(sensorToken, config);
87         } catch (SensorCreationException e) {
88             throw new RuntimeException(
89                     "Failed to create virtual sensor '" + config.getName() + "'.", e);
90         }
91     }
92 
createSensorInternal(IBinder sensorToken, VirtualSensorConfig config)93     private int createSensorInternal(IBinder sensorToken, VirtualSensorConfig config)
94             throws SensorCreationException {
95         if (config.getType() <= 0) {
96             throw new SensorCreationException("Received an invalid virtual sensor type.");
97         }
98         final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
99                 config.getType(), config.getName(),
100                 config.getVendor() == null ? "" : config.getVendor(), config.getMaximumRange(),
101                 config.getResolution(), config.getPower(), config.getMinDelay(),
102                 config.getMaxDelay(), config.getFlags(), mRuntimeSensorCallback);
103         if (handle <= 0) {
104             throw new SensorCreationException("Received an invalid virtual sensor handle.");
105         }
106 
107         synchronized (mLock) {
108             SensorDescriptor sensorDescriptor = new SensorDescriptor(
109                     handle, config.getType(), config.getName());
110             mSensorDescriptors.put(sensorToken, sensorDescriptor);
111         }
112         return handle;
113     }
114 
sendSensorEvent(@onNull IBinder token, @NonNull VirtualSensorEvent event)115     boolean sendSensorEvent(@NonNull IBinder token, @NonNull VirtualSensorEvent event) {
116         Objects.requireNonNull(token);
117         Objects.requireNonNull(event);
118         synchronized (mLock) {
119             final SensorDescriptor sensorDescriptor = mSensorDescriptors.get(token);
120             if (sensorDescriptor == null) {
121                 throw new IllegalArgumentException("Could not send sensor event for given token");
122             }
123             return mSensorManagerInternal.sendSensorEvent(
124                     sensorDescriptor.getHandle(), sensorDescriptor.getType(),
125                     event.getTimestampNanos(), event.getValues());
126         }
127     }
128 
unregisterSensor(@onNull IBinder token)129     void unregisterSensor(@NonNull IBinder token) {
130         Objects.requireNonNull(token);
131         synchronized (mLock) {
132             final SensorDescriptor sensorDescriptor = mSensorDescriptors.remove(token);
133             if (sensorDescriptor == null) {
134                 throw new IllegalArgumentException("Could not unregister sensor for given token");
135             }
136             mSensorManagerInternal.removeRuntimeSensor(sensorDescriptor.getHandle());
137         }
138     }
139 
140 
dump(@onNull PrintWriter fout)141     void dump(@NonNull PrintWriter fout) {
142         fout.println("    SensorController: ");
143         synchronized (mLock) {
144             fout.println("      Active descriptors: ");
145             for (SensorDescriptor sensorDescriptor : mSensorDescriptors.values()) {
146                 fout.println("        handle: " + sensorDescriptor.getHandle());
147                 fout.println("          type: " + sensorDescriptor.getType());
148                 fout.println("          name: " + sensorDescriptor.getName());
149             }
150         }
151     }
152 
153     @VisibleForTesting
addSensorForTesting(IBinder deviceToken, int handle, int type, String name)154     void addSensorForTesting(IBinder deviceToken, int handle, int type, String name) {
155         synchronized (mLock) {
156             mSensorDescriptors.put(deviceToken,
157                     new SensorDescriptor(handle, type, name));
158         }
159     }
160 
161     @VisibleForTesting
getSensorDescriptors()162     Map<IBinder, SensorDescriptor> getSensorDescriptors() {
163         synchronized (mLock) {
164             return new ArrayMap<>(mSensorDescriptors);
165         }
166     }
167 
168     private final class RuntimeSensorCallbackWrapper
169             implements SensorManagerInternal.RuntimeSensorCallback {
170         @Nullable
171         private IVirtualSensorCallback mCallback;
172 
RuntimeSensorCallbackWrapper(@ullable IVirtualSensorCallback callback)173         RuntimeSensorCallbackWrapper(@Nullable IVirtualSensorCallback callback) {
174             mCallback = callback;
175         }
176 
177         @Override
onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros, int batchReportLatencyMicros)178         public int onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros,
179                 int batchReportLatencyMicros) {
180             if (mCallback == null) {
181                 Slog.e(TAG, "No sensor callback configured for sensor handle " + handle);
182                 return BAD_VALUE;
183             }
184             VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, handle);
185             if (sensor == null) {
186                 Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
187                         + " and sensor handle=" + handle);
188                 return BAD_VALUE;
189             }
190             try {
191                 mCallback.onConfigurationChanged(sensor, enabled, samplingPeriodMicros,
192                         batchReportLatencyMicros);
193             } catch (RemoteException e) {
194                 Slog.e(TAG, "Failed to call sensor callback: " + e);
195                 return UNKNOWN_ERROR;
196             }
197             return OK;
198         }
199 
200         @Override
onDirectChannelCreated(ParcelFileDescriptor fd)201         public int onDirectChannelCreated(ParcelFileDescriptor fd) {
202             if (mCallback == null) {
203                 Slog.e(TAG, "No sensor callback for virtual deviceId " + mVirtualDeviceId);
204                 return BAD_VALUE;
205             } else if (fd == null) {
206                 Slog.e(TAG, "Received invalid ParcelFileDescriptor");
207                 return BAD_VALUE;
208             }
209             final int channelHandle = sNextDirectChannelHandle.getAndIncrement();
210             SharedMemory sharedMemory = SharedMemory.fromFileDescriptor(fd);
211             try {
212                 mCallback.onDirectChannelCreated(channelHandle, sharedMemory);
213             } catch (RemoteException e) {
214                 Slog.e(TAG, "Failed to call sensor callback: " + e);
215                 return UNKNOWN_ERROR;
216             }
217             return channelHandle;
218         }
219 
220         @Override
onDirectChannelDestroyed(int channelHandle)221         public void onDirectChannelDestroyed(int channelHandle) {
222             if (mCallback == null) {
223                 Slog.e(TAG, "No sensor callback for virtual deviceId " + mVirtualDeviceId);
224                 return;
225             }
226             try {
227                 mCallback.onDirectChannelDestroyed(channelHandle);
228             } catch (RemoteException e) {
229                 Slog.e(TAG, "Failed to call sensor callback: " + e);
230             }
231         }
232 
233         @Override
onDirectChannelConfigured(int channelHandle, int sensorHandle, @SensorDirectChannel.RateLevel int rateLevel)234         public int onDirectChannelConfigured(int channelHandle, int sensorHandle,
235                 @SensorDirectChannel.RateLevel int rateLevel) {
236             if (mCallback == null) {
237                 Slog.e(TAG, "No runtime sensor callback configured.");
238                 return BAD_VALUE;
239             }
240             VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, sensorHandle);
241             if (sensor == null) {
242                 Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
243                         + " and sensor handle=" + sensorHandle);
244                 return BAD_VALUE;
245             }
246             try {
247                 mCallback.onDirectChannelConfigured(channelHandle, sensor, rateLevel, sensorHandle);
248             } catch (RemoteException e) {
249                 Slog.e(TAG, "Failed to call sensor callback: " + e);
250                 return UNKNOWN_ERROR;
251             }
252             if (rateLevel == SensorDirectChannel.RATE_STOP) {
253                 return OK;
254             } else {
255                 // Use the sensor handle as a report token, i.e. a unique identifier of the sensor.
256                 return sensorHandle;
257             }
258         }
259     }
260 
261     @VisibleForTesting
262     static final class SensorDescriptor {
263 
264         private final int mHandle;
265         private final int mType;
266         private final String mName;
267 
SensorDescriptor(int handle, int type, String name)268         SensorDescriptor(int handle, int type, String name) {
269             mHandle = handle;
270             mType = type;
271             mName = name;
272         }
getHandle()273         public int getHandle() {
274             return mHandle;
275         }
getType()276         public int getType() {
277             return mType;
278         }
getName()279         public String getName() {
280             return mName;
281         }
282     }
283 
284     /** An internal exception that is thrown to indicate an error when opening a virtual sensor. */
285     private static class SensorCreationException extends Exception {
SensorCreationException(String message)286         SensorCreationException(String message) {
287             super(message);
288         }
SensorCreationException(String message, Exception cause)289         SensorCreationException(String message, Exception cause) {
290             super(message, cause);
291         }
292     }
293 }
294