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