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

Commit 398e1183 authored by Aravind Akella's avatar Aravind Akella Committed by Android (Google) Code Review
Browse files

Merge "Add hidden SensorManager APIs for injecting sensor data."

parents 09f9a7ad 18ebf732
Loading
Loading
Loading
Loading
+3 −0
Original line number Diff line number Diff line
@@ -13256,6 +13256,7 @@ package android.hardware {
    method public int getType();
    method public java.lang.String getVendor();
    method public int getVersion();
    method public boolean isDataInjectionSupported();
    method public boolean isWakeUpSensor();
    field public static final int REPORTING_MODE_CONTINUOUS = 0; // 0x0
    field public static final int REPORTING_MODE_ONE_SHOT = 2; // 0x2
@@ -13331,6 +13332,7 @@ package android.hardware {
  public abstract class SensorManager {
    method public boolean cancelTriggerSensor(android.hardware.TriggerEventListener, android.hardware.Sensor);
    method public boolean enableDataInjectionMode(boolean);
    method public boolean flush(android.hardware.SensorEventListener);
    method public static float getAltitude(float, float);
    method public static void getAngleChange(float[], float[], float[]);
@@ -13343,6 +13345,7 @@ package android.hardware {
    method public static void getRotationMatrixFromVector(float[], float[]);
    method public java.util.List<android.hardware.Sensor> getSensorList(int);
    method public deprecated int getSensors();
    method public boolean injectSensorData(android.hardware.Sensor, float[], int, long);
    method public deprecated boolean registerListener(android.hardware.SensorListener, int);
    method public deprecated boolean registerListener(android.hardware.SensorListener, int, int);
    method public boolean registerListener(android.hardware.SensorEventListener, android.hardware.Sensor, int);
+18 −0
Original line number Diff line number Diff line
@@ -580,6 +580,10 @@ public final class Sensor {
    private static final int REPORTING_MODE_MASK = 0xE;
    private static final int REPORTING_MODE_SHIFT = 1;

    // MASK for LSB fifth bit. Used to know whether the sensor supports data injection or not.
    private static final int DATA_INJECTION_MASK = 0x10;
    private static final int DATA_INJECTION_SHIFT = 4;

    // TODO(): The following arrays are fragile and error-prone. This needs to be refactored.

    // Note: This needs to be updated, whenever a new sensor is added.
@@ -822,6 +826,20 @@ public final class Sensor {
        return (mFlags & SENSOR_FLAG_WAKE_UP_SENSOR) != 0;
    }

    /**
     * Returns true if the sensor supports data injection when the
     * HAL is set to data injection mode.
     *
     * @return <code>true</code> if the sensor supports data
     *         injection when the HAL is set in injection mode,
     *         false otherwise.
     * @hide
     */
    @SystemApi
    public boolean isDataInjectionSupported() {
        return (((mFlags & DATA_INJECTION_MASK) >> DATA_INJECTION_SHIFT)) != 0;
    }

    void setRange(float max, float res) {
        mMaxRange = max;
        mResolution = res;
+100 −0
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@

package android.hardware;

import android.annotation.SystemApi;
import android.os.Build;
import android.os.Handler;
import android.os.SystemClock;
import android.util.Log;
import android.util.SparseArray;

@@ -1555,6 +1558,103 @@ public abstract class SensorManager {
            Sensor sensor, boolean disable);


    /**
     * For testing purposes only. Not for third party applications.
     *
     * Enable data injection mode in sensor service. This mode is
     * expected to be used only for testing purposes. If the HAL is
     * set to data injection mode, it will ignore the input from
     * physical sensors and read sensor data that is injected from
     * the test application. This mode is used for testing vendor
     * implementations for various algorithms like Rotation Vector,
     * Significant Motion, Step Counter etc.
     *
     * The tests which call this API need to have {@code
     * android.permission.HARDWARE_TEST} permission which isn't
     * available for third party applications.
     *
     * @param enable True to set the HAL in DATA_INJECTION mode.
     *               False to reset the HAL back to NORMAL mode.
     *
     * @return true if the HAL supports data injection and false
     *         otherwise.
     * @hide
     */
    @SystemApi
    public boolean enableDataInjectionMode(boolean enable) {
          return enableDataInjectionImpl(enable);
    }

    /**
     * @hide
     */
    protected abstract boolean enableDataInjectionImpl(boolean enable);

    /**
     * For testing purposes only. Not for third party applications.
     *
     * This method is used to inject raw sensor data into the HAL.
     * Call enableDataInjection before this method to set the HAL in
     * data injection mode. This method should be called only if a
     * previous call to enableDataInjection has been successful and
     * the HAL is already in data injection mode.
     *
     * The tests which call this API need to have {@code
     * android.permission.HARDWARE_TEST} permission which isn't
     * available for third party applications.
     *
     * @param sensor The sensor to inject.
     * @param values Sensor values to inject. The length of this
     *               array must be exactly equal to the number of
     *               values reported by the sensor type.
     * @param accuracy Accuracy of the sensor.
     * @param timestamp Sensor timestamp associated with the event.
     *
     * @return boolean True if the data injection succeeds, false
     *         otherwise.
     * @throws IllegalArgumentException when the sensor is null,
     *         data injection is not supported by the sensor, values
     *         are null, incorrect number of values for the sensor,
     *         sensor accuracy is incorrect or timestamps are
     *         invalid.
     * @hide
     */
    @SystemApi
    public boolean injectSensorData(Sensor sensor, float[] values, int accuracy,
                long timestamp) {
        if (sensor == null) {
            throw new IllegalArgumentException("sensor cannot be null");
        }
        if (!sensor.isDataInjectionSupported()) {
            throw new IllegalArgumentException("sensor does not support data injection");
        }
        if (values == null) {
            throw new IllegalArgumentException("sensor data cannot be null");
        }
        int expectedNumValues = Sensor.getMaxLengthValuesArray(sensor, Build.VERSION_CODES.MNC);
        if (values.length != expectedNumValues) {
            throw new  IllegalArgumentException ("Wrong number of values for sensor " +
                    sensor.getName() + " actual=" + values.length + " expected=" +
                                                  expectedNumValues);
        }
        if (accuracy < SENSOR_STATUS_NO_CONTACT || accuracy > SENSOR_STATUS_ACCURACY_HIGH) {
            throw new IllegalArgumentException("Invalid sensor accuracy");
        }
        if (timestamp <= 0) {
            throw new IllegalArgumentException("Negative or zero sensor timestamp");
        }
        if (timestamp > SystemClock.elapsedRealtimeNanos()) {
            throw new IllegalArgumentException("Sensor timestamp into the future");
        }
        return injectSensorDataImpl(sensor, values, accuracy, timestamp);
    }

    /**
     * @hide
     */
    protected abstract boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
                long timestamp);

    private LegacySensorManager getLegacySensorManager() {
        synchronized (mSensorListByType) {
            if (mLegacySensorManager == null) {
+105 −7
Original line number Diff line number Diff line
@@ -16,7 +16,9 @@

package android.hardware;

import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.os.MessageQueue;
@@ -40,11 +42,14 @@ import java.util.List;
public class SystemSensorManager extends SensorManager {
    private static native void nativeClassInit();
    private static native int nativeGetNextSensor(Sensor sensor, int next);
    private static native int nativeEnableDataInjection(boolean enable);

    private static boolean sSensorModuleInitialized = false;
    private static final Object sSensorModuleLock = new Object();
    private static final ArrayList<Sensor> sFullSensorsList = new ArrayList<Sensor>();
    private static final SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
    private static InjectEventQueue mInjectEventQueue = null;
    private static boolean mDataInjectionMode = false;

    // Listener list
    private final HashMap<SensorEventListener, SensorEventQueue> mSensorListeners =
@@ -56,6 +61,7 @@ public class SystemSensorManager extends SensorManager {
    private final Looper mMainLooper;
    private final int mTargetSdkLevel;
    private final String mPackageName;
    private final boolean mHasDataInjectionPermissions;

    /** {@hide} */
    public SystemSensorManager(Context context, Looper mainLooper) {
@@ -82,6 +88,8 @@ public class SystemSensorManager extends SensorManager {
                    }
                } while (i>0);
            }
            mHasDataInjectionPermissions = context.checkSelfPermission(
                    Manifest.permission.HARDWARE_TEST) == PackageManager.PERMISSION_GRANTED;
        }
    }

@@ -219,19 +227,72 @@ public class SystemSensorManager extends SensorManager {
        }
    }

    protected boolean enableDataInjectionImpl(boolean enable) {
        if (!mHasDataInjectionPermissions) {
            throw new SecurityException("Permission denial. Calling enableDataInjection without "
                    + Manifest.permission.HARDWARE_TEST);
        }
        synchronized (sSensorModuleLock) {
            int ret = nativeEnableDataInjection(enable);
            // The HAL does not support injection. Ignore.
            if (ret != 0) {
                Log.e(TAG, "HAL does not support data injection");
                return false;
            }
            mDataInjectionMode = enable;
            // If data injection is being disabled clean up the native resources.
            if (!enable && mInjectEventQueue != null) {
                mInjectEventQueue.dispose();
                mInjectEventQueue = null;
            }
            return true;
        }
    }

    protected boolean injectSensorDataImpl(Sensor sensor, float[] values, int accuracy,
            long timestamp) {
        if (!mHasDataInjectionPermissions) {
            throw new SecurityException("Permission denial. Calling injectSensorData without "
                    + Manifest.permission.HARDWARE_TEST);
        }
        synchronized (sSensorModuleLock) {
            if (!mDataInjectionMode) {
                Log.e(TAG, "Data injection mode not activated before calling injectSensorData");
                return false;
            }
            if (mInjectEventQueue == null) {
                mInjectEventQueue = new InjectEventQueue(mMainLooper, this);
            }
            int ret = mInjectEventQueue.injectSensorData(sensor.getHandle(), values, accuracy,
                                                         timestamp);
            // If there are any errors in data injection clean up the native resources.
            if (ret != 0) {
                mInjectEventQueue.dispose();
                mInjectEventQueue = null;
                mDataInjectionMode = false;
            }
            return ret == 0;
        }
    }

    /*
     * BaseEventQueue is the communication channel with the sensor service,
     * SensorEventQueue, TriggerEventQueue are subclases and there is one-to-one mapping between
     * the queues and the listeners.
     * the queues and the listeners. InjectEventQueue is also a sub-class which is a special case
     * where data is being injected into the sensor HAL through the sensor service. It is not
     * associated with any listener and there is one InjectEventQueue associated with a
     * SensorManager instance.
     */
    private static abstract class BaseEventQueue {
        private native long nativeInitBaseEventQueue(WeakReference<BaseEventQueue> eventQWeak,
                MessageQueue msgQ, float[] scratch, String packageName);
               MessageQueue msgQ, float[] scratch, String packageName, int mode);
        private static native int nativeEnableSensor(long eventQ, int handle, int rateUs,
                int maxBatchReportLatencyUs);
        private static native int nativeDisableSensor(long eventQ, int handle);
        private static native void nativeDestroySensorEventQueue(long eventQ);
        private static native int nativeFlushSensor(long eventQ);
        private static native int nativeInjectSensorData(long eventQ, int handle,
                                                    float[] values,int accuracy, long timestamp);
        private long nSensorEventQueue;
        private final SparseBooleanArray mActiveSensors = new SparseBooleanArray();
        protected final SparseIntArray mSensorAccuracies = new SparseIntArray();
@@ -240,10 +301,12 @@ public class SystemSensorManager extends SensorManager {
        private final float[] mScratch = new float[16];
        protected final SystemSensorManager mManager;

        BaseEventQueue(Looper looper, SystemSensorManager manager) {
        protected static final int OPERATING_MODE_NORMAL = 0;
        protected static final int OPERATING_MODE_DATA_INJECTION = 1;

        BaseEventQueue(Looper looper, SystemSensorManager manager, int mode) {
            nSensorEventQueue = nativeInitBaseEventQueue(new WeakReference<BaseEventQueue>(this),
                    looper.getQueue(), mScratch,
                    manager.mPackageName);
                    looper.getQueue(), mScratch, manager.mPackageName, mode);
            mCloseGuard.open("dispose");
            mManager = manager;
        }
@@ -340,6 +403,11 @@ public class SystemSensorManager extends SensorManager {
                    maxBatchReportLatencyUs);
        }

        protected int injectSensorDataBase(int handle, float[] values, int accuracy,
                                           long timestamp) {
            return nativeInjectSensorData(nSensorEventQueue, handle, values, accuracy, timestamp);
        }

        private int disableSensor(Sensor sensor) {
            if (nSensorEventQueue == 0) throw new NullPointerException();
            if (sensor == null) throw new NullPointerException();
@@ -359,7 +427,7 @@ public class SystemSensorManager extends SensorManager {

        public SensorEventQueue(SensorEventListener listener, Looper looper,
                SystemSensorManager manager) {
            super(looper, manager);
            super(looper, manager, OPERATING_MODE_NORMAL);
            mListener = listener;
        }

@@ -426,7 +494,7 @@ public class SystemSensorManager extends SensorManager {

        public TriggerEventQueue(TriggerEventListener listener, Looper looper,
                SystemSensorManager manager) {
            super(looper, manager);
            super(looper, manager, OPERATING_MODE_NORMAL);
            mListener = listener;
        }

@@ -477,4 +545,34 @@ public class SystemSensorManager extends SensorManager {
        protected void dispatchFlushCompleteEvent(int handle) {
        }
    }

    static final class InjectEventQueue extends BaseEventQueue {
        public InjectEventQueue(Looper looper, SystemSensorManager manager) {
            super(looper, manager, OPERATING_MODE_DATA_INJECTION);
        }

        int injectSensorData(int handle, float[] values,int accuracy, long timestamp) {
             return injectSensorDataBase(handle, values, accuracy, timestamp);
        }

        @SuppressWarnings("unused")
        protected void dispatchSensorEvent(int handle, float[] values, int accuracy,
                long timestamp) {
        }

        @SuppressWarnings("unused")
        protected void dispatchFlushCompleteEvent(int handle) {

        }

        @SuppressWarnings("unused")
        protected void addSensorEvent(Sensor sensor) {

        }

        @SuppressWarnings("unused")
        protected void removeSensorEvent(Sensor sensor) {

        }
    }
}
+28 −5
Original line number Diff line number Diff line
@@ -174,6 +174,11 @@ nativeGetNextSensor(JNIEnv *env, jclass clazz, jobject sensor, jint next)
    return size_t(next) < count ? next : 0;
}

static int nativeEnableDataInjection(JNIEnv *_env, jclass _this, jboolean enable) {
     SensorManager& mgr(SensorManager::getInstance());
     return mgr.enableDataInjection(enable);
}

//----------------------------------------------------------------------------

class Receiver : public LooperCallback {
@@ -277,11 +282,11 @@ private:
};

static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject eventQWeak, jobject msgQ,
        jfloatArray scratch, jstring packageName) {
        jfloatArray scratch, jstring packageName, jint mode) {
    SensorManager& mgr(SensorManager::getInstance());
    ScopedUtfChars packageUtf(env, packageName);
    String8 clientName(packageUtf.c_str());
    sp<SensorEventQueue> queue(mgr.createEventQueue(clientName));
    sp<SensorEventQueue> queue(mgr.createEventQueue(clientName, mode));

    sp<MessageQueue> messageQueue = android_os_MessageQueue_getMessageQueue(env, msgQ);
    if (messageQueue == NULL) {
@@ -297,7 +302,6 @@ static jlong nativeInitSensorEventQueue(JNIEnv *env, jclass clazz, jobject event
static jint nativeEnableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint handle, jint rate_us,
                               jint maxBatchReportLatency) {
    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));

    return receiver->getSensorEventQueue()->enableSensor(handle, rate_us, maxBatchReportLatency,
                                                         0);
}
@@ -307,7 +311,7 @@ static jint nativeDisableSensor(JNIEnv *env, jclass clazz, jlong eventQ, jint ha
    return receiver->getSensorEventQueue()->disableSensor(handle);
}

static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ, jint handle) {
static void nativeDestroySensorEventQueue(JNIEnv *env, jclass clazz, jlong eventQ) {
    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    receiver->destroy();
    receiver->decStrong((void*)nativeInitSensorEventQueue);
@@ -318,6 +322,17 @@ static jint nativeFlushSensor(JNIEnv *env, jclass clazz, jlong eventQ) {
    return receiver->getSensorEventQueue()->flush();
}

static jint nativeInjectSensorData(JNIEnv *env, jclass clazz, jlong eventQ, jint handle,
        jfloatArray values, jint accuracy, jlong timestamp) {
    sp<Receiver> receiver(reinterpret_cast<Receiver *>(eventQ));
    // Create a sensor_event from the above data which can be injected into the HAL.
    ASensorEvent sensor_event;
    memset(&sensor_event, 0, sizeof(sensor_event));
    sensor_event.sensor = handle;
    sensor_event.timestamp = timestamp;
    env->GetFloatArrayRegion(values, 0, env->GetArrayLength(values), sensor_event.data);
    return receiver->getSensorEventQueue()->injectSensorEvent(sensor_event);
}
//----------------------------------------------------------------------------

static JNINativeMethod gSystemSensorManagerMethods[] = {
@@ -328,11 +343,15 @@ static JNINativeMethod gSystemSensorManagerMethods[] = {
    {"nativeGetNextSensor",
            "(Landroid/hardware/Sensor;I)I",
            (void*)nativeGetNextSensor },

    {"nativeEnableDataInjection",
            "(Z)I",
            (void*)nativeEnableDataInjection },
};

static JNINativeMethod gBaseEventQueueMethods[] = {
    {"nativeInitBaseEventQueue",
     "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;)J",
     "(Ljava/lang/ref/WeakReference;Landroid/os/MessageQueue;[FLjava/lang/String;I)J",
     (void*)nativeInitSensorEventQueue },

    {"nativeEnableSensor",
@@ -350,6 +369,10 @@ static JNINativeMethod gBaseEventQueueMethods[] = {
    {"nativeFlushSensor",
            "(J)I",
            (void*)nativeFlushSensor },

    {"nativeInjectSensorData",
            "(JI[FIJ)I",
            (void*)nativeInjectSensorData },
};

}; // namespace android