Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0acd6cd authored by Vladimir Komsiyski's avatar Vladimir Komsiyski
Browse files

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
parent 30ea4280
Loading
Loading
Loading
Loading
+21 −0
Original line number Diff line number Diff line
@@ -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(
+110 −2
Original line number Diff line number Diff line
@@ -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,14 +163,65 @@ 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() {
        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 */
    @Override
    protected List<Sensor> getFullDynamicSensorList() {
@@ -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");
                        }
+37 −34
Original line number Diff line number Diff line
@@ -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 },

    {"nativeGetSensorAtIndex",
            "(JLandroid/hardware/Sensor;I)Z",
        {"nativeClassInit", "()V", (void *)nativeClassInit},
        {"nativeCreate", "(Ljava/lang/String;)J", (void *)nativeCreate},

        {"nativeGetSensorAtIndex", "(JLandroid/hardware/Sensor;I)Z",
         (void *)nativeGetSensorAtIndex},

    {"nativeGetDynamicSensors",
            "(JLjava/util/List;)V",
            (void*)nativeGetDynamicSensors },
        {"nativeGetDynamicSensors", "(JLjava/util/List;)V", (void *)nativeGetDynamicSensors},

        {"nativeGetRuntimeSensors", "(JILjava/util/List;)V", (void *)nativeGetRuntimeSensors},

    {"nativeIsDataInjectionEnabled",
            "(J)Z",
            (void*)nativeIsDataInjectionEnabled },
        {"nativeIsDataInjectionEnabled", "(J)Z", (void *)nativeIsDataInjectionEnabled},

    {"nativeCreateDirectChannel",
            "(JJIILandroid/hardware/HardwareBuffer;)I",
        {"nativeCreateDirectChannel", "(JJIILandroid/hardware/HardwareBuffer;)I",
         (void *)nativeCreateDirectChannel},

    {"nativeDestroyDirectChannel",
            "(JI)V",
            (void*)nativeDestroyDirectChannel },
        {"nativeDestroyDirectChannel", "(JI)V", (void *)nativeDestroyDirectChannel},

    {"nativeConfigDirectChannel",
            "(JIII)I",
            (void*)nativeConfigDirectChannel },
        {"nativeConfigDirectChannel", "(JIII)I", (void *)nativeConfigDirectChannel},

    {"nativeSetOperationParameter",
            "(JII[F[I)I",
            (void*)nativeSetOperationParameter },
        {"nativeSetOperationParameter", "(JII[F[I)I", (void *)nativeSetOperationParameter},
};

static const JNINativeMethod gBaseEventQueueMethods[] = {
+17 −1
Original line number Diff line number Diff line
@@ -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();