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();