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:
Mike Lockwood
2009-05-22 10:02:14 -04:00
parent fea1a459aa
commit 270e87f71a
5 changed files with 147 additions and 49 deletions

View File

@@ -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);
} }

View File

@@ -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);
} }

View File

@@ -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 },
}; };

View File

@@ -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();

View File

@@ -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));