Sensors: Use a native_handle for the data channel instead of a single file descriptor.
This eliminates the requirement that all sensors share a single file descriptor. This, along with concurrent changes in other projects, fixes bugs b/1614524 and b/1614481 Signed-off-by: Mike Lockwood <lockwood@android.com>
This commit is contained in:
@@ -17,13 +17,13 @@
|
|||||||
|
|
||||||
package android.hardware;
|
package android.hardware;
|
||||||
|
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.Bundle;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* {@hide}
|
* {@hide}
|
||||||
*/
|
*/
|
||||||
interface ISensorService
|
interface ISensorService
|
||||||
{
|
{
|
||||||
ParcelFileDescriptor getDataChanel();
|
Bundle getDataChannel();
|
||||||
boolean enableSensor(IBinder listener, String name, int sensor, int enable);
|
boolean enableSensor(IBinder listener, String name, int sensor, int enable);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,7 +18,9 @@ package android.hardware;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
|
import android.os.Bundle;
|
||||||
import android.os.Looper;
|
import android.os.Looper;
|
||||||
|
import android.os.Parcelable;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.ParcelFileDescriptor;
|
||||||
import android.os.Process;
|
import android.os.Process;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
@@ -280,8 +282,8 @@ public class SensorManager
|
|||||||
void startLocked(ISensorService service) {
|
void startLocked(ISensorService service) {
|
||||||
try {
|
try {
|
||||||
if (mThread == null) {
|
if (mThread == null) {
|
||||||
ParcelFileDescriptor fd = service.getDataChanel();
|
Bundle dataChannel = service.getDataChannel();
|
||||||
mThread = new Thread(new SensorThreadRunnable(fd),
|
mThread = new Thread(new SensorThreadRunnable(dataChannel),
|
||||||
SensorThread.class.getName());
|
SensorThread.class.getName());
|
||||||
mThread.start();
|
mThread.start();
|
||||||
}
|
}
|
||||||
@@ -291,10 +293,52 @@ public class SensorManager
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class SensorThreadRunnable implements Runnable {
|
private class SensorThreadRunnable implements Runnable {
|
||||||
private ParcelFileDescriptor mSensorDataFd;
|
private Bundle mDataChannel;
|
||||||
SensorThreadRunnable(ParcelFileDescriptor fd) {
|
SensorThreadRunnable(Bundle dataChannel) {
|
||||||
mSensorDataFd = fd;
|
mDataChannel = dataChannel;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private boolean open() {
|
||||||
|
if (mDataChannel == null) {
|
||||||
|
Log.e(TAG, "mDataChannel == NULL, exiting");
|
||||||
|
synchronized (sListeners) {
|
||||||
|
mThread = null;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// this thread is guaranteed to be unique
|
||||||
|
Parcelable[] pfds = mDataChannel.getParcelableArray("fds");
|
||||||
|
FileDescriptor[] fds;
|
||||||
|
if (pfds != null) {
|
||||||
|
int length = pfds.length;
|
||||||
|
fds = new FileDescriptor[length];
|
||||||
|
for (int i = 0; i < length; i++) {
|
||||||
|
ParcelFileDescriptor pfd = (ParcelFileDescriptor)pfds[i];
|
||||||
|
fds[i] = pfd.getFileDescriptor();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fds = null;
|
||||||
|
}
|
||||||
|
int[] ints = mDataChannel.getIntArray("ints");
|
||||||
|
sensors_data_open(fds, ints);
|
||||||
|
if (pfds != null) {
|
||||||
|
try {
|
||||||
|
// close our copies of the file descriptors,
|
||||||
|
// since we are just passing these to the JNI code and not using them here.
|
||||||
|
for (int i = pfds.length - 1; i >= 0; i--) {
|
||||||
|
ParcelFileDescriptor pfd = (ParcelFileDescriptor)pfds[i];
|
||||||
|
pfd.close();
|
||||||
|
}
|
||||||
|
} catch (IOException e) {
|
||||||
|
// *shrug*
|
||||||
|
Log.e(TAG, "IOException: ", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mDataChannel = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
public void run() {
|
public void run() {
|
||||||
//Log.d(TAG, "entering main sensor thread");
|
//Log.d(TAG, "entering main sensor thread");
|
||||||
final float[] values = new float[3];
|
final float[] values = new float[3];
|
||||||
@@ -302,23 +346,9 @@ public class SensorManager
|
|||||||
final long timestamp[] = new long[1];
|
final long timestamp[] = new long[1];
|
||||||
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
|
Process.setThreadPriority(Process.THREAD_PRIORITY_DISPLAY);
|
||||||
|
|
||||||
if (mSensorDataFd == null) {
|
if (!open()) {
|
||||||
Log.e(TAG, "mSensorDataFd == NULL, exiting");
|
|
||||||
synchronized (sListeners) {
|
|
||||||
mThread = null;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// this thread is guaranteed to be unique
|
|
||||||
sensors_data_open(mSensorDataFd.getFileDescriptor());
|
|
||||||
try {
|
|
||||||
mSensorDataFd.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
// *shrug*
|
|
||||||
Log.e(TAG, "IOException: ", e);
|
|
||||||
}
|
|
||||||
mSensorDataFd = null;
|
|
||||||
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
// wait for an event
|
// wait for an event
|
||||||
@@ -1469,7 +1499,7 @@ public class SensorManager
|
|||||||
// Used within this module from outside SensorManager, don't make private
|
// Used within this module from outside SensorManager, don't make private
|
||||||
static native int sensors_data_init();
|
static native int sensors_data_init();
|
||||||
static native int sensors_data_uninit();
|
static native int sensors_data_uninit();
|
||||||
static native int sensors_data_open(FileDescriptor fd);
|
static native int sensors_data_open(FileDescriptor[] fds, int[] ints);
|
||||||
static native int sensors_data_close();
|
static native int sensors_data_close();
|
||||||
static native int sensors_data_poll(float[] values, int[] status, long[] timestamp);
|
static native int sensors_data_poll(float[] values, int[] status, long[] timestamp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,9 +14,13 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LOG_TAG "Sensors"
|
#define LOG_TAG "SensorManager"
|
||||||
|
|
||||||
|
#define LOG_NDEBUG 0
|
||||||
|
#include "utils/Log.h"
|
||||||
|
|
||||||
#include <hardware/sensors.h>
|
#include <hardware/sensors.h>
|
||||||
|
#include <cutils/native_handle.h>
|
||||||
|
|
||||||
#include "jni.h"
|
#include "jni.h"
|
||||||
#include "JNIHelp.h"
|
#include "JNIHelp.h"
|
||||||
@@ -106,12 +110,33 @@ sensors_data_uninit(JNIEnv *env, jclass clazz)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static jint
|
static jint
|
||||||
sensors_data_open(JNIEnv *env, jclass clazz, jobject fdo)
|
sensors_data_open(JNIEnv *env, jclass clazz, jobjectArray fdArray, jintArray intArray)
|
||||||
{
|
{
|
||||||
jclass FileDescriptor = env->FindClass("java/io/FileDescriptor");
|
jclass FileDescriptor = env->FindClass("java/io/FileDescriptor");
|
||||||
jfieldID offset = env->GetFieldID(FileDescriptor, "descriptor", "I");
|
jfieldID fieldOffset = env->GetFieldID(FileDescriptor, "descriptor", "I");
|
||||||
int fd = env->GetIntField(fdo, offset);
|
int numFds = (fdArray ? env->GetArrayLength(fdArray) : 0);
|
||||||
return sSensorDevice->data_open(sSensorDevice, fd); // doesn't take ownership of fd
|
int numInts = (intArray ? env->GetArrayLength(intArray) : 0);
|
||||||
|
native_handle_t* handle = native_handle_create(numFds, numInts);
|
||||||
|
int offset = 0;
|
||||||
|
|
||||||
|
for (int i = 0; i < numFds; i++) {
|
||||||
|
jobject fdo = env->GetObjectArrayElement(fdArray, i);
|
||||||
|
if (fdo) {
|
||||||
|
handle->data[offset++] = env->GetIntField(fdo, fieldOffset);
|
||||||
|
} else {
|
||||||
|
handle->data[offset++] = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (numInts > 0) {
|
||||||
|
jint* ints = env->GetIntArrayElements(intArray, 0);
|
||||||
|
for (int i = 0; i < numInts; i++) {
|
||||||
|
handle->data[offset++] = ints[i];
|
||||||
|
}
|
||||||
|
env->ReleaseIntArrayElements(intArray, ints, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// doesn't take ownership of the native handle
|
||||||
|
return sSensorDevice->data_open(sSensorDevice, handle);
|
||||||
}
|
}
|
||||||
|
|
||||||
static jint
|
static jint
|
||||||
@@ -157,7 +182,7 @@ static JNINativeMethod gMethods[] = {
|
|||||||
(void*)sensors_module_get_next_sensor },
|
(void*)sensors_module_get_next_sensor },
|
||||||
{"sensors_data_init", "()I", (void*)sensors_data_init },
|
{"sensors_data_init", "()I", (void*)sensors_data_init },
|
||||||
{"sensors_data_uninit", "()I", (void*)sensors_data_uninit },
|
{"sensors_data_uninit", "()I", (void*)sensors_data_uninit },
|
||||||
{"sensors_data_open", "(Ljava/io/FileDescriptor;)I", (void*)sensors_data_open },
|
{"sensors_data_open", "([Ljava/io/FileDescriptor;[I)I", (void*)sensors_data_open },
|
||||||
{"sensors_data_close", "()I", (void*)sensors_data_close },
|
{"sensors_data_close", "()I", (void*)sensors_data_close },
|
||||||
{"sensors_data_poll", "([F[I[J)I", (void*)sensors_data_poll },
|
{"sensors_data_poll", "([F[I[J)I", (void*)sensors_data_poll },
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ package com.android.server;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.hardware.ISensorService;
|
import android.hardware.ISensorService;
|
||||||
import android.os.Binder;
|
import android.os.Binder;
|
||||||
import android.os.ParcelFileDescriptor;
|
import android.os.Bundle;
|
||||||
import android.os.RemoteException;
|
import android.os.RemoteException;
|
||||||
import android.os.IBinder;
|
import android.os.IBinder;
|
||||||
import android.util.Config;
|
import android.util.Config;
|
||||||
@@ -101,7 +101,7 @@ class SensorService extends ISensorService.Stub {
|
|||||||
_sensors_control_init();
|
_sensors_control_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParcelFileDescriptor getDataChanel() throws RemoteException {
|
public Bundle getDataChannel() throws RemoteException {
|
||||||
return _sensors_control_open();
|
return _sensors_control_open();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -190,7 +190,7 @@ class SensorService extends ISensorService.Stub {
|
|||||||
ArrayList<Listener> mListeners = new ArrayList<Listener>();
|
ArrayList<Listener> mListeners = new ArrayList<Listener>();
|
||||||
|
|
||||||
private static native int _sensors_control_init();
|
private static native int _sensors_control_init();
|
||||||
private static native ParcelFileDescriptor _sensors_control_open();
|
private static native Bundle _sensors_control_open();
|
||||||
private static native boolean _sensors_control_activate(int sensor, boolean activate);
|
private static native boolean _sensors_control_activate(int sensor, boolean activate);
|
||||||
private static native int _sensors_control_set_delay(int ms);
|
private static native int _sensors_control_set_delay(int ms);
|
||||||
private static native int _sensors_control_wake();
|
private static native int _sensors_control_wake();
|
||||||
|
|||||||
@@ -14,7 +14,10 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define LOG_TAG "Sensors"
|
#define LOG_TAG "SensorService"
|
||||||
|
|
||||||
|
#define LOG_NDEBUG 0
|
||||||
|
#include "utils/Log.h"
|
||||||
|
|
||||||
#include <hardware/sensors.h>
|
#include <hardware/sensors.h>
|
||||||
|
|
||||||
@@ -36,6 +39,14 @@ static struct parcel_file_descriptor_offsets_t
|
|||||||
jmethodID mConstructor;
|
jmethodID mConstructor;
|
||||||
} gParcelFileDescriptorOffsets;
|
} gParcelFileDescriptorOffsets;
|
||||||
|
|
||||||
|
static struct bundle_descriptor_offsets_t
|
||||||
|
{
|
||||||
|
jclass mClass;
|
||||||
|
jmethodID mConstructor;
|
||||||
|
jmethodID mPutIntArray;
|
||||||
|
jmethodID mPutParcelableArray;
|
||||||
|
} gBundleOffsets;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The method below are not thread-safe and not intended to be
|
* The method below are not thread-safe and not intended to be
|
||||||
*/
|
*/
|
||||||
@@ -59,21 +70,45 @@ android_init(JNIEnv *env, jclass clazz)
|
|||||||
static jobject
|
static jobject
|
||||||
android_open(JNIEnv *env, jclass clazz)
|
android_open(JNIEnv *env, jclass clazz)
|
||||||
{
|
{
|
||||||
int fd = sSensorDevice->open_data_source(sSensorDevice);
|
native_handle_t* handle = sSensorDevice->open_data_source(sSensorDevice);
|
||||||
// new FileDescriptor()
|
if (!handle) {
|
||||||
jobject filedescriptor = env->NewObject(
|
return NULL;
|
||||||
gFileDescriptorOffsets.mClass,
|
|
||||||
gFileDescriptorOffsets.mConstructor);
|
|
||||||
|
|
||||||
if (filedescriptor != NULL) {
|
|
||||||
env->SetIntField(filedescriptor, gFileDescriptorOffsets.mDescriptor, fd);
|
|
||||||
// new ParcelFileDescriptor()
|
|
||||||
return env->NewObject(gParcelFileDescriptorOffsets.mClass,
|
|
||||||
gParcelFileDescriptorOffsets.mConstructor,
|
|
||||||
filedescriptor);
|
|
||||||
}
|
}
|
||||||
close(fd);
|
|
||||||
return NULL;
|
// new Bundle()
|
||||||
|
jobject bundle = env->NewObject(
|
||||||
|
gBundleOffsets.mClass,
|
||||||
|
gBundleOffsets.mConstructor);
|
||||||
|
|
||||||
|
if (handle->numFds > 0) {
|
||||||
|
jobjectArray fdArray = env->NewObjectArray(handle->numFds,
|
||||||
|
gParcelFileDescriptorOffsets.mClass, NULL);
|
||||||
|
for (int i = 0; i < handle->numFds; i++) {
|
||||||
|
// new FileDescriptor()
|
||||||
|
jobject fd = env->NewObject(gFileDescriptorOffsets.mClass,
|
||||||
|
gFileDescriptorOffsets.mConstructor);
|
||||||
|
env->SetIntField(fd, gFileDescriptorOffsets.mDescriptor, handle->data[i]);
|
||||||
|
// new ParcelFileDescriptor()
|
||||||
|
jobject pfd = env->NewObject(gParcelFileDescriptorOffsets.mClass,
|
||||||
|
gParcelFileDescriptorOffsets.mConstructor, fd);
|
||||||
|
env->SetObjectArrayElement(fdArray, i, pfd);
|
||||||
|
}
|
||||||
|
// bundle.putParcelableArray("fds", fdArray);
|
||||||
|
env->CallVoidMethod(bundle, gBundleOffsets.mPutParcelableArray,
|
||||||
|
env->NewStringUTF("fds"), fdArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (handle->numInts > 0) {
|
||||||
|
jintArray intArray = env->NewIntArray(handle->numInts);
|
||||||
|
env->SetIntArrayRegion(intArray, 0, handle->numInts, &handle->data[handle->numInts]);
|
||||||
|
// bundle.putIntArray("ints", intArray);
|
||||||
|
env->CallVoidMethod(bundle, gBundleOffsets.mPutIntArray,
|
||||||
|
env->NewStringUTF("ints"), intArray);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete the file handle, but don't close any file descriptors
|
||||||
|
native_handle_delete(handle);
|
||||||
|
return bundle;
|
||||||
}
|
}
|
||||||
|
|
||||||
static jboolean
|
static jboolean
|
||||||
@@ -99,7 +134,7 @@ android_data_wake(JNIEnv *env, jclass clazz)
|
|||||||
|
|
||||||
static JNINativeMethod gMethods[] = {
|
static JNINativeMethod gMethods[] = {
|
||||||
{"_sensors_control_init", "()I", (void*) android_init },
|
{"_sensors_control_init", "()I", (void*) android_init },
|
||||||
{"_sensors_control_open", "()Landroid/os/ParcelFileDescriptor;", (void*) android_open },
|
{"_sensors_control_open", "()Landroid/os/Bundle;", (void*) android_open },
|
||||||
{"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
|
{"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
|
||||||
{"_sensors_control_wake", "()I", (void*) android_data_wake },
|
{"_sensors_control_wake", "()I", (void*) android_data_wake },
|
||||||
{"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
|
{"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
|
||||||
@@ -116,7 +151,15 @@ int register_android_server_SensorService(JNIEnv *env)
|
|||||||
|
|
||||||
clazz = env->FindClass("android/os/ParcelFileDescriptor");
|
clazz = env->FindClass("android/os/ParcelFileDescriptor");
|
||||||
gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
|
gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
|
||||||
gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "(Ljava/io/FileDescriptor;)V");
|
gParcelFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>",
|
||||||
|
"(Ljava/io/FileDescriptor;)V");
|
||||||
|
|
||||||
|
clazz = env->FindClass("android/os/Bundle");
|
||||||
|
gBundleOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
|
||||||
|
gBundleOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
|
||||||
|
gBundleOffsets.mPutIntArray = env->GetMethodID(clazz, "putIntArray", "(Ljava/lang/String;[I)V");
|
||||||
|
gBundleOffsets.mPutParcelableArray = env->GetMethodID(clazz, "putParcelableArray",
|
||||||
|
"(Ljava/lang/String;[Landroid/os/Parcelable;)V");
|
||||||
|
|
||||||
return jniRegisterNativeMethods(env, "com/android/server/SensorService",
|
return jniRegisterNativeMethods(env, "com/android/server/SensorService",
|
||||||
gMethods, NELEM(gMethods));
|
gMethods, NELEM(gMethods));
|
||||||
|
|||||||
Reference in New Issue
Block a user