Merge "Various changes to improve rtsp networking, reduce packet loss and adapt to ALooper API changes." into gingerbread
diff --git a/Android.mk b/Android.mk
index 69a40c1..5db6610 100644
--- a/Android.mk
+++ b/Android.mk
@@ -113,7 +113,6 @@
 	core/java/android/content/pm/IPackageMoveObserver.aidl \
 	core/java/android/content/pm/IPackageStatsObserver.aidl \
 	core/java/android/database/IContentObserver.aidl \
-	core/java/android/hardware/ISensorService.aidl \
 	core/java/android/net/IConnectivityManager.aidl \
 	core/java/android/net/INetworkManagementEventObserver.aidl \
 	core/java/android/net/IThrottleManager.aidl \
diff --git a/cmds/system_server/library/Android.mk b/cmds/system_server/library/Android.mk
index a880a91..457cbd4 100644
--- a/cmds/system_server/library/Android.mk
+++ b/cmds/system_server/library/Android.mk
@@ -10,11 +10,13 @@
 	$(base)/services/camera/libcameraservice \
 	$(base)/services/audioflinger \
 	$(base)/services/surfaceflinger \
+	$(base)/services/sensorservice \
 	$(base)/media/libmediaplayerservice \
 	$(JNI_H_INCLUDE)
 
 LOCAL_SHARED_LIBRARIES := \
 	libandroid_runtime \
+	libsensorservice \
 	libsurfaceflinger \
 	libaudioflinger \
     libcameraservice \
diff --git a/cmds/system_server/library/system_init.cpp b/cmds/system_server/library/system_init.cpp
index 1d57fdc..a29ba73 100644
--- a/cmds/system_server/library/system_init.cpp
+++ b/cmds/system_server/library/system_init.cpp
@@ -19,6 +19,7 @@
 #include <CameraService.h>
 #include <AudioPolicyService.h>
 #include <MediaPlayerService.h>
+#include <SensorService.h>
 
 #include <android_runtime/AndroidRuntime.h>
 
@@ -69,6 +70,9 @@
         SurfaceFlinger::instantiate();
     }
 
+    // Start the sensor service
+    SensorService::instantiate();
+
     // On the simulator, audioflinger et al don't get started the
     // same way as on the device, and we need to start them here
     if (!proc->supportsProcesses()) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 167bd3c..e99d4b4 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -1198,7 +1198,7 @@
     private DownloadManager getDownloadManager() {
         synchronized (mSync) {
             if (mDownloadManager == null) {
-                mDownloadManager = new DownloadManager(getContentResolver());
+                mDownloadManager = new DownloadManager(getContentResolver(), getPackageName());
             }
         }
         return mDownloadManager;
diff --git a/core/java/android/hardware/ISensorService.aidl b/core/java/android/hardware/ISensorService.aidl
deleted file mode 100644
index 67180bd..0000000
--- a/core/java/android/hardware/ISensorService.aidl
+++ /dev/null
@@ -1,29 +0,0 @@
-/* //device/java/android/android/hardware/ISensorService.aidl
-**
-** Copyright 2008, The Android Open Source Project
-**
-** Licensed under the Apache License, Version 2.0 (the "License"); 
-** you may not use this file except in compliance with the License. 
-** You may obtain a copy of the License at 
-**
-**     http://www.apache.org/licenses/LICENSE-2.0 
-**
-** Unless required by applicable law or agreed to in writing, software 
-** distributed under the License is distributed on an "AS IS" BASIS, 
-** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
-** See the License for the specific language governing permissions and 
-** limitations under the License.
-*/
-
-package android.hardware;
-
-import android.os.Bundle;
-
-/**
- * {@hide}
- */
-interface ISensorService
-{
-    Bundle getDataChannel();
-    boolean enableSensor(IBinder listener, String name, int sensor, int enable);
-}
diff --git a/core/java/android/hardware/SensorManager.java b/core/java/android/hardware/SensorManager.java
index 492f8cc..e6750e6 100644
--- a/core/java/android/hardware/SensorManager.java
+++ b/core/java/android/hardware/SensorManager.java
@@ -16,12 +16,7 @@
 
 package android.hardware;
 
-import android.content.Context;
-import android.os.Binder;
-import android.os.Bundle;
 import android.os.Looper;
-import android.os.Parcelable;
-import android.os.ParcelFileDescriptor;
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.Handler;
@@ -33,8 +28,6 @@
 import android.view.IWindowManager;
 import android.view.Surface;
 
-import java.io.FileDescriptor;
-import java.io.IOException;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
@@ -339,7 +332,6 @@
 
     /*-----------------------------------------------------------------------*/
 
-    private ISensorService mSensorService;
     Looper mMainLooper;
     @SuppressWarnings("deprecation")
     private HashMap<SensorListener, LegacyListener> mLegacyListenersMap =
@@ -356,6 +348,7 @@
     /* The thread and the sensor list are global to the process
      * but the actual thread is spawned on demand */
     private static SensorThread sSensorThread;
+    private static int sQueue;
 
     // Used within this module from outside SensorManager, don't make private
     static SparseArray<Sensor> sHandleToSensor = new SparseArray<Sensor>();
@@ -370,80 +363,41 @@
         boolean mSensorsReady;
 
         SensorThread() {
-            // this gets to the sensor module. We can have only one per process.
-            sensors_data_init();
         }
 
         @Override
         protected void finalize() {
-            sensors_data_uninit();
         }
 
         // must be called with sListeners lock
-        boolean startLocked(ISensorService service) {
+        boolean startLocked() {
             try {
                 if (mThread == null) {
-                    Bundle dataChannel = service.getDataChannel();
-                    if (dataChannel != null) {
-                        mSensorsReady = false;
-                        SensorThreadRunnable runnable = new SensorThreadRunnable(dataChannel);
-                        Thread thread = new Thread(runnable, SensorThread.class.getName());
-                        thread.start();
-                        synchronized (runnable) {
-                            while (mSensorsReady == false) {
-                                runnable.wait();
-                            }
+                    mSensorsReady = false;
+                    SensorThreadRunnable runnable = new SensorThreadRunnable();
+                    Thread thread = new Thread(runnable, SensorThread.class.getName());
+                    thread.start();
+                    synchronized (runnable) {
+                        while (mSensorsReady == false) {
+                            runnable.wait();
                         }
-                        mThread = thread;
                     }
+                    mThread = thread;
                 }
-            } catch (RemoteException e) {
-                Log.e(TAG, "RemoteException in startLocked: ", e);
             } catch (InterruptedException e) {
             }
             return mThread == null ? false : true;
         }
 
         private class SensorThreadRunnable implements Runnable {
-            private Bundle mDataChannel;
-            SensorThreadRunnable(Bundle dataChannel) {
-                mDataChannel = dataChannel;
+            SensorThreadRunnable() {
             }
 
             private boolean open() {
                 // NOTE: this cannot synchronize on sListeners, since
                 // it's held in the main thread at least until we
                 // return from here.
-
-                // 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;
+                sQueue = sensors_create_queue();
                 return true;
             }
 
@@ -466,7 +420,7 @@
 
                 while (true) {
                     // wait for an event
-                    final int sensor = sensors_data_poll(values, status, timestamp);
+                    final int sensor = sensors_data_poll(sQueue, values, status, timestamp);
 
                     int accuracy = status[0];
                     synchronized (sListeners) {
@@ -478,7 +432,8 @@
                             }
 
                             // we have no more listeners or polling failed, terminate the thread
-                            sensors_data_close();
+                            sensors_destroy_queue(sQueue);
+                            sQueue = 0;
                             mThread = null;
                             break;
                         }
@@ -506,7 +461,7 @@
 
     /*-----------------------------------------------------------------------*/
 
-    private class ListenerDelegate extends Binder {
+    private class ListenerDelegate {
         final SensorEventListener mSensorEventListener;
         private final ArrayList<Sensor> mSensorList = new ArrayList<Sensor>();
         private final Handler mHandler;
@@ -602,8 +557,6 @@
      * {@hide}
      */
     public SensorManager(Looper mainLooper) {
-        mSensorService = ISensorService.Stub.asInterface(
-                ServiceManager.getService(Context.SENSOR_SERVICE));
         mMainLooper = mainLooper;
 
 
@@ -1051,42 +1004,37 @@
                 return false;
         }
 
-        try {
-            synchronized (sListeners) {
-                ListenerDelegate l = null;
-                for (ListenerDelegate i : sListeners) {
-                    if (i.getListener() == listener) {
-                        l = i;
-                        break;
-                    }
-                }
-
-                String name = sensor.getName();
-                int handle = sensor.getHandle();
-                if (l == null) {
-                    result = false;
-                    l = new ListenerDelegate(listener, sensor, handler);
-                    sListeners.add(l);
-                    if (!sListeners.isEmpty()) {
-                        result = sSensorThread.startLocked(mSensorService);
-                        if (result) {
-                            result = mSensorService.enableSensor(l, name, handle, delay);
-                            if (!result) {
-                                // there was an error, remove the listeners
-                                sListeners.remove(l);
-                            }
-                        }
-                    }
-                } else {
-                    result = mSensorService.enableSensor(l, name, handle, delay);
-                    if (result) {
-                        l.addSensor(sensor);
-                    }
+        synchronized (sListeners) {
+            ListenerDelegate l = null;
+            for (ListenerDelegate i : sListeners) {
+                if (i.getListener() == listener) {
+                    l = i;
+                    break;
                 }
             }
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in registerListener: ", e);
-            result = false;
+
+            String name = sensor.getName();
+            int handle = sensor.getHandle();
+            if (l == null) {
+                result = false;
+                l = new ListenerDelegate(listener, sensor, handler);
+                sListeners.add(l);
+                if (!sListeners.isEmpty()) {
+                    result = sSensorThread.startLocked();
+                    if (result) {
+                        result = sensors_enable_sensor(sQueue, name, handle, delay);
+                        if (!result) {
+                            // there was an error, remove the listeners
+                            sListeners.remove(l);
+                        }
+                    }
+                }
+            } else {
+                result = sensors_enable_sensor(sQueue, name, handle, delay);
+                if (result) {
+                    l.addSensor(sensor);
+                }
+            }
         }
         return result;
     }
@@ -1095,27 +1043,23 @@
         if (listener == null || sensor == null) {
             return;
         }
-        try {
-            synchronized (sListeners) {
-                final int size = sListeners.size();
-                for (int i=0 ; i<size ; i++) {
-                    ListenerDelegate l = sListeners.get(i);
-                    if (l.getListener() == listener) {
-                        // disable these sensors
-                        String name = sensor.getName();
-                        int handle = sensor.getHandle();
-                        mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE);
-                        // if we have no more sensors enabled on this listener,
-                        // take it off the list.
-                        if (l.removeSensor(sensor) == 0) {
-                            sListeners.remove(i);
-                        }
-                        break;
+        synchronized (sListeners) {
+            final int size = sListeners.size();
+            for (int i=0 ; i<size ; i++) {
+                ListenerDelegate l = sListeners.get(i);
+                if (l.getListener() == listener) {
+                    // disable these sensors
+                    String name = sensor.getName();
+                    int handle = sensor.getHandle();
+                    sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
+                    // if we have no more sensors enabled on this listener,
+                    // take it off the list.
+                    if (l.removeSensor(sensor) == 0) {
+                        sListeners.remove(i);
                     }
+                    break;
                 }
             }
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in unregisterListener: ", e);
         }
     }
 
@@ -1123,25 +1067,21 @@
         if (listener == null) {
             return;
         }
-        try {
-            synchronized (sListeners) {
-                final int size = sListeners.size();
-                for (int i=0 ; i<size ; i++) {
-                    ListenerDelegate l = sListeners.get(i);
-                    if (l.getListener() == listener) {
-                        // disable all sensors for this listener
-                        for (Sensor sensor : l.getSensors()) {
-                            String name = sensor.getName();
-                            int handle = sensor.getHandle();
-                            mSensorService.enableSensor(l, name, handle, SENSOR_DISABLE);
-                        }
-                        sListeners.remove(i);
-                        break;
+        synchronized (sListeners) {
+            final int size = sListeners.size();
+            for (int i=0 ; i<size ; i++) {
+                ListenerDelegate l = sListeners.get(i);
+                if (l.getListener() == listener) {
+                    // disable all sensors for this listener
+                    for (Sensor sensor : l.getSensors()) {
+                        String name = sensor.getName();
+                        int handle = sensor.getHandle();
+                        sensors_enable_sensor(sQueue, name, handle, SENSOR_DISABLE);
                     }
+                    sListeners.remove(i);
+                    break;
                 }
             }
-        } catch (RemoteException e) {
-            Log.e(TAG, "RemoteException in unregisterListener: ", e);
         }
     }
 
@@ -1794,9 +1734,8 @@
     private static native int sensors_module_get_next_sensor(Sensor sensor, int next);
 
     // Used within this module from outside SensorManager, don't make private
-    static native int sensors_data_init();
-    static native int sensors_data_uninit();
-    static native int sensors_data_open(FileDescriptor[] fds, int[] ints);
-    static native int sensors_data_close();
-    static native int sensors_data_poll(float[] values, int[] status, long[] timestamp);
+    static native int sensors_create_queue();
+    static native void sensors_destroy_queue(int queue);
+    static native boolean sensors_enable_sensor(int queue, String name, int sensor, int enable);
+    static native int sensors_data_poll(int queue, float[] values, int[] status, long[] timestamp);
 }
diff --git a/core/java/android/net/DownloadManager.java b/core/java/android/net/DownloadManager.java
index 00b6864..455bd36 100644
--- a/core/java/android/net/DownloadManager.java
+++ b/core/java/android/net/DownloadManager.java
@@ -22,7 +22,6 @@
 import android.database.CursorWrapper;
 import android.os.ParcelFileDescriptor;
 import android.provider.Downloads;
-import android.util.Log;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -187,6 +186,23 @@
      */
     public final static int ERROR_DEVICE_NOT_FOUND = 1007;
 
+    /**
+     * Broadcast intent action sent by the download manager when a download completes.
+     */
+    public final static String ACTION_DOWNLOAD_COMPLETE = "android.intent.action.DOWNLOAD_COMPLETE";
+
+    /**
+     * Broadcast intent action sent by the download manager when a running download notification is
+     * clicked.
+     */
+    public final static String ACTION_NOTIFICATION_CLICKED =
+            "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
+
+    /**
+     * Intent extra included with {@link #ACTION_DOWNLOAD_COMPLETE} intents, indicating the ID (as a
+     * long) of the download that just completed.
+     */
+    public static final String EXTRA_DOWNLOAD_ID = "extra_download_id";
 
     // this array must contain all public columns
     private static final String[] COLUMNS = new String[] {
@@ -227,19 +243,38 @@
      */
     public static class Request {
         /**
-         * Bit flag for setShowNotification indicated a notification should be created while the
-         * download is running.
+         * Bit flag for {@link #setShowNotification} indicating a notification should be created
+         * while the download is running.
          */
-        private static final int NOTIFICATION_WHEN_RUNNING = 1;
+        public static final int NOTIFICATION_WHEN_RUNNING = 1;
 
-        Uri mUri;
-        Uri mDestinationUri;
-        Map<String, String> mRequestHeaders = new HashMap<String, String>();
-        String mTitle;
-        String mDescription;
-        int mNotificationFlags;
+        /**
+         * Bit flag for {@link #setAllowedNetworkTypes} corresponding to
+         * {@link ConnectivityManager#TYPE_MOBILE}.
+         */
+        public static final int NETWORK_MOBILE = 1 << 0;
 
+        /**
+         * Bit flag for {@link #setAllowedNetworkTypes} corresponding to
+         * {@link ConnectivityManager#TYPE_WIFI}.
+         */
+        public static final int NETWORK_WIFI = 1 << 1;
+
+        /**
+         * Bit flag for {@link #setAllowedNetworkTypes} corresponding to
+         * {@link ConnectivityManager#TYPE_WIMAX}.
+         */
+        public static final int NETWORK_WIMAX = 1 << 2;
+
+        private Uri mUri;
+        private Uri mDestinationUri;
+        private Map<String, String> mRequestHeaders = new HashMap<String, String>();
+        private String mTitle;
+        private String mDescription;
+        private int mNotificationFlags = 0;
         private String mMediaType;
+        private boolean mRoamingAllowed = true;
+        private int mAllowedNetworkTypes = ~0; // default to all network types allowed
 
         /**
          * @param uri the HTTP URI to download.
@@ -313,7 +348,7 @@
         /**
          * Control system notifications posted by the download manager for this download.  If
          * enabled, the download manager posts notifications about downloads through the system
-         * {@link android.app.NotificationManager}.
+         * {@link android.app.NotificationManager}. By default, no notification is shown.
          *
          * @param flags any combination of the NOTIFICATION_* bit flags
          * @return this object
@@ -323,23 +358,37 @@
             return this;
         }
 
+        /**
+         * Restrict the types of networks over which this download may proceed.  By default, all
+         * network types are allowed.
+         * @param flags any combination of the NETWORK_* bit flags.
+         * @return this object
+         */
         public Request setAllowedNetworkTypes(int flags) {
-            // TODO allowed networks support
-            throw new UnsupportedOperationException();
+            mAllowedNetworkTypes = flags;
+            return this;
         }
 
+        /**
+         * Set whether this download may proceed over a roaming connection.  By default, roaming is
+         * allowed.
+         * @param allowed whether to allow a roaming connection to be used
+         * @return this object
+         */
         public Request setAllowedOverRoaming(boolean allowed) {
-            // TODO roaming support
-            throw new UnsupportedOperationException();
+            mRoamingAllowed = allowed;
+            return this;
         }
 
         /**
          * @return ContentValues to be passed to DownloadProvider.insert()
          */
-        ContentValues toContentValues() {
+        ContentValues toContentValues(String packageName) {
             ContentValues values = new ContentValues();
             assert mUri != null;
             values.put(Downloads.COLUMN_URI, mUri.toString());
+            values.put(Downloads.Impl.COLUMN_IS_PUBLIC_API, true);
+            values.put(Downloads.COLUMN_NOTIFICATION_PACKAGE, packageName);
 
             if (mDestinationUri != null) {
                 values.put(Downloads.COLUMN_DESTINATION, Downloads.Impl.DESTINATION_FILE_URI);
@@ -363,6 +412,9 @@
             }
             values.put(Downloads.COLUMN_VISIBILITY, visibility);
 
+            values.put(Downloads.Impl.COLUMN_ALLOWED_NETWORK_TYPES, mAllowedNetworkTypes);
+            values.put(Downloads.Impl.COLUMN_ALLOW_ROAMING, mRoamingAllowed);
+
             return values;
         }
 
@@ -441,7 +493,6 @@
                               + " AND " + statusClause("<", 600) + ")");
                 }
                 selection = joinStrings(" OR ", parts);
-                Log.w("DownloadManagerPublic", selection);
             }
             String orderBy = Downloads.COLUMN_LAST_MODIFICATION + " DESC";
             return resolver.query(uri, projection, selection, null, orderBy);
@@ -466,12 +517,14 @@
     }
 
     private ContentResolver mResolver;
+    private String mPackageName;
 
     /**
      * @hide
      */
-    public DownloadManager(ContentResolver resolver) {
+    public DownloadManager(ContentResolver resolver, String packageName) {
         mResolver = resolver;
+        mPackageName = packageName;
     }
 
     /**
@@ -483,7 +536,7 @@
      * calls related to this download.
      */
     public long enqueue(Request request) {
-        ContentValues values = request.toContentValues();
+        ContentValues values = request.toContentValues(mPackageName);
         Uri downloadUri = mResolver.insert(Downloads.CONTENT_URI, values);
         long id = Long.parseLong(downloadUri.getLastPathSegment());
         return id;
diff --git a/core/java/android/os/DropBoxManager.java b/core/java/android/os/DropBoxManager.java
index 4df33e0..23fdb0b 100644
--- a/core/java/android/os/DropBoxManager.java
+++ b/core/java/android/os/DropBoxManager.java
@@ -53,6 +53,9 @@
     /** Flag value: Content can be decompressed with {@link java.util.zip.GZIPOutputStream}. */
     public static final int IS_GZIPPED = 4;
 
+    /** Flag value for serialization only: Value is a byte array, not a file descriptor */
+    private static final int HAS_BYTE_ARRAY = 8;
+
     /**
      * A single entry retrieved from the drop box.
      * This may include a reference to a stream, so you must call
@@ -68,12 +71,25 @@
 
         /** Create a new empty Entry with no contents. */
         public Entry(String tag, long millis) {
-            this(tag, millis, (Object) null, IS_EMPTY);
+            if (tag == null) throw new NullPointerException("tag == null");
+
+            mTag = tag;
+            mTimeMillis = millis;
+            mData = null;
+            mFileDescriptor = null;
+            mFlags = IS_EMPTY;
         }
 
         /** Create a new Entry with plain text contents. */
         public Entry(String tag, long millis, String text) {
-            this(tag, millis, (Object) text.getBytes(), IS_TEXT);
+            if (tag == null) throw new NullPointerException("tag == null");
+            if (text == null) throw new NullPointerException("text == null");
+
+            mTag = tag;
+            mTimeMillis = millis;
+            mData = text.getBytes();
+            mFileDescriptor = null;
+            mFlags = IS_TEXT;
         }
 
         /**
@@ -81,7 +97,16 @@
          * The data array must not be modified after creating this entry.
          */
         public Entry(String tag, long millis, byte[] data, int flags) {
-            this(tag, millis, (Object) data, flags);
+            if (tag == null) throw new NullPointerException("tag == null");
+            if (((flags & IS_EMPTY) != 0) != (data == null)) {
+                throw new IllegalArgumentException("Bad flags: " + flags);
+            }
+
+            mTag = tag;
+            mTimeMillis = millis;
+            mData = data;
+            mFileDescriptor = null;
+            mFlags = flags;
         }
 
         /**
@@ -89,7 +114,16 @@
          * Takes ownership of the ParcelFileDescriptor.
          */
         public Entry(String tag, long millis, ParcelFileDescriptor data, int flags) {
-            this(tag, millis, (Object) data, flags);
+            if (tag == null) throw new NullPointerException("tag == null");
+            if (((flags & IS_EMPTY) != 0) != (data == null)) {
+                throw new IllegalArgumentException("Bad flags: " + flags);
+            }
+
+            mTag = tag;
+            mTimeMillis = millis;
+            mData = null;
+            mFileDescriptor = data;
+            mFlags = flags;
         }
 
         /**
@@ -97,31 +131,14 @@
          * The file will be read when the entry's contents are requested.
          */
         public Entry(String tag, long millis, File data, int flags) throws IOException {
-            this(tag, millis, (Object) ParcelFileDescriptor.open(
-                    data, ParcelFileDescriptor.MODE_READ_ONLY), flags);
-        }
-
-        /** Internal constructor for CREATOR.createFromParcel(). */
-        private Entry(String tag, long millis, Object value, int flags) {
-            if (tag == null) throw new NullPointerException();
-            if (((flags & IS_EMPTY) != 0) != (value == null)) throw new IllegalArgumentException();
+            if (tag == null) throw new NullPointerException("tag == null");
+            if ((flags & IS_EMPTY) != 0) throw new IllegalArgumentException("Bad flags: " + flags);
 
             mTag = tag;
             mTimeMillis = millis;
+            mData = null;
+            mFileDescriptor = ParcelFileDescriptor.open(data, ParcelFileDescriptor.MODE_READ_ONLY);
             mFlags = flags;
-
-            if (value == null) {
-                mData = null;
-                mFileDescriptor = null;
-            } else if (value instanceof byte[]) {
-                mData = (byte[]) value;
-                mFileDescriptor = null;
-            } else if (value instanceof ParcelFileDescriptor) {
-                mData = null;
-                mFileDescriptor = (ParcelFileDescriptor) value;
-            } else {
-                throw new IllegalArgumentException();
-            }
         }
 
         /** Close the input stream associated with this entry. */
@@ -149,6 +166,7 @@
             InputStream is = null;
             try {
                 is = getInputStream();
+                if (is == null) return null;
                 byte[] buf = new byte[maxBytes];
                 return new String(buf, 0, Math.max(0, is.read(buf)));
             } catch (IOException e) {
@@ -174,8 +192,14 @@
         public static final Parcelable.Creator<Entry> CREATOR = new Parcelable.Creator() {
             public Entry[] newArray(int size) { return new Entry[size]; }
             public Entry createFromParcel(Parcel in) {
-                return new Entry(
-                        in.readString(), in.readLong(), in.readValue(null), in.readInt());
+                String tag = in.readString();
+                long millis = in.readLong();
+                int flags = in.readInt();
+                if ((flags & HAS_BYTE_ARRAY) != 0) {
+                    return new Entry(tag, millis, in.createByteArray(), flags & ~HAS_BYTE_ARRAY);
+                } else {
+                    return new Entry(tag, millis, in.readFileDescriptor(), flags);
+                }
             }
         };
 
@@ -187,11 +211,12 @@
             out.writeString(mTag);
             out.writeLong(mTimeMillis);
             if (mFileDescriptor != null) {
-                out.writeValue(mFileDescriptor);
+                out.writeInt(mFlags & ~HAS_BYTE_ARRAY);  // Clear bit just to be safe
+                mFileDescriptor.writeToParcel(out, flags);
             } else {
-                out.writeValue(mData);
+                out.writeInt(mFlags | HAS_BYTE_ARRAY);
+                out.writeByteArray(mData);
             }
-            out.writeInt(mFlags);
         }
     }
 
@@ -225,7 +250,7 @@
      * @param flags describing the data
      */
     public void addData(String tag, byte[] data, int flags) {
-        if (data == null) throw new NullPointerException();
+        if (data == null) throw new NullPointerException("data == null");
         try { mService.add(new Entry(tag, 0, data, flags)); } catch (RemoteException e) {}
     }
 
@@ -239,7 +264,7 @@
      * @throws IOException if the file can't be opened
      */
     public void addFile(String tag, File file, int flags) throws IOException {
-        if (file == null) throw new NullPointerException();
+        if (file == null) throw new NullPointerException("file == null");
         Entry entry = new Entry(tag, 0, file, flags);
         try {
             mService.add(entry);
diff --git a/core/java/android/provider/Downloads.java b/core/java/android/provider/Downloads.java
index 2a612fe..7e1d685 100644
--- a/core/java/android/provider/Downloads.java
+++ b/core/java/android/provider/Downloads.java
@@ -17,11 +17,6 @@
 package android.provider;
 
 import android.net.Uri;
-import android.content.ContentUris;
-import android.content.ContentValues;
-import android.content.Context;
-
-import java.io.File;
 
 /**
  * The Download Manager
@@ -629,14 +624,6 @@
                 "android.permission.SEND_DOWNLOAD_COMPLETED_INTENTS";
 
         /**
-         * The permission to access downloads to {@link DESTINATION_EXTERNAL}
-         * which were downloaded by other applications.
-         * @hide
-         */
-        public static final String PERMISSION_SEE_ALL_EXTERNAL =
-                "android.permission.SEE_ALL_EXTERNAL";
-
-        /**
          * The content:// URI for the data table in the provider
          */
         public static final Uri CONTENT_URI =
@@ -856,6 +843,30 @@
          */
         public static final String COLUMN_DESCRIPTION = "description";
 
+        /**
+         * The name of the column indicating whether the download was requesting through the public
+         * API.  This controls some differences in behavior.
+         * <P>Type: BOOLEAN</P>
+         * <P>Owner can Init/Read</P>
+         */
+        public static final String COLUMN_IS_PUBLIC_API = "is_public_api";
+
+        /**
+         * The name of the column indicating whether roaming connections can be used.  This is only
+         * used for public API downloads.
+         * <P>Type: BOOLEAN</P>
+         * <P>Owner can Init/Read</P>
+         */
+        public static final String COLUMN_ALLOW_ROAMING = "allow_roaming";
+
+        /**
+         * The name of the column holding a bitmask of allowed network types.  This is only used for
+         * public API downloads.
+         * <P>Type: INTEGER</P>
+         * <P>Owner can Init/Read</P>
+         */
+        public static final String COLUMN_ALLOWED_NETWORK_TYPES = "allowed_network_types";
+
         /*
          * Lists the destinations that an application can specify for a download.
          */
diff --git a/core/jni/Android.mk b/core/jni/Android.mk
index 89fea41..5c37c7c 100644
--- a/core/jni/Android.mk
+++ b/core/jni/Android.mk
@@ -168,6 +168,7 @@
 	libbinder \
 	libnetutils \
 	libui \
+	libgui \
 	libsurfaceflinger_client \
 	libcamera_client \
 	libskiagl \
diff --git a/core/jni/android_hardware_SensorManager.cpp b/core/jni/android_hardware_SensorManager.cpp
index 9a90b72..7b23418 100644
--- a/core/jni/android_hardware_SensorManager.cpp
+++ b/core/jni/android_hardware_SensorManager.cpp
@@ -18,8 +18,9 @@
 
 #include "utils/Log.h"
 
-#include <hardware/sensors.h>
-#include <cutils/native_handle.h>
+#include <gui/Sensor.h>
+#include <gui/SensorManager.h>
+#include <gui/SensorEventQueue.h>
 
 #include "jni.h"
 #include "JNIHelp.h"
@@ -43,44 +44,36 @@
  * The method below are not thread-safe and not intended to be
  */
 
-static sensors_module_t* sSensorModule = 0;
-static sensors_data_device_t* sSensorDevice = 0;
 
 static jint
 sensors_module_init(JNIEnv *env, jclass clazz)
 {
-    int err = 0;
-    sensors_module_t const* module;
-    err = hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t **)&module);
-    if (err == 0)
-        sSensorModule = (sensors_module_t*)module;
-    return err;
+    SensorManager::getInstance();
+    return 0;
 }
 
 static jint
 sensors_module_get_next_sensor(JNIEnv *env, jobject clazz, jobject sensor, jint next)
 {
-    if (sSensorModule == NULL)
-        return 0;
+    SensorManager& mgr(SensorManager::getInstance());
 
-    SensorOffsets& sensorOffsets = gSensorOffsets;
-    const struct sensor_t* list;
-    int count = sSensorModule->get_sensors_list(sSensorModule, &list);
+    Sensor const* const* sensorList;
+    size_t count = mgr.getSensorList(&sensorList);
     if (next >= count)
         return -1;
     
-    list += next;
-
-    jstring name = env->NewStringUTF(list->name);
-    jstring vendor = env->NewStringUTF(list->vendor);
+    Sensor const* const list = sensorList[next];
+    const SensorOffsets& sensorOffsets(gSensorOffsets);
+    jstring name = env->NewStringUTF(list->getName().string());
+    jstring vendor = env->NewStringUTF(list->getVendor().string());
     env->SetObjectField(sensor, sensorOffsets.name,      name);
     env->SetObjectField(sensor, sensorOffsets.vendor,    vendor);
-    env->SetIntField(sensor, sensorOffsets.version,      list->version);
-    env->SetIntField(sensor, sensorOffsets.handle,       list->handle);
-    env->SetIntField(sensor, sensorOffsets.type,         list->type);
-    env->SetFloatField(sensor, sensorOffsets.range,      list->maxRange);
-    env->SetFloatField(sensor, sensorOffsets.resolution, list->resolution);
-    env->SetFloatField(sensor, sensorOffsets.power,      list->power);
+    env->SetIntField(sensor, sensorOffsets.version,      1);
+    env->SetIntField(sensor, sensorOffsets.handle,       list->getHandle());
+    env->SetIntField(sensor, sensorOffsets.type,         list->getType());
+    env->SetFloatField(sensor, sensorOffsets.range,      list->getMaxValue());
+    env->SetFloatField(sensor, sensorOffsets.resolution, list->getResolution());
+    env->SetFloatField(sensor, sensorOffsets.power,      list->getPowerUsage());
     
     next++;
     return next<count ? next : 0;
@@ -88,75 +81,64 @@
 
 //----------------------------------------------------------------------------
 static jint
-sensors_data_init(JNIEnv *env, jclass clazz)
+sensors_create_queue(JNIEnv *env, jclass clazz)
 {
-    if (sSensorModule == NULL)
-        return -1;
-    int err = sensors_data_open(&sSensorModule->common, &sSensorDevice);
-    return err;
+    SensorManager& mgr(SensorManager::getInstance());
+    sp<SensorEventQueue> queue(mgr.createEventQueue());
+    queue->incStrong(clazz);
+    return reinterpret_cast<int>(queue.get());
 }
 
-static jint
-sensors_data_uninit(JNIEnv *env, jclass clazz)
+static void
+sensors_destroy_queue(JNIEnv *env, jclass clazz, jint nativeQueue)
 {
-    int err = 0;
-    if (sSensorDevice) {
-        err = sensors_data_close(sSensorDevice);
-        if (err == 0)
-            sSensorDevice = 0;
+    sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));
+    if (queue != 0) {
+        queue->decStrong(clazz);
     }
-    return err;
 }
 
-static jint
-sensors_data_open(JNIEnv *env, jclass clazz, jobjectArray fdArray, jintArray intArray)
+static jboolean
+sensors_enable_sensor(JNIEnv *env, jclass clazz,
+        jint nativeQueue, jstring name, jint sensor, jint delay)
 {
-    jclass FileDescriptor = env->FindClass("java/io/FileDescriptor");
-    jfieldID fieldOffset = env->GetFieldID(FileDescriptor, "descriptor", "I");
-    int numFds = (fdArray ? env->GetArrayLength(fdArray) : 0);
-    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;
-        }
+    sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));
+    if (queue == 0) return JNI_FALSE;
+    status_t res;
+    if (delay >= 0) {
+        res = queue->enableSensor(sensor, delay);
+    } else {
+        res = queue->disableSensor(sensor);
     }
-    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);
+    return res == NO_ERROR ? true : false;
 }
 
 static jint
-sensors_data_close(JNIEnv *env, jclass clazz)
-{
-    return sSensorDevice->data_close(sSensorDevice);
-}
-
-static jint
-sensors_data_poll(JNIEnv *env, jclass clazz, 
+sensors_data_poll(JNIEnv *env, jclass clazz, jint nativeQueue,
         jfloatArray values, jintArray status, jlongArray timestamp)
 {
-    sensors_data_t data;
-    int res = sSensorDevice->poll(sSensorDevice, &data);
-    if (res >= 0) {
-        jint accuracy = data.vector.status;
-        env->SetFloatArrayRegion(values, 0, 3, data.vector.v);
-        env->SetIntArrayRegion(status, 0, 1, &accuracy);
-        env->SetLongArrayRegion(timestamp, 0, 1, &data.time);
+    sp<SensorEventQueue> queue(reinterpret_cast<SensorEventQueue *>(nativeQueue));
+    if (queue == 0) return -1;
+
+    status_t res;
+    ASensorEvent event;
+
+    res = queue->read(&event, 1);
+    if (res == -EAGAIN) {
+        res = queue->waitForEvent();
+        if (res != NO_ERROR)
+            return -1;
+        res = queue->read(&event, 1);
     }
-    return res;
+    if (res < 0)
+        return -1;
+
+    jint accuracy = event.vector.status;
+    env->SetFloatArrayRegion(values, 0, 3, event.vector.v);
+    env->SetIntArrayRegion(status, 0, 1, &accuracy);
+    env->SetLongArrayRegion(timestamp, 0, 1, &event.timestamp);
+
+    return event.sensor;
 }
 
 static void
@@ -179,11 +161,13 @@
     {"sensors_module_init","()I",           (void*)sensors_module_init },
     {"sensors_module_get_next_sensor","(Landroid/hardware/Sensor;I)I",
                                             (void*)sensors_module_get_next_sensor },
-    {"sensors_data_init", "()I",            (void*)sensors_data_init },
-    {"sensors_data_uninit", "()I",          (void*)sensors_data_uninit },
-    {"sensors_data_open",  "([Ljava/io/FileDescriptor;[I)I",  (void*)sensors_data_open },
-    {"sensors_data_close", "()I",           (void*)sensors_data_close },
-    {"sensors_data_poll",  "([F[I[J)I",     (void*)sensors_data_poll },
+
+    {"sensors_create_queue",  "()I",        (void*)sensors_create_queue },
+    {"sensors_destroy_queue", "(I)V",       (void*)sensors_destroy_queue },
+    {"sensors_enable_sensor", "(ILjava/lang/String;II)Z",
+                                            (void*)sensors_enable_sensor },
+
+    {"sensors_data_poll",  "(I[F[I[J)I",     (void*)sensors_data_poll },
 };
 
 }; // namespace android
diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h
index 3e05076..9c8afc5 100644
--- a/include/gui/ISensorServer.h
+++ b/include/gui/ISensorServer.h
@@ -36,7 +36,7 @@
 public:
     DECLARE_META_INTERFACE(SensorServer);
 
-    virtual Vector<Sensor> getSensorList()= 0;
+    virtual Vector<Sensor> getSensorList() = 0;
     virtual sp<ISensorEventConnection> createSensorEventConnection() = 0;
 };
 
diff --git a/include/gui/Sensor.h b/include/gui/Sensor.h
index 86a16f1..e696d63 100644
--- a/include/gui/Sensor.h
+++ b/include/gui/Sensor.h
@@ -51,7 +51,8 @@
         TYPE_PROXIMITY      = ASENSOR_TYPE_PROXIMITY
     };
 
-    Sensor();
+            Sensor();
+            Sensor(struct sensor_t const* hwSensor);
     virtual ~Sensor();
 
     const String8& getName() const;
diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h
index d8d8128..ad36dac 100644
--- a/include/gui/SensorEventQueue.h
+++ b/include/gui/SensorEventQueue.h
@@ -42,6 +42,7 @@
 
 class ISensorEventConnection;
 class Sensor;
+class PollLoop;
 
 // ----------------------------------------------------------------------------
 
@@ -56,13 +57,23 @@
     ssize_t write(ASensorEvent const* events, size_t numEvents);
     ssize_t read(ASensorEvent* events, size_t numEvents);
 
+    status_t waitForEvent() const;
+    status_t wake() const;
+
     status_t enableSensor(Sensor const* sensor) const;
     status_t disableSensor(Sensor const* sensor) const;
     status_t setEventRate(Sensor const* sensor, nsecs_t ns) const;
 
+    // these are here only to support SensorManager.java
+    status_t enableSensor(int32_t handle, int32_t ms) const;
+    status_t disableSensor(int32_t handle) const;
+
 private:
+    sp<PollLoop> getPollLoop() const;
     sp<ISensorEventConnection> mSensorEventConnection;
     sp<SensorChannel> mSensorChannel;
+    mutable Mutex mLock;
+    mutable sp<PollLoop> mPollLoop;
 };
 
 // ----------------------------------------------------------------------------
diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h
index 0d65334..e1b1a7be 100644
--- a/include/gui/SensorManager.h
+++ b/include/gui/SensorManager.h
@@ -47,13 +47,13 @@
     SensorManager();
     ~SensorManager();
 
-    ssize_t getSensorList(Sensor**) const;
-    Sensor* getDefaultSensor(int type);
+    ssize_t getSensorList(Sensor const* const** list) const;
+    Sensor const* getDefaultSensor(int type);
     sp<SensorEventQueue> createEventQueue();
 
 private:
     sp<ISensorServer> mSensorServer;
-    Sensor* mSensorList;
+    Sensor const** mSensorList;
     Vector<Sensor> mSensors;
 };
 
diff --git a/libs/gui/ISensorEventConnection.cpp b/libs/gui/ISensorEventConnection.cpp
index 3e9d456..a5083fe 100644
--- a/libs/gui/ISensorEventConnection.cpp
+++ b/libs/gui/ISensorEventConnection.cpp
@@ -47,6 +47,7 @@
     virtual sp<SensorChannel> getSensorChannel() const
     {
         Parcel data, reply;
+        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
         remote()->transact(GET_SENSOR_CHANNEL, data, &reply);
         return new SensorChannel(reply);
     }
@@ -54,6 +55,7 @@
     virtual status_t enableDisable(int handle, bool enabled)
     {
         Parcel data, reply;
+        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
         data.writeInt32(handle);
         data.writeInt32(enabled);
         remote()->transact(ENABLE_DISABLE, data, &reply);
@@ -63,6 +65,7 @@
     virtual status_t setEventRate(int handle, nsecs_t ns)
     {
         Parcel data, reply;
+        data.writeInterfaceToken(ISensorEventConnection::getInterfaceDescriptor());
         data.writeInt32(handle);
         data.writeInt64(ns);
         remote()->transact(SET_EVENT_RATE, data, &reply);
diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp
index c6177bc..7111092 100644
--- a/libs/gui/ISensorServer.cpp
+++ b/libs/gui/ISensorServer.cpp
@@ -48,6 +48,7 @@
     virtual Vector<Sensor> getSensorList()
     {
         Parcel data, reply;
+        data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
         remote()->transact(GET_SENSOR_LIST, data, &reply);
         Sensor s;
         Vector<Sensor> v;
@@ -63,6 +64,7 @@
     virtual sp<ISensorEventConnection> createSensorEventConnection()
     {
         Parcel data, reply;
+        data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor());
         remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply);
         return interface_cast<ISensorEventConnection>(reply.readStrongBinder());
     }
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 1fdd285..48e1cb7 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -36,6 +36,18 @@
 {
 }
 
+Sensor::Sensor(struct sensor_t const* hwSensor)
+{
+    mName = hwSensor->name;
+    mVendor = hwSensor->vendor;
+    mHandle = hwSensor->handle;
+    mType = hwSensor->type;
+    mMinValue = 0;                      // FIXME: minValue
+    mMaxValue = hwSensor->maxRange;     // FIXME: maxValue
+    mResolution = hwSensor->resolution;
+    mPower = hwSensor->power;
+}
+
 Sensor::~Sensor()
 {
 }
diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp
index f922ac4..4b46842 100644
--- a/libs/gui/SensorEventQueue.cpp
+++ b/libs/gui/SensorEventQueue.cpp
@@ -13,11 +13,15 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
+
+#define LOG_TAG "Sensors"
+
 #include <stdint.h>
 #include <sys/types.h>
 
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
+#include <utils/PollLoop.h>
 
 #include <gui/Sensor.h>
 #include <gui/SensorChannel.h>
@@ -68,7 +72,7 @@
     ssize_t size = mSensorChannel->read(events, numEvents*sizeof(events[0]));
     if (size >= 0) {
         if (size % sizeof(events[0])) {
-            // partial write!!! should never happen.
+            // partial read!!! should never happen.
             return -EINVAL;
         }
         // returns number of events read
@@ -77,18 +81,52 @@
     return size;
 }
 
-status_t SensorEventQueue::enableSensor(Sensor const* sensor) const
+sp<PollLoop> SensorEventQueue::getPollLoop() const
 {
+    Mutex::Autolock _l(mLock);
+    if (mPollLoop == 0) {
+        mPollLoop = new PollLoop(true);
+        mPollLoop->setCallback(getFd(), POLLIN, NULL, NULL);
+    }
+    return mPollLoop;
+}
+
+status_t SensorEventQueue::waitForEvent() const
+{
+    const int fd = getFd();
+    sp<PollLoop> pollLoop(getPollLoop());
+    int32_t result = pollLoop->pollOnce(-1, NULL, NULL);
+    return (result == fd) ? NO_ERROR : -1;
+}
+
+status_t SensorEventQueue::wake() const
+{
+    sp<PollLoop> pollLoop(getPollLoop());
+    pollLoop->wake();
+    return NO_ERROR;
+}
+
+status_t SensorEventQueue::enableSensor(Sensor const* sensor) const {
     return mSensorEventConnection->enableDisable(sensor->getHandle(), true);
 }
 
-status_t SensorEventQueue::disableSensor(Sensor const* sensor) const
-{
+status_t SensorEventQueue::disableSensor(Sensor const* sensor) const {
     return mSensorEventConnection->enableDisable(sensor->getHandle(), false);
 }
 
-status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const
-{
+status_t SensorEventQueue::enableSensor(int32_t handle, int32_t ms) const {
+    status_t err = mSensorEventConnection->enableDisable(handle, true);
+    if (err == NO_ERROR) {
+        mSensorEventConnection->setEventRate(handle, ms2ns(ms));
+    }
+    return err;
+}
+
+status_t SensorEventQueue::disableSensor(int32_t handle) const {
+    return mSensorEventConnection->enableDisable(handle, false);
+}
+
+status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const {
     return mSensorEventConnection->setEventRate(sensor->getHandle(), ns);
 }
 
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index cd89285..d719efb 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "Sensors"
+
 #include <stdint.h>
 #include <sys/types.h>
 
@@ -21,6 +23,8 @@
 #include <utils/RefBase.h>
 #include <utils/Singleton.h>
 
+#include <binder/IServiceManager.h>
+
 #include <gui/ISensorServer.h>
 #include <gui/ISensorEventConnection.h>
 #include <gui/Sensor.h>
@@ -36,25 +40,40 @@
 SensorManager::SensorManager()
     : mSensorList(0)
 {
+    const String16 name("sensorservice");
+    while (getService(name, &mSensorServer) != NO_ERROR) {
+        usleep(250000);
+    }
+
     mSensors = mSensorServer->getSensorList();
-    // TODO: needs implementation
+    size_t count = mSensors.size();
+    mSensorList = (Sensor const**)malloc(count * sizeof(Sensor*));
+    for (size_t i=0 ; i<count ; i++) {
+        mSensorList[i] = mSensors.array() + i;
+    }
 }
 
 SensorManager::~SensorManager()
 {
-    // TODO: needs implementation
+    free(mSensorList);
 }
 
-ssize_t SensorManager::getSensorList(Sensor** list) const
+ssize_t SensorManager::getSensorList(Sensor const* const** list) const
 {
     *list = mSensorList;
     return mSensors.size();
 }
 
-Sensor* SensorManager::getDefaultSensor(int type)
+Sensor const* SensorManager::getDefaultSensor(int type)
 {
-    // TODO: needs implementation
-    return mSensorList;
+    // For now we just return the first sensor of that type we find.
+    // in the future it will make sense to let the SensorService make
+    // that decision.
+    for (size_t i=0 ; i<mSensors.size() ; i++) {
+        if (mSensorList[i]->getType() == type)
+            return mSensorList[i];
+    }
+    return NULL;
 }
 
 sp<SensorEventQueue> SensorManager::createEventQueue()
diff --git a/native/android/sensor.cpp b/native/android/sensor.cpp
index 7a3907e..e1fc4e7 100644
--- a/native/android/sensor.cpp
+++ b/native/android/sensor.cpp
@@ -43,17 +43,18 @@
     return &SensorManager::getInstance();
 }
 
-int ASensorManager_getSensorList(ASensorManager* manager, ASensor** list)
+int ASensorManager_getSensorList(ASensorManager* manager,
+        ASensorList* list)
 {
-    Sensor* l;
+    Sensor const* const* l;
     int c = static_cast<SensorManager*>(manager)->getSensorList(&l);
     if (list) {
-        *list = l;
+        *list = reinterpret_cast<ASensorList>(l);
     }
     return c;
 }
 
-ASensor* ASensorManager_getDefaultSensor(ASensorManager* manager, int type)
+ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type)
 {
     return static_cast<SensorManager*>(manager)->getDefaultSensor(type);
 }
@@ -82,23 +83,23 @@
 
 /*****************************************************************************/
 
-int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor* sensor)
+int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor)
 {
     return static_cast<SensorEventQueue*>(queue)->enableSensor(
-            static_cast<Sensor*>(sensor));
+            static_cast<Sensor const*>(sensor));
 }
 
-int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor* sensor)
+int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor)
 {
     return static_cast<SensorEventQueue*>(queue)->disableSensor(
-            static_cast<Sensor*>(sensor));
+            static_cast<Sensor const*>(sensor));
 }
 
-int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor* sensor,
+int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor,
         int32_t usec)
 {
     return static_cast<SensorEventQueue*>(queue)->setEventRate(
-            static_cast<Sensor*>(sensor), us2ns(usec));
+            static_cast<Sensor const*>(sensor), us2ns(usec));
 }
 
 int ASensorEventQueue_hasEvents(ASensorEventQueue* queue)
@@ -128,23 +129,23 @@
 
 /*****************************************************************************/
 
-const char* ASensor_getName(ASensor* sensor)
+const char* ASensor_getName(ASensor const* sensor)
 {
-    return static_cast<Sensor*>(sensor)->getName().string();
+    return static_cast<Sensor const*>(sensor)->getName().string();
 }
 
-const char* ASensor_getVendor(ASensor* sensor)
+const char* ASensor_getVendor(ASensor const* sensor)
 {
-    return static_cast<Sensor*>(sensor)->getVendor().string();
+    return static_cast<Sensor const*>(sensor)->getVendor().string();
 }
 
-int ASensor_getType(ASensor* sensor)
+int ASensor_getType(ASensor const* sensor)
 {
-    return static_cast<Sensor*>(sensor)->getType();
+    return static_cast<Sensor const*>(sensor)->getType();
 }
 
-float ASensor_getResolution(ASensor* sensor)
+float ASensor_getResolution(ASensor const* sensor)
 {
-    return static_cast<Sensor*>(sensor)->getResolution();
+    return static_cast<Sensor const*>(sensor)->getResolution();
 }
 
diff --git a/native/include/android/sensor.h b/native/include/android/sensor.h
index 4291d3e..00d95d8 100644
--- a/native/include/android/sensor.h
+++ b/native/include/android/sensor.h
@@ -87,6 +87,7 @@
  * A sensor event.
  */
 
+/* NOTE: Must match hardware/sensors.h */
 typedef struct ASensorVector {
     union {
         float v[3];
@@ -95,23 +96,32 @@
             float y;
             float z;
         };
+        struct {
+            float azimuth;
+            float pitch;
+            float roll;
+        };
     };
     int8_t status;
     uint8_t reserved[3];
 } ASensorVector;
 
+/* NOTE: Must match hardware/sensors.h */
 typedef struct ASensorEvent {
-    int sensor;
+    int32_t version; /* sizeof(struct ASensorEvent) */
+    int32_t sensor;
+    int32_t type;
     int32_t reserved0;
+    int64_t timestamp;
     union {
         float           data[16];
+        ASensorVector   vector;
         ASensorVector   acceleration;
         ASensorVector   magnetic;
         float           temperature;
         float           distance;
         float           light;
     };
-    int64_t timestamp;
     int32_t reserved1[4];
 } ASensorEvent;
 
@@ -124,6 +134,8 @@
 
 struct ASensor;
 typedef struct ASensor ASensor;
+typedef ASensor const* ASensorRef;
+typedef ASensorRef const* ASensorList;
 
 /*****************************************************************************/
 
@@ -141,13 +153,13 @@
 /*
  * Returns the list of available sensors.
  */
-int ASensorManager_getSensorList(ASensorManager* manager, ASensor** list);
+int ASensorManager_getSensorList(ASensorManager* manager, ASensorList* list);
 
 /*
  * Returns the default sensor for the given type, or NULL if no sensor
  * of that type exist.
  */
-ASensor* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
+ASensor const* ASensorManager_getDefaultSensor(ASensorManager* manager, int type);
 
 /*
  * Creates a new sensor event queue and associate it with a looper.
@@ -166,12 +178,12 @@
 /*
  * Enable the selected sensor. Returns a negative error code on failure.
  */
-int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor* sensor);
+int ASensorEventQueue_enableSensor(ASensorEventQueue* queue, ASensor const* sensor);
 
 /*
  * Disable the selected sensor. Returns a negative error code on failure.
  */
-int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor* sensor);
+int ASensorEventQueue_disableSensor(ASensorEventQueue* queue, ASensor const* sensor);
 
 /*
  * Sets the delivery rate of events in microseconds for the given sensor.
@@ -179,7 +191,7 @@
  * rate.
  * Returns a negative error code on failure.
  */
-int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor* sensor, int32_t usec);
+int ASensorEventQueue_setEventRate(ASensorEventQueue* queue, ASensor const* sensor, int32_t usec);
 
 /*
  * Returns true if there are one or more events available in the
@@ -210,22 +222,22 @@
 /*
  * Returns this sensor's name (non localized)
  */
-const char* ASensor_getName(ASensor* sensor);
+const char* ASensor_getName(ASensor const* sensor);
 
 /*
  * Returns this sensor's vendor's name (non localized)
  */
-const char* ASensor_getVendor(ASensor* sensor);
+const char* ASensor_getVendor(ASensor const* sensor);
 
 /*
  * Return this sensor's type
  */
-int ASensor_getType(ASensor* sensor);
+int ASensor_getType(ASensor const* sensor);
 
 /*
  * Returns this sensors's resolution
  */
-float ASensor_getResolution(ASensor* sensor);
+float ASensor_getResolution(ASensor const* sensor);
 
 
 #ifdef __cplusplus
diff --git a/services/java/com/android/server/SensorService.java b/services/java/com/android/server/SensorService.java
deleted file mode 100644
index 9f5718f..0000000
--- a/services/java/com/android/server/SensorService.java
+++ /dev/null
@@ -1,282 +0,0 @@
-/*
- * Copyright (C) 2008 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server;
-
-import android.content.Context;
-import android.hardware.ISensorService;
-import android.os.Binder;
-import android.os.Bundle;
-import android.os.RemoteException;
-import android.os.IBinder;
-import android.util.Config;
-import android.util.Slog;
-import android.util.PrintWriterPrinter;
-import android.util.Printer;
-
-import java.io.FileDescriptor;
-import java.io.PrintWriter;
-import java.util.ArrayList;
-
-import com.android.internal.app.IBatteryStats;
-import com.android.server.am.BatteryStatsService;
-
-
-/**
- * Class that manages the device's sensors. It register clients and activate
- * the needed sensors. The sensor events themselves are not broadcasted from
- * this service, instead, a file descriptor is provided to each client they
- * can read events from.
- */
-
-class SensorService extends ISensorService.Stub {
-    static final String TAG = SensorService.class.getSimpleName();
-    private static final boolean DEBUG = false;
-    private static final boolean localLOGV = DEBUG ? Config.LOGD : Config.LOGV;
-    private static final int SENSOR_DISABLE = -1;
-    private int mCurrentDelay = 0;
-    
-    /**
-     * Battery statistics to be updated when sensors are enabled and disabled.
-     */
-    final IBatteryStats mBatteryStats = BatteryStatsService.getService();
-
-    private final class Listener implements IBinder.DeathRecipient {
-        final IBinder mToken;
-        final int mUid;
-
-        int mSensors = 0;
-        int mDelay = 0x7FFFFFFF;
-        
-        Listener(IBinder token, int uid) {
-            mToken = token;
-            mUid = uid;
-        }
-        
-        void addSensor(int sensor, int delay) {
-            mSensors |= (1<<sensor);
-            if (delay < mDelay)
-            	mDelay = delay;
-        }
-        
-        void removeSensor(int sensor) {
-            mSensors &= ~(1<<sensor);
-        }
-
-        boolean hasSensor(int sensor) {
-            return ((mSensors & (1<<sensor)) != 0);
-        }
-
-        public void binderDied() {
-            if (localLOGV) Slog.d(TAG, "sensor listener died");
-            synchronized(mListeners) {
-                mListeners.remove(this);
-                mToken.unlinkToDeath(this, 0);
-                // go through the lists of sensors used by the listener that 
-                // died and deactivate them.
-                for (int sensor=0 ; sensor<32 && mSensors!=0 ; sensor++) {
-                    if (hasSensor(sensor)) {
-                        removeSensor(sensor);
-                        deactivateIfUnusedLocked(sensor);
-                        try {
-                            mBatteryStats.noteStopSensor(mUid, sensor);
-                        } catch (RemoteException e) {
-                            // oops. not a big deal.
-                        }
-                    }
-                }
-                if (mListeners.size() == 0) {
-                    _sensors_control_wake();
-                    _sensors_control_close();
-                } else {
-                    // TODO: we should recalculate the delay, since removing
-                    // a listener may increase the overall rate.
-                }
-                mListeners.notify();
-            }
-        }
-    }
-
-    @SuppressWarnings("unused")
-    public SensorService(Context context) {
-        if (localLOGV) Slog.d(TAG, "SensorService startup");
-        _sensors_control_init();
-    }
-    
-    public Bundle getDataChannel() throws RemoteException {
-        // synchronize so we do not require sensor HAL to be thread-safe.
-        synchronized(mListeners) {
-            return _sensors_control_open();
-        }
-    }
-
-    public boolean enableSensor(IBinder binder, String name, int sensor, int enable)
-            throws RemoteException {
-        
-        if (localLOGV) Slog.d(TAG, "enableSensor " + name + "(#" + sensor + ") " + enable);
-
-        if (binder == null) {
-            Slog.e(TAG, "listener is null (sensor=" + name + ", id=" + sensor + ")");
-            return false;
-        }
-
-        if (enable < 0 && (enable != SENSOR_DISABLE)) {
-            Slog.e(TAG, "invalid enable parameter (enable=" + enable +
-                    ", sensor=" + name + ", id=" + sensor + ")");
-            return false;
-        }
-
-        boolean res;
-        int uid = Binder.getCallingUid();
-        synchronized(mListeners) {
-            res = enableSensorInternalLocked(binder, uid, name, sensor, enable);
-            if (res == true) {
-                // Inform battery statistics service of status change
-                long identity = Binder.clearCallingIdentity();
-                if (enable == SENSOR_DISABLE) {
-                    mBatteryStats.noteStopSensor(uid, sensor);
-                } else {
-                    mBatteryStats.noteStartSensor(uid, sensor);
-                }
-                Binder.restoreCallingIdentity(identity);
-            }
-        }
-        return res;
-    }
-
-    private boolean enableSensorInternalLocked(IBinder binder, int uid,
-            String name, int sensor, int enable) throws RemoteException {
-
-        // check if we have this listener
-        Listener l = null;
-        for (Listener listener : mListeners) {
-            if (binder == listener.mToken) {
-                l = listener;
-                break;
-            }
-        }
-
-        if (enable != SENSOR_DISABLE) {
-            // Activate the requested sensor
-            if (_sensors_control_activate(sensor, true) == false) {
-                Slog.w(TAG, "could not enable sensor " + sensor);
-                return false;
-            }
-
-            if (l == null) {
-                /*
-                 * we don't have a listener for this binder yet, so
-                 * create a new one and add it to the list.
-                 */
-                l = new Listener(binder, uid);
-                binder.linkToDeath(l, 0);
-                mListeners.add(l);
-                mListeners.notify();
-            }
-
-            // take note that this sensor is now used by this client
-            l.addSensor(sensor, enable);
-
-        } else {
-
-            if (l == null) {
-                /*
-                 *  This client isn't in the list, this usually happens
-                 *  when enabling the sensor failed, but the client
-                 *  didn't handle the error and later tries to shut that
-                 *  sensor off.
-                 */
-                Slog.w(TAG, "listener with binder " + binder +
-                        ", doesn't exist (sensor=" + name +
-                        ", id=" + sensor + ")");
-                return false;
-            }
-
-            // remove this sensor from this client
-            l.removeSensor(sensor);
-
-            // see if we need to deactivate this sensors=
-            deactivateIfUnusedLocked(sensor);
-
-            // if the listener doesn't have any more sensors active
-            // we can get rid of it
-            if (l.mSensors == 0) {
-                // we won't need this death notification anymore
-                binder.unlinkToDeath(l, 0);
-                // remove the listener from the list
-                mListeners.remove(l);
-                // and if the list is empty, turn off the whole sensor h/w
-                if (mListeners.size() == 0) {
-                    _sensors_control_wake();
-                    _sensors_control_close();
-                }
-                mListeners.notify();
-            }
-        }
-
-        // calculate and set the new delay
-        int minDelay = 0x7FFFFFFF;
-        for (Listener listener : mListeners) {
-            if (listener.mDelay < minDelay)
-                minDelay = listener.mDelay;
-        }
-        if (minDelay != 0x7FFFFFFF) {
-            mCurrentDelay = minDelay;
-            _sensors_control_set_delay(minDelay);
-        }
-
-        return true;
-    }
-
-    private void deactivateIfUnusedLocked(int sensor) {
-        int size = mListeners.size();
-        for (int i=0 ; i<size ; i++) {
-            if (mListeners.get(i).hasSensor(sensor)) {
-                // this sensor is still in use, don't turn it off
-                return;
-            }
-        }
-        if (_sensors_control_activate(sensor, false) == false) {
-            Slog.w(TAG, "could not disable sensor " + sensor);
-        }
-    }
-
-    @Override
-    protected void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-        synchronized (mListeners) {
-            Printer pr = new PrintWriterPrinter(pw);
-            int c = 0;
-            pr.println(mListeners.size() + " listener(s), delay=" + mCurrentDelay + " ms");
-            for (Listener l : mListeners) {
-                pr.println("listener[" + c + "] " +
-                        "sensors=0x" + Integer.toString(l.mSensors, 16) +
-                        ", uid=" + l.mUid +
-                        ", delay=" +
-                        l.mDelay + " ms");
-                c++;
-            }
-        }
-    }
-
-    private ArrayList<Listener> mListeners = new ArrayList<Listener>();
-
-    private static native int _sensors_control_init();
-    private static native Bundle _sensors_control_open();
-    private static native int _sensors_control_close();
-    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_wake();
-}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index c01680e..ab869bb 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -165,10 +165,6 @@
             Watchdog.getInstance().init(context, battery, power, alarm,
                     ActivityManagerService.self());
 
-            // Sensor Service is needed by Window Manager, so this goes first
-            Slog.i(TAG, "Sensor Service");
-            ServiceManager.addService(Context.SENSOR_SERVICE, new SensorService(context));
-
             Slog.i(TAG, "Window Manager");
             wm = WindowManagerService.main(context, power,
                     factoryTest != SystemServer.FACTORY_TEST_LOW_LEVEL);
diff --git a/services/jni/Android.mk b/services/jni/Android.mk
index 0cf36b3..cdc0a6f 100644
--- a/services/jni/Android.mk
+++ b/services/jni/Android.mk
@@ -7,7 +7,6 @@
     com_android_server_InputManager.cpp \
     com_android_server_LightsService.cpp \
     com_android_server_PowerManagerService.cpp \
-    com_android_server_SensorService.cpp \
     com_android_server_SystemServer.cpp \
     com_android_server_VibratorService.cpp \
 	com_android_server_location_GpsLocationProvider.cpp \
diff --git a/services/jni/com_android_server_SensorService.cpp b/services/jni/com_android_server_SensorService.cpp
deleted file mode 100644
index 77db6da..0000000
--- a/services/jni/com_android_server_SensorService.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/*
- * Copyright 2008, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "SensorService"
-
-#include "utils/Log.h"
-
-#include <hardware/sensors.h>
-
-#include "jni.h"
-#include "JNIHelp.h"
-
-namespace android {
-
-static struct file_descriptor_offsets_t
-{
-    jclass mClass;
-    jmethodID mConstructor;
-    jfieldID mDescriptor;
-} gFileDescriptorOffsets;
-
-static struct parcel_file_descriptor_offsets_t
-{
-    jclass mClass;
-    jmethodID mConstructor;
-} 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 
- */
-
-static sensors_control_device_t* sSensorDevice = 0;
-
-static jint
-android_init(JNIEnv *env, jclass clazz)
-{
-    sensors_module_t* module;
-    if (hw_get_module(SENSORS_HARDWARE_MODULE_ID, (const hw_module_t**)&module) == 0) {
-        if (sensors_control_open(&module->common, &sSensorDevice) == 0) {
-            const struct sensor_t* list;
-            int count = module->get_sensors_list(module, &list);
-            return count;
-        }
-    }
-    return 0;
-}
-
-static jobject
-android_open(JNIEnv *env, jclass clazz)
-{
-    native_handle_t* handle = sSensorDevice->open_data_source(sSensorDevice);
-    if (!handle) {
-        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 jint
-android_close(JNIEnv *env, jclass clazz)
-{
-    if (sSensorDevice->close_data_source)
-        return sSensorDevice->close_data_source(sSensorDevice);
-    else
-        return 0;
-}
-
-static jboolean
-android_activate(JNIEnv *env, jclass clazz, jint sensor, jboolean activate)
-{
-    int active = sSensorDevice->activate(sSensorDevice, sensor, activate);
-    return (active<0) ? false : true;
-}
-
-static jint
-android_set_delay(JNIEnv *env, jclass clazz, jint ms)
-{
-    return sSensorDevice->set_delay(sSensorDevice, ms);
-}
-
-static jint
-android_data_wake(JNIEnv *env, jclass clazz)
-{
-    int res = sSensorDevice->wake(sSensorDevice);
-    return res;
-}
-
-
-static JNINativeMethod gMethods[] = {
-    {"_sensors_control_init",     "()I",   (void*) android_init },
-    {"_sensors_control_open",     "()Landroid/os/Bundle;",  (void*) android_open },
-    {"_sensors_control_close",     "()I",  (void*) android_close },
-    {"_sensors_control_activate", "(IZ)Z", (void*) android_activate },
-    {"_sensors_control_wake",     "()I", (void*) android_data_wake },
-    {"_sensors_control_set_delay","(I)I", (void*) android_set_delay },
-};
-
-int register_android_server_SensorService(JNIEnv *env)
-{
-    jclass clazz;
-
-    clazz = env->FindClass("java/io/FileDescriptor");
-    gFileDescriptorOffsets.mClass = (jclass)env->NewGlobalRef(clazz);
-    gFileDescriptorOffsets.mConstructor = env->GetMethodID(clazz, "<init>", "()V");
-    gFileDescriptorOffsets.mDescriptor = env->GetFieldID(clazz, "descriptor", "I");
-
-    clazz = env->FindClass("android/os/ParcelFileDescriptor");
-    gParcelFileDescriptorOffsets.mClass = (jclass) env->NewGlobalRef(clazz);
-    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",
-            gMethods, NELEM(gMethods));
-}
-
-}; // namespace android
diff --git a/services/jni/onload.cpp b/services/jni/onload.cpp
index 1a2d8b6..cd4f0a4 100644
--- a/services/jni/onload.cpp
+++ b/services/jni/onload.cpp
@@ -9,7 +9,6 @@
 int register_android_server_InputManager(JNIEnv* env);
 int register_android_server_LightsService(JNIEnv* env);
 int register_android_server_PowerManagerService(JNIEnv* env);
-int register_android_server_SensorService(JNIEnv* env);
 int register_android_server_VibratorService(JNIEnv* env);
 int register_android_server_SystemServer(JNIEnv* env);
 int register_android_server_location_GpsLocationProvider(JNIEnv* env);
@@ -33,7 +32,6 @@
     register_android_server_LightsService(env);
     register_android_server_AlarmManagerService(env);
     register_android_server_BatteryService(env);
-    register_android_server_SensorService(env);
     register_android_server_VibratorService(env);
     register_android_server_SystemServer(env);
     register_android_server_location_GpsLocationProvider(env);
diff --git a/services/sensorservice/Android.mk b/services/sensorservice/Android.mk
new file mode 100644
index 0000000..75f690f
--- /dev/null
+++ b/services/sensorservice/Android.mk
@@ -0,0 +1,28 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+    SensorService.cpp
+
+LOCAL_CFLAGS:= -DLOG_TAG=\"SensorService\"
+
+# need "-lrt" on Linux simulator to pick up clock_gettime
+ifeq ($(TARGET_SIMULATOR),true)
+	ifeq ($(HOST_OS),linux)
+		LOCAL_LDLIBS += -lrt -lpthread
+	endif
+endif
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils \
+	libhardware \
+	libutils \
+	libbinder \
+	libui \
+	libgui
+
+LOCAL_PRELINK_MODULE := false
+
+LOCAL_MODULE:= libsensorservice
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
new file mode 100644
index 0000000..a4f6549
--- /dev/null
+++ b/services/sensorservice/SensorService.cpp
@@ -0,0 +1,437 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/Atomic.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include <utils/Singleton.h>
+
+#include <binder/BinderService.h>
+#include <binder/IServiceManager.h>
+
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+
+#include <hardware/sensors.h>
+
+#include "SensorService.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+/*
+ * TODO:
+ * - handle per-connection event rate
+ * - filter events per connection
+ * - make sure to keep the last value of each event type so we can quickly
+ *   send something to application when they enable a sensor that is already
+ *   active (the issue here is that it can take time before a value is
+ *   produced by the h/w if the rate is low or if it's a one-shot sensor).
+ * - send sensor info to battery service
+ */
+
+// ---------------------------------------------------------------------------
+
+class BatteryService : public Singleton<BatteryService> {
+    friend class Singleton<BatteryService>;
+    sp<IBinder> mBatteryStatService;
+    BatteryService() {
+        const String16 name("batteryinfo");
+        //getService(name, &mBatteryStatService);
+    }
+public:
+    void enableSensor(int handle) {
+        if (mBatteryStatService != 0) {
+            int uid = IPCThreadState::self()->getCallingUid();
+            //mBatteryStatService->noteStartSensor(uid, handle);
+        }
+    }
+    void disableSensor(int handle) {
+        if (mBatteryStatService != 0) {
+            int uid = IPCThreadState::self()->getCallingUid();
+            //mBatteryStatService->noteStopSensor(uid, handle);
+        }
+    }
+};
+
+ANDROID_SINGLETON_STATIC_INSTANCE(BatteryService)
+
+// ---------------------------------------------------------------------------
+
+// 100 events/s max
+static const nsecs_t MINIMUM_EVENT_PERIOD = ms2ns(10);
+
+SensorService::SensorService()
+    : Thread(false),
+      mSensorDevice(0),
+      mSensorModule(0),
+      mDump("android.permission.DUMP"),
+      mInitCheck(NO_INIT)
+{
+}
+
+void SensorService::onFirstRef()
+{
+    LOGD("nuSensorService starting...");
+
+    status_t err = hw_get_module(SENSORS_HARDWARE_MODULE_ID,
+            (hw_module_t const**)&mSensorModule);
+
+    LOGE_IF(err, "couldn't load %s module (%s)",
+            SENSORS_HARDWARE_MODULE_ID, strerror(-err));
+
+    if (mSensorModule) {
+        err = sensors_open(&mSensorModule->common, &mSensorDevice);
+
+        LOGE_IF(err, "couldn't open device for module %s (%s)",
+                SENSORS_HARDWARE_MODULE_ID, strerror(-err));
+
+        struct sensor_t const* list;
+        int count = mSensorModule->get_sensors_list(mSensorModule, &list);
+        for (int i=0 ; i<count ; i++) {
+            Sensor sensor(list + i);
+            LOGI("%s", sensor.getName().string());
+            mSensorList.add(sensor);
+            if (mSensorDevice) {
+                mSensorDevice->activate(mSensorDevice, sensor.getHandle(), 0);
+            }
+        }
+
+        if (mSensorDevice) {
+            run("SensorService", PRIORITY_URGENT_DISPLAY);
+            mInitCheck = NO_ERROR;
+        }
+    }
+}
+
+SensorService::~SensorService()
+{
+}
+
+status_t SensorService::dump(int fd, const Vector<String16>& args)
+{
+    const size_t SIZE = 1024;
+    char buffer[SIZE];
+    String8 result;
+    if (!mDump.checkCalling()) {
+        snprintf(buffer, SIZE, "Permission Denial: "
+                "can't dump SurfaceFlinger from pid=%d, uid=%d\n",
+                IPCThreadState::self()->getCallingPid(),
+                IPCThreadState::self()->getCallingUid());
+        result.append(buffer);
+    } else {
+        Mutex::Autolock _l(mLock);
+        snprintf(buffer, SIZE, "%d connections / %d active\n",
+                mConnections.size(), mActiveConnections.size());
+        result.append(buffer);
+        snprintf(buffer, SIZE, "Active sensors:\n");
+        result.append(buffer);
+        for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
+            int handle = mActiveSensors.keyAt(i);
+            snprintf(buffer, SIZE, "%s (handle=%d, connections=%d)\n",
+                    getSensorName(handle).string(),
+                    handle,
+                    mActiveSensors.valueAt(i)->getNumConnections());
+            result.append(buffer);
+        }
+    }
+    write(fd, result.string(), result.size());
+    return NO_ERROR;
+}
+
+bool SensorService::threadLoop()
+{
+    LOGD("nuSensorService thread starting...");
+
+    sensors_event_t buffer[16];
+    struct sensors_poll_device_t* device = mSensorDevice;
+    ssize_t count;
+
+    do {
+        count = device->poll(device, buffer, sizeof(buffer)/sizeof(*buffer));
+        if (count<0) {
+            LOGE("sensor poll failed (%s)", strerror(-count));
+            break;
+        }
+
+        const SortedVector< wp<SensorEventConnection> > activeConnections(
+                getActiveConnections());
+
+        size_t numConnections = activeConnections.size();
+        if (numConnections) {
+            for (size_t i=0 ; i<numConnections ; i++) {
+                sp<SensorEventConnection> connection(activeConnections[i].promote());
+                if (connection != 0) {
+                    connection->sendEvents(buffer, count);
+                }
+            }
+        }
+
+    } while (count >= 0 || Thread::exitPending());
+
+    LOGW("Exiting SensorService::threadLoop!");
+    return false;
+}
+
+SortedVector< wp<SensorService::SensorEventConnection> >
+SensorService::getActiveConnections() const
+{
+    Mutex::Autolock _l(mLock);
+    return mActiveConnections;
+}
+
+String8 SensorService::getSensorName(int handle) const {
+    size_t count = mSensorList.size();
+    for (size_t i=0 ; i<count ; i++) {
+        const Sensor& sensor(mSensorList[i]);
+        if (sensor.getHandle() == handle) {
+            return sensor.getName();
+        }
+    }
+    String8 result("unknown");
+    return result;
+}
+
+Vector<Sensor> SensorService::getSensorList()
+{
+    return mSensorList;
+}
+
+sp<ISensorEventConnection> SensorService::createSensorEventConnection()
+{
+    sp<SensorEventConnection> result(new SensorEventConnection(this));
+    Mutex::Autolock _l(mLock);
+    mConnections.add(result);
+    return result;
+}
+
+void SensorService::cleanupConnection(const wp<SensorEventConnection>& connection)
+{
+    Mutex::Autolock _l(mLock);
+    ssize_t index = mConnections.indexOf(connection);
+    if (index >= 0) {
+
+        size_t size = mActiveSensors.size();
+        for (size_t i=0 ; i<size ; ) {
+            SensorRecord* rec = mActiveSensors.valueAt(i);
+            if (rec && rec->removeConnection(connection)) {
+                mSensorDevice->activate(mSensorDevice, mActiveSensors.keyAt(i), 0);
+                mActiveSensors.removeItemsAt(i, 1);
+                delete rec;
+                size--;
+            } else {
+                i++;
+            }
+        }
+
+        mActiveConnections.remove(connection);
+        mConnections.removeItemsAt(index, 1);
+    }
+}
+
+status_t SensorService::enable(const sp<SensorEventConnection>& connection,
+        int handle)
+{
+    if (mInitCheck != NO_ERROR)
+        return mInitCheck;
+
+    status_t err = NO_ERROR;
+    Mutex::Autolock _l(mLock);
+    SensorRecord* rec = mActiveSensors.valueFor(handle);
+    if (rec == 0) {
+        rec = new SensorRecord(connection);
+        mActiveSensors.add(handle, rec);
+        err = mSensorDevice->activate(mSensorDevice, handle, 1);
+        LOGE_IF(err, "Error activating sensor %d (%s)", handle, strerror(-err));
+        if (err == 0) {
+            BatteryService::getInstance().enableSensor(handle);
+        }
+    } else {
+        err = rec->addConnection(connection);
+    }
+    if (err == NO_ERROR) {
+        // connection now active
+        connection->addSensor(handle);
+        if (mActiveConnections.indexOf(connection) < 0) {
+            mActiveConnections.add(connection);
+        }
+    }
+    return err;
+}
+
+status_t SensorService::disable(const sp<SensorEventConnection>& connection,
+        int handle)
+{
+    if (mInitCheck != NO_ERROR)
+        return mInitCheck;
+
+    status_t err = NO_ERROR;
+    Mutex::Autolock _l(mLock);
+    SensorRecord* rec = mActiveSensors.valueFor(handle);
+    if (rec) {
+        // see if this connection becomes inactive
+        connection->removeSensor(handle);
+        if (connection->hasAnySensor() == false) {
+            mActiveConnections.remove(connection);
+        }
+        // see if this sensor becomes inactive
+        if (rec->removeConnection(connection)) {
+            mActiveSensors.removeItem(handle);
+            delete rec;
+            err = mSensorDevice->activate(mSensorDevice, handle, 0);
+            if (err == 0) {
+                BatteryService::getInstance().disableSensor(handle);
+            }
+        }
+    }
+    return err;
+}
+
+status_t SensorService::setRate(const sp<SensorEventConnection>& connection,
+        int handle, nsecs_t ns)
+{
+    if (mInitCheck != NO_ERROR)
+        return mInitCheck;
+
+    if (ns < 0)
+        return BAD_VALUE;
+
+    if (ns < MINIMUM_EVENT_PERIOD)
+        ns = MINIMUM_EVENT_PERIOD;
+
+    status_t err = NO_ERROR;
+    Mutex::Autolock _l(mLock);
+
+    err = mSensorDevice->setDelay(mSensorDevice, handle, ns);
+
+    // TODO: handle rate per connection
+    return err;
+}
+
+// ---------------------------------------------------------------------------
+
+SensorService::SensorRecord::SensorRecord(
+        const sp<SensorEventConnection>& connection)
+{
+    mConnections.add(connection);
+}
+
+status_t SensorService::SensorRecord::addConnection(
+        const sp<SensorEventConnection>& connection)
+{
+    if (mConnections.indexOf(connection) < 0) {
+        mConnections.add(connection);
+    }
+    return NO_ERROR;
+}
+
+bool SensorService::SensorRecord::removeConnection(
+        const wp<SensorEventConnection>& connection)
+{
+    ssize_t index = mConnections.indexOf(connection);
+    if (index >= 0) {
+        mConnections.removeItemsAt(index, 1);
+    }
+    return mConnections.size() ? false : true;
+}
+
+// ---------------------------------------------------------------------------
+
+SensorService::SensorEventConnection::SensorEventConnection(
+        const sp<SensorService>& service)
+    : mService(service), mChannel(new SensorChannel())
+{
+}
+
+SensorService::SensorEventConnection::~SensorEventConnection()
+{
+    mService->cleanupConnection(this);
+}
+
+void SensorService::SensorEventConnection::onFirstRef()
+{
+}
+
+void SensorService::SensorEventConnection::addSensor(int32_t handle) {
+    if (mSensorList.indexOf(handle) <= 0) {
+        mSensorList.add(handle);
+    }
+}
+
+void SensorService::SensorEventConnection::removeSensor(int32_t handle) {
+    mSensorList.remove(handle);
+}
+
+bool SensorService::SensorEventConnection::hasSensor(int32_t handle) const {
+    return mSensorList.indexOf(handle) >= 0;
+}
+
+bool SensorService::SensorEventConnection::hasAnySensor() const {
+    return mSensorList.size() ? true : false;
+}
+
+status_t SensorService::SensorEventConnection::sendEvents(
+        sensors_event_t const* buffer, size_t count)
+{
+    // TODO: we should only send the events for the sensors this connection
+    // is registered for.
+
+    ssize_t size = mChannel->write(buffer, count*sizeof(sensors_event_t));
+    if (size == -EAGAIN) {
+        // the destination doesn't accept events anymore, it's probably
+        // full. For now, we just drop the events on the floor.
+        LOGW("dropping %d events on the floor", count);
+        return size;
+    }
+
+    LOGE_IF(size<0, "dropping %d events on the floor (%s)",
+            count, strerror(-size));
+
+    return size < 0 ? size : NO_ERROR;
+}
+
+sp<SensorChannel> SensorService::SensorEventConnection::getSensorChannel() const
+{
+    return mChannel;
+}
+
+status_t SensorService::SensorEventConnection::enableDisable(
+        int handle, bool enabled)
+{
+    status_t err;
+    if (enabled) {
+        err = mService->enable(this, handle);
+    } else {
+        err = mService->disable(this, handle);
+    }
+    return err;
+}
+
+status_t SensorService::SensorEventConnection::setEventRate(
+        int handle, nsecs_t ns)
+{
+    return mService->setRate(this, handle, ns);
+}
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
new file mode 100644
index 0000000..8731956
--- /dev/null
+++ b/services/sensorservice/SensorService.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_SENSOR_SERVICE_H
+#define ANDROID_SENSOR_SERVICE_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Vector.h>
+#include <utils/SortedVector.h>
+#include <utils/KeyedVector.h>
+#include <utils/threads.h>
+#include <utils/RefBase.h>
+
+#include <binder/BinderService.h>
+#include <binder/Permission.h>
+
+#include <gui/Sensor.h>
+#include <gui/SensorChannel.h>
+#include <gui/ISensorServer.h>
+#include <gui/ISensorEventConnection.h>
+
+// ---------------------------------------------------------------------------
+
+struct sensors_poll_device_t;
+struct sensors_module_t;
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+class SensorService :
+        public BinderService<SensorService>,
+        public BnSensorServer,
+        protected Thread
+{
+   friend class BinderService<SensorService>;
+
+            SensorService();
+    virtual ~SensorService();
+
+    virtual void onFirstRef();
+
+    // Thread interface
+    virtual bool threadLoop();
+
+    // ISensorServer interface
+    virtual Vector<Sensor> getSensorList();
+    virtual sp<ISensorEventConnection> createSensorEventConnection();
+    virtual status_t dump(int fd, const Vector<String16>& args);
+
+
+    class SensorEventConnection : public BnSensorEventConnection {
+        virtual sp<SensorChannel> getSensorChannel() const;
+        virtual status_t enableDisable(int handle, bool enabled);
+        virtual status_t setEventRate(int handle, nsecs_t ns);
+        sp<SensorService> const mService;
+        sp<SensorChannel> const mChannel;
+        SortedVector<int32_t> mSensorList;
+    public:
+        SensorEventConnection(const sp<SensorService>& service);
+        virtual ~SensorEventConnection();
+        virtual void onFirstRef();
+        status_t sendEvents(sensors_event_t const* buffer, size_t count);
+        bool hasSensor(int32_t handle) const;
+        bool hasAnySensor() const;
+        void addSensor(int32_t handle);
+        void removeSensor(int32_t handle);
+    };
+
+    class SensorRecord {
+        SortedVector< wp<SensorEventConnection> > mConnections;
+    public:
+        SensorRecord(const sp<SensorEventConnection>& connection);
+        status_t addConnection(const sp<SensorEventConnection>& connection);
+        bool removeConnection(const wp<SensorEventConnection>& connection);
+        size_t getNumConnections() const { return mConnections.size(); }
+    };
+
+    SortedVector< wp<SensorEventConnection> > getActiveConnections() const;
+    String8 getSensorName(int handle) const;
+
+    // constants
+    Vector<Sensor> mSensorList;
+    struct sensors_poll_device_t* mSensorDevice;
+    struct sensors_module_t* mSensorModule;
+    Permission mDump;
+    status_t mInitCheck;
+
+    // protected by mLock
+    mutable Mutex mLock;
+    SortedVector< wp<SensorEventConnection> > mConnections;
+    DefaultKeyedVector<int, SensorRecord*> mActiveSensors;
+    SortedVector< wp<SensorEventConnection> > mActiveConnections;
+
+public:
+    static char const* getServiceName() { return "sensorservice"; }
+
+    void cleanupConnection(const wp<SensorEventConnection>& connection);
+    status_t enable(const sp<SensorEventConnection>& connection, int handle);
+    status_t disable(const sp<SensorEventConnection>& connection, int handle);
+    status_t setRate(const sp<SensorEventConnection>& connection, int handle, nsecs_t ns);
+};
+
+// ---------------------------------------------------------------------------
+}; // namespace android
+
+#endif // ANDROID_SENSOR_SERVICE_H
diff --git a/services/sensorservice/tests/Android.mk b/services/sensorservice/tests/Android.mk
new file mode 100644
index 0000000..45296dd
--- /dev/null
+++ b/services/sensorservice/tests/Android.mk
@@ -0,0 +1,14 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	sensorservicetest.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libcutils libutils libui libgui
+
+LOCAL_MODULE:= test-sensorservice
+
+LOCAL_MODULE_TAGS := optional
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/sensorservice/tests/sensorservicetest.cpp b/services/sensorservice/tests/sensorservicetest.cpp
new file mode 100644
index 0000000..e464713
--- /dev/null
+++ b/services/sensorservice/tests/sensorservicetest.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <android/sensor.h>
+#include <gui/Sensor.h>
+#include <gui/SensorManager.h>
+#include <gui/SensorEventQueue.h>
+#include <utils/PollLoop.h>
+
+using namespace android;
+
+bool receiver(int fd, int events, void* data)
+{
+    sp<SensorEventQueue> q((SensorEventQueue*)data);
+    ssize_t n;
+    ASensorEvent buffer[8];
+    while ((n = q->read(buffer, 8)) > 0) {
+        for (int i=0 ; i<n ; i++) {
+            if (buffer[i].type == Sensor::TYPE_ACCELEROMETER) {
+                printf("time=%lld, value=<%5.1f,%5.1f,%5.1f>\n",
+                        buffer[i].timestamp,
+                        buffer[i].acceleration.x,
+                        buffer[i].acceleration.y,
+                        buffer[i].acceleration.z);
+            }
+        }
+    }
+    if (n<0 && n != -EAGAIN) {
+        printf("error reading events (%s)\n", strerror(-n));
+    }
+    return true;
+}
+
+
+int main(int argc, char** argv)
+{
+    SensorManager& mgr(SensorManager::getInstance());
+
+    Sensor const* const* list;
+    ssize_t count = mgr.getSensorList(&list);
+    printf("numSensors=%d\n", count);
+
+    sp<SensorEventQueue> q = mgr.createEventQueue();
+    printf("queue=%p\n", q.get());
+
+    Sensor const* accelerometer = mgr.getDefaultSensor(Sensor::TYPE_ACCELEROMETER);
+    printf("accelerometer=%p (%s)\n",
+            accelerometer, accelerometer->getName().string());
+    q->enableSensor(accelerometer);
+
+    q->setEventRate(accelerometer, ms2ns(10));
+
+    sp<PollLoop> loop = new PollLoop(false);
+    loop->setCallback(q->getFd(), POLLIN, receiver, q.get());
+
+    do {
+        //printf("about to poll...\n");
+        int32_t ret = loop->pollOnce(-1, 0, 0);
+        switch (ret) {
+            case ALOOPER_POLL_CALLBACK:
+                //("ALOOPER_POLL_CALLBACK\n");
+                break;
+            case ALOOPER_POLL_TIMEOUT:
+                printf("ALOOPER_POLL_TIMEOUT\n");
+                break;
+            case ALOOPER_POLL_ERROR:
+                printf("ALOOPER_POLL_TIMEOUT\n");
+                break;
+            default:
+                printf("ugh? poll returned %d\n", ret);
+                break;
+        }
+    } while (1);
+
+
+    return 0;
+}
diff --git a/services/tests/servicestests/src/com/android/server/DropBoxTest.java b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
index 78a90fb..f3baff4 100644
--- a/services/tests/servicestests/src/com/android/server/DropBoxTest.java
+++ b/services/tests/servicestests/src/com/android/server/DropBoxTest.java
@@ -20,6 +20,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.os.DropBoxManager;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.ParcelFileDescriptor;
+import android.os.Process;
 import android.os.ServiceManager;
 import android.os.StatFs;
 import android.provider.Settings;
@@ -27,10 +31,13 @@
 
 import com.android.server.DropBoxManagerService;
 
+import java.io.BufferedReader;
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.FileWriter;
+import java.io.IOException;
 import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.Random;
 import java.util.zip.GZIPOutputStream;
 
@@ -531,6 +538,203 @@
         service.stop();
     }
 
+    public void testDropBoxEntrySerialization() throws Exception {
+        // Make sure DropBoxManager.Entry can be serialized to a Parcel and back
+        // under a variety of conditions.
+
+        Parcel parcel = Parcel.obtain();
+        File dir = getEmptyDir("testDropBoxEntrySerialization");
+
+        new DropBoxManager.Entry("empty", 1000000).writeToParcel(parcel, 0);
+        new DropBoxManager.Entry("string", 2000000, "String Value").writeToParcel(parcel, 0);
+        new DropBoxManager.Entry("bytes", 3000000, "Bytes Value".getBytes(),
+                DropBoxManager.IS_TEXT).writeToParcel(parcel, 0);
+        new DropBoxManager.Entry("zerobytes", 4000000, new byte[0], 0).writeToParcel(parcel, 0);
+        new DropBoxManager.Entry("emptybytes", 5000000, (byte[]) null,
+                DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
+
+        try {
+            new DropBoxManager.Entry("badbytes", 99999,
+                    "Bad Bytes Value".getBytes(),
+                    DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
+            fail("IllegalArgumentException expected for non-null byte[] and IS_EMPTY flags");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            new DropBoxManager.Entry("badbytes", 99999, (byte[]) null, 0).writeToParcel(parcel, 0);
+            fail("IllegalArgumentException expected for null byte[] and non-IS_EMPTY flags");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        File f = new File(dir, "file.dat");
+        FileOutputStream os = new FileOutputStream(f);
+        os.write("File Value".getBytes());
+        os.close();
+
+        new DropBoxManager.Entry("file", 6000000, f, DropBoxManager.IS_TEXT).writeToParcel(
+                parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        new DropBoxManager.Entry("binfile", 7000000, f, 0).writeToParcel(
+                parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        new DropBoxManager.Entry("emptyfile", 8000000, (ParcelFileDescriptor) null,
+                DropBoxManager.IS_EMPTY).writeToParcel(parcel, 0);
+
+        try {
+            new DropBoxManager.Entry("badfile", 99999, new File(dir, "nonexist.dat"), 0);
+            fail("IOException expected for nonexistent file");
+        } catch (IOException e) {
+            // expected
+        }
+
+        try {
+            new DropBoxManager.Entry("badfile", 99999, f, DropBoxManager.IS_EMPTY).writeToParcel(
+                    parcel, 0);
+            fail("IllegalArgumentException expected for non-null file and IS_EMPTY flags");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        try {
+            new DropBoxManager.Entry("badfile", 99999, (ParcelFileDescriptor) null, 0);
+            fail("IllegalArgumentException expected for null PFD and non-IS_EMPTY flags");
+        } catch (IllegalArgumentException e) {
+            // expected
+        }
+
+        File gz = new File(dir, "file.gz");
+        GZIPOutputStream gzout = new GZIPOutputStream(new FileOutputStream(gz));
+        gzout.write("Gzip File Value".getBytes());
+        gzout.close();
+
+        new DropBoxManager.Entry("gzipfile", 9000000, gz,
+                DropBoxManager.IS_TEXT | DropBoxManager.IS_GZIPPED).writeToParcel(
+                    parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+        new DropBoxManager.Entry("gzipbinfile", 10000000, gz,
+                DropBoxManager.IS_GZIPPED).writeToParcel(
+                    parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+
+        //
+        // Switch from writing to reading
+        //
+
+        parcel.setDataPosition(0);
+        DropBoxManager.Entry e;
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("empty", e.getTag());
+        assertEquals(1000000, e.getTimeMillis());
+        assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
+        assertEquals(null, e.getText(100));
+        assertEquals(null, e.getInputStream());
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("string", e.getTag());
+        assertEquals(2000000, e.getTimeMillis());
+        assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
+        assertEquals("String Value", e.getText(100));
+        assertEquals("String Value",
+                new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("bytes", e.getTag());
+        assertEquals(3000000, e.getTimeMillis());
+        assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
+        assertEquals("Bytes Value", e.getText(100));
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("zerobytes", e.getTag());
+        assertEquals(4000000, e.getTimeMillis());
+        assertEquals(0, e.getFlags());
+        assertEquals(null, e.getText(100));
+        assertEquals(null,
+                new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("emptybytes", e.getTag());
+        assertEquals(5000000, e.getTimeMillis());
+        assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
+        assertEquals(null, e.getText(100));
+        assertEquals(null, e.getInputStream());
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("file", e.getTag());
+        assertEquals(6000000, e.getTimeMillis());
+        assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
+        assertEquals("File Value", e.getText(100));
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("binfile", e.getTag());
+        assertEquals(7000000, e.getTimeMillis());
+        assertEquals(0, e.getFlags());
+        assertEquals(null, e.getText(100));
+        assertEquals("File Value",
+                new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("emptyfile", e.getTag());
+        assertEquals(8000000, e.getTimeMillis());
+        assertEquals(DropBoxManager.IS_EMPTY, e.getFlags());
+        assertEquals(null, e.getText(100));
+        assertEquals(null, e.getInputStream());
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("gzipfile", e.getTag());
+        assertEquals(9000000, e.getTimeMillis());
+        assertEquals(DropBoxManager.IS_TEXT, e.getFlags());
+        assertEquals("Gzip File Value", e.getText(100));
+        e.close();
+
+        e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+        assertEquals("gzipbinfile", e.getTag());
+        assertEquals(10000000, e.getTimeMillis());
+        assertEquals(0, e.getFlags());
+        assertEquals(null, e.getText(100));
+        assertEquals("Gzip File Value",
+                new BufferedReader(new InputStreamReader(e.getInputStream())).readLine());
+        e.close();
+
+        assertEquals(0, parcel.dataAvail());
+        parcel.recycle();
+    }
+
+    public void testDropBoxEntrySerializationDoesntLeakFileDescriptors() throws Exception {
+        File dir = getEmptyDir("testDropBoxEntrySerialization");
+        File f = new File(dir, "file.dat");
+        FileOutputStream os = new FileOutputStream(f);
+        os.write("File Value".getBytes());
+        os.close();
+
+        int before = countOpenFiles();
+        assertTrue(before > 0);
+
+        for (int i = 0; i < 1000; i++) {
+            Parcel parcel = Parcel.obtain();
+            new DropBoxManager.Entry("file", 1000000, f, 0).writeToParcel(
+                    parcel, Parcelable.PARCELABLE_WRITE_RETURN_VALUE);
+
+            parcel.setDataPosition(0);
+            DropBoxManager.Entry e = DropBoxManager.Entry.CREATOR.createFromParcel(parcel);
+            assertEquals("file", e.getTag());
+            e.close();
+
+            parcel.recycle();
+        }
+
+        int after = countOpenFiles();
+        assertTrue(after > 0);
+        assertTrue(after < before + 20);
+    }
+
     private void addRandomEntry(DropBoxManager dropbox, String tag, int size) throws Exception {
         byte[] bytes = new byte[size];
         new Random(System.currentTimeMillis()).nextBytes(bytes);
@@ -564,4 +768,8 @@
         assertTrue(dir.listFiles().length == 0);
         return dir;
     }
+
+    private int countOpenFiles() {
+        return new File("/proc/" + Process.myPid() + "/fd").listFiles().length;
+    }
 }