Merge "Direct connection API for runtime sensors." into udc-dev

This commit is contained in:
Vladimir Komsiyski
2023-02-28 08:01:04 +00:00
committed by Android (Google) Code Review
14 changed files with 459 additions and 29 deletions

View File

@@ -3347,10 +3347,15 @@ package android.companion.virtual.sensor {
public interface VirtualSensorCallback {
method public void onConfigurationChanged(@NonNull android.companion.virtual.sensor.VirtualSensor, boolean, @NonNull java.time.Duration, @NonNull java.time.Duration);
method public default void onDirectChannelConfigured(@IntRange(from=1) int, @NonNull android.companion.virtual.sensor.VirtualSensor, int, @IntRange(from=1) int);
method public default void onDirectChannelCreated(@IntRange(from=1) int, @NonNull android.os.SharedMemory);
method public default void onDirectChannelDestroyed(@IntRange(from=1) int);
}
public final class VirtualSensorConfig implements android.os.Parcelable {
method public int describeContents();
method public int getDirectChannelTypesSupported();
method public int getHighestDirectReportRateLevel();
method @NonNull public String getName();
method public int getType();
method @Nullable public String getVendor();
@@ -3361,6 +3366,8 @@ package android.companion.virtual.sensor {
public static final class VirtualSensorConfig.Builder {
ctor public VirtualSensorConfig.Builder(int, @NonNull String);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig build();
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setDirectChannelTypesSupported(int);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setHighestDirectReportRateLevel(int);
method @NonNull public android.companion.virtual.sensor.VirtualSensorConfig.Builder setVendor(@Nullable String);
}

View File

@@ -35,6 +35,7 @@ import android.companion.virtual.sensor.VirtualSensorConfig;
import android.content.ComponentName;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SharedMemory;
import android.os.UserHandle;
import android.util.ArraySet;
import android.util.SparseArray;
@@ -577,6 +578,25 @@ public final class VirtualDeviceParams implements Parcelable {
mExecutor.execute(() -> mCallback.onConfigurationChanged(
sensor, enabled, samplingPeriod, batchReportingLatency));
}
@Override
public void onDirectChannelCreated(int channelHandle,
@NonNull SharedMemory sharedMemory) {
mExecutor.execute(
() -> mCallback.onDirectChannelCreated(channelHandle, sharedMemory));
}
@Override
public void onDirectChannelDestroyed(int channelHandle) {
mExecutor.execute(() -> mCallback.onDirectChannelDestroyed(channelHandle));
}
@Override
public void onDirectChannelConfigured(int channelHandle, @NonNull VirtualSensor sensor,
int rateLevel, int reportToken) {
mExecutor.execute(() -> mCallback.onDirectChannelConfigured(
channelHandle, sensor, rateLevel, reportToken));
}
}
/**

View File

@@ -17,6 +17,7 @@
package android.companion.virtual.sensor;
import android.companion.virtual.sensor.VirtualSensor;
import android.os.SharedMemory;
/**
* Interface for notifying the sensor owner about whether and how sensor events should be injected.
@@ -36,4 +37,31 @@ oneway interface IVirtualSensorCallback {
*/
void onConfigurationChanged(in VirtualSensor sensor, boolean enabled, int samplingPeriodMicros,
int batchReportLatencyMicros);
/**
* Called when a sensor direct channel is created.
*
* @param channelHandle Identifier of the channel that was created.
* @param sharedMemory The shared memory region for the direct sensor channel.
*/
void onDirectChannelCreated(int channelHandle, in SharedMemory sharedMemory);
/**
* Called when a sensor direct channel is destroyed.
*
* @param channelHandle Identifier of the channel that was destroyed.
*/
void onDirectChannelDestroyed(int channelHandle);
/**
* Called when a sensor direct channel is configured.
*
* @param channelHandle Identifier of the channel that was configured.
* @param sensor The sensor, for which the channel was configured.
* @param rateLevel The rate level used to configure the direct sensor channel.
* @param reportToken A positive sensor report token, used to differentiate between events from
* different sensors within the same channel.
*/
void onDirectChannelConfigured(int channelHandle, in VirtualSensor sensor, int rateLevel,
int reportToken);
}

View File

@@ -17,8 +17,13 @@
package android.companion.virtual.sensor;
import android.annotation.IntRange;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.hardware.Sensor;
import android.hardware.SensorDirectChannel;
import android.os.MemoryFile;
import android.os.SharedMemory;
import java.time.Duration;
@@ -50,4 +55,74 @@ public interface VirtualSensorCallback {
*/
void onConfigurationChanged(@NonNull VirtualSensor sensor, boolean enabled,
@NonNull Duration samplingPeriod, @NonNull Duration batchReportLatency);
/**
* Called when a {@link android.hardware.SensorDirectChannel} is created.
*
* <p>The {@link android.hardware.SensorManager} instance used to create the direct channel must
* be associated with the virtual device.
*
* <p>A typical order of callback invocations is:
* <ul>
* <li>{@code onDirectChannelCreated} - the channel handle and the associated shared memory
* should be stored by the virtual device</li>
* <li>{@code onDirectChannelConfigured} with a positive {@code rateLevel} - the virtual
* device should start writing to the shared memory for the associated channel with the
* requested parameters.</li>
* <li>{@code onDirectChannelConfigured} with a {@code rateLevel = RATE_STOP} - the virtual
* device should stop writing to the shared memory for the associated channel.</li>
* <li>{@code onDirectChannelDestroyed} - the shared memory associated with the channel
* handle should be closed.</li>
* </ul>
*
* @param channelHandle Identifier of the newly created channel.
* @param sharedMemory writable shared memory region.
*
* @see android.hardware.SensorManager#createDirectChannel(MemoryFile)
* @see #onDirectChannelConfigured
* @see #onDirectChannelDestroyed
*/
default void onDirectChannelCreated(@IntRange(from = 1) int channelHandle,
@NonNull SharedMemory sharedMemory) {}
/**
* Called when a {@link android.hardware.SensorDirectChannel} is destroyed.
*
* <p>The virtual device must perform any clean-up and close the shared memory that was
* received with the {@link #onDirectChannelCreated} callback and the corresponding
* {@code channelHandle}.
*
* @param channelHandle Identifier of the channel that was destroyed.
*
* @see SensorDirectChannel#close()
*/
default void onDirectChannelDestroyed(@IntRange(from = 1) int channelHandle) {}
/**
* Called when a {@link android.hardware.SensorDirectChannel} is configured.
*
* <p>Sensor events for the corresponding sensor should be written at the indicated rate to the
* shared memory region that was received with the {@link #onDirectChannelCreated} callback and
* the corresponding {@code channelHandle}. The events should be written in the correct format
* and with the provided {@code reportToken} until the channel is reconfigured with
* {@link SensorDirectChannel#RATE_STOP}.
*
* <p>The sensor must support direct channel in order for this callback to be invoked. Only
* {@link MemoryFile} sensor direct channels are supported for virtual sensors.
*
* @param channelHandle Identifier of the channel that was configured.
* @param sensor The sensor, for which the channel was configured.
* @param rateLevel The rate level used to configure the direct sensor channel.
* @param reportToken A positive sensor report token, used to differentiate between events from
* different sensors within the same channel.
*
* @see VirtualSensorConfig.Builder#setHighestDirectReportRateLevel(int)
* @see VirtualSensorConfig.Builder#setDirectChannelTypesSupported(int)
* @see android.hardware.SensorManager#createDirectChannel(MemoryFile)
* @see #onDirectChannelCreated
* @see SensorDirectChannel#configure(Sensor, int)
*/
default void onDirectChannelConfigured(@IntRange(from = 1) int channelHandle,
@NonNull VirtualSensor sensor, @SensorDirectChannel.RateLevel int rateLevel,
@IntRange(from = 1) int reportToken) {}
}

View File

@@ -21,11 +21,13 @@ import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.SystemApi;
import android.hardware.Sensor;
import android.hardware.SensorDirectChannel;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
/**
* Configuration for creation of a virtual sensor.
* @see VirtualSensor
@@ -33,6 +35,14 @@ import java.util.Objects;
*/
@SystemApi
public final class VirtualSensorConfig implements Parcelable {
private static final String TAG = "VirtualSensorConfig";
// Mask for direct mode highest rate level, bit 7, 8, 9.
private static final int DIRECT_REPORT_MASK = 0x380;
private static final int DIRECT_REPORT_SHIFT = 7;
// Mask for supported direct channel, bit 10, 11
private static final int DIRECT_CHANNEL_SHIFT = 10;
private final int mType;
@NonNull
@@ -40,16 +50,21 @@ public final class VirtualSensorConfig implements Parcelable {
@Nullable
private final String mVendor;
private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor) {
private final int mFlags;
private VirtualSensorConfig(int type, @NonNull String name, @Nullable String vendor,
int flags) {
mType = type;
mName = name;
mVendor = vendor;
mFlags = flags;
}
private VirtualSensorConfig(@NonNull Parcel parcel) {
mType = parcel.readInt();
mName = parcel.readString8();
mVendor = parcel.readString8();
mFlags = parcel.readInt();
}
@Override
@@ -62,6 +77,7 @@ public final class VirtualSensorConfig implements Parcelable {
parcel.writeInt(mType);
parcel.writeString8(mName);
parcel.writeString8(mVendor);
parcel.writeInt(mFlags);
}
/**
@@ -91,23 +107,65 @@ public final class VirtualSensorConfig implements Parcelable {
return mVendor;
}
/**
* Returns the highest supported direct report mode rate level of the sensor.
*
* @see Sensor#getHighestDirectReportRateLevel()
*/
@SensorDirectChannel.RateLevel
public int getHighestDirectReportRateLevel() {
int rateLevel = ((mFlags & DIRECT_REPORT_MASK) >> DIRECT_REPORT_SHIFT);
return rateLevel <= SensorDirectChannel.RATE_VERY_FAST
? rateLevel : SensorDirectChannel.RATE_VERY_FAST;
}
/**
* Returns a combination of all supported direct channel types.
*
* @see Builder#setDirectChannelTypesSupported(int)
* @see Sensor#isDirectChannelTypeSupported(int)
*/
public @SensorDirectChannel.MemoryType int getDirectChannelTypesSupported() {
int memoryTypes = 0;
if ((mFlags & (1 << DIRECT_CHANNEL_SHIFT)) > 0) {
memoryTypes |= SensorDirectChannel.TYPE_MEMORY_FILE;
}
if ((mFlags & (1 << (DIRECT_CHANNEL_SHIFT + 1))) > 0) {
memoryTypes |= SensorDirectChannel.TYPE_HARDWARE_BUFFER;
}
return memoryTypes;
}
/**
* Returns the sensor flags.
* @hide
*/
public int getFlags() {
return mFlags;
}
/**
* Builder for {@link VirtualSensorConfig}.
*/
public static final class Builder {
private static final int FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED =
1 << DIRECT_CHANNEL_SHIFT;
private final int mType;
@NonNull
private final String mName;
@Nullable
private String mVendor;
private int mFlags;
@SensorDirectChannel.RateLevel
int mHighestDirectReportRateLevel;
/**
* Creates a new builder.
*
* @param type The type of the sensor, matching {@link Sensor#getType}.
* @param name The name of the sensor. Must be unique among all sensors with the same type
* that belong to the same virtual device.
* that belong to the same virtual device.
*/
public Builder(int type, @NonNull String name) {
mType = type;
@@ -119,7 +177,19 @@ public final class VirtualSensorConfig implements Parcelable {
*/
@NonNull
public VirtualSensorConfig build() {
return new VirtualSensorConfig(mType, mName, mVendor);
if (mHighestDirectReportRateLevel > 0) {
if ((mFlags & FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED) == 0) {
throw new IllegalArgumentException("Setting direct channel type is required "
+ "for sensors with direct channel support.");
}
mFlags |= mHighestDirectReportRateLevel << DIRECT_REPORT_SHIFT;
}
if ((mFlags & FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED) > 0
&& mHighestDirectReportRateLevel == 0) {
throw new IllegalArgumentException("Highest direct report rate level is "
+ "required for sensors with direct channel support.");
}
return new VirtualSensorConfig(mType, mName, mVendor, mFlags);
}
/**
@@ -130,6 +200,44 @@ public final class VirtualSensorConfig implements Parcelable {
mVendor = vendor;
return this;
}
/**
* Sets the highest supported rate level for direct sensor report.
*
* @see VirtualSensorConfig#getHighestDirectReportRateLevel()
*/
@NonNull
public VirtualSensorConfig.Builder setHighestDirectReportRateLevel(
@SensorDirectChannel.RateLevel int rateLevel) {
mHighestDirectReportRateLevel = rateLevel;
return this;
}
/**
* Sets whether direct sensor channel of the given types is supported.
*
* @param memoryTypes A combination of {@link SensorDirectChannel.MemoryType} flags
* indicating the types of shared memory supported for creating direct channels. Only
* {@link SensorDirectChannel#TYPE_MEMORY_FILE} direct channels may be supported for virtual
* sensors.
* @throws IllegalArgumentException if {@link SensorDirectChannel#TYPE_HARDWARE_BUFFER} is
* set to be supported.
*/
@NonNull
public VirtualSensorConfig.Builder setDirectChannelTypesSupported(
@SensorDirectChannel.MemoryType int memoryTypes) {
if ((memoryTypes & SensorDirectChannel.TYPE_MEMORY_FILE) > 0) {
mFlags |= FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED;
} else {
mFlags &= ~FLAG_MEMORY_FILE_DIRECT_CHANNEL_SUPPORTED;
}
if ((memoryTypes & ~SensorDirectChannel.TYPE_MEMORY_FILE) > 0) {
throw new IllegalArgumentException(
"Only TYPE_MEMORY_FILE direct channels can be supported for virtual "
+ "sensors.");
}
return this;
}
}
@NonNull

View File

@@ -92,7 +92,8 @@ public class SystemSensorManager extends SensorManager {
private static native boolean nativeIsDataInjectionEnabled(long nativeInstance);
private static native int nativeCreateDirectChannel(
long nativeInstance, long size, int channelType, int fd, HardwareBuffer buffer);
long nativeInstance, int deviceId, long size, int channelType, int fd,
HardwareBuffer buffer);
private static native void nativeDestroyDirectChannel(
long nativeInstance, int channelHandle);
private static native int nativeConfigDirectChannel(
@@ -695,6 +696,10 @@ public class SystemSensorManager extends SensorManager {
/** @hide */
protected SensorDirectChannel createDirectChannelImpl(
MemoryFile memoryFile, HardwareBuffer hardwareBuffer) {
int deviceId = mContext.getDeviceId();
if (isDeviceSensorPolicyDefault(deviceId)) {
deviceId = DEVICE_ID_DEFAULT;
}
int id;
int type;
long size;
@@ -713,8 +718,8 @@ public class SystemSensorManager extends SensorManager {
}
size = memoryFile.length();
id = nativeCreateDirectChannel(
mNativeInstance, size, SensorDirectChannel.TYPE_MEMORY_FILE, fd, null);
id = nativeCreateDirectChannel(mNativeInstance, deviceId, size,
SensorDirectChannel.TYPE_MEMORY_FILE, fd, null);
if (id <= 0) {
throw new UncheckedIOException(
new IOException("create MemoryFile direct channel failed " + id));
@@ -738,7 +743,7 @@ public class SystemSensorManager extends SensorManager {
}
size = hardwareBuffer.getWidth();
id = nativeCreateDirectChannel(
mNativeInstance, size, SensorDirectChannel.TYPE_HARDWARE_BUFFER,
mNativeInstance, deviceId, size, SensorDirectChannel.TYPE_HARDWARE_BUFFER,
-1, hardwareBuffer);
if (id <= 0) {
throw new UncheckedIOException(

View File

@@ -266,7 +266,8 @@ static jboolean nativeIsDataInjectionEnabled(JNIEnv *_env, jclass _this, jlong s
}
static jint nativeCreateDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
jlong size, jint channelType, jint fd, jobject hardwareBufferObj) {
jint deviceId, jlong size, jint channelType, jint fd,
jobject hardwareBufferObj) {
const native_handle_t *nativeHandle = nullptr;
NATIVE_HANDLE_DECLARE_STORAGE(ashmemHandle, 1, 0);
@@ -287,7 +288,7 @@ static jint nativeCreateDirectChannel(JNIEnv *_env, jclass _this, jlong sensorMa
}
SensorManager* mgr = reinterpret_cast<SensorManager*>(sensorManager);
return mgr->createDirectChannel(size, channelType, nativeHandle);
return mgr->createDirectChannel(deviceId, size, channelType, nativeHandle);
}
static void nativeDestroyDirectChannel(JNIEnv *_env, jclass _this, jlong sensorManager,
@@ -532,7 +533,7 @@ static const JNINativeMethod gSystemSensorManagerMethods[] = {
{"nativeIsDataInjectionEnabled", "(J)Z", (void *)nativeIsDataInjectionEnabled},
{"nativeCreateDirectChannel", "(JJIILandroid/hardware/HardwareBuffer;)I",
{"nativeCreateDirectChannel", "(JIJIILandroid/hardware/HardwareBuffer;)I",
(void *)nativeCreateDirectChannel},
{"nativeDestroyDirectChannel", "(JI)V", (void *)nativeDestroyDirectChannel},

View File

@@ -17,9 +17,15 @@
package android.companion.virtual.sensor;
import static android.hardware.Sensor.TYPE_ACCELEROMETER;
import static android.hardware.SensorDirectChannel.RATE_STOP;
import static android.hardware.SensorDirectChannel.RATE_VERY_FAST;
import static android.hardware.SensorDirectChannel.TYPE_HARDWARE_BUFFER;
import static android.hardware.SensorDirectChannel.TYPE_MEMORY_FILE;
import static com.google.common.truth.Truth.assertThat;
import static org.testng.Assert.assertThrows;
import android.os.Parcel;
import android.platform.test.annotations.Presubmit;
@@ -40,6 +46,8 @@ public class VirtualSensorConfigTest {
final VirtualSensorConfig originalConfig =
new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
.setVendor(SENSOR_VENDOR)
.setHighestDirectReportRateLevel(RATE_VERY_FAST)
.setDirectChannelTypesSupported(TYPE_MEMORY_FILE)
.build();
final Parcel parcel = Parcel.obtain();
originalConfig.writeToParcel(parcel, /* flags= */ 0);
@@ -49,6 +57,39 @@ public class VirtualSensorConfigTest {
assertThat(recreatedConfig.getType()).isEqualTo(originalConfig.getType());
assertThat(recreatedConfig.getName()).isEqualTo(originalConfig.getName());
assertThat(recreatedConfig.getVendor()).isEqualTo(originalConfig.getVendor());
assertThat(recreatedConfig.getHighestDirectReportRateLevel()).isEqualTo(RATE_VERY_FAST);
assertThat(recreatedConfig.getDirectChannelTypesSupported()).isEqualTo(TYPE_MEMORY_FILE);
// From hardware/libhardware/include/hardware/sensors-base.h:
// 0x400 is SENSOR_FLAG_DIRECT_CHANNEL_ASHMEM (i.e. TYPE_MEMORY_FILE)
// 0x800 is SENSOR_FLAG_DIRECT_CHANNEL_GRALLOC (i.e. TYPE_HARDWARE_BUFFER)
// 7 is SENSOR_FLAG_SHIFT_DIRECT_REPORT
assertThat(recreatedConfig.getFlags()).isEqualTo(0x400 | RATE_VERY_FAST << 7);
}
@Test
public void hardwareBufferDirectChannelTypeSupported_throwsException() {
assertThrows(
IllegalArgumentException.class,
() -> new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
.setDirectChannelTypesSupported(TYPE_HARDWARE_BUFFER | TYPE_MEMORY_FILE));
}
@Test
public void directChannelTypeSupported_missingHighestReportRateLevel_throwsException() {
assertThrows(
IllegalArgumentException.class,
() -> new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
.setDirectChannelTypesSupported(TYPE_MEMORY_FILE)
.build());
}
@Test
public void directChannelTypeSupported_missingDirectChannelTypeSupported_throwsException() {
assertThrows(
IllegalArgumentException.class,
() -> new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME)
.setHighestDirectReportRateLevel(RATE_VERY_FAST)
.build());
}
@Test
@@ -56,5 +97,8 @@ public class VirtualSensorConfigTest {
final VirtualSensorConfig config =
new VirtualSensorConfig.Builder(TYPE_ACCELEROMETER, SENSOR_NAME).build();
assertThat(config.getVendor()).isNull();
assertThat(config.getHighestDirectReportRateLevel()).isEqualTo(RATE_STOP);
assertThat(config.getDirectChannelTypesSupported()).isEqualTo(0);
assertThat(config.getFlags()).isEqualTo(0);
}
}

View File

@@ -22,8 +22,11 @@ import android.companion.virtual.sensor.IVirtualSensorCallback;
import android.companion.virtual.sensor.VirtualSensor;
import android.companion.virtual.sensor.VirtualSensorConfig;
import android.companion.virtual.sensor.VirtualSensorEvent;
import android.hardware.SensorDirectChannel;
import android.os.IBinder;
import android.os.ParcelFileDescriptor;
import android.os.RemoteException;
import android.os.SharedMemory;
import android.util.ArrayMap;
import android.util.Slog;
@@ -36,6 +39,7 @@ import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.atomic.AtomicInteger;
/** Controls virtual sensors, including their lifecycle and sensor event dispatch. */
public class SensorController {
@@ -47,6 +51,8 @@ public class SensorController {
private static final int UNKNOWN_ERROR = (-2147483647 - 1); // INT32_MIN value
private static final int BAD_VALUE = -22;
private static AtomicInteger sNextDirectChannelHandle = new AtomicInteger(1);
private final Object mLock;
private final int mVirtualDeviceId;
@GuardedBy("mLock")
@@ -57,8 +63,6 @@ public class SensorController {
private final SensorManagerInternal mSensorManagerInternal;
private final VirtualDeviceManagerInternal mVdmInternal;
public SensorController(@NonNull Object lock, int virtualDeviceId,
@Nullable IVirtualSensorCallback virtualSensorCallback) {
mLock = lock;
@@ -97,7 +101,7 @@ public class SensorController {
throws SensorCreationException {
final int handle = mSensorManagerInternal.createRuntimeSensor(mVirtualDeviceId,
config.getType(), config.getName(),
config.getVendor() == null ? "" : config.getVendor(),
config.getVendor() == null ? "" : config.getVendor(), config.getFlags(),
mRuntimeSensorCallback);
if (handle <= 0) {
throw new SensorCreationException("Received an invalid virtual sensor handle.");
@@ -212,6 +216,66 @@ public class SensorController {
}
return OK;
}
@Override
public int onDirectChannelCreated(ParcelFileDescriptor fd) {
if (mCallback == null) {
Slog.e(TAG, "No sensor callback for virtual deviceId " + mVirtualDeviceId);
return BAD_VALUE;
} else if (fd == null) {
Slog.e(TAG, "Received invalid ParcelFileDescriptor");
return BAD_VALUE;
}
final int channelHandle = sNextDirectChannelHandle.getAndIncrement();
SharedMemory sharedMemory = SharedMemory.fromFileDescriptor(fd);
try {
mCallback.onDirectChannelCreated(channelHandle, sharedMemory);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to call sensor callback: " + e);
return UNKNOWN_ERROR;
}
return channelHandle;
}
@Override
public void onDirectChannelDestroyed(int channelHandle) {
if (mCallback == null) {
Slog.e(TAG, "No sensor callback for virtual deviceId " + mVirtualDeviceId);
return;
}
try {
mCallback.onDirectChannelDestroyed(channelHandle);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to call sensor callback: " + e);
}
}
@Override
public int onDirectChannelConfigured(int channelHandle, int sensorHandle,
@SensorDirectChannel.RateLevel int rateLevel) {
if (mCallback == null) {
Slog.e(TAG, "No runtime sensor callback configured.");
return BAD_VALUE;
}
VirtualSensor sensor = mVdmInternal.getVirtualSensor(mVirtualDeviceId, sensorHandle);
if (sensor == null) {
Slog.e(TAG, "No sensor found for deviceId=" + mVirtualDeviceId
+ " and sensor handle=" + sensorHandle);
return BAD_VALUE;
}
try {
mCallback.onDirectChannelConfigured(channelHandle, sensor, rateLevel, sensorHandle);
} catch (RemoteException e) {
Slog.e(TAG, "Failed to call sensor callback: " + e);
return UNKNOWN_ERROR;
}
if (rateLevel == SensorDirectChannel.RATE_STOP) {
return OK;
} else {
// Use the sensor handle as a report token, i.e. a unique identifier of the sensor.
return sensorHandle;
}
}
}
@VisibleForTesting

View File

@@ -17,6 +17,8 @@
package com.android.server.sensors;
import android.annotation.NonNull;
import android.hardware.SensorDirectChannel;
import android.os.ParcelFileDescriptor;
import java.util.concurrent.Executor;
@@ -58,7 +60,7 @@ public abstract class SensorManagerInternal {
* @return The sensor handle.
*/
public abstract int createRuntimeSensor(int deviceId, int type, @NonNull String name,
@NonNull String vendor, @NonNull RuntimeSensorCallback callback);
@NonNull String vendor, int flags, @NonNull RuntimeSensorCallback callback);
/**
* Unregisters the sensor with the given handle from the framework.
@@ -98,9 +100,31 @@ public abstract class SensorManagerInternal {
public interface RuntimeSensorCallback {
/**
* Invoked when the listeners of the runtime sensor have changed.
* Returns an error code if the invocation was unsuccessful, zero otherwise.
* Returns zero on success, negative error code otherwise.
*/
int onConfigurationChanged(int handle, boolean enabled, int samplingPeriodMicros,
int batchReportLatencyMicros);
/**
* Invoked when a direct sensor channel has been created.
* Wraps the file descriptor in a {@link android.os.SharedMemory} object and passes it to
* the client process.
* Returns a positive identifier of the channel on success, negative error code otherwise.
*/
int onDirectChannelCreated(ParcelFileDescriptor fd);
/**
* Invoked when a direct sensor channel has been destroyed.
*/
void onDirectChannelDestroyed(int channelHandle);
/**
* Invoked when a direct sensor channel has been configured for a sensor.
* If the invocation is unsuccessful, a negative error code is returned.
* On success, the return value is zero if the rate level is {@code RATE_STOP}, and a
* positive report token otherwise.
*/
int onDirectChannelConfigured(int channelHandle, int sensorHandle,
@SensorDirectChannel.RateLevel int rateLevel);
}
}

View File

@@ -56,7 +56,8 @@ public class SensorService extends SystemService {
private static native void unregisterProximityActiveListenerNative(long ptr);
private static native int registerRuntimeSensorNative(long ptr, int deviceId, int type,
String name, String vendor, SensorManagerInternal.RuntimeSensorCallback callback);
String name, String vendor, int flags,
SensorManagerInternal.RuntimeSensorCallback callback);
private static native void unregisterRuntimeSensorNative(long ptr, int handle);
private static native boolean sendRuntimeSensorEventNative(long ptr, int handle, int type,
long timestampNanos, float[] values);
@@ -95,9 +96,9 @@ public class SensorService extends SystemService {
class LocalService extends SensorManagerInternal {
@Override
public int createRuntimeSensor(int deviceId, int type, @NonNull String name,
@NonNull String vendor, @NonNull RuntimeSensorCallback callback) {
@NonNull String vendor, int flags, @NonNull RuntimeSensorCallback callback) {
synchronized (mLock) {
int handle = registerRuntimeSensorNative(mPtr, deviceId, type, name, vendor,
int handle = registerRuntimeSensorNative(mPtr, deviceId, type, name, vendor, flags,
callback);
mRuntimeSensorHandles.add(handle);
return handle;

View File

@@ -17,10 +17,13 @@
#define LOG_TAG "NativeSensorService"
#include <android-base/properties.h>
#include <android_os_NativeHandle.h>
#include <android_runtime/AndroidRuntime.h>
#include <core_jni_helpers.h>
#include <cutils/native_handle.h>
#include <cutils/properties.h>
#include <jni.h>
#include <nativehelper/JNIPlatformHelp.h>
#include <sensorservice/SensorService.h>
#include <string.h>
#include <utils/Log.h>
@@ -28,6 +31,8 @@
#include <mutex>
#include "android_util_Binder.h"
#define PROXIMITY_ACTIVE_CLASS \
"com/android/server/sensors/SensorManagerInternal$ProximityActiveListener"
@@ -38,7 +43,10 @@ namespace android {
static JavaVM* sJvm = nullptr;
static jmethodID sMethodIdOnProximityActive;
static jmethodID sMethodIdOnConfigurationChanged;
static jmethodID sMethodIdRuntimeSensorOnConfigurationChanged;
static jmethodID sMethodIdRuntimeSensorOnDirectChannelCreated;
static jmethodID sMethodIdRuntimeSensorOnDirectChannelDestroyed;
static jmethodID sMethodIdRuntimeSensorOnDirectChannelConfigured;
class NativeSensorService {
public:
@@ -47,7 +55,7 @@ public:
void registerProximityActiveListener();
void unregisterProximityActiveListener();
jint registerRuntimeSensor(JNIEnv* env, jint deviceId, jint type, jstring name, jstring vendor,
jobject callback);
jint flags, jobject callback);
void unregisterRuntimeSensor(jint handle);
jboolean sendRuntimeSensorEvent(JNIEnv* env, jint handle, jint type, jlong timestamp,
jfloatArray values);
@@ -74,6 +82,9 @@ private:
status_t onConfigurationChanged(int32_t handle, bool enabled, int64_t samplingPeriodNs,
int64_t batchReportLatencyNs) override;
int onDirectChannelCreated(int fd) override;
void onDirectChannelDestroyed(int channelHandle) override;
int onDirectChannelConfigured(int channelHandle, int sensorHandle, int rateLevel) override;
private:
jobject mCallback;
@@ -108,7 +119,7 @@ void NativeSensorService::unregisterProximityActiveListener() {
}
jint NativeSensorService::registerRuntimeSensor(JNIEnv* env, jint deviceId, jint type, jstring name,
jstring vendor, jobject callback) {
jstring vendor, jint flags, jobject callback) {
if (mService == nullptr) {
ALOGD("Dropping registerRuntimeSensor, sensor service not available.");
return -1;
@@ -119,6 +130,11 @@ jint NativeSensorService::registerRuntimeSensor(JNIEnv* env, jint deviceId, jint
.vendor = env->GetStringUTFChars(vendor, 0),
.version = sizeof(sensor_t),
.type = type,
#ifdef __LP64__
.flags = static_cast<uint64_t>(flags),
#else
.flags = static_cast<uint32_t>(flags),
#endif
};
sp<RuntimeSensorCallbackDelegate> callbackDelegate(
@@ -234,12 +250,39 @@ NativeSensorService::RuntimeSensorCallbackDelegate::~RuntimeSensorCallbackDelega
status_t NativeSensorService::RuntimeSensorCallbackDelegate::onConfigurationChanged(
int32_t handle, bool enabled, int64_t samplingPeriodNs, int64_t batchReportLatencyNs) {
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
return jniEnv->CallIntMethod(mCallback, sMethodIdOnConfigurationChanged,
return jniEnv->CallIntMethod(mCallback, sMethodIdRuntimeSensorOnConfigurationChanged,
static_cast<jint>(handle), static_cast<jboolean>(enabled),
static_cast<jint>(ns2us(samplingPeriodNs)),
static_cast<jint>(ns2us(batchReportLatencyNs)));
}
int NativeSensorService::RuntimeSensorCallbackDelegate::onDirectChannelCreated(int fd) {
if (fd <= 0) {
return 0;
}
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
jobject jfd = jniCreateFileDescriptor(jniEnv, fd);
jobject parcelFileDescriptor = newParcelFileDescriptor(jniEnv, jfd);
return jniEnv->CallIntMethod(mCallback, sMethodIdRuntimeSensorOnDirectChannelCreated,
parcelFileDescriptor);
}
void NativeSensorService::RuntimeSensorCallbackDelegate::onDirectChannelDestroyed(
int channelHandle) {
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
return jniEnv->CallVoidMethod(mCallback, sMethodIdRuntimeSensorOnDirectChannelDestroyed,
static_cast<jint>(channelHandle));
}
int NativeSensorService::RuntimeSensorCallbackDelegate::onDirectChannelConfigured(int channelHandle,
int sensorHandle,
int rateLevel) {
auto jniEnv = GetOrAttachJNIEnvironment(sJvm);
return jniEnv->CallIntMethod(mCallback, sMethodIdRuntimeSensorOnDirectChannelConfigured,
static_cast<jint>(channelHandle), static_cast<jint>(sensorHandle),
static_cast<jint>(rateLevel));
}
static jlong startSensorServiceNative(JNIEnv* env, jclass, jobject listener) {
NativeSensorService* service = new NativeSensorService(env, listener);
return reinterpret_cast<jlong>(service);
@@ -256,9 +299,10 @@ static void unregisterProximityActiveListenerNative(JNIEnv* env, jclass, jlong p
}
static jint registerRuntimeSensorNative(JNIEnv* env, jclass, jlong ptr, jint deviceId, jint type,
jstring name, jstring vendor, jobject callback) {
jstring name, jstring vendor, jint flags,
jobject callback) {
auto* service = reinterpret_cast<NativeSensorService*>(ptr);
return service->registerRuntimeSensor(env, deviceId, type, name, vendor, callback);
return service->registerRuntimeSensor(env, deviceId, type, name, vendor, flags, callback);
}
static void unregisterRuntimeSensorNative(JNIEnv* env, jclass, jlong ptr, jint handle) {
@@ -280,7 +324,7 @@ static const JNINativeMethod methods[] = {
{"unregisterProximityActiveListenerNative", "(J)V",
reinterpret_cast<void*>(unregisterProximityActiveListenerNative)},
{"registerRuntimeSensorNative",
"(JIILjava/lang/String;Ljava/lang/String;L" RUNTIME_SENSOR_CALLBACK_CLASS ";)I",
"(JIILjava/lang/String;Ljava/lang/String;IL" RUNTIME_SENSOR_CALLBACK_CLASS ";)I",
reinterpret_cast<void*>(registerRuntimeSensorNative)},
{"unregisterRuntimeSensorNative", "(JI)V",
reinterpret_cast<void*>(unregisterRuntimeSensorNative)},
@@ -293,8 +337,17 @@ int register_android_server_sensor_SensorService(JavaVM* vm, JNIEnv* env) {
jclass listenerClass = FindClassOrDie(env, PROXIMITY_ACTIVE_CLASS);
sMethodIdOnProximityActive = GetMethodIDOrDie(env, listenerClass, "onProximityActive", "(Z)V");
jclass runtimeSensorCallbackClass = FindClassOrDie(env, RUNTIME_SENSOR_CALLBACK_CLASS);
sMethodIdOnConfigurationChanged =
sMethodIdRuntimeSensorOnConfigurationChanged =
GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onConfigurationChanged", "(IZII)I");
sMethodIdRuntimeSensorOnDirectChannelCreated =
GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onDirectChannelCreated",
"(Landroid/os/ParcelFileDescriptor;)I");
sMethodIdRuntimeSensorOnDirectChannelDestroyed =
GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onDirectChannelDestroyed", "(I)V");
sMethodIdRuntimeSensorOnDirectChannelConfigured =
GetMethodIDOrDie(env, runtimeSensorCallbackClass, "onDirectChannelConfigured",
"(III)I");
return jniRegisterNativeMethods(env, "com/android/server/sensors/SensorService", methods,
NELEM(methods));
}

View File

@@ -81,7 +81,7 @@ public class SensorControllerTest {
@Test
public void createSensor_invalidHandle_throwsException() {
doReturn(/* handle= */0).when(mSensorManagerInternalMock).createRuntimeSensor(
anyInt(), anyInt(), anyString(), anyString(), any());
anyInt(), anyInt(), anyString(), anyString(), anyInt(), any());
Throwable thrown = assertThrows(
RuntimeException.class,
@@ -138,7 +138,7 @@ public class SensorControllerTest {
private void doCreateSensorSuccessfully() {
doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
anyInt(), anyInt(), anyString(), anyString(), any());
anyInt(), anyInt(), anyString(), anyString(), anyInt(), any());
assertThat(mSensorController.createSensor(mSensorToken, mVirtualSensorConfig))
.isEqualTo(SENSOR_HANDLE);
}

View File

@@ -500,7 +500,7 @@ public class VirtualDeviceManagerServiceTest {
.build();
doReturn(SENSOR_HANDLE).when(mSensorManagerInternalMock).createRuntimeSensor(
anyInt(), anyInt(), anyString(), anyString(), any());
anyInt(), anyInt(), anyString(), anyString(), anyInt(), any());
mDeviceImpl = createVirtualDevice(VIRTUAL_DEVICE_ID_1, DEVICE_OWNER_UID_1, params);
VirtualSensor sensor = mLocalService.getVirtualSensor(VIRTUAL_DEVICE_ID_1, SENSOR_HANDLE);