From c0acd6cd17a41c3a4717cd0f927f18de06c91d5e Mon Sep 17 00:00:00 2001 From: Vladimir Komsiyski Date: Sun, 23 Oct 2022 18:34:40 +0200 Subject: [PATCH] Adjust the behavior of SensorManager for virtual device sensors. The virtual device sensors are handled as runtime sensors internally. They are returned from getSensorsList *iff* the current context in SensorManager is associated with a virtual device, which has a custom sensors policy. The SystemSensorManager adds a new implementation of getSensorList in order to avoid the cache the per-device sensor lists separately. The virtual device sensors do not trigger DynamicSensorCallbacks and are removed from the system when the virtual device is closed. The virtual device broadcasts the fact that it's being closed so the SensorManager can clean up any cached lists associated with that device. Bug: 237278244 Test: atest cts/tests/sensor Change-Id: I63938377f4eedca32fba14d8e15e09be1b85e460 --- .../virtual/VirtualDeviceManager.java | 21 ++++ .../android/hardware/SystemSensorManager.java | 112 +++++++++++++++++- core/jni/android_hardware_SensorManager.cpp | 57 ++++----- .../virtual/VirtualDeviceManagerService.java | 18 ++- 4 files changed, 178 insertions(+), 30 deletions(-) diff --git a/core/java/android/companion/virtual/VirtualDeviceManager.java b/core/java/android/companion/virtual/VirtualDeviceManager.java index fbb4bd0bdb3f8..08002da41cfc3 100644 --- a/core/java/android/companion/virtual/VirtualDeviceManager.java +++ b/core/java/android/companion/virtual/VirtualDeviceManager.java @@ -22,6 +22,7 @@ import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; import android.annotation.RequiresPermission; +import android.annotation.SdkConstant; import android.annotation.SystemApi; import android.annotation.SystemService; import android.app.PendingIntent; @@ -91,6 +92,26 @@ public final class VirtualDeviceManager { */ public static final int INVALID_DEVICE_ID = -1; + /** + * Broadcast Action: A Virtual Device was removed. + * + *

This is a protected intent that can only be sent by the system.

+ * + * @hide + */ + @SdkConstant(SdkConstant.SdkConstantType.BROADCAST_INTENT_ACTION) + public static final String ACTION_VIRTUAL_DEVICE_REMOVED = + "android.companion.virtual.action.VIRTUAL_DEVICE_REMOVED"; + + /** + * Int intent extra to be used with {@link #ACTION_VIRTUAL_DEVICE_REMOVED}. + * Contains the identifier of the virtual device, which was removed. + * + * @hide + */ + public static final String EXTRA_VIRTUAL_DEVICE_ID = + "android.companion.virtual.extra.VIRTUAL_DEVICE_ID"; + /** @hide */ @Retention(RetentionPolicy.SOURCE) @IntDef( diff --git a/core/java/android/hardware/SystemSensorManager.java b/core/java/android/hardware/SystemSensorManager.java index 1c4898a4c8d0f..18118f5bfe29a 100644 --- a/core/java/android/hardware/SystemSensorManager.java +++ b/core/java/android/hardware/SystemSensorManager.java @@ -16,8 +16,14 @@ package android.hardware; +import static android.companion.virtual.VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED; +import static android.companion.virtual.VirtualDeviceManager.DEFAULT_DEVICE_ID; +import static android.companion.virtual.VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID; +import static android.companion.virtual.VirtualDeviceParams.DEVICE_POLICY_DEFAULT; +import static android.companion.virtual.VirtualDeviceParams.POLICY_TYPE_SENSORS; import static android.content.pm.PackageManager.PERMISSION_GRANTED; +import android.companion.virtual.VirtualDeviceManager; import android.compat.Compatibility; import android.compat.annotation.ChangeId; import android.compat.annotation.EnabledAfter; @@ -45,6 +51,7 @@ import java.io.IOException; import java.io.UncheckedIOException; import java.lang.ref.WeakReference; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -80,6 +87,8 @@ public class SystemSensorManager extends SensorManager { private static native boolean nativeGetSensorAtIndex(long nativeInstance, Sensor sensor, int index); private static native void nativeGetDynamicSensors(long nativeInstance, List list); + private static native void nativeGetRuntimeSensors( + long nativeInstance, int deviceId, List list); private static native boolean nativeIsDataInjectionEnabled(long nativeInstance); private static native int nativeCreateDirectChannel( @@ -100,6 +109,10 @@ public class SystemSensorManager extends SensorManager { private final ArrayList mFullSensorsList = new ArrayList<>(); private List mFullDynamicSensorsList = new ArrayList<>(); + private final SparseArray> mFullRuntimeSensorListByDevice = new SparseArray<>(); + private final SparseArray>> mRuntimeSensorListByDeviceByType = + new SparseArray<>(); + private boolean mDynamicSensorListDirty = true; private final HashMap mHandleToSensor = new HashMap<>(); @@ -114,6 +127,7 @@ public class SystemSensorManager extends SensorManager { private HashMap mDynamicSensorCallbacks = new HashMap<>(); private BroadcastReceiver mDynamicSensorBroadcastReceiver; + private BroadcastReceiver mRuntimeSensorBroadcastReceiver; // Looper associated with the context in which this instance was created. private final Looper mMainLooper; @@ -121,6 +135,7 @@ public class SystemSensorManager extends SensorManager { private final boolean mIsPackageDebuggable; private final Context mContext; private final long mNativeInstance; + private final VirtualDeviceManager mVdm; private Optional mHasHighSamplingRateSensorsPermission = Optional.empty(); @@ -139,6 +154,7 @@ public class SystemSensorManager extends SensorManager { mContext = context; mNativeInstance = nativeCreate(context.getOpPackageName()); mIsPackageDebuggable = (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE)); + mVdm = mContext.getSystemService(VirtualDeviceManager.class); // initialize the sensor list for (int index = 0;; ++index) { @@ -147,12 +163,63 @@ public class SystemSensorManager extends SensorManager { mFullSensorsList.add(sensor); mHandleToSensor.put(sensor.getHandle(), sensor); } + + } + + /** @hide */ + @Override + public List getSensorList(int type) { + final int deviceId = mContext.getDeviceId(); + if (deviceId == DEFAULT_DEVICE_ID || mVdm == null + || mVdm.getDevicePolicy(deviceId, POLICY_TYPE_SENSORS) == DEVICE_POLICY_DEFAULT) { + return super.getSensorList(type); + } + + // Cache the per-device lists on demand. + List list; + synchronized (mFullRuntimeSensorListByDevice) { + List fullList = mFullRuntimeSensorListByDevice.get(deviceId); + if (fullList == null) { + fullList = createRuntimeSensorListLocked(deviceId); + } + SparseArray> deviceSensorListByType = + mRuntimeSensorListByDeviceByType.get(deviceId); + list = deviceSensorListByType.get(type); + if (list == null) { + if (type == Sensor.TYPE_ALL) { + list = fullList; + } else { + list = new ArrayList<>(); + for (Sensor i : fullList) { + if (i.getType() == type) { + list.add(i); + } + } + } + list = Collections.unmodifiableList(list); + deviceSensorListByType.append(type, list); + } + } + return list; } /** @hide */ @Override protected List getFullSensorList() { - return mFullSensorsList; + final int deviceId = mContext.getDeviceId(); + if (deviceId == DEFAULT_DEVICE_ID || mVdm == null + || mVdm.getDevicePolicy(deviceId, POLICY_TYPE_SENSORS) == DEVICE_POLICY_DEFAULT) { + return mFullSensorsList; + } + + List fullList; + synchronized (mFullRuntimeSensorListByDevice) { + fullList = mFullRuntimeSensorListByDevice.get(deviceId); + if (fullList == null) { + fullList = createRuntimeSensorListLocked(deviceId); + } + } + return fullList; } /** @hide */ @@ -446,12 +513,53 @@ public class SystemSensorManager extends SensorManager { } } + private List createRuntimeSensorListLocked(int deviceId) { + setupRuntimeSensorBroadcastReceiver(); + List list = new ArrayList<>(); + nativeGetRuntimeSensors(mNativeInstance, deviceId, list); + mFullRuntimeSensorListByDevice.put(deviceId, list); + mRuntimeSensorListByDeviceByType.put(deviceId, new SparseArray<>()); + for (Sensor s : list) { + mHandleToSensor.put(s.getHandle(), s); + } + return list; + } + + private void setupRuntimeSensorBroadcastReceiver() { + if (mRuntimeSensorBroadcastReceiver == null) { + mRuntimeSensorBroadcastReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ACTION_VIRTUAL_DEVICE_REMOVED)) { + synchronized (mFullRuntimeSensorListByDevice) { + final int deviceId = intent.getIntExtra( + EXTRA_VIRTUAL_DEVICE_ID, DEFAULT_DEVICE_ID); + List removedSensors = + mFullRuntimeSensorListByDevice.removeReturnOld(deviceId); + if (removedSensors != null) { + for (Sensor s : removedSensors) { + cleanupSensorConnection(s); + } + } + mRuntimeSensorListByDeviceByType.remove(deviceId); + } + } + } + }; + + IntentFilter filter = new IntentFilter("virtual_device_removed"); + filter.addAction(ACTION_VIRTUAL_DEVICE_REMOVED); + mContext.registerReceiver(mRuntimeSensorBroadcastReceiver, filter, + Context.RECEIVER_NOT_EXPORTED); + } + } + private void setupDynamicSensorBroadcastReceiver() { if (mDynamicSensorBroadcastReceiver == null) { mDynamicSensorBroadcastReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { - if (intent.getAction() == Intent.ACTION_DYNAMIC_SENSOR_CHANGED) { + if (intent.getAction().equals(Intent.ACTION_DYNAMIC_SENSOR_CHANGED)) { if (DEBUG_DYNAMIC_SENSOR) { Log.i(TAG, "DYNS received DYNAMIC_SENSOR_CHANED broadcast"); } diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp index cb97698fefea5..939a0e4119139 100644 --- a/core/jni/android_hardware_SensorManager.cpp +++ b/core/jni/android_hardware_SensorManager.cpp @@ -243,6 +243,23 @@ nativeGetDynamicSensors(JNIEnv *env, jclass clazz, jlong sensorManager, jobject } } +static void nativeGetRuntimeSensors(JNIEnv *env, jclass clazz, jlong sensorManager, jint deviceId, + jobject sensorList) { + SensorManager *mgr = reinterpret_cast(sensorManager); + const ListOffsets &listOffsets(gListOffsets); + + Vector nativeList; + + mgr->getRuntimeSensorList(deviceId, nativeList); + + ALOGI("DYNS native SensorManager.getRuntimeSensorList return %zu sensors", nativeList.size()); + for (size_t i = 0; i < nativeList.size(); ++i) { + jobject sensor = translateNativeSensorToJavaSensor(env, NULL, nativeList[i]); + // add to list + env->CallBooleanMethod(sensorList, listOffsets.add, sensor); + } +} + static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong sensorManager) { SensorManager* mgr = reinterpret_cast(sensorManager); return mgr->isDataInjectionEnabled(); @@ -503,40 +520,26 @@ static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint //---------------------------------------------------------------------------- static const JNINativeMethod gSystemSensorManagerMethods[] = { - {"nativeClassInit", - "()V", - (void*)nativeClassInit }, - {"nativeCreate", - "(Ljava/lang/String;)J", - (void*)nativeCreate }, + {"nativeClassInit", "()V", (void *)nativeClassInit}, + {"nativeCreate", "(Ljava/lang/String;)J", (void *)nativeCreate}, - {"nativeGetSensorAtIndex", - "(JLandroid/hardware/Sensor;I)Z", - (void*)nativeGetSensorAtIndex }, + {"nativeGetSensorAtIndex", "(JLandroid/hardware/Sensor;I)Z", + (void *)nativeGetSensorAtIndex}, - {"nativeGetDynamicSensors", - "(JLjava/util/List;)V", - (void*)nativeGetDynamicSensors }, + {"nativeGetDynamicSensors", "(JLjava/util/List;)V", (void *)nativeGetDynamicSensors}, - {"nativeIsDataInjectionEnabled", - "(J)Z", - (void*)nativeIsDataInjectionEnabled }, + {"nativeGetRuntimeSensors", "(JILjava/util/List;)V", (void *)nativeGetRuntimeSensors}, - {"nativeCreateDirectChannel", - "(JJIILandroid/hardware/HardwareBuffer;)I", - (void*)nativeCreateDirectChannel }, + {"nativeIsDataInjectionEnabled", "(J)Z", (void *)nativeIsDataInjectionEnabled}, - {"nativeDestroyDirectChannel", - "(JI)V", - (void*)nativeDestroyDirectChannel }, + {"nativeCreateDirectChannel", "(JJIILandroid/hardware/HardwareBuffer;)I", + (void *)nativeCreateDirectChannel}, - {"nativeConfigDirectChannel", - "(JIII)I", - (void*)nativeConfigDirectChannel }, + {"nativeDestroyDirectChannel", "(JI)V", (void *)nativeDestroyDirectChannel}, - {"nativeSetOperationParameter", - "(JII[F[I)I", - (void*)nativeSetOperationParameter }, + {"nativeConfigDirectChannel", "(JIII)I", (void *)nativeConfigDirectChannel}, + + {"nativeSetOperationParameter", "(JII[F[I)I", (void *)nativeSetOperationParameter}, }; static const JNINativeMethod gBaseEventQueueMethods[] = { diff --git a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java index a8797a05ed240..ea957044bebe2 100644 --- a/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java +++ b/services/companion/java/com/android/server/companion/virtual/VirtualDeviceManagerService.java @@ -32,6 +32,7 @@ import android.companion.virtual.VirtualDevice; import android.companion.virtual.VirtualDeviceManager; import android.companion.virtual.VirtualDeviceParams; import android.content.Context; +import android.content.Intent; import android.hardware.display.DisplayManagerInternal; import android.hardware.display.IVirtualDisplayCallback; import android.hardware.display.VirtualDisplayConfig; @@ -280,7 +281,22 @@ public class VirtualDeviceManagerService extends SystemService { @Override public void onClose(int associationId) { synchronized (mVirtualDeviceManagerLock) { - mVirtualDevices.remove(associationId); + VirtualDeviceImpl removedDevice = + mVirtualDevices.removeReturnOld(associationId); + if (removedDevice != null) { + Intent i = new Intent( + VirtualDeviceManager.ACTION_VIRTUAL_DEVICE_REMOVED); + i.putExtra( + VirtualDeviceManager.EXTRA_VIRTUAL_DEVICE_ID, + removedDevice.getDeviceId()); + i.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY); + final long identity = Binder.clearCallingIdentity(); + try { + getContext().sendBroadcastAsUser(i, UserHandle.ALL); + } finally { + Binder.restoreCallingIdentity(identity); + } + } mAppsOnVirtualDevices.remove(associationId); if (cameraAccessController != null) { cameraAccessController.stopObservingIfNeeded();