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
This commit is contained in:
Vladimir Komsiyski
2022-10-23 18:34:40 +02:00
parent 30ea428016
commit c0acd6cd17
4 changed files with 178 additions and 30 deletions

View File

@@ -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.
*
* <p class="note">This is a protected intent that can only be sent by the system.</p>
*
* @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(

View File

@@ -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<Sensor> list);
private static native void nativeGetRuntimeSensors(
long nativeInstance, int deviceId, List<Sensor> 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<Sensor> mFullSensorsList = new ArrayList<>();
private List<Sensor> mFullDynamicSensorsList = new ArrayList<>();
private final SparseArray<List<Sensor>> mFullRuntimeSensorListByDevice = new SparseArray<>();
private final SparseArray<SparseArray<List<Sensor>>> mRuntimeSensorListByDeviceByType =
new SparseArray<>();
private boolean mDynamicSensorListDirty = true;
private final HashMap<Integer, Sensor> mHandleToSensor = new HashMap<>();
@@ -114,6 +127,7 @@ public class SystemSensorManager extends SensorManager {
private HashMap<DynamicSensorCallback, Handler>
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<Boolean> 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<Sensor> 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<Sensor> list;
synchronized (mFullRuntimeSensorListByDevice) {
List<Sensor> fullList = mFullRuntimeSensorListByDevice.get(deviceId);
if (fullList == null) {
fullList = createRuntimeSensorListLocked(deviceId);
}
SparseArray<List<Sensor>> 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<Sensor> 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<Sensor> 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<Sensor> createRuntimeSensorListLocked(int deviceId) {
setupRuntimeSensorBroadcastReceiver();
List<Sensor> 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<Sensor> 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");
}

View File

@@ -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 *>(sensorManager);
const ListOffsets &listOffsets(gListOffsets);
Vector<Sensor> 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*>(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[] = {

View File

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