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:
@@ -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(
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -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();
|
||||
|
||||
Reference in New Issue
Block a user