Merge "native: Rename mBuf to mSlot"
diff --git a/cmds/atrace/Android.mk b/cmds/atrace/Android.mk
index 028ca8f..a787e95 100644
--- a/cmds/atrace/Android.mk
+++ b/cmds/atrace/Android.mk
@@ -17,4 +17,6 @@
     libutils \
     libz \
 
+LOCAL_INIT_RC := atrace.rc
+
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 5a33417..d63019b 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -92,6 +92,7 @@
     { "bionic",     "Bionic C Library", ATRACE_TAG_BIONIC, { } },
     { "power",      "Power Management", ATRACE_TAG_POWER, { } },
     { "pm",         "Package Manager",  ATRACE_TAG_PACKAGE_MANAGER, { } },
+    { "ss",         "System Server",    ATRACE_TAG_SYSTEM_SERVER, { } },
     { "sched",      "CPU Scheduling",   0, {
         { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_switch/enable" },
         { REQ,      "/sys/kernel/debug/tracing/events/sched/sched_wakeup/enable" },
@@ -142,6 +143,15 @@
     { "regulators",  "Voltage and Current Regulators", 0, {
         { REQ,      "/sys/kernel/debug/tracing/events/regulator/enable" },
     } },
+    { "binder_driver", "Binder Kernel driver", 0, {
+        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_transaction/enable" },
+        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable" },
+    } },
+    { "binder_lock", "Binder global lock trace", 0, {
+        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_lock/enable" },
+        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_locked/enable" },
+        { REQ,      "/sys/kernel/debug/tracing/events/binder/binder_unlock/enable" },
+    } },
 };
 
 /* Command line options */
@@ -267,9 +277,27 @@
 static void writeClockSyncMarker()
 {
   char buffer[128];
+  int len = 0;
+  int fd = open(k_traceMarkerPath, O_WRONLY);
+  if (fd == -1) {
+      fprintf(stderr, "error opening %s: %s (%d)\n", k_traceMarkerPath,
+              strerror(errno), errno);
+      return;
+  }
   float now_in_seconds = systemTime(CLOCK_MONOTONIC) / 1000000000.0f;
-  snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
-  writeStr(k_traceMarkerPath, buffer);
+
+  len = snprintf(buffer, 128, "trace_event_clock_sync: parent_ts=%f\n", now_in_seconds);
+  if (write(fd, buffer, len) != len) {
+      fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
+  }
+
+  int64_t realtime_in_ms = systemTime(CLOCK_REALTIME) / 1000000;
+  len = snprintf(buffer, 128, "trace_event_clock_sync: realtime_ts=%" PRId64 "\n", realtime_in_ms);
+  if (write(fd, buffer, len) != len) {
+      fprintf(stderr, "error writing clock sync marker %s (%d)\n", strerror(errno), errno);
+  }
+
+  close(fd);
 }
 
 // Enable or disable a kernel option by writing a "1" or a "0" into a /sys
@@ -696,7 +724,6 @@
 // Disable tracing in the kernel.
 static void stopTrace()
 {
-    writeClockSyncMarker();
     setTracingEnabled(false);
 }
 
@@ -972,6 +999,7 @@
         // another.
         ok = clearTrace();
 
+        writeClockSyncMarker();
         if (ok && !async) {
             // Sleep to allow the trace to be captured.
             struct timespec timeLeft;
diff --git a/cmds/atrace/atrace.rc b/cmds/atrace/atrace.rc
new file mode 100644
index 0000000..cde9c37
--- /dev/null
+++ b/cmds/atrace/atrace.rc
@@ -0,0 +1,62 @@
+## Permissions to allow system-wide tracing to the kernel trace buffer.
+##
+on boot
+
+# Allow writing to the kernel trace log.
+    chmod 0222 /sys/kernel/debug/tracing/trace_marker
+
+# Allow the shell group to enable (some) kernel tracing.
+    chown root shell /sys/kernel/debug/tracing/trace_clock
+    chown root shell /sys/kernel/debug/tracing/buffer_size_kb
+    chown root shell /sys/kernel/debug/tracing/options/overwrite
+    chown root shell /sys/kernel/debug/tracing/options/print-tgid
+    chown root shell /sys/kernel/debug/tracing/events/sched/sched_switch/enable
+    chown root shell /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+    chown root shell /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
+    chown root shell /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+    chown root shell /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
+    chown root shell /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chown root shell /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+    chown root shell /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+
+    chown root shell /sys/kernel/debug/tracing/tracing_on
+
+    chmod 0664 /sys/kernel/debug/tracing/trace_clock
+    chmod 0664 /sys/kernel/debug/tracing/buffer_size_kb
+    chmod 0664 /sys/kernel/debug/tracing/options/overwrite
+    chmod 0664 /sys/kernel/debug/tracing/options/print-tgid
+    chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_switch/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/sched/sched_wakeup/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_frequency/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/power/cpu_idle/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/power/clock_set_rate/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/cpufreq_interactive/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_begin/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_direct_reclaim_end/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_wake/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/vmscan/mm_vmscan_kswapd_sleep/enable
+    chmod 0664 /sys/kernel/debug/tracing/tracing_on
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_transaction_received/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_lock/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_locked/enable
+    chmod 0664 /sys/kernel/debug/tracing/events/binder/binder_unlock/enable
+
+# Allow only the shell group to read and truncate the kernel trace.
+    chown root shell /sys/kernel/debug/tracing/trace
+    chmod 0660 /sys/kernel/debug/tracing/trace
+
+on property:persist.debug.atrace.boottrace=1
+    start boottrace
+
+# Run atrace with the categories written in a file
+service boottrace /system/bin/atrace --async_start -f /data/misc/boottrace/categories
+    disabled
+    oneshot
diff --git a/cmds/dumpstate/Android.mk b/cmds/dumpstate/Android.mk
index 9065ee1..8c7c4a8 100644
--- a/cmds/dumpstate/Android.mk
+++ b/cmds/dumpstate/Android.mk
@@ -17,5 +17,6 @@
 LOCAL_SHARED_LIBRARIES := libcutils liblog libselinux
 LOCAL_HAL_STATIC_LIBRARIES := libdumpstate
 LOCAL_CFLAGS += -Wall -Wno-unused-parameter -std=gnu99
+LOCAL_INIT_RC := dumpstate.rc
 
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
new file mode 100644
index 0000000..cd5d6c4
--- /dev/null
+++ b/cmds/dumpstate/dumpstate.rc
@@ -0,0 +1,5 @@
+service dumpstate /system/bin/dumpstate -s
+    class main
+    socket dumpstate stream 0660 shell log
+    disabled
+    oneshot
diff --git a/cmds/installd/Android.mk b/cmds/installd/Android.mk
index 6dec7f6..eaeeb22 100644
--- a/cmds/installd/Android.mk
+++ b/cmds/installd/Android.mk
@@ -38,5 +38,6 @@
 
 LOCAL_STATIC_LIBRARIES := libdiskusage
 LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
+LOCAL_INIT_RC := installd.rc
 LOCAL_CLANG := true
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/installd/installd.rc b/cmds/installd/installd.rc
new file mode 100644
index 0000000..5e4c925
--- /dev/null
+++ b/cmds/installd/installd.rc
@@ -0,0 +1,3 @@
+service installd /system/bin/installd
+    class main
+    socket installd stream 600 system system
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index 7db3fb9..e58391f 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -256,7 +256,7 @@
                 if ((name[1] == '.') && (name[2] == 0)) continue;
             }
 
-            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
+            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
             if (subfd < 0) {
                 ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
                 result = -1;
@@ -316,7 +316,7 @@
     int fd, res;
     DIR *d;
 
-    fd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
+    fd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
     if (fd < 0) {
         ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
         return -1;
@@ -656,7 +656,7 @@
                 if ((name[1] == '.') && (name[2] == 0)) continue;
             }
 
-            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY);
+            subfd = openat(dfd, name, O_RDONLY | O_DIRECTORY | O_NOFOLLOW | O_CLOEXEC);
             if (subfd < 0) {
                 ALOGE("Couldn't openat %s: %s\n", name, strerror(errno));
                 continue;
diff --git a/cmds/servicemanager/Android.mk b/cmds/servicemanager/Android.mk
index 155cfc5..7ee0dd1 100644
--- a/cmds/servicemanager/Android.mk
+++ b/cmds/servicemanager/Android.mk
@@ -22,4 +22,5 @@
 LOCAL_SRC_FILES := service_manager.c binder.c
 LOCAL_CFLAGS += $(svc_c_flags)
 LOCAL_MODULE := servicemanager
+LOCAL_INIT_RC := servicemanager.rc
 include $(BUILD_EXECUTABLE)
diff --git a/cmds/servicemanager/servicemanager.rc b/cmds/servicemanager/servicemanager.rc
new file mode 100644
index 0000000..7154fab
--- /dev/null
+++ b/cmds/servicemanager/servicemanager.rc
@@ -0,0 +1,11 @@
+service servicemanager /system/bin/servicemanager
+    class core
+    user system
+    group system
+    critical
+    onrestart restart healthd
+    onrestart restart zygote
+    onrestart restart media
+    onrestart restart surfaceflinger
+    onrestart restart inputflinger
+    onrestart restart drm
diff --git a/data/etc/android.hardware.audio.pro.xml b/data/etc/android.hardware.audio.pro.xml
new file mode 100644
index 0000000..5328d41
--- /dev/null
+++ b/data/etc/android.hardware.audio.pro.xml
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2015 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.
+-->
+
+<!-- This is the feature indicating professional audio, as specified by the
+     CDD. ONLY devices that meet the CDD's requirements may declare this
+     feature. -->
+<permissions>
+    <feature name="android.hardware.audio.pro" />
+</permissions>
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index f671116..ac07190 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -731,7 +731,27 @@
     /** Generic stem key 2 for Wear */
     AKEYCODE_STEM_2 = 266,
     /** Generic stem key 3 for Wear */
-    AKEYCODE_STEM_3 = 267
+    AKEYCODE_STEM_3 = 267,
+    /** Directional Pad Up-Left */
+    AKEYCODE_DPAD_UP_LEFT    = 268,
+    /** Directional Pad Down-Left */
+    AKEYCODE_DPAD_DOWN_LEFT  = 269,
+    /** Directional Pad Up-Right */
+    AKEYCODE_DPAD_UP_RIGHT   = 270,
+    /** Directional Pad Down-Right */
+    AKEYCODE_DPAD_DOWN_RIGHT = 271,
+    /** Skip forward media key */
+    AKEYCODE_MEDIA_SKIP_FORWARD = 272,
+    /** Skip backward media key */
+    AKEYCODE_MEDIA_SKIP_BACKWARD = 273,
+    /** Step forward media key.
+     * Steps media forward one from at a time. */
+    AKEYCODE_MEDIA_STEP_FORWARD = 274,
+    /** Step backward media key.
+     * Steps media backward one from at a time. */
+    AKEYCODE_MEDIA_STEP_BACKWARD = 275,
+    /** Put device to sleep unless a wakelock is held. */
+    AKEYCODE_SOFT_SLEEP = 276
 
     // NOTE: If you add a new keycode here you must also add it to several other files.
     //       Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list.
diff --git a/include/android/sensor.h b/include/android/sensor.h
index 73928ea..9472ad6 100644
--- a/include/android/sensor.h
+++ b/include/android/sensor.h
@@ -59,7 +59,7 @@
 
 /**
  * Sensor types.
- * (keep in sync with hardware/sensor.h)
+ * (keep in sync with hardware/sensors.h)
  */
 enum {
     /**
@@ -69,7 +69,7 @@
      *  All values are in SI units (m/s^2) and measure the acceleration of the
      *  device minus the force of gravity.
      */
-    ASENSOR_TYPE_ACCELEROMETER      = 1,
+    ASENSOR_TYPE_ACCELEROMETER       = 1,
     /**
      * {@link ASENSOR_TYPE_MAGNETIC_FIELD}
      * reporting-mode: continuous
@@ -77,7 +77,7 @@
      *  All values are in micro-Tesla (uT) and measure the geomagnetic
      *  field in the X, Y and Z axis.
      */
-    ASENSOR_TYPE_MAGNETIC_FIELD     = 2,
+    ASENSOR_TYPE_MAGNETIC_FIELD      = 2,
     /**
      * {@link ASENSOR_TYPE_GYROSCOPE}
      * reporting-mode: continuous
@@ -85,14 +85,14 @@
      *  All values are in radians/second and measure the rate of rotation
      *  around the X, Y and Z axis.
      */
-    ASENSOR_TYPE_GYROSCOPE          = 4,
+    ASENSOR_TYPE_GYROSCOPE           = 4,
     /**
      * {@link ASENSOR_TYPE_LIGHT}
      * reporting-mode: on-change
      *
      * The light sensor value is returned in SI lux units.
      */
-    ASENSOR_TYPE_LIGHT              = 5,
+    ASENSOR_TYPE_LIGHT               = 5,
     /**
      * {@link ASENSOR_TYPE_PROXIMITY}
      * reporting-mode: on-change
@@ -103,7 +103,15 @@
      * SENSOR_FLAG_WAKE_UP.
      * The value corresponds to the distance to the nearest object in centimeters.
      */
-    ASENSOR_TYPE_PROXIMITY          = 8
+    ASENSOR_TYPE_PROXIMITY           = 8,
+    /**
+     * {@link ASENSOR_TYPE_LINEAR_ACCELERATION}
+     * reporting-mode: continuous
+     *
+     *  All values are in SI units (m/s^2) and measure the acceleration of the
+     *  device not including the force of gravity.
+     */
+    ASENSOR_TYPE_LINEAR_ACCELERATION = 10
 };
 
 /**
diff --git a/include/batteryservice/BatteryService.h b/include/batteryservice/BatteryService.h
index f0a2790..9a8e2f7 100644
--- a/include/batteryservice/BatteryService.h
+++ b/include/batteryservice/BatteryService.h
@@ -64,6 +64,9 @@
     int batteryLevel;
     int batteryVoltage;
     int batteryTemperature;
+    int batteryCurrent;
+    int batteryCycleCount;
+    int batteryFullCharge;
     String8 batteryTechnology;
 
     status_t writeToParcel(Parcel* parcel) const;
diff --git a/include/binder/Binder.h b/include/binder/Binder.h
index 86628a0..f849fd4 100644
--- a/include/binder/Binder.h
+++ b/include/binder/Binder.h
@@ -17,7 +17,7 @@
 #ifndef ANDROID_BINDER_H
 #define ANDROID_BINDER_H
 
-#include <stdatomic.h>
+#include <atomic>
 #include <stdint.h>
 #include <binder/IBinder.h>
 
@@ -71,7 +71,7 @@
 
     class Extras;
 
-    atomic_uintptr_t    mExtras;  // should be atomic<Extras *>
+    std::atomic<Extras*> mExtras;
             void*       mReserved0;
 };
 
@@ -95,7 +95,7 @@
 
     IBinder* const          mRemote;
     RefBase::weakref_type*  mRefs;
-    volatile int32_t        mState;
+    std::atomic<int32_t>    mState;
 };
 
 }; // namespace android
diff --git a/include/gui/BufferQueueCore.h b/include/gui/BufferQueueCore.h
index 99134ea..c6643ea 100644
--- a/include/gui/BufferQueueCore.h
+++ b/include/gui/BufferQueueCore.h
@@ -192,13 +192,6 @@
     // a buffer attached
     std::list<int> mFreeBuffers;
 
-    // mOverrideMaxBufferCount is the limit on the number of buffers that will
-    // be allocated at one time. This value is set by the producer by calling
-    // setBufferCount. The default is 0, which means that the producer doesn't
-    // care about the number of buffers in the pool. In that case,
-    // mDefaultMaxBufferCount is used as the limit.
-    int mOverrideMaxBufferCount;
-
     // mDequeueCondition is a condition variable used for dequeueBuffer in
     // synchronous mode.
     mutable Condition mDequeueCondition;
@@ -242,6 +235,18 @@
     // the value returned for the MIN_UNDEQUEUED_BUFFERS query to the producer.
     int mMaxAcquiredBufferCount;
 
+    // mMaxDequeuedBufferCount is the number of buffers that the producer may
+    // dequeue at one time. It defaults to 1, and can be changed by the producer
+    // via setMaxDequeuedBufferCount.
+    int mMaxDequeuedBufferCount;
+
+    // mOverrideMaxBufferCount defaults to false and is set to true once the
+    // producer has called setMaxDequeuedBufferCount or setAsyncMode. Once it is
+    // set mDefaultMaxBufferCount is ignored and the max buffer count is
+    // calculated based on mMaxAcquiredBufferCount, mMaxDequeuedBufferCount, and
+    // mAsyncMode.
+    bool mOverrideMaxBufferCount;
+
     // mBufferHasBeenQueued is true once a buffer has been queued. It is reset
     // when something causes all buffers to be freed (e.g., changing the buffer
     // count).
@@ -280,6 +285,11 @@
     // number will fail.
     uint32_t mGenerationNumber;
 
+    // mAsyncMode indicates whether or not async mode is enabled.
+    // In async mode an extra buffer will be allocated to allow the producer to
+    // enqueue buffers without blocking.
+    bool mAsyncMode;
+
 }; // class BufferQueueCore
 
 } // namespace android
diff --git a/include/gui/BufferQueueProducer.h b/include/gui/BufferQueueProducer.h
index 9754a89..7827072 100644
--- a/include/gui/BufferQueueProducer.h
+++ b/include/gui/BufferQueueProducer.h
@@ -39,22 +39,11 @@
     // flags indicating that previously-returned buffers are no longer valid.
     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
 
-    // setBufferCount updates the number of available buffer slots.  If this
-    // method succeeds, buffer slots will be both unallocated and owned by
-    // the BufferQueue object (i.e. they are not owned by the producer or
-    // consumer).
-    //
-    // This will fail if the producer has dequeued any buffers, or if
-    // bufferCount is invalid.  bufferCount must generally be a value
-    // between the minimum undequeued buffer count (exclusive) and NUM_BUFFER_SLOTS
-    // (inclusive).  It may also be set to zero (the default) to indicate
-    // that the producer does not wish to set a value.  The minimum value
-    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
-    // ...).
-    //
-    // This may only be called by the producer.  The consumer will be told
-    // to discard buffers through the onBuffersReleased callback.
-    virtual status_t setBufferCount(int bufferCount);
+    // see IGraphicsBufferProducer::setMaxDequeuedBufferCount
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+
+    // see IGraphicsBufferProducer::setAsyncMode
+    virtual status_t setAsyncMode(bool async);
 
     // dequeueBuffer gets the next buffer slot index for the producer to use.
     // If a buffer slot is available then that slot index is written to the
diff --git a/include/gui/CpuConsumer.h b/include/gui/CpuConsumer.h
index 3b07a31..f9d0e7d 100644
--- a/include/gui/CpuConsumer.h
+++ b/include/gui/CpuConsumer.h
@@ -67,6 +67,25 @@
         uint8_t    *dataCr;
         uint32_t    chromaStride;
         uint32_t    chromaStep;
+
+        LockedBuffer() :
+            data(NULL),
+            width(0),
+            height(0),
+            format(PIXEL_FORMAT_NONE),
+            stride(0),
+            crop(0, 0, 0, 0),
+            transform(0),
+            scalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
+            timestamp(0),
+            dataSpace(HAL_DATASPACE_UNKNOWN),
+            frameNumber(0),
+            flexFormat(PIXEL_FORMAT_NONE),
+            dataCb(NULL),
+            dataCr(NULL),
+            chromaStride(0),
+            chromaStep(0)
+        {}
     };
 
     // Create a new CPU consumer. The maxLockedBuffers parameter specifies
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index 9530de1..91502e2 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -80,27 +80,44 @@
     //              * buffer specified by the slot is not dequeued
     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf) = 0;
 
-    // setBufferCount sets the number of buffer slots available. Calling this
-    // will also cause all buffer slots to be emptied. The caller should empty
-    // its mirrored copy of the buffer slots when calling this method.
+    // setMaxDequeuedBufferCount sets the maximum number of buffers that can be
+    // dequeued by the producer at one time. If this method succeeds, buffer
+    // slots will be both unallocated and owned by the BufferQueue object (i.e.
+    // they are not owned by the producer or consumer). Calling this will also
+    // cause all buffer slots to be emptied. If the caller is caching the
+    // contents of the buffer slots, it should empty that cache after calling
+    // this method.
     //
-    // This function should not be called when there are any dequeued buffer
-    // slots, doing so will result in a BAD_VALUE error returned.
+    // This function should not be called when there are any currently dequeued
+    // buffer slots. Doing so will result in a BAD_VALUE error.
     //
-    // The buffer count should be at most NUM_BUFFER_SLOTS (inclusive), but at least
-    // the minimum undequeued buffer count (exclusive). The minimum value
-    // can be obtained by calling query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS).
-    // In particular the range is (minUndequeudBuffers, NUM_BUFFER_SLOTS].
-    //
-    // The buffer count may also be set to 0 (the default), to indicate that
-    // the producer does not wish to set a value.
+    // The buffer count should be at least 1 (inclusive), but at most
+    // (NUM_BUFFER_SLOTS - the minimum undequeued buffer count) (exclusive). The
+    // minimum undequeued buffer count can be obtained by calling
+    // query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS).
     //
     // Return of a value other than NO_ERROR means an error has occurred:
     // * NO_INIT - the buffer queue has been abandoned.
     // * BAD_VALUE - one of the below conditions occurred:
     //              * bufferCount was out of range (see above)
     //              * client has one or more buffers dequeued
-    virtual status_t setBufferCount(int bufferCount) = 0;
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) = 0;
+
+    // Set the async flag if the producer intends to asynchronously queue
+    // buffers without blocking. Typically this is used for triple-buffering
+    // and/or when the swap interval is set to zero.
+    //
+    // Enabling async mode will internally allocate an additional buffer to
+    // allow for the asynchronous behavior. If it is not enabled queue/dequeue
+    // calls may block.
+    //
+    // This function should not be called when there are any currently dequeued
+    // buffer slots, doing so will result in a BAD_VALUE error.
+    //
+    // Return of a value other than NO_ERROR means an error has occurred:
+    // * NO_INIT - the buffer queue has been abandoned.
+    // * BAD_VALUE - client has one or more buffers dequeued
+    virtual status_t setAsyncMode(bool async) = 0;
 
     // dequeueBuffer requests a new buffer slot for the client to use. Ownership
     // of the slot is transfered to the client, meaning that the server will not
diff --git a/include/gui/Surface.h b/include/gui/Surface.h
index 72f1067..25b6719 100644
--- a/include/gui/Surface.h
+++ b/include/gui/Surface.h
@@ -170,6 +170,8 @@
     virtual int connect(int api);
     virtual int disconnect(int api);
     virtual int setBufferCount(int bufferCount);
+    virtual int setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+    virtual int setAsyncMode(bool async);
     virtual int setBuffersDimensions(uint32_t width, uint32_t height);
     virtual int setBuffersUserDimensions(uint32_t width, uint32_t height);
     virtual int setBuffersFormat(PixelFormat format);
diff --git a/include/input/Input.h b/include/input/Input.h
index 4a67f47..093219a 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -134,7 +134,7 @@
 
 namespace android {
 
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
 class Parcel;
 #endif
 
@@ -229,7 +229,7 @@
         return getAxisValue(AMOTION_EVENT_AXIS_Y);
     }
 
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
     status_t readFromParcel(Parcel* parcel);
     status_t writeToParcel(Parcel* parcel) const;
 #endif
@@ -567,7 +567,7 @@
     // Matrix is in row-major form and compatible with SkMatrix.
     void transform(const float matrix[9]);
 
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
     status_t readFromParcel(Parcel* parcel);
     status_t writeToParcel(Parcel* parcel) const;
 #endif
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index a38de00..efc1687 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -307,6 +307,15 @@
     DEFINE_KEYCODE(STEM_1),
     DEFINE_KEYCODE(STEM_2),
     DEFINE_KEYCODE(STEM_3),
+    DEFINE_KEYCODE(DPAD_UP_LEFT),
+    DEFINE_KEYCODE(DPAD_DOWN_LEFT),
+    DEFINE_KEYCODE(DPAD_UP_RIGHT),
+    DEFINE_KEYCODE(DPAD_DOWN_RIGHT),
+    DEFINE_KEYCODE(MEDIA_SKIP_FORWARD),
+    DEFINE_KEYCODE(MEDIA_SKIP_BACKWARD),
+    DEFINE_KEYCODE(MEDIA_STEP_FORWARD),
+    DEFINE_KEYCODE(MEDIA_STEP_BACKWARD),
+    DEFINE_KEYCODE(SOFT_SLEEP),
 
     { NULL, 0 }
 };
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index e70666a..111139b 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -19,7 +19,7 @@
 
 #include <stdint.h>
 
-#if HAVE_ANDROID_OS
+#ifdef __ANDROID__
 #include <binder/IBinder.h>
 #endif
 
@@ -124,7 +124,7 @@
      * the mapping in some way. */
     status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
 
-#if HAVE_ANDROID_OS
+#ifdef __ANDROID__
     /* Reads a key map from a parcel. */
     static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
 
diff --git a/include/private/gui/LayerState.h b/include/private/gui/LayerState.h
index cbe8733..b2574d0 100644
--- a/include/private/gui/LayerState.h
+++ b/include/private/gui/LayerState.h
@@ -58,11 +58,10 @@
         :   what(0),
             x(0), y(0), z(0), w(0), h(0), layerStack(0),
             alpha(0), flags(0), mask(0),
-            reserved(0)
+            reserved(0), crop(Rect::INVALID_RECT)
     {
         matrix.dsdx = matrix.dtdy = 1.0f;
         matrix.dsdy = matrix.dtdx = 0.0f;
-        crop.makeInvalid();
     }
 
     status_t    write(Parcel& output) const;
@@ -117,6 +116,8 @@
         eDisplaySizeChanged         = 0x08
     };
 
+    DisplayState();
+
     uint32_t what;
     sp<IBinder> token;
     sp<IGraphicBufferProducer> surface;
diff --git a/include/private/ui/RegionHelper.h b/include/private/ui/RegionHelper.h
index 8c190dd..84eb100 100644
--- a/include/private/ui/RegionHelper.h
+++ b/include/private/ui/RegionHelper.h
@@ -72,7 +72,7 @@
     }
 
     void operator()(region_rasterizer& rasterizer) {
-        RECT current;
+        RECT current(Rect::EMPTY_RECT);
         do {
             SpannerInner spannerInner(spanner.lhs, spanner.rhs);
             int inside = spanner.next(current.top, current.bottom);
diff --git a/include/ui/DisplayInfo.h b/include/ui/DisplayInfo.h
index 799944f..ad73ee7 100644
--- a/include/ui/DisplayInfo.h
+++ b/include/ui/DisplayInfo.h
@@ -36,6 +36,7 @@
     bool secure;
     nsecs_t appVsyncOffset;
     nsecs_t presentationDeadline;
+    int colorTransform;
 };
 
 /* Display orientations as defined in Surface.java and ISurfaceComposer.h. */
diff --git a/include/ui/Rect.h b/include/ui/Rect.h
index 3886f93..6310502 100644
--- a/include/ui/Rect.h
+++ b/include/ui/Rect.h
@@ -32,13 +32,12 @@
     typedef ARect::value_type value_type;
 
     static const Rect INVALID_RECT;
+    static const Rect EMPTY_RECT;
 
     // we don't provide copy-ctor and operator= on purpose
     // because we want the compiler generated versions
 
-    inline Rect() {
-      left = right = top = bottom = 0;
-    }
+    inline Rect() : Rect(INVALID_RECT) {}
 
     inline Rect(int32_t w, int32_t h) {
         left = top = 0;
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index d5860ef..ce29ea6 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -43,6 +43,9 @@
 include $(CLEAR_VARS)
 LOCAL_MODULE := libbinder
 LOCAL_SHARED_LIBRARIES := liblog libcutils libutils
+
+LOCAL_CLANG := true
+LOCAL_SANITIZE := integer
 LOCAL_SRC_FILES := $(sources)
 ifneq ($(TARGET_USES_64_BIT_BINDER),true)
 ifneq ($(TARGET_IS_64_BIT),true)
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index 9d200fb..e39093d 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -16,7 +16,7 @@
 
 #include <binder/Binder.h>
 
-#include <stdatomic.h>
+#include <atomic>
 #include <utils/misc.h>
 #include <binder/BpBinder.h>
 #include <binder/IInterface.h>
@@ -70,9 +70,8 @@
 
 // ---------------------------------------------------------------------------
 
-BBinder::BBinder()
+BBinder::BBinder() : mExtras(nullptr)
 {
-  atomic_init(&mExtras, static_cast<uintptr_t>(0));
 }
 
 bool BBinder::isBinderAlive() const
@@ -139,19 +138,16 @@
     const void* objectID, void* object, void* cleanupCookie,
     object_cleanup_func func)
 {
-    Extras* e = reinterpret_cast<Extras*>(
-                    atomic_load_explicit(&mExtras, memory_order_acquire));
+    Extras* e = mExtras.load(std::memory_order_acquire);
 
     if (!e) {
         e = new Extras;
-        uintptr_t expected = 0;
-        if (!atomic_compare_exchange_strong_explicit(
-                                        &mExtras, &expected,
-                                        reinterpret_cast<uintptr_t>(e),
-                                        memory_order_release,
-                                        memory_order_acquire)) {
+        Extras* expected = nullptr;
+        if (!mExtras.compare_exchange_strong(expected, e,
+                                             std::memory_order_release,
+                                             std::memory_order_acquire)) {
             delete e;
-            e = reinterpret_cast<Extras*>(expected);  // Filled in by CAS
+            e = expected;  // Filled in by CAS
         }
         if (e == 0) return; // out of memory
     }
@@ -160,18 +156,9 @@
     e->mObjects.attach(objectID, object, cleanupCookie, func);
 }
 
-// The C11 standard doesn't allow atomic loads from const fields,
-// though C++11 does.  Fudge it until standards get straightened out.
-static inline uintptr_t load_const_atomic(const atomic_uintptr_t* p,
-                                          memory_order mo) {
-    atomic_uintptr_t* non_const_p = const_cast<atomic_uintptr_t*>(p);
-    return atomic_load_explicit(non_const_p, mo);
-}
-
 void* BBinder::findObject(const void* objectID) const
 {
-    Extras* e = reinterpret_cast<Extras*>(
-                    load_const_atomic(&mExtras, memory_order_acquire));
+    Extras* e = mExtras.load(std::memory_order_acquire);
     if (!e) return NULL;
 
     AutoMutex _l(e->mLock);
@@ -180,8 +167,7 @@
 
 void BBinder::detachObject(const void* objectID)
 {
-    Extras* e = reinterpret_cast<Extras*>(
-                    atomic_load_explicit(&mExtras, memory_order_acquire));
+    Extras* e = mExtras.load(std::memory_order_acquire);
     if (!e) return;
 
     AutoMutex _l(e->mLock);
@@ -195,8 +181,7 @@
 
 BBinder::~BBinder()
 {
-    Extras* e = reinterpret_cast<Extras*>(
-                    atomic_load_explicit(&mExtras, memory_order_relaxed));
+    Extras* e = mExtras.load(std::memory_order_relaxed);
     if (e) delete e;
 }
 
@@ -252,7 +237,7 @@
 BpRefBase::~BpRefBase()
 {
     if (mRemote) {
-        if (!(mState&kRemoteAcquired)) {
+        if (!(mState.load(std::memory_order_relaxed)&kRemoteAcquired)) {
             mRemote->decStrong(this);
         }
         mRefs->decWeak(this);
@@ -261,7 +246,7 @@
 
 void BpRefBase::onFirstRef()
 {
-    android_atomic_or(kRemoteAcquired, &mState);
+    mState.fetch_or(kRemoteAcquired, std::memory_order_relaxed);
 }
 
 void BpRefBase::onLastStrongRef(const void* /*id*/)
diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp
index ef88181..a237684 100644
--- a/libs/binder/IPCThreadState.cpp
+++ b/libs/binder/IPCThreadState.cpp
@@ -852,7 +852,7 @@
         IF_LOG_COMMANDS() {
             alog << "About to read/write, write size = " << mOut.dataSize() << endl;
         }
-#if defined(HAVE_ANDROID_OS)
+#if defined(__ANDROID__)
         if (ioctl(mProcess->mDriverFD, BINDER_WRITE_READ, &bwr) >= 0)
             err = NO_ERROR;
         else
@@ -1158,7 +1158,7 @@
         IPCThreadState* const self = static_cast<IPCThreadState*>(st);
         if (self) {
                 self->flushCommands();
-#if defined(HAVE_ANDROID_OS)
+#if defined(__ANDROID__)
         if (self->mProcess->mDriverFD > 0) {
             ioctl(self->mProcess->mDriverFD, BINDER_THREAD_EXIT, 0);
         }
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 7a4ddc4..45191f5 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -1645,8 +1645,14 @@
         if (mData) {
             LOG_ALLOC("Parcel %p: freeing with %zu capacity", this, mDataCapacity);
             pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
-            gParcelGlobalAllocSize -= mDataCapacity;
-            gParcelGlobalAllocCount--;
+            if (mDataCapacity <= gParcelGlobalAllocSize) {
+              gParcelGlobalAllocSize = gParcelGlobalAllocSize - mDataCapacity;
+            } else {
+              gParcelGlobalAllocSize = 0;
+            }
+            if (gParcelGlobalAllocCount > 0) {
+              gParcelGlobalAllocCount--;
+            }
             pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
             free(mData);
         }
@@ -1825,6 +1831,7 @@
                 pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
                 gParcelGlobalAllocSize += desired;
                 gParcelGlobalAllocSize -= mDataCapacity;
+                gParcelGlobalAllocCount++;
                 pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
                 mData = data;
                 mDataCapacity = desired;
diff --git a/libs/binder/tests/Android.mk b/libs/binder/tests/Android.mk
index 3668729..a40523d 100644
--- a/libs/binder/tests/Android.mk
+++ b/libs/binder/tests/Android.mk
@@ -32,3 +32,11 @@
 LOCAL_SRC_FILES := binderLibTest.cpp
 LOCAL_SHARED_LIBRARIES := libbinder libutils
 include $(BUILD_NATIVE_TEST)
+
+include $(CLEAR_VARS)
+LOCAL_MODULE := binderThroughputTest
+LOCAL_SRC_FILES := binderThroughputTest.cpp
+LOCAL_SHARED_LIBRARIES := libbinder libutils
+LOCAL_CLANG := true
+LOCAL_CFLAGS += -g -Wall -Werror -std=c++11 -Wno-missing-field-initializers -Wno-sign-compare -O3
+include $(BUILD_NATIVE_TEST)
diff --git a/libs/binder/tests/binderThroughputTest.cpp b/libs/binder/tests/binderThroughputTest.cpp
new file mode 100644
index 0000000..71b96d4
--- /dev/null
+++ b/libs/binder/tests/binderThroughputTest.cpp
@@ -0,0 +1,317 @@
+#include <binder/Binder.h>
+#include <binder/IBinder.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <string>
+#include <cstring>
+#include <cstdlib>
+#include <cstdio>
+
+#include <iostream>
+#include <vector>
+#include <tuple>
+
+#include <unistd.h>
+#include <sys/wait.h>
+
+using namespace std;
+using namespace android;
+
+enum BinderWorkerServiceCode {
+    BINDER_NOP = IBinder::FIRST_CALL_TRANSACTION,
+};
+
+#define ASSERT_TRUE(cond) \
+do { \
+    if (!(cond)) {\
+       cerr << __func__ << ":" << __LINE__ << " condition:" << #cond << " failed\n" << endl; \
+       exit(EXIT_FAILURE); \
+    } \
+} while (0)
+
+class BinderWorkerService : public BBinder
+{
+public:
+    BinderWorkerService() {}
+    ~BinderWorkerService() {}
+    virtual status_t onTransact(uint32_t code,
+                                const Parcel& data, Parcel* reply,
+                                uint32_t flags = 0) {
+        (void)flags;
+        (void)data;
+        (void)reply;
+        switch (code) {
+        case BINDER_NOP:
+            return NO_ERROR;
+        default:
+            return UNKNOWN_TRANSACTION;
+        };
+    }
+};
+
+class Pipe {
+    int m_readFd;
+    int m_writeFd;
+    Pipe(int readFd, int writeFd) : m_readFd{readFd}, m_writeFd{writeFd} {}
+    Pipe(const Pipe &) = delete;
+    Pipe& operator=(const Pipe &) = delete;
+    Pipe& operator=(const Pipe &&) = delete;
+public:
+    Pipe(Pipe&& rval) noexcept {
+        m_readFd = rval.m_readFd;
+        m_writeFd = rval.m_writeFd;
+        rval.m_readFd = 0;
+        rval.m_writeFd = 0;
+    }
+    ~Pipe() {
+        if (m_readFd)
+            close(m_readFd);
+        if (m_writeFd)
+            close(m_writeFd);
+    }
+    void signal() {
+        bool val = true;
+        int error = write(m_writeFd, &val, sizeof(val));
+        ASSERT_TRUE(error >= 0);
+    };
+    void wait() {
+        bool val = false;
+        int error = read(m_readFd, &val, sizeof(val));
+        ASSERT_TRUE(error >= 0);
+    }
+    template <typename T> void send(const T& v) {
+        int error = write(m_writeFd, &v, sizeof(T));
+        ASSERT_TRUE(error >= 0);
+    }
+    template <typename T> void recv(T& v) {
+        int error = read(m_readFd, &v, sizeof(T));
+        ASSERT_TRUE(error >= 0);
+    }
+    static tuple<Pipe, Pipe> createPipePair() {
+        int a[2];
+        int b[2];
+
+        int error1 = pipe(a);
+        int error2 = pipe(b);
+        ASSERT_TRUE(error1 >= 0);
+        ASSERT_TRUE(error2 >= 0);
+
+        return make_tuple(Pipe(a[0], b[1]), Pipe(b[0], a[1]));
+    }
+};
+
+static const uint32_t num_buckets = 128;
+static const uint64_t max_time_bucket = 50ull * 1000000;
+static const uint64_t time_per_bucket = max_time_bucket / num_buckets;
+static constexpr float time_per_bucket_ms = time_per_bucket / 1.0E6;
+
+struct ProcResults {
+    uint64_t m_best = max_time_bucket;
+    uint64_t m_worst = 0;
+    uint32_t m_buckets[num_buckets] = {0};
+    uint64_t m_transactions = 0;
+    uint64_t m_total_time = 0;
+
+    void add_time(uint64_t time) {
+        m_buckets[min(time, max_time_bucket-1) / time_per_bucket] += 1;
+        m_best = min(time, m_best);
+        m_worst = max(time, m_worst);
+        m_transactions += 1;
+        m_total_time += time;
+    }
+    static ProcResults combine(const ProcResults& a, const ProcResults& b) {
+        ProcResults ret;
+        for (int i = 0; i < num_buckets; i++) {
+            ret.m_buckets[i] = a.m_buckets[i] + b.m_buckets[i];
+        }
+        ret.m_worst = max(a.m_worst, b.m_worst);
+        ret.m_best = min(a.m_best, b.m_best);
+        ret.m_transactions = a.m_transactions + b.m_transactions;
+        ret.m_total_time = a.m_total_time + b.m_total_time;
+        return ret;
+    }
+    void dump() {
+        double best = (double)m_best / 1.0E6;
+        double worst = (double)m_worst / 1.0E6;
+        double average = (double)m_total_time / m_transactions / 1.0E6;
+        cout << "average:" << average << "ms worst:" << worst << "ms best:" << best << "ms" << endl;
+
+        uint64_t cur_total = 0;
+        for (int i = 0; i < num_buckets; i++) {
+            float cur_time = time_per_bucket_ms * i + 0.5f * time_per_bucket_ms;
+            if ((cur_total < 0.5f * m_transactions) && (cur_total + m_buckets[i] >= 0.5f * m_transactions)) {
+                cout << "50%: " << cur_time << " ";
+            }
+            if ((cur_total < 0.9f * m_transactions) && (cur_total + m_buckets[i] >= 0.9f * m_transactions)) {
+                cout << "90%: " << cur_time << " ";
+            }
+            if ((cur_total < 0.95f * m_transactions) && (cur_total + m_buckets[i] >= 0.95f * m_transactions)) {
+                cout << "95%: " << cur_time << " ";
+            }
+            if ((cur_total < 0.99f * m_transactions) && (cur_total + m_buckets[i] >= 0.99f * m_transactions)) {
+                cout << "99%: " << cur_time << " ";
+            }
+            cur_total += m_buckets[i];
+        }
+        cout << endl;
+
+    }
+};
+
+String16 generateServiceName(int num)
+{
+    char num_str[32];
+    snprintf(num_str, sizeof(num_str), "%d", num);
+    String16 serviceName = String16("binderWorker") + String16(num_str);
+    return serviceName;
+}
+
+void worker_fx(
+    int num,
+    int worker_count,
+    int iterations,
+    Pipe p)
+{
+    // Create BinderWorkerService and for go.
+    ProcessState::self()->startThreadPool();
+    sp<IServiceManager> serviceMgr = defaultServiceManager();
+    sp<BinderWorkerService> service = new BinderWorkerService;
+    serviceMgr->addService(generateServiceName(num), service);
+
+    srand(num);
+    p.signal();
+    p.wait();
+
+    // Get references to other binder services.
+    cout << "Created BinderWorker" << num << endl;
+    (void)worker_count;
+    vector<sp<IBinder> > workers;
+    for (int i = 0; i < worker_count; i++) {
+        if (num == i)
+            continue;
+        workers.push_back(serviceMgr->getService(generateServiceName(i)));
+    }
+
+    // Run the benchmark.
+    ProcResults results;
+    chrono::time_point<chrono::high_resolution_clock> start, end;
+    for (int i = 0; i < iterations; i++) {
+        int target = rand() % workers.size();
+        Parcel data, reply;
+        start = chrono::high_resolution_clock::now();
+        status_t ret = workers[target]->transact(BINDER_NOP, data, &reply);
+        end = chrono::high_resolution_clock::now();
+
+        uint64_t cur_time = uint64_t(chrono::duration_cast<chrono::nanoseconds>(end - start).count());
+        results.add_time(cur_time);
+
+        if (ret != NO_ERROR) {
+           cout << "thread " << num << " failed " << ret << "i : " << i << endl;
+           exit(EXIT_FAILURE);
+        }
+    }
+    // Signal completion to master and wait.
+    p.signal();
+    p.wait();
+
+    // Send results to master and wait for go to exit.
+    p.send(results);
+    p.wait();
+
+    exit(EXIT_SUCCESS);
+}
+
+Pipe make_worker(int num, int iterations, int worker_count)
+{
+    auto pipe_pair = Pipe::createPipePair();
+    pid_t pid = fork();
+    if (pid) {
+        /* parent */
+        return move(get<0>(pipe_pair));
+    } else {
+        /* child */
+        worker_fx(num, worker_count, iterations, move(get<1>(pipe_pair)));
+        /* never get here */
+        return move(get<0>(pipe_pair));
+    }
+
+}
+
+void wait_all(vector<Pipe>& v)
+{
+    for (int i = 0; i < v.size(); i++) {
+        v[i].wait();
+    }
+}
+
+void signal_all(vector<Pipe>& v)
+{
+    for (int i = 0; i < v.size(); i++) {
+        v[i].signal();
+    }
+}
+
+int main(int argc, char *argv[])
+{
+    int workers = 2;
+    int iterations = 10000;
+    (void)argc;
+    (void)argv;
+    vector<Pipe> pipes;
+
+    // Parse arguments.
+    for (int i = 1; i < argc; i++) {
+        if (string(argv[i]) == "-w") {
+            workers = atoi(argv[i+1]);
+            i++;
+            continue;
+        }
+        if (string(argv[i]) == "-i") {
+            iterations = atoi(argv[i+1]);
+            i++;
+            continue;
+        }
+    }
+
+    // Create all the workers and wait for them to spawn.
+    for (int i = 0; i < workers; i++) {
+        pipes.push_back(make_worker(i, iterations, workers));
+    }
+    wait_all(pipes);
+
+
+    // Run the workers and wait for completion.
+    chrono::time_point<chrono::high_resolution_clock> start, end;
+    cout << "waiting for workers to complete" << endl;
+    start = chrono::high_resolution_clock::now();
+    signal_all(pipes);
+    wait_all(pipes);
+    end = chrono::high_resolution_clock::now();
+
+    // Calculate overall throughput.
+    double iterations_per_sec = double(iterations * workers) / (chrono::duration_cast<chrono::nanoseconds>(end - start).count() / 1.0E9);
+    cout << "iterations per sec: " << iterations_per_sec << endl;
+
+    // Collect all results from the workers.
+    cout << "collecting results" << endl;
+    signal_all(pipes);
+    ProcResults tot_results;
+    for (int i = 0; i < workers; i++) {
+        ProcResults tmp_results;
+        pipes[i].recv(tmp_results);
+        tot_results = ProcResults::combine(tot_results, tmp_results);
+    }
+    tot_results.dump();
+
+    // Kill all the workers.
+    cout << "killing workers" << endl;
+    signal_all(pipes);
+    for (int i = 0; i < workers; i++) {
+        int status;
+        wait(&status);
+        if (status != 0) {
+            cout << "nonzero child status" << status << endl;
+        }
+    }
+    return 0;
+}
diff --git a/libs/gui/BufferItem.cpp b/libs/gui/BufferItem.cpp
index 8f64ae0..6a883cf 100644
--- a/libs/gui/BufferItem.cpp
+++ b/libs/gui/BufferItem.cpp
@@ -24,6 +24,7 @@
 namespace android {
 
 BufferItem::BufferItem() :
+    mCrop(Rect::INVALID_RECT),
     mTransform(0),
     mScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mTimestamp(0),
@@ -34,7 +35,6 @@
     mIsDroppable(false),
     mAcquireCalled(false),
     mTransformToDisplayInverse(false) {
-    mCrop.makeInvalid();
 }
 
 BufferItem::~BufferItem() {}
diff --git a/libs/gui/BufferQueueCore.cpp b/libs/gui/BufferQueueCore.cpp
index 851a396..d297112 100644
--- a/libs/gui/BufferQueueCore.cpp
+++ b/libs/gui/BufferQueueCore.cpp
@@ -55,7 +55,6 @@
     mQueue(),
     mFreeSlots(),
     mFreeBuffers(),
-    mOverrideMaxBufferCount(0),
     mDequeueCondition(),
     mUseAsyncBuffer(true),
     mDequeueBufferCannotBlock(false),
@@ -65,6 +64,8 @@
     mDefaultBufferDataSpace(HAL_DATASPACE_UNKNOWN),
     mDefaultMaxBufferCount(2),
     mMaxAcquiredBufferCount(1),
+    mMaxDequeuedBufferCount(1),
+    mOverrideMaxBufferCount(false),
     mBufferHasBeenQueued(false),
     mFrameCounter(0),
     mTransformHint(0),
@@ -72,7 +73,8 @@
     mIsAllocatingCondition(),
     mAllowAllocation(true),
     mBufferAge(0),
-    mGenerationNumber(0)
+    mGenerationNumber(0),
+    mAsyncMode(false)
 {
     if (allocator == NULL) {
         sp<ISurfaceComposer> composer(ComposerService::getComposerService());
@@ -104,11 +106,12 @@
     }
 
     result.appendFormat("%s-BufferQueue mMaxAcquiredBufferCount=%d, "
-            "mDequeueBufferCannotBlock=%d, default-size=[%dx%d], "
-            "default-format=%d, transform-hint=%02x, FIFO(%zu)={%s}\n",
-            prefix, mMaxAcquiredBufferCount, mDequeueBufferCannotBlock,
-            mDefaultWidth, mDefaultHeight, mDefaultBufferFormat, mTransformHint,
-            mQueue.size(), fifo.string());
+            "mMaxDequeuedBufferCount=%d, mDequeueBufferCannotBlock=%d, "
+            "default-size=[%dx%d], default-format=%d, transform-hint=%02x, "
+            "FIFO(%zu)={%s}\n",
+            prefix, mMaxAcquiredBufferCount, mMaxDequeuedBufferCount,
+            mDequeueBufferCannotBlock, mDefaultWidth, mDefaultHeight,
+            mDefaultBufferFormat, mTransformHint, mQueue.size(), fifo.string());
 
     // Trim the free buffers so as to not spam the dump
     int maxBufferCount = 0;
@@ -161,9 +164,11 @@
     int minMaxBufferCount = getMinMaxBufferCountLocked(async);
 
     int maxBufferCount = max(mDefaultMaxBufferCount, minMaxBufferCount);
-    if (mOverrideMaxBufferCount != 0) {
-        assert(mOverrideMaxBufferCount >= minMaxBufferCount);
-        maxBufferCount = mOverrideMaxBufferCount;
+    if (mOverrideMaxBufferCount) {
+        int bufferCount = mMaxAcquiredBufferCount + mMaxDequeuedBufferCount +
+                (async ? 1 : 0);
+        assert(bufferCount >= minMaxBufferCount);
+        maxBufferCount = bufferCount;
     }
 
     // Any buffers that are dequeued by the producer or sitting in the queue
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 87e5b4d..61878f6 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -72,9 +72,11 @@
     return NO_ERROR;
 }
 
-status_t BufferQueueProducer::setBufferCount(int bufferCount) {
+status_t BufferQueueProducer::setMaxDequeuedBufferCount(
+        int maxDequeuedBuffers) {
     ATRACE_CALL();
-    BQ_LOGV("setBufferCount: count = %d", bufferCount);
+    BQ_LOGV("setMaxDequeuedBufferCount: maxDequeuedBuffers = %d",
+            maxDequeuedBuffers);
 
     sp<IConsumerListener> listener;
     { // Autolock scope
@@ -82,34 +84,34 @@
         mCore->waitWhileAllocatingLocked();
 
         if (mCore->mIsAbandoned) {
-            BQ_LOGE("setBufferCount: BufferQueue has been abandoned");
+            BQ_LOGE("setMaxDequeuedBufferCount: BufferQueue has been "
+                    "abandoned");
             return NO_INIT;
         }
 
-        if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
-            BQ_LOGE("setBufferCount: bufferCount %d too large (max %d)",
-                    bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
-            return BAD_VALUE;
-        }
-
         // There must be no dequeued buffers when changing the buffer count.
         for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
             if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) {
-                BQ_LOGE("setBufferCount: buffer owned by producer");
+                BQ_LOGE("setMaxDequeuedBufferCount: buffer owned by producer");
                 return BAD_VALUE;
             }
         }
 
-        if (bufferCount == 0) {
-            mCore->mOverrideMaxBufferCount = 0;
-            mCore->mDequeueCondition.broadcast();
-            return NO_ERROR;
+        int bufferCount = mCore->getMinUndequeuedBufferCountLocked(
+                mCore->mAsyncMode);
+        bufferCount += maxDequeuedBuffers;
+
+        if (bufferCount > BufferQueueDefs::NUM_BUFFER_SLOTS) {
+            BQ_LOGE("setMaxDequeuedBufferCount: bufferCount %d too large "
+                    "(max %d)", bufferCount, BufferQueueDefs::NUM_BUFFER_SLOTS);
+            return BAD_VALUE;
         }
 
-        const int minBufferSlots = mCore->getMinMaxBufferCountLocked(false);
+        const int minBufferSlots = mCore->getMinMaxBufferCountLocked(
+                mCore->mAsyncMode);
         if (bufferCount < minBufferSlots) {
-            BQ_LOGE("setBufferCount: requested buffer count %d is less than "
-                    "minimum %d", bufferCount, minBufferSlots);
+            BQ_LOGE("setMaxDequeuedBufferCount: requested buffer count %d is "
+                    "less than minimum %d", bufferCount, minBufferSlots);
             return BAD_VALUE;
         }
 
@@ -118,7 +120,8 @@
         // clear the queue, however, so that currently queued buffers still
         // get displayed.
         mCore->freeAllBuffersLocked();
-        mCore->mOverrideMaxBufferCount = bufferCount;
+        mCore->mMaxDequeuedBufferCount = maxDequeuedBuffers;
+        mCore->mOverrideMaxBufferCount = true;
         mCore->mDequeueCondition.broadcast();
         listener = mCore->mConsumerListener;
     } // Autolock scope
@@ -131,6 +134,41 @@
     return NO_ERROR;
 }
 
+status_t BufferQueueProducer::setAsyncMode(bool async) {
+    ATRACE_CALL();
+    BQ_LOGV("setAsyncMode: async = %d", async);
+
+    sp<IConsumerListener> listener;
+    { // Autolock scope
+        Mutex::Autolock lock(mCore->mMutex);
+        mCore->waitWhileAllocatingLocked();
+
+        if (mCore->mIsAbandoned) {
+            BQ_LOGE("setAsyncMode: BufferQueue has been abandoned");
+            return NO_INIT;
+        }
+
+        // There must be no dequeued buffers when changing the async mode.
+        for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
+            if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) {
+                BQ_LOGE("setAsyncMode: buffer owned by producer");
+                return BAD_VALUE;
+            }
+        }
+
+        mCore->mAsyncMode = async;
+        mCore->mOverrideMaxBufferCount = true;
+        mCore->mDequeueCondition.broadcast();
+        listener = mCore->mConsumerListener;
+    } // Autolock scope
+
+    // Call back without lock held
+    if (listener != NULL) {
+        listener->onBuffersReleased();
+    }
+    return NO_ERROR;
+}
+
 status_t BufferQueueProducer::waitForFreeSlotThenRelock(const char* caller,
         bool async, int* found, status_t* returnFlags) const {
     bool tryAgain = true;
@@ -141,16 +179,6 @@
         }
 
         const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
-        if (async && mCore->mOverrideMaxBufferCount) {
-            // FIXME: Some drivers are manually setting the buffer count
-            // (which they shouldn't), so we do this extra test here to
-            // handle that case. This is TEMPORARY until we get this fixed.
-            if (mCore->mOverrideMaxBufferCount < maxBufferCount) {
-                BQ_LOGE("%s: async mode is invalid with buffer count override",
-                        caller);
-                return BAD_VALUE;
-            }
-        }
 
         // Free up any buffers that are in slots beyond the max buffer count
         for (int s = maxBufferCount; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
@@ -176,33 +204,16 @@
             }
         }
 
-        // Producers are not allowed to dequeue more than one buffer if they
-        // did not set a buffer count
-        if (!mCore->mOverrideMaxBufferCount && dequeuedCount) {
-            BQ_LOGE("%s: can't dequeue multiple buffers without setting the "
-                    "buffer count", caller);
+        // Producers are not allowed to dequeue more than
+        // mMaxDequeuedBufferCount buffers.
+        // This check is only done if a buffer has already been queued
+        if (mCore->mBufferHasBeenQueued &&
+                dequeuedCount >= mCore->mMaxDequeuedBufferCount) {
+            BQ_LOGE("%s: attempting to exceed the max dequeued buffer count "
+                    "(%d)", caller, mCore->mMaxDequeuedBufferCount);
             return INVALID_OPERATION;
         }
 
-        // See whether a buffer has been queued since the last
-        // setBufferCount so we know whether to perform the min undequeued
-        // buffers check below
-        if (mCore->mBufferHasBeenQueued) {
-            // Make sure the producer is not trying to dequeue more buffers
-            // than allowed
-            const int newUndequeuedCount =
-                maxBufferCount - (dequeuedCount + 1);
-            const int minUndequeuedCount =
-                mCore->getMinUndequeuedBufferCountLocked(async);
-            if (newUndequeuedCount < minUndequeuedCount) {
-                BQ_LOGE("%s: min undequeued buffer count (%d) exceeded "
-                        "(dequeued=%d undequeued=%d)",
-                        caller, minUndequeuedCount,
-                        dequeuedCount, newUndequeuedCount);
-                return INVALID_OPERATION;
-            }
-        }
-
         *found = BufferQueueCore::INVALID_BUFFER_SLOT;
 
         // If we disconnect and reconnect quickly, we can be in a state where
@@ -241,7 +252,7 @@
             // buffer (which could cause us to have to wait here), which is
             // okay, since it is only used to implement an atomic acquire +
             // release (e.g., in GLConsumer::updateTexImage())
-            if (mCore->mDequeueBufferCannotBlock &&
+            if ((mCore->mDequeueBufferCannotBlock || mCore->mAsyncMode) &&
                     (acquiredCount <= mCore->mMaxAcquiredBufferCount)) {
                 return WOULD_BLOCK;
             }
@@ -547,7 +558,7 @@
     int64_t timestamp;
     bool isAutoTimestamp;
     android_dataspace dataSpace;
-    Rect crop;
+    Rect crop(Rect::EMPTY_RECT);
     int scalingMode;
     uint32_t transform;
     uint32_t stickyTransform;
@@ -586,16 +597,6 @@
         }
 
         const int maxBufferCount = mCore->getMaxBufferCountLocked(async);
-        if (async && mCore->mOverrideMaxBufferCount) {
-            // FIXME: Some drivers are manually setting the buffer count
-            // (which they shouldn't), so we do this extra test here to
-            // handle that case. This is TEMPORARY until we get this fixed.
-            if (mCore->mOverrideMaxBufferCount < maxBufferCount) {
-                BQ_LOGE("queueBuffer: async mode is invalid with "
-                        "buffer count override");
-                return BAD_VALUE;
-            }
-        }
 
         if (slot < 0 || slot >= maxBufferCount) {
             BQ_LOGE("queueBuffer: slot index %d out of range [0, %d)",
@@ -619,7 +620,7 @@
 
         const sp<GraphicBuffer>& graphicBuffer(mSlots[slot].mGraphicBuffer);
         Rect bufferRect(graphicBuffer->getWidth(), graphicBuffer->getHeight());
-        Rect croppedRect;
+        Rect croppedRect(Rect::EMPTY_RECT);
         crop.intersect(bufferRect, &croppedRect);
         if (croppedRect != crop) {
             BQ_LOGE("queueBuffer: crop rect is not contained within the "
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index e3f40f5..bf34c6a 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -130,6 +130,7 @@
 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t tex,
         uint32_t texTarget, bool useFenceSync, bool isControlledByApp) :
     ConsumerBase(bq, isControlledByApp),
+    mCurrentCrop(Rect::EMPTY_RECT),
     mCurrentTransform(0),
     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mCurrentFence(Fence::NO_FENCE),
@@ -157,6 +158,7 @@
 GLConsumer::GLConsumer(const sp<IGraphicBufferConsumer>& bq, uint32_t texTarget,
         bool useFenceSync, bool isControlledByApp) :
     ConsumerBase(bq, isControlledByApp),
+    mCurrentCrop(Rect::EMPTY_RECT),
     mCurrentTransform(0),
     mCurrentScalingMode(NATIVE_WINDOW_SCALING_MODE_FREEZE),
     mCurrentFence(Fence::NO_FENCE),
@@ -1083,7 +1085,8 @@
 GLConsumer::EglImage::EglImage(sp<GraphicBuffer> graphicBuffer) :
     mGraphicBuffer(graphicBuffer),
     mEglImage(EGL_NO_IMAGE_KHR),
-    mEglDisplay(EGL_NO_DISPLAY) {
+    mEglDisplay(EGL_NO_DISPLAY),
+    mCropRect(Rect::EMPTY_RECT) {
 }
 
 GLConsumer::EglImage::~EglImage() {
diff --git a/libs/gui/IGraphicBufferProducer.cpp b/libs/gui/IGraphicBufferProducer.cpp
index d7a7885..6495aa9 100644
--- a/libs/gui/IGraphicBufferProducer.cpp
+++ b/libs/gui/IGraphicBufferProducer.cpp
@@ -34,7 +34,6 @@
 
 enum {
     REQUEST_BUFFER = IBinder::FIRST_CALL_TRANSACTION,
-    SET_BUFFER_COUNT,
     DEQUEUE_BUFFER,
     DETACH_BUFFER,
     DETACH_NEXT_BUFFER,
@@ -49,6 +48,8 @@
     ALLOW_ALLOCATION,
     SET_GENERATION_NUMBER,
     GET_CONSUMER_NAME,
+    SET_MAX_DEQUEUED_BUFFER_COUNT,
+    SET_ASYNC_MODE
 };
 
 class BpGraphicBufferProducer : public BpInterface<IGraphicBufferProducer>
@@ -82,12 +83,27 @@
         return result;
     }
 
-    virtual status_t setBufferCount(int bufferCount)
-    {
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers) {
         Parcel data, reply;
-        data.writeInterfaceToken(IGraphicBufferProducer::getInterfaceDescriptor());
-        data.writeInt32(bufferCount);
-        status_t result =remote()->transact(SET_BUFFER_COUNT, data, &reply);
+        data.writeInterfaceToken(
+                IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeInt32(maxDequeuedBuffers);
+        status_t result = remote()->transact(SET_MAX_DEQUEUED_BUFFER_COUNT,
+                data, &reply);
+        if (result != NO_ERROR) {
+            return result;
+        }
+        result = reply.readInt32();
+        return result;
+    }
+
+    virtual status_t setAsyncMode(bool async) {
+        Parcel data, reply;
+        data.writeInterfaceToken(
+                IGraphicBufferProducer::getInterfaceDescriptor());
+        data.writeInt32(async);
+        status_t result = remote()->transact(SET_ASYNC_MODE,
+                data, &reply);
         if (result != NO_ERROR) {
             return result;
         }
@@ -334,10 +350,17 @@
             reply->writeInt32(result);
             return NO_ERROR;
         }
-        case SET_BUFFER_COUNT: {
+        case SET_MAX_DEQUEUED_BUFFER_COUNT: {
             CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
-            int bufferCount = data.readInt32();
-            int result = setBufferCount(bufferCount);
+            int maxDequeuedBuffers = data.readInt32();
+            int result = setMaxDequeuedBufferCount(maxDequeuedBuffers);
+            reply->writeInt32(result);
+            return NO_ERROR;
+        }
+        case SET_ASYNC_MODE: {
+            CHECK_INTERFACE(IGraphicBufferProducer, data, reply);
+            bool async = data.readInt32();
+            int result = setAsyncMode(async);
             reply->writeInt32(result);
             return NO_ERROR;
         }
diff --git a/libs/gui/ISurfaceComposer.cpp b/libs/gui/ISurfaceComposer.cpp
index 78886d5..b4cbf84 100644
--- a/libs/gui/ISurfaceComposer.cpp
+++ b/libs/gui/ISurfaceComposer.cpp
@@ -353,7 +353,7 @@
             sp<IBinder> display = data.readStrongBinder();
             sp<IGraphicBufferProducer> producer =
                     interface_cast<IGraphicBufferProducer>(data.readStrongBinder());
-            Rect sourceCrop;
+            Rect sourceCrop(Rect::EMPTY_RECT);
             data.read(sourceCrop);
             uint32_t reqWidth = data.readUint32();
             uint32_t reqHeight = data.readUint32();
diff --git a/libs/gui/LayerState.cpp b/libs/gui/LayerState.cpp
index 00323dc..eafda86 100644
--- a/libs/gui/LayerState.cpp
+++ b/libs/gui/LayerState.cpp
@@ -77,6 +77,16 @@
 }
 
 
+DisplayState::DisplayState() :
+    what(0),
+    layerStack(0),
+    orientation(eOrientationDefault),
+    viewport(Rect::EMPTY_RECT),
+    frame(Rect::EMPTY_RECT),
+    width(0),
+    height(0) {
+}
+
 status_t DisplayState::write(Parcel& output) const {
     output.writeStrongBinder(token);
     output.writeStrongBinder(IInterface::asBinder(surface));
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 1b40c87..81c0549 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -224,6 +224,10 @@
         }
         if (halVersion > SENSORS_DEVICE_API_VERSION_1_0 && hwSensor->requiredPermission) {
             mRequiredPermission = hwSensor->requiredPermission;
+            if (!strcmp(mRequiredPermission, SENSOR_PERMISSION_BODY_SENSORS)) {
+                AppOpsManager appOps;
+                mRequiredAppOp = appOps.permissionToOpCode(String16(SENSOR_PERMISSION_BODY_SENSORS));
+            }
         }
 
         if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp
index 9934151..33608b5 100644
--- a/libs/gui/SensorManager.cpp
+++ b/libs/gui/SensorManager.cpp
@@ -110,10 +110,20 @@
 }
 
 status_t SensorManager::assertStateLocked() const {
+    bool initSensorManager = false;
     if (mSensorServer == NULL) {
-        // try for 10 seconds before giving up ...
+        initSensorManager = true;
+    } else {
+        // Ping binder to check if sensorservice is alive.
+        status_t err = IInterface::asBinder(mSensorServer)->pingBinder();
+        if (err != NO_ERROR) {
+            initSensorManager = true;
+        }
+    }
+    if (initSensorManager) {
+        // try for 300 seconds (60*5(getService() tries for 5 seconds)) before giving up ...
         const String16 name("sensorservice");
-        for (int i = 0;i < 10; i++) {
+        for (int i = 0; i < 60; i++) {
             status_t err = getService(name, &mSensorServer);
             if (err == NAME_NOT_FOUND) {
                 sleep(1);
@@ -135,9 +145,7 @@
             DeathObserver(SensorManager& mgr) : mSensorManger(mgr) { }
         };
 
-        if (mSensorServer == NULL) {
-            ALOGE("FATAL getsensorservice returned NULL");
-        }
+        LOG_ALWAYS_FATAL_IF(mSensorServer.get() == NULL, "getService(SensorService) NULL");
 
         mDeathObserver = new DeathObserver(*const_cast<SensorManager *>(this));
         IInterface::asBinder(mSensorServer)->linkToDeath(mDeathObserver);
@@ -146,6 +154,8 @@
         size_t count = mSensors.size();
         mSensorList =
                 static_cast<Sensor const**>(malloc(count * sizeof(Sensor*)));
+        LOG_ALWAYS_FATAL_IF(mSensorList == NULL, "mSensorList NULL");
+
         for (size_t i=0 ; i<count ; i++) {
             mSensorList[i] = mSensors.array() + i;
         }
diff --git a/libs/gui/Surface.cpp b/libs/gui/Surface.cpp
index 4b76f98..de5c275 100644
--- a/libs/gui/Surface.cpp
+++ b/libs/gui/Surface.cpp
@@ -43,6 +43,7 @@
         const sp<IGraphicBufferProducer>& bufferProducer,
         bool controlledByApp)
     : mGraphicBufferProducer(bufferProducer),
+      mCrop(Rect::EMPTY_RECT),
       mGenerationNumber(0)
 {
     // Initialize the ANativeWindow function pointers.
@@ -67,7 +68,6 @@
     mReqUsage = 0;
     mTimestamp = NATIVE_WINDOW_TIMESTAMP_AUTO;
     mDataSpace = HAL_DATASPACE_UNKNOWN;
-    mCrop.clear();
     mScalingMode = NATIVE_WINDOW_SCALING_MODE_FREEZE;
     mTransform = 0;
     mStickyTransform = 0;
@@ -184,7 +184,9 @@
     va_list args;
     va_start(args, operation);
     Surface* c = getSelf(window);
-    return c->perform(operation, args);
+    int result = c->perform(operation, args);
+    va_end(args);
+    return result;
 }
 
 int Surface::setSwapInterval(int interval) {
@@ -332,7 +334,7 @@
 
 
     // Make sure the crop rectangle is entirely inside the buffer.
-    Rect crop;
+    Rect crop(Rect::EMPTY_RECT);
     mCrop.intersect(Rect(buffer->width, buffer->height), &crop);
 
     sp<Fence> fence(fenceFd >= 0 ? new Fence(fenceFd) : Fence::NO_FENCE);
@@ -779,7 +781,7 @@
 {
     ATRACE_CALL();
 
-    Rect realRect;
+    Rect realRect(Rect::EMPTY_RECT);
     if (rect == NULL || rect->isEmpty()) {
         realRect.clear();
     } else {
@@ -800,9 +802,54 @@
     ALOGV("Surface::setBufferCount");
     Mutex::Autolock lock(mMutex);
 
-    status_t err = mGraphicBufferProducer->setBufferCount(bufferCount);
+    status_t err = NO_ERROR;
+    if (bufferCount == 0) {
+        err = mGraphicBufferProducer->setMaxDequeuedBufferCount(1);
+    } else {
+        int minUndequeuedBuffers = 0;
+        err = mGraphicBufferProducer->query(
+                NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minUndequeuedBuffers);
+        if (err == NO_ERROR) {
+            err = mGraphicBufferProducer->setMaxDequeuedBufferCount(
+                    bufferCount - minUndequeuedBuffers);
+        }
+    }
+
+    if (err == NO_ERROR) {
+        freeAllBuffers();
+    }
+
     ALOGE_IF(err, "IGraphicBufferProducer::setBufferCount(%d) returned %s",
-            bufferCount, strerror(-err));
+             bufferCount, strerror(-err));
+
+    return err;
+}
+
+int Surface::setMaxDequeuedBufferCount(int maxDequeuedBuffers) {
+    ATRACE_CALL();
+    ALOGV("Surface::setMaxDequeuedBufferCount");
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = mGraphicBufferProducer->setMaxDequeuedBufferCount(
+            maxDequeuedBuffers);
+    ALOGE_IF(err, "IGraphicBufferProducer::setMaxDequeuedBufferCount(%d) "
+            "returned %s", maxDequeuedBuffers, strerror(-err));
+
+    if (err == NO_ERROR) {
+        freeAllBuffers();
+    }
+
+    return err;
+}
+
+int Surface::setAsyncMode(bool async) {
+    ATRACE_CALL();
+    ALOGV("Surface::setAsyncMode");
+    Mutex::Autolock lock(mMutex);
+
+    status_t err = mGraphicBufferProducer->setAsyncMode(async);
+    ALOGE_IF(err, "IGraphicBufferProducer::setAsyncMode(%d) returned %s",
+            async, strerror(-err));
 
     if (err == NO_ERROR) {
         freeAllBuffers();
diff --git a/libs/gui/tests/BufferQueue_test.cpp b/libs/gui/tests/BufferQueue_test.cpp
index deec68c..e2bf6a0 100644
--- a/libs/gui/tests/BufferQueue_test.cpp
+++ b/libs/gui/tests/BufferQueue_test.cpp
@@ -145,7 +145,7 @@
     IGraphicBufferProducer::QueueBufferOutput qbo;
     mProducer->connect(new DummyProducerListener, NATIVE_WINDOW_API_CPU, false,
             &qbo);
-    mProducer->setBufferCount(4);
+    mProducer->setMaxDequeuedBufferCount(3);
 
     int slot;
     sp<Fence> fence;
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 4ef9a69..d6bd8a8 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -481,19 +481,17 @@
     mProducer->cancelBuffer(dequeuedSlot, dequeuedFence);
 }
 
-TEST_F(IGraphicBufferProducerTest, SetBufferCount_Succeeds) {
+TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Succeeds) {
+    int minUndequeuedBuffers;
+    ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+            &minUndequeuedBuffers));
 
-    // The producer does not wish to set a buffer count
-    EXPECT_OK(mProducer->setBufferCount(0)) << "bufferCount: " << 0;
-    // TODO: how to test "0" buffer count?
+    const int minBuffers = 1;
+    const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
 
-    int minBuffers;
-    ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minBuffers));
-
-    // The MIN_UNDEQUEUED_BUFFERS limit is exclusive, so need to increment by at least 1
-    minBuffers++;
-
-    ASSERT_OK(mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers;
+    ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false;
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(minBuffers))
+            << "bufferCount: " << minBuffers;
 
     std::vector<DequeueBufferResult> dequeueList;
 
@@ -511,41 +509,43 @@
     }
 
     // Cancel every buffer, so we can set buffer count again
-    for (int i = 0; i < minBuffers; ++i) {
-        DequeueBufferResult& result = dequeueList[i];
+    for (auto& result : dequeueList) {
         mProducer->cancelBuffer(result.slot, result.fence);
     }
 
-    ASSERT_OK(mProducer->setBufferCount(BufferQueue::NUM_BUFFER_SLOTS));
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(maxBuffers));
 
-    // Should now be able to dequeue up to NUM_BUFFER_SLOTS times
-    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; ++i) {
+    // Should now be able to dequeue up to maxBuffers times
+    for (int i = 0; i < maxBuffers; ++i) {
         int dequeuedSlot = -1;
         sp<Fence> dequeuedFence;
 
         EXPECT_LE(OK,
                 mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                          QUEUE_BUFFER_INPUT_ASYNC,
-                                         DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                         DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                                         DEFAULT_FORMAT,
                                          TEST_PRODUCER_USAGE_BITS))
                 << "iteration: " << i << ", slot: " << dequeuedSlot;
     }
 }
 
-TEST_F(IGraphicBufferProducerTest, SetBufferCount_Fails) {
-    int minBuffers;
-    ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS, &minBuffers));
+TEST_F(IGraphicBufferProducerTest, SetMaxDequeuedBufferCount_Fails) {
+    int minUndequeuedBuffers;
+    ASSERT_OK(mProducer->query(NATIVE_WINDOW_MIN_UNDEQUEUED_BUFFERS,
+                               &minUndequeuedBuffers));
 
-    // The MIN_UNDEQUEUED_BUFFERS limit is exclusive, so need to increment by at least 1
-    minBuffers++;
+    const int minBuffers = 1;
+    const int maxBuffers = BufferQueue::NUM_BUFFER_SLOTS - minUndequeuedBuffers;
 
+    ASSERT_OK(mProducer->setAsyncMode(false)) << "async mode: " << false;
     // Buffer count was out of range
-    EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(-1)) << "bufferCount: " << -1;
-    EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(minBuffers - 1)) << "bufferCount: " << minBuffers - 1;
-    EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(BufferQueue::NUM_BUFFER_SLOTS + 1))
-            << "bufferCount: " << BufferQueue::NUM_BUFFER_SLOTS + 1;
+    EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(0))
+            << "bufferCount: " << 0;
+    EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(maxBuffers + 1))
+            << "bufferCount: " << maxBuffers + 1;
 
-    // Pre-requisite to fail out a valid setBufferCount call
+    // Prerequisite to fail out a valid setBufferCount call
     {
         int dequeuedSlot = -1;
         sp<Fence> dequeuedFence;
@@ -553,20 +553,73 @@
         ASSERT_LE(OK,
                 mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
                                          QUEUE_BUFFER_INPUT_ASYNC,
-                                         DEFAULT_WIDTH, DEFAULT_HEIGHT, DEFAULT_FORMAT,
+                                         DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                                         DEFAULT_FORMAT,
                                          TEST_PRODUCER_USAGE_BITS))
                 << "slot: " << dequeuedSlot;
     }
 
     // Client has one or more buffers dequeued
-    EXPECT_EQ(BAD_VALUE, mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers;
+    EXPECT_EQ(BAD_VALUE, mProducer->setMaxDequeuedBufferCount(minBuffers))
+            << "bufferCount: " << minBuffers;
 
     // Abandon buffer queue
     ASSERT_OK(mConsumer->consumerDisconnect());
 
     // Fail because the buffer queue was abandoned
-    EXPECT_EQ(NO_INIT, mProducer->setBufferCount(minBuffers)) << "bufferCount: " << minBuffers;
+    EXPECT_EQ(NO_INIT, mProducer->setMaxDequeuedBufferCount(minBuffers))
+            << "bufferCount: " << minBuffers;
 
 }
 
+TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Succeeds) {
+    ASSERT_OK(mConsumer->setMaxAcquiredBufferCount(1)) << "maxAcquire: " << 1;
+    ASSERT_OK(mProducer->setAsyncMode(true)) << "async mode: " << true;
+    ASSERT_OK(mProducer->setMaxDequeuedBufferCount(1)) << "maxDequeue: " << 1;
+
+    int dequeuedSlot = -1;
+    sp<Fence> dequeuedFence;
+    IGraphicBufferProducer::QueueBufferInput input(QUEUE_BUFFER_INPUT_TIMESTAMP,
+            QUEUE_BUFFER_INPUT_IS_AUTO_TIMESTAMP, QUEUE_BUFFER_INPUT_DATASPACE,
+            QUEUE_BUFFER_INPUT_RECT, QUEUE_BUFFER_INPUT_SCALING_MODE,
+            QUEUE_BUFFER_INPUT_TRANSFORM, true, QUEUE_BUFFER_INPUT_FENCE);
+    IGraphicBufferProducer::QueueBufferOutput output;
+    sp<GraphicBuffer> dequeuedBuffer;
+
+    // Should now be able to queue/dequeue as many buffers as we want without
+    // blocking
+    for (int i = 0; i < 5; ++i) {
+        ASSERT_LE(OK, mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+                true, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)) << "slot : "
+                << dequeuedSlot;
+        ASSERT_OK(mProducer->requestBuffer(dequeuedSlot, &dequeuedBuffer));
+        ASSERT_OK(mProducer->queueBuffer(dequeuedSlot, input, &output));
+    }
+}
+
+TEST_F(IGraphicBufferProducerTest, SetAsyncMode_Fails) {
+    // Prerequisite to fail out a valid setBufferCount call
+    {
+        int dequeuedSlot = -1;
+        sp<Fence> dequeuedFence;
+
+        ASSERT_LE(OK, mProducer->dequeueBuffer(&dequeuedSlot, &dequeuedFence,
+                QUEUE_BUFFER_INPUT_ASYNC, DEFAULT_WIDTH, DEFAULT_HEIGHT,
+                DEFAULT_FORMAT, TEST_PRODUCER_USAGE_BITS)) << "slot: "
+                        << dequeuedSlot;
+    }
+
+    // Client has one or more buffers dequeued
+    EXPECT_EQ(BAD_VALUE, mProducer->setAsyncMode(false)) << "asyncMode: "
+            << false;
+
+    // Abandon buffer queue
+    ASSERT_OK(mConsumer->consumerDisconnect());
+
+    // Fail because the buffer queue was abandoned
+    EXPECT_EQ(NO_INIT, mProducer->setAsyncMode(false)) << "asyncMode: "
+            << false;
+}
+
 } // namespace android
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 2c1418e..88cd653 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -23,7 +23,7 @@
 #include <input/Input.h>
 #include <input/InputEventLabels.h>
 
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
 #include <binder/Parcel.h>
 #endif
 
@@ -144,7 +144,7 @@
     setAxisValue(AMOTION_EVENT_AXIS_Y, getY() + yOffset);
 }
 
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
 status_t PointerCoords::readFromParcel(Parcel* parcel) {
     bits = parcel->readInt64();
 
@@ -420,7 +420,7 @@
     }
 }
 
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
 status_t MotionEvent::readFromParcel(Parcel* parcel) {
     size_t pointerCount = parcel->readInt32();
     size_t sampleCount = parcel->readInt32();
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index b03e01e..732ebd0 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -19,7 +19,7 @@
 #include <stdlib.h>
 #include <string.h>
 
-#if HAVE_ANDROID_OS
+#ifdef __ANDROID__
 #include <binder/Parcel.h>
 #endif
 
@@ -557,7 +557,7 @@
     }
 }
 
-#if HAVE_ANDROID_OS
+#ifdef __ANDROID__
 sp<KeyCharacterMap> KeyCharacterMap::readFromParcel(Parcel* parcel) {
     sp<KeyCharacterMap> map = new KeyCharacterMap();
     map->mType = parcel->readInt32();
diff --git a/libs/ui/Android.mk b/libs/ui/Android.mk
index 1ce8626..54ff741 100644
--- a/libs/ui/Android.mk
+++ b/libs/ui/Android.mk
@@ -17,6 +17,7 @@
 
 LOCAL_CLANG := true
 LOCAL_CPPFLAGS := -std=c++1y -Weverything -Werror
+LOCAL_SANITIZE := integer
 
 # The static constructors and destructors in this library have not been noted to
 # introduce significant overheads
diff --git a/libs/ui/Rect.cpp b/libs/ui/Rect.cpp
index dcce21f..99cbedc 100644
--- a/libs/ui/Rect.cpp
+++ b/libs/ui/Rect.cpp
@@ -20,6 +20,7 @@
 namespace android {
 
 const Rect Rect::INVALID_RECT{0, 0, -1, -1};
+const Rect Rect::EMPTY_RECT{0, 0, 0, 0};
 
 static inline int32_t min(int32_t a, int32_t b) {
     return (a < b) ? a : b;
@@ -110,7 +111,7 @@
 }
 
 Rect Rect::reduce(const Rect& exclude) const {
-    Rect result;
+    Rect result(Rect::EMPTY_RECT);
 
     uint32_t mask = 0;
     mask |= (exclude.left   > left)   ? 1 : 0;
diff --git a/libs/ui/Region.cpp b/libs/ui/Region.cpp
index 3810da4..7792975 100644
--- a/libs/ui/Region.cpp
+++ b/libs/ui/Region.cpp
@@ -798,7 +798,7 @@
     Region result;
     result.mStorage.clear();
     for (size_t r = 0; r < numRects; ++r) {
-        Rect rect;
+        Rect rect(Rect::EMPTY_RECT);
         status_t status = rect.unflatten(buffer, size);
         if (status != NO_ERROR) {
             return status;
diff --git a/opengl/libagl/context.h b/opengl/libagl/context.h
index c599a55..d23f435 100644
--- a/opengl/libagl/context.h
+++ b/opengl/libagl/context.h
@@ -21,7 +21,7 @@
 #include <stddef.h>
 #include <sys/types.h>
 #include <pthread.h>
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
 #include <bionic_tls.h>
 #endif
 
@@ -579,7 +579,7 @@
 // state
 // ----------------------------------------------------------------------------
 
-#ifdef HAVE_ANDROID_OS
+#ifdef __ANDROID__
     // We have a dedicated TLS slot in bionic
     inline void setGlThreadSpecific(ogles_context_t *value) {
         __get_tls()[TLS_SLOT_OPENGL] = value;
diff --git a/opengl/libagl/egl.cpp b/opengl/libagl/egl.cpp
index 593d0c2..7560d8f 100644
--- a/opengl/libagl/egl.cpp
+++ b/opengl/libagl/egl.cpp
@@ -64,7 +64,7 @@
 static pthread_mutex_t gInitMutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_mutex_t gErrorKeyMutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_key_t gEGLErrorKey = -1;
-#ifndef HAVE_ANDROID_OS
+#ifndef __ANDROID__
 namespace gl {
 pthread_key_t gGLKey = -1;
 }; // namespace gl
@@ -1373,7 +1373,7 @@
 
     int32_t w = 0;
     int32_t h = 0;
-    while (attrib_list[0]) {
+    while (attrib_list[0] != EGL_NONE) {
         if (attrib_list[0] == EGL_WIDTH)  w = attrib_list[1];
         if (attrib_list[0] == EGL_HEIGHT) h = attrib_list[1];
         attrib_list+=2;
@@ -1403,7 +1403,7 @@
 
 EGLDisplay eglGetDisplay(NativeDisplayType display)
 {
-#ifndef HAVE_ANDROID_OS
+#ifndef __ANDROID__
     // this just needs to be done once
     if (gGLKey == -1) {
         pthread_mutex_lock(&gInitMutex);
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 8d42690..29749c0 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -144,6 +144,7 @@
 #
 
 LOCAL_MODULE:= libETC1
+LOCAL_MODULE_HOST_OS := darwin linux windows
 
 include $(BUILD_HOST_STATIC_LIBRARY)
 
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
index b828175..0a7fc27 100644
--- a/services/inputflinger/host/Android.mk
+++ b/services/inputflinger/host/Android.mk
@@ -58,5 +58,6 @@
 	libutils
 
 LOCAL_MODULE := inputflinger
+LOCAL_INIT_RC := inputflinger.rc
 
 include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/host/inputflinger.rc b/services/inputflinger/host/inputflinger.rc
new file mode 100644
index 0000000..ae71ee5
--- /dev/null
+++ b/services/inputflinger/host/inputflinger.rc
@@ -0,0 +1,5 @@
+service inputflinger /system/bin/inputflinger
+    class main
+    user system
+    group input
+#    onrestart restart zygote
diff --git a/services/sensorservice/CorrectedGyroSensor.cpp b/services/sensorservice/CorrectedGyroSensor.cpp
index b07d544..7b1f346 100644
--- a/services/sensorservice/CorrectedGyroSensor.cpp
+++ b/services/sensorservice/CorrectedGyroSensor.cpp
@@ -58,12 +58,12 @@
 
 status_t CorrectedGyroSensor::activate(void* ident, bool enabled) {
     mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(FUSION_9AXIS, ident, enabled);
 }
 
 status_t CorrectedGyroSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
     mSensorDevice.setDelay(ident, mGyro.getHandle(), ns);
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
 Sensor CorrectedGyroSensor::getSensor() const {
diff --git a/services/sensorservice/Fusion.cpp b/services/sensorservice/Fusion.cpp
index 4f63c31..359d289 100644
--- a/services/sensorservice/Fusion.cpp
+++ b/services/sensorservice/Fusion.cpp
@@ -24,28 +24,44 @@
 
 // -----------------------------------------------------------------------
 
+/*==================== BEGIN FUSION SENSOR PARAMETER =========================*/
+
+/* Note:
+ *   If a platform uses software fusion, it is necessary to tune the following
+ *   parameters to fit the hardware sensors prior to release.
+ *
+ *   The DEFAULT_ parameters will be used in FUSION_9AXIS and FUSION_NOMAG mode.
+ *   The GEOMAG_ parameters will be used in FUSION_NOGYRO mode.
+ */
+
 /*
- * gyroVAR gives the measured variance of the gyro's output per
+ * GYRO_VAR gives the measured variance of the gyro's output per
  * Hz (or variance at 1 Hz). This is an "intrinsic" parameter of the gyro,
  * which is independent of the sampling frequency.
  *
  * The variance of gyro's output at a given sampling period can be
  * calculated as:
- *      variance(T) = gyroVAR / T
+ *      variance(T) = GYRO_VAR / T
  *
  * The variance of the INTEGRATED OUTPUT at a given sampling period can be
  * calculated as:
- *       variance_integrate_output(T) = gyroVAR * T
- *
+ *       variance_integrate_output(T) = GYRO_VAR * T
  */
-static const float gyroVAR = 1e-7;      // (rad/s)^2 / Hz
-static const float biasVAR = 1e-8;      // (rad/s)^2 / s (guessed)
+static const float DEFAULT_GYRO_VAR = 1e-7;      // (rad/s)^2 / Hz
+static const float DEFAULT_GYRO_BIAS_VAR = 1e-12;  // (rad/s)^2 / s (guessed)
+static const float GEOMAG_GYRO_VAR = 1e-4;      // (rad/s)^2 / Hz
+static const float GEOMAG_GYRO_BIAS_VAR = 1e-8;  // (rad/s)^2 / s (guessed)
 
 /*
  * Standard deviations of accelerometer and magnetometer
  */
-static const float accSTDEV  = 0.05f;   // m/s^2 (measured 0.08 / CDD 0.05)
-static const float magSTDEV  = 0.5f;    // uT    (measured 0.7  / CDD 0.5)
+static const float DEFAULT_ACC_STDEV  = 0.015f; // m/s^2 (measured 0.08 / CDD 0.05)
+static const float DEFAULT_MAG_STDEV  = 0.1f;   // uT    (measured 0.7  / CDD 0.5)
+static const float GEOMAG_ACC_STDEV  = 0.05f; // m/s^2 (measured 0.08 / CDD 0.05)
+static const float GEOMAG_MAG_STDEV  = 0.1f;   // uT    (measured 0.7  / CDD 0.5)
+
+
+/* ====================== END FUSION SENSOR PARAMETER ========================*/
 
 static const float SYMMETRY_TOLERANCE = 1e-10f;
 
@@ -54,7 +70,8 @@
  * ill-conditioning and div by zeros.
  * Threshhold: 10% of g, in m/s^2
  */
-static const float FREE_FALL_THRESHOLD = 0.981f;
+static const float NOMINAL_GRAVITY = 9.81f;
+static const float FREE_FALL_THRESHOLD = 0.1f * (NOMINAL_GRAVITY);
 static const float FREE_FALL_THRESHOLD_SQ =
         FREE_FALL_THRESHOLD*FREE_FALL_THRESHOLD;
 
@@ -87,6 +104,9 @@
 static const float MIN_VALID_CROSS_PRODUCT_MAG_SQ =
     MIN_VALID_CROSS_PRODUCT_MAG*MIN_VALID_CROSS_PRODUCT_MAG;
 
+static const float W_EPS = 1e-4f;
+static const float SQRT_3 = 1.732f;
+static const float WVEC_EPS = 1e-4f/SQRT_3;
 // -----------------------------------------------------------------------
 
 template <typename TYPE, size_t C, size_t R>
@@ -173,7 +193,7 @@
     init();
 }
 
-void Fusion::init() {
+void Fusion::init(int mode) {
     mInitState = 0;
 
     mGyroRate = 0;
@@ -183,6 +203,19 @@
     mCount[2] = 0;
 
     mData = 0;
+    mMode = mode;
+
+    if (mMode != FUSION_NOGYRO) { //normal or game rotation
+        mParam.gyroVar = DEFAULT_GYRO_VAR;
+        mParam.gyroBiasVar = DEFAULT_GYRO_BIAS_VAR;
+        mParam.accStdev = DEFAULT_ACC_STDEV;
+        mParam.magStdev = DEFAULT_MAG_STDEV;
+    } else {
+        mParam.gyroVar = GEOMAG_GYRO_VAR;
+        mParam.gyroBiasVar = GEOMAG_GYRO_BIAS_VAR;
+        mParam.accStdev = GEOMAG_ACC_STDEV;
+        mParam.magStdev = GEOMAG_MAG_STDEV;
+    }
 }
 
 void Fusion::initFusion(const vec4_t& q, float dT)
@@ -205,11 +238,11 @@
     const float dT3 = dT2*dT;
 
     // variance of integrated output at 1/dT Hz (random drift)
-    const float q00 = gyroVAR * dT + 0.33333f * biasVAR * dT3;
+    const float q00 = mParam.gyroVar * dT + 0.33333f * mParam.gyroBiasVar * dT3;
 
     // variance of drift rate ramp
-    const float q11 = biasVAR * dT;
-    const float q10 = 0.5f * biasVAR * dT2;
+    const float q11 = mParam.gyroBiasVar * dT;
+    const float q10 = 0.5f * mParam.gyroBiasVar * dT2;
     const float q01 = q10;
 
     GQGt[0][0] =  q00;      // rad^2
@@ -223,7 +256,9 @@
 }
 
 bool Fusion::hasEstimate() const {
-    return (mInitState == (MAG|ACC|GYRO));
+    return ((mInitState & MAG) || (mMode == FUSION_NOMAG)) &&
+           ((mInitState & GYRO) || (mMode == FUSION_NOGYRO)) &&
+           (mInitState & ACC);
 }
 
 bool Fusion::checkInitComplete(int what, const vec3_t& d, float dT) {
@@ -234,6 +269,9 @@
         mData[0] += d * (1/length(d));
         mCount[0]++;
         mInitState |= ACC;
+        if (mMode == FUSION_NOGYRO ) {
+            mGyroRate = dT;
+        }
     } else if (what == MAG) {
         mData[1] += d * (1/length(d));
         mCount[1]++;
@@ -242,25 +280,29 @@
         mGyroRate = dT;
         mData[2] += d*dT;
         mCount[2]++;
-        if (mCount[2] == 64) {
-            // 64 samples is good enough to estimate the gyro drift and
-            // doesn't take too much time.
-            mInitState |= GYRO;
-        }
+        mInitState |= GYRO;
     }
 
-    if (mInitState == (MAG|ACC|GYRO)) {
+    if (hasEstimate()) {
         // Average all the values we collected so far
         mData[0] *= 1.0f/mCount[0];
-        mData[1] *= 1.0f/mCount[1];
+        if (mMode != FUSION_NOMAG) {
+            mData[1] *= 1.0f/mCount[1];
+        }
         mData[2] *= 1.0f/mCount[2];
 
         // calculate the MRPs from the data collection, this gives us
         // a rough estimate of our initial state
         mat33_t R;
-        vec3_t up(mData[0]);
-        vec3_t east(cross_product(mData[1], up));
-        east *= 1/length(east);
+        vec3_t  up(mData[0]);
+        vec3_t  east;
+
+        if (mMode != FUSION_NOMAG) {
+            east = normalize(cross_product(mData[1], up));
+        } else {
+            east = getOrthogonal(up);
+        }
+
         vec3_t north(cross_product(up, east));
         R << east << north << up;
         const vec4_t q = matrixToQuat(R);
@@ -278,21 +320,43 @@
     predict(w, dT);
 }
 
-status_t Fusion::handleAcc(const vec3_t& a) {
+status_t Fusion::handleAcc(const vec3_t& a, float dT) {
+    if (!checkInitComplete(ACC, a, dT))
+        return BAD_VALUE;
+
     // ignore acceleration data if we're close to free-fall
-    if (length_squared(a) < FREE_FALL_THRESHOLD_SQ) {
+    const float l = length(a);
+    if (l < FREE_FALL_THRESHOLD) {
         return BAD_VALUE;
     }
 
-    if (!checkInitComplete(ACC, a))
-        return BAD_VALUE;
+    const float l_inv = 1.0f/l;
 
-    const float l = 1/length(a);
-    update(a*l, Ba, accSTDEV*l);
+    if ( mMode == FUSION_NOGYRO ) {
+        //geo mag
+        vec3_t w_dummy;
+        w_dummy = x1; //bias
+        predict(w_dummy, dT);
+    }
+
+    if ( mMode == FUSION_NOMAG) {
+        vec3_t m;
+        m = getRotationMatrix()*Bm;
+        update(m, Bm, mParam.magStdev);
+    }
+
+    vec3_t unityA = a * l_inv;
+    const float d = sqrtf(fabsf(l- NOMINAL_GRAVITY));
+    const float p = l_inv * mParam.accStdev*expf(d);
+
+    update(unityA, Ba, p);
     return NO_ERROR;
 }
 
 status_t Fusion::handleMag(const vec3_t& m) {
+    if (!checkInitComplete(MAG, m))
+        return BAD_VALUE;
+
     // the geomagnetic-field should be between 30uT and 60uT
     // reject if too large to avoid spurious magnetic sources
     const float magFieldSq = length_squared(m);
@@ -304,9 +368,6 @@
         return BAD_VALUE;
     }
 
-    if (!checkInitComplete(MAG, m))
-        return BAD_VALUE;
-
     // Orthogonalize the magnetic field to the gravity field, mapping it into
     // tangent to Earth.
     const vec3_t up( getRotationMatrix() * Ba );
@@ -324,10 +385,10 @@
     // then pass it in as the update.
     vec3_t north( cross_product(up, east) );
 
-    const float l = 1 / length(north);
-    north *= l;
+    const float l_inv = 1 / length(north);
+    north *= l_inv;
 
-    update(north, Bm, magSTDEV*l);
+    update(north, Bm,  mParam.magStdev*l_inv);
     return NO_ERROR;
 }
 
@@ -372,8 +433,11 @@
 void Fusion::predict(const vec3_t& w, float dT) {
     const vec4_t q  = x0;
     const vec3_t b  = x1;
-    const vec3_t we = w - b;
+    vec3_t we = w - b;
 
+    if (length(we) < WVEC_EPS) {
+        we = (we[0]>0.f)?WVEC_EPS:-WVEC_EPS;
+    }
     // q(k+1) = O(we)*q(k)
     // --------------------
     //
@@ -406,7 +470,7 @@
     const mat33_t wx2(wx*wx);
     const float lwedT = length(we)*dT;
     const float hlwedT = 0.5f*lwedT;
-    const float ilwe = 1/length(we);
+    const float ilwe = 1.f/length(we);
     const float k0 = (1-cosf(lwedT))*(ilwe*ilwe);
     const float k1 = sinf(lwedT);
     const float k2 = cosf(hlwedT);
@@ -422,6 +486,7 @@
     Phi[1][0] = wx*k0 - I33dT - wx2*(ilwe*ilwe*ilwe)*(lwedT-k1);
 
     x0 = O*q;
+
     if (x0.w < 0)
         x0 = -x0;
 
@@ -466,15 +531,37 @@
 
     const vec3_t e(z - Bb);
     const vec3_t dq(K[0]*e);
-    const vec3_t db(K[1]*e);
 
     q += getF(q)*(0.5f*dq);
     x0 = normalize_quat(q);
-    x1 += db;
+
+    if (mMode != FUSION_NOMAG) {
+        const vec3_t db(K[1]*e);
+        x1 += db;
+    }
 
     checkState();
 }
 
+vec3_t Fusion::getOrthogonal(const vec3_t &v) {
+    vec3_t w;
+    if (fabsf(v[0])<= fabsf(v[1]) && fabsf(v[0]) <= fabsf(v[2]))  {
+        w[0]=0.f;
+        w[1] = v[2];
+        w[2] = -v[1];
+    } else if (fabsf(v[1]) <= fabsf(v[2])) {
+        w[0] = v[2];
+        w[1] = 0.f;
+        w[2] = -v[0];
+    }else {
+        w[0] = v[1];
+        w[1] = -v[0];
+        w[2] = 0.f;
+    }
+    return normalize(w);
+}
+
+
 // -----------------------------------------------------------------------
 
 }; // namespace android
diff --git a/services/sensorservice/Fusion.h b/services/sensorservice/Fusion.h
index 7062999..602779f 100644
--- a/services/sensorservice/Fusion.h
+++ b/services/sensorservice/Fusion.h
@@ -27,6 +27,13 @@
 
 typedef mat<float, 3, 4> mat34_t;
 
+enum FUSION_MODE{
+    FUSION_9AXIS, // use accel gyro mag
+    FUSION_NOMAG, // use accel gyro (game rotation, gravity)
+    FUSION_NOGYRO, // use accel mag (geomag rotation)
+    NUM_FUSION_MODE
+};
+
 class Fusion {
     /*
      * the state vector is made of two sub-vector containing respectively:
@@ -55,9 +62,9 @@
 
 public:
     Fusion();
-    void init();
+    void init(int mode = FUSION_9AXIS);
     void handleGyro(const vec3_t& w, float dT);
-    status_t handleAcc(const vec3_t& a);
+    status_t handleAcc(const vec3_t& a, float dT);
     status_t handleMag(const vec3_t& m);
     vec4_t getAttitude() const;
     vec3_t getBias() const;
@@ -65,12 +72,21 @@
     bool hasEstimate() const;
 
 private:
+    struct Parameter {
+        float gyroVar;
+        float gyroBiasVar;
+        float accStdev;
+        float magStdev;
+    } mParam;
+
     mat<mat33_t, 2, 2> Phi;
     vec3_t Ba, Bm;
     uint32_t mInitState;
     float mGyroRate;
     vec<vec3_t, 3> mData;
     size_t mCount[3];
+    int mMode;
+
     enum { ACC=0x1, MAG=0x2, GYRO=0x4 };
     bool checkInitComplete(int, const vec3_t& w, float d = 0);
     void initFusion(const vec4_t& q0, float dT);
@@ -78,6 +94,7 @@
     void predict(const vec3_t& w, float dT);
     void update(const vec3_t& z, const vec3_t& Bi, float sigma);
     static mat34_t getF(const vec4_t& p);
+    static vec3_t getOrthogonal(const vec3_t &v);
 };
 
 }; // namespace android
diff --git a/services/sensorservice/GravitySensor.cpp b/services/sensorservice/GravitySensor.cpp
index 61118bc..a165a5b 100644
--- a/services/sensorservice/GravitySensor.cpp
+++ b/services/sensorservice/GravitySensor.cpp
@@ -46,9 +46,9 @@
 {
     if (event.type == SENSOR_TYPE_ACCELEROMETER) {
         vec3_t g;
-        if (!mSensorFusion.hasEstimate())
+        if (!mSensorFusion.hasEstimate(FUSION_NOMAG))
             return false;
-        const mat33_t R(mSensorFusion.getRotationMatrix());
+        const mat33_t R(mSensorFusion.getRotationMatrix(FUSION_NOMAG));
         // FIXME: we need to estimate the length of gravity because
         // the accelerometer may have a small scaling error. This
         // translates to an offset in the linear-acceleration sensor.
@@ -66,11 +66,11 @@
 }
 
 status_t GravitySensor::activate(void* ident, bool enabled) {
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(FUSION_NOMAG, ident, enabled);
 }
 
 status_t GravitySensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(FUSION_NOMAG, ident, ns);
 }
 
 Sensor GravitySensor::getSensor() const {
diff --git a/services/sensorservice/OrientationSensor.cpp b/services/sensorservice/OrientationSensor.cpp
index 6d85cca..d55f336 100644
--- a/services/sensorservice/OrientationSensor.cpp
+++ b/services/sensorservice/OrientationSensor.cpp
@@ -66,11 +66,11 @@
 }
 
 status_t OrientationSensor::activate(void* ident, bool enabled) {
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(FUSION_9AXIS, ident, enabled);
 }
 
 status_t OrientationSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
 Sensor OrientationSensor::getSensor() const {
diff --git a/services/sensorservice/RotationVectorSensor.cpp b/services/sensorservice/RotationVectorSensor.cpp
index cb305eb..238845b 100644
--- a/services/sensorservice/RotationVectorSensor.cpp
+++ b/services/sensorservice/RotationVectorSensor.cpp
@@ -27,9 +27,10 @@
 namespace android {
 // ---------------------------------------------------------------------------
 
-RotationVectorSensor::RotationVectorSensor()
+RotationVectorSensor::RotationVectorSensor(int mode)
     : mSensorDevice(SensorDevice::getInstance()),
-      mSensorFusion(SensorFusion::getInstance())
+      mSensorFusion(SensorFusion::getInstance()),
+      mMode(mode)
 {
 }
 
@@ -37,15 +38,15 @@
         const sensors_event_t& event)
 {
     if (event.type == SENSOR_TYPE_ACCELEROMETER) {
-        if (mSensorFusion.hasEstimate()) {
-            const vec4_t q(mSensorFusion.getAttitude());
+        if (mSensorFusion.hasEstimate(mMode)) {
+            const vec4_t q(mSensorFusion.getAttitude(mMode));
             *outEvent = event;
             outEvent->data[0] = q.x;
             outEvent->data[1] = q.y;
             outEvent->data[2] = q.z;
             outEvent->data[3] = q.w;
-            outEvent->sensor = '_rov';
-            outEvent->type = SENSOR_TYPE_ROTATION_VECTOR;
+            outEvent->sensor = getSensorToken();
+            outEvent->type = getSensorType();
             return true;
         }
     }
@@ -53,20 +54,20 @@
 }
 
 status_t RotationVectorSensor::activate(void* ident, bool enabled) {
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(mMode, ident, enabled);
 }
 
 status_t RotationVectorSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(mMode, ident, ns);
 }
 
 Sensor RotationVectorSensor::getSensor() const {
     sensor_t hwSensor;
-    hwSensor.name       = "Rotation Vector Sensor";
+    hwSensor.name       = getSensorName();
     hwSensor.vendor     = "AOSP";
     hwSensor.version    = 3;
-    hwSensor.handle     = '_rov';
-    hwSensor.type       = SENSOR_TYPE_ROTATION_VECTOR;
+    hwSensor.handle     = getSensorToken();
+    hwSensor.type       = getSensorType();
     hwSensor.maxRange   = 1;
     hwSensor.resolution = 1.0f / (1<<24);
     hwSensor.power      = mSensorFusion.getPowerUsage();
@@ -75,6 +76,48 @@
     return sensor;
 }
 
+int RotationVectorSensor::getSensorType() const {
+    switch(mMode) {
+        case FUSION_9AXIS:
+            return SENSOR_TYPE_ROTATION_VECTOR;
+        case FUSION_NOMAG:
+            return SENSOR_TYPE_GAME_ROTATION_VECTOR;
+        case FUSION_NOGYRO:
+            return SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR;
+        default:
+            assert(0);
+            return 0;
+    }
+}
+
+const char* RotationVectorSensor::getSensorName() const {
+    switch(mMode) {
+        case FUSION_9AXIS:
+            return "Rotation Vector Sensor";
+        case FUSION_NOMAG:
+            return "Game Rotation Vector Sensor";
+        case FUSION_NOGYRO:
+            return "GeoMag Rotation Vector Sensor";
+        default:
+            assert(0);
+            return NULL;
+    }
+}
+
+int RotationVectorSensor::getSensorToken() const {
+    switch(mMode) {
+        case FUSION_9AXIS:
+            return '_rov';
+        case FUSION_NOMAG:
+            return '_gar';
+        case FUSION_NOGYRO:
+            return '_geo';
+        default:
+            assert(0);
+            return 0;
+    }
+}
+
 // ---------------------------------------------------------------------------
 
 GyroDriftSensor::GyroDriftSensor()
@@ -102,11 +145,11 @@
 }
 
 status_t GyroDriftSensor::activate(void* ident, bool enabled) {
-    return mSensorFusion.activate(ident, enabled);
+    return mSensorFusion.activate(FUSION_9AXIS, ident, enabled);
 }
 
 status_t GyroDriftSensor::setDelay(void* ident, int /*handle*/, int64_t ns) {
-    return mSensorFusion.setDelay(ident, ns);
+    return mSensorFusion.setDelay(FUSION_9AXIS, ident, ns);
 }
 
 Sensor GyroDriftSensor::getSensor() const {
diff --git a/services/sensorservice/RotationVectorSensor.h b/services/sensorservice/RotationVectorSensor.h
index bb97fe1..1fc316b 100644
--- a/services/sensorservice/RotationVectorSensor.h
+++ b/services/sensorservice/RotationVectorSensor.h
@@ -35,9 +35,14 @@
 class RotationVectorSensor : public SensorInterface {
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
+    int mMode;
+
+    int getSensorType() const;
+    const char* getSensorName() const ;
+    int getSensorToken() const ;
 
 public:
-    RotationVectorSensor();
+    RotationVectorSensor(int mode = FUSION_9AXIS);
     virtual bool process(sensors_event_t* outEvent,
             const sensors_event_t& event);
     virtual status_t activate(void* ident, bool enabled);
@@ -46,6 +51,16 @@
     virtual bool isVirtual() const { return true; }
 };
 
+class GameRotationVectorSensor : public RotationVectorSensor {
+public:
+    GameRotationVectorSensor() : RotationVectorSensor(FUSION_NOMAG) {}
+};
+
+class GeoMagRotationVectorSensor : public RotationVectorSensor {
+public:
+    GeoMagRotationVectorSensor() : RotationVectorSensor(FUSION_NOGYRO) {}
+};
+
 class GyroDriftSensor : public SensorInterface {
     SensorDevice& mSensorDevice;
     SensorFusion& mSensorFusion;
diff --git a/services/sensorservice/SensorFusion.cpp b/services/sensorservice/SensorFusion.cpp
index 6d93009..9863f62 100644
--- a/services/sensorservice/SensorFusion.cpp
+++ b/services/sensorservice/SensorFusion.cpp
@@ -25,11 +25,17 @@
 
 SensorFusion::SensorFusion()
     : mSensorDevice(SensorDevice::getInstance()),
-      mEnabled(false), mGyroTime(0)
+      mAttitude(mAttitudes[FUSION_9AXIS]),
+      mGyroTime(0), mAccTime(0)
 {
     sensor_t const* list;
     Sensor uncalibratedGyro;
     ssize_t count = mSensorDevice.getSensorList(&list);
+
+    mEnabled[FUSION_9AXIS] = false;
+    mEnabled[FUSION_NOMAG] = false;
+    mEnabled[FUSION_NOGYRO] = false;
+
     if (count > 0) {
         for (size_t i=0 ; i<size_t(count) ; i++) {
             if (list[i].type == SENSOR_TYPE_ACCELEROMETER) {
@@ -55,81 +61,121 @@
         // and power/cpu usage.
         mEstimatedGyroRate = 200;
         mTargetDelayNs = 1000000000LL/mEstimatedGyroRate;
-        mFusion.init();
+
+        for (int i = 0; i<NUM_FUSION_MODE; ++i) {
+            mFusions[i].init(i);
+        }
     }
 }
 
 void SensorFusion::process(const sensors_event_t& event) {
+
     if (event.type == mGyro.getType()) {
-        if (mGyroTime != 0) {
-            const float dT = (event.timestamp - mGyroTime) / 1000000000.0f;
-            mFusion.handleGyro(vec3_t(event.data), dT);
+        float dT;
+        if ( event.timestamp - mGyroTime> 0 &&
+             event.timestamp - mGyroTime< (int64_t)(5e7) ) { //0.05sec
+
+            dT = (event.timestamp - mGyroTime) / 1000000000.0f;
             // here we estimate the gyro rate (useful for debugging)
             const float freq = 1 / dT;
             if (freq >= 100 && freq<1000) { // filter values obviously wrong
                 const float alpha = 1 / (1 + dT); // 1s time-constant
                 mEstimatedGyroRate = freq + (mEstimatedGyroRate - freq)*alpha;
             }
+
+            const vec3_t gyro(event.data);
+            for (int i = 0; i<NUM_FUSION_MODE; ++i) {
+                if (mEnabled[i]) {
+                    // fusion in no gyro mode will ignore
+                    mFusions[i].handleGyro(gyro, dT);
+                }
+            }
         }
         mGyroTime = event.timestamp;
     } else if (event.type == SENSOR_TYPE_MAGNETIC_FIELD) {
         const vec3_t mag(event.data);
-        mFusion.handleMag(mag);
+        for (int i = 0; i<NUM_FUSION_MODE; ++i) {
+            if (mEnabled[i]) {
+                mFusions[i].handleMag(mag);// fusion in no mag mode will ignore
+            }
+        }
     } else if (event.type == SENSOR_TYPE_ACCELEROMETER) {
-        const vec3_t acc(event.data);
-        mFusion.handleAcc(acc);
-        mAttitude = mFusion.getAttitude();
+        float dT;
+        if ( event.timestamp - mAccTime> 0 &&
+             event.timestamp - mAccTime< (int64_t)(1e8) ) { //0.1sec
+            dT = (event.timestamp - mAccTime) / 1000000000.0f;
+
+            const vec3_t acc(event.data);
+            for (int i = 0; i<NUM_FUSION_MODE; ++i) {
+                if (mEnabled[i]) {
+                    mFusions[i].handleAcc(acc, dT);
+                    mAttitudes[i] = mFusions[i].getAttitude();
+                }
+            }
+        }
+        mAccTime = event.timestamp;
     }
 }
 
 template <typename T> inline T min(T a, T b) { return a<b ? a : b; }
 template <typename T> inline T max(T a, T b) { return a>b ? a : b; }
 
-status_t SensorFusion::activate(void* ident, bool enabled) {
+status_t SensorFusion::activate(int mode, void* ident, bool enabled) {
 
     ALOGD_IF(DEBUG_CONNECTIONS,
-            "SensorFusion::activate(ident=%p, enabled=%d)",
-            ident, enabled);
+            "SensorFusion::activate(mode=%d, ident=%p, enabled=%d)",
+            mode, ident, enabled);
 
-    const ssize_t idx = mClients.indexOf(ident);
+    const ssize_t idx = mClients[mode].indexOf(ident);
     if (enabled) {
         if (idx < 0) {
-            mClients.add(ident);
+            mClients[mode].add(ident);
         }
     } else {
         if (idx >= 0) {
-            mClients.removeItemsAt(idx);
+            mClients[mode].removeItemsAt(idx);
+        }
+    }
+
+    const bool newState = mClients[mode].size() != 0;
+    if (newState != mEnabled[mode]) {
+        mEnabled[mode] = newState;
+        if (newState) {
+            mFusions[mode].init(mode);
         }
     }
 
     mSensorDevice.activate(ident, mAcc.getHandle(), enabled);
-    mSensorDevice.activate(ident, mMag.getHandle(), enabled);
-    mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
+    if (mode != FUSION_NOMAG) {
+        mSensorDevice.activate(ident, mMag.getHandle(), enabled);
+    }
+    if (mode != FUSION_NOGYRO) {
+        mSensorDevice.activate(ident, mGyro.getHandle(), enabled);
+    }
 
-    const bool newState = mClients.size() != 0;
-    if (newState != mEnabled) {
-        mEnabled = newState;
-        if (newState) {
-            mFusion.init();
-            mGyroTime = 0;
-        }
+    return NO_ERROR;
+}
+
+status_t SensorFusion::setDelay(int mode, void* ident, int64_t ns) {
+    // Call batch with timeout zero instead of setDelay().
+    if (ns > (int64_t)5e7) {
+        ns = (int64_t)(5e7);
+    }
+    mSensorDevice.batch(ident, mAcc.getHandle(), 0, ns, 0);
+    if (mode != FUSION_NOMAG) {
+        mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(20), 0);
+    }
+    if (mode != FUSION_NOGYRO) {
+        mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0);
     }
     return NO_ERROR;
 }
 
-status_t SensorFusion::setDelay(void* ident, int64_t ns) {
-    // Call batch with timeout zero instead of setDelay().
-    mSensorDevice.batch(ident, mAcc.getHandle(), 0, ns, 0);
-    mSensorDevice.batch(ident, mMag.getHandle(), 0, ms2ns(20), 0);
-    mSensorDevice.batch(ident, mGyro.getHandle(), 0, mTargetDelayNs, 0);
-    return NO_ERROR;
-}
 
-
-float SensorFusion::getPowerUsage() const {
+float SensorFusion::getPowerUsage(int mode) const {
     float power =   mAcc.getPowerUsage() +
-                    mMag.getPowerUsage() +
-                    mGyro.getPowerUsage();
+                    ((mode != FUSION_NOMAG) ? mMag.getPowerUsage() : 0) +
+                    ((mode != FUSION_NOGYRO) ? mGyro.getPowerUsage() : 0);
     return power;
 }
 
@@ -138,21 +184,55 @@
 }
 
 void SensorFusion::dump(String8& result) {
-    const Fusion& fusion(mFusion);
+    const Fusion& fusion_9axis(mFusions[FUSION_9AXIS]);
     result.appendFormat("9-axis fusion %s (%zd clients), gyro-rate=%7.2fHz, "
             "q=< %g, %g, %g, %g > (%g), "
             "b=< %g, %g, %g >\n",
-            mEnabled ? "enabled" : "disabled",
-            mClients.size(),
+            mEnabled[FUSION_9AXIS] ? "enabled" : "disabled",
+            mClients[FUSION_9AXIS].size(),
             mEstimatedGyroRate,
-            fusion.getAttitude().x,
-            fusion.getAttitude().y,
-            fusion.getAttitude().z,
-            fusion.getAttitude().w,
-            length(fusion.getAttitude()),
-            fusion.getBias().x,
-            fusion.getBias().y,
-            fusion.getBias().z);
+            fusion_9axis.getAttitude().x,
+            fusion_9axis.getAttitude().y,
+            fusion_9axis.getAttitude().z,
+            fusion_9axis.getAttitude().w,
+            length(fusion_9axis.getAttitude()),
+            fusion_9axis.getBias().x,
+            fusion_9axis.getBias().y,
+            fusion_9axis.getBias().z);
+
+    const Fusion& fusion_nomag(mFusions[FUSION_NOMAG]);
+    result.appendFormat("game fusion(no mag) %s (%zd clients), "
+            "gyro-rate=%7.2fHz, "
+            "q=< %g, %g, %g, %g > (%g), "
+            "b=< %g, %g, %g >\n",
+            mEnabled[FUSION_NOMAG] ? "enabled" : "disabled",
+            mClients[FUSION_NOMAG].size(),
+            mEstimatedGyroRate,
+            fusion_nomag.getAttitude().x,
+            fusion_nomag.getAttitude().y,
+            fusion_nomag.getAttitude().z,
+            fusion_nomag.getAttitude().w,
+            length(fusion_nomag.getAttitude()),
+            fusion_nomag.getBias().x,
+            fusion_nomag.getBias().y,
+            fusion_nomag.getBias().z);
+
+    const Fusion& fusion_nogyro(mFusions[FUSION_NOGYRO]);
+    result.appendFormat("geomag fusion (no gyro) %s (%zd clients), "
+            "gyro-rate=%7.2fHz, "
+            "q=< %g, %g, %g, %g > (%g), "
+            "b=< %g, %g, %g >\n",
+            mEnabled[FUSION_NOGYRO] ? "enabled" : "disabled",
+            mClients[FUSION_NOGYRO].size(),
+            mEstimatedGyroRate,
+            fusion_nogyro.getAttitude().x,
+            fusion_nogyro.getAttitude().y,
+            fusion_nogyro.getAttitude().z,
+            fusion_nogyro.getAttitude().w,
+            length(fusion_nogyro.getAttitude()),
+            fusion_nogyro.getBias().x,
+            fusion_nogyro.getBias().y,
+            fusion_nogyro.getBias().z);
 }
 
 // ---------------------------------------------------------------------------
diff --git a/services/sensorservice/SensorFusion.h b/services/sensorservice/SensorFusion.h
index 432adbc..ad636d5 100644
--- a/services/sensorservice/SensorFusion.h
+++ b/services/sensorservice/SensorFusion.h
@@ -42,30 +42,52 @@
     Sensor mAcc;
     Sensor mMag;
     Sensor mGyro;
-    Fusion mFusion;
-    bool mEnabled;
+
+    Fusion mFusions[NUM_FUSION_MODE]; // normal, no_mag, no_gyro
+
+    bool mEnabled[NUM_FUSION_MODE];
+
+    vec4_t &mAttitude;
+    vec4_t mAttitudes[NUM_FUSION_MODE];
+
+    SortedVector<void*> mClients[3];
+
     float mEstimatedGyroRate;
     nsecs_t mTargetDelayNs;
+
     nsecs_t mGyroTime;
-    vec4_t mAttitude;
-    SortedVector<void*> mClients;
+    nsecs_t mAccTime;
 
     SensorFusion();
 
 public:
     void process(const sensors_event_t& event);
 
-    bool isEnabled() const { return mEnabled; }
-    bool hasEstimate() const { return mFusion.hasEstimate(); }
-    mat33_t getRotationMatrix() const { return mFusion.getRotationMatrix(); }
-    vec4_t getAttitude() const { return mAttitude; }
-    vec3_t getGyroBias() const { return mFusion.getBias(); }
+    bool isEnabled() const {
+        return mEnabled[FUSION_9AXIS] ||
+                mEnabled[FUSION_NOMAG] ||
+                mEnabled[FUSION_NOGYRO];
+    }
+
+    bool hasEstimate(int mode = FUSION_9AXIS) const {
+        return mFusions[mode].hasEstimate();
+    }
+
+    mat33_t getRotationMatrix(int mode = FUSION_9AXIS) const {
+        return mFusions[mode].getRotationMatrix();
+    }
+
+    vec4_t getAttitude(int mode = FUSION_9AXIS) const {
+        return mAttitudes[mode];
+    }
+
+    vec3_t getGyroBias() const { return mFusions[FUSION_9AXIS].getBias(); }
     float getEstimatedRate() const { return mEstimatedGyroRate; }
 
-    status_t activate(void* ident, bool enabled);
-    status_t setDelay(void* ident, int64_t ns);
+    status_t activate(int mode, void* ident, bool enabled);
+    status_t setDelay(int mode, void* ident, int64_t ns);
 
-    float getPowerUsage() const;
+    float getPowerUsage(int mode=FUSION_9AXIS) const;
     int32_t getMinDelay() const;
 
     void dump(String8& result);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 1a486a3..8e2109b 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -88,11 +88,14 @@
             uint32_t virtualSensorsNeeds =
                     (1<<SENSOR_TYPE_GRAVITY) |
                     (1<<SENSOR_TYPE_LINEAR_ACCELERATION) |
-                    (1<<SENSOR_TYPE_ROTATION_VECTOR);
+                    (1<<SENSOR_TYPE_ROTATION_VECTOR) |
+                    (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR) |
+                    (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR);
 
             mLastEventSeen.setCapacity(count);
             for (ssize_t i=0 ; i<count ; i++) {
-                registerSensor( new HardwareSensor(list[i]) );
+                bool useThisSensor=true;
+
                 switch (list[i].type) {
                     case SENSOR_TYPE_ACCELEROMETER:
                         hasAccel = true;
@@ -110,9 +113,18 @@
                     case SENSOR_TYPE_GRAVITY:
                     case SENSOR_TYPE_LINEAR_ACCELERATION:
                     case SENSOR_TYPE_ROTATION_VECTOR:
-                        virtualSensorsNeeds &= ~(1<<list[i].type);
+                    case SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR:
+                    case SENSOR_TYPE_GAME_ROTATION_VECTOR:
+                        if (IGNORE_HARDWARE_FUSION) {
+                            useThisSensor = false;
+                        } else {
+                            virtualSensorsNeeds &= ~(1<<list[i].type);
+                        }
                         break;
                 }
+                if (useThisSensor) {
+                    registerSensor( new HardwareSensor(list[i]) );
+                }
             }
 
             // it's safe to instantiate the SensorFusion object here
@@ -124,26 +136,15 @@
             mUserSensorList = mSensorList;
 
             if (hasGyro && hasAccel && hasMag) {
-                Sensor aSensor;
-
                 // Add Android virtual sensors if they're not already
                 // available in the HAL
+                Sensor aSensor;
 
                 aSensor = registerVirtualSensor( new RotationVectorSensor() );
                 if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) {
                     mUserSensorList.add(aSensor);
                 }
 
-                aSensor = registerVirtualSensor( new GravitySensor(list, count) );
-                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) {
-                    mUserSensorList.add(aSensor);
-                }
-
-                aSensor = registerVirtualSensor( new LinearAccelerationSensor(list, count) );
-                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) {
-                    mUserSensorList.add(aSensor);
-                }
-
                 aSensor = registerVirtualSensor( new OrientationSensor() );
                 if (virtualSensorsNeeds & (1<<SENSOR_TYPE_ROTATION_VECTOR)) {
                     // if we are doing our own rotation-vector, also add
@@ -151,11 +152,46 @@
                     mUserSensorList.replaceAt(aSensor, orientationIndex);
                 }
 
+                aSensor = registerVirtualSensor(
+                                new LinearAccelerationSensor(list, count) );
+                if (virtualSensorsNeeds &
+                            (1<<SENSOR_TYPE_LINEAR_ACCELERATION)) {
+                    mUserSensorList.add(aSensor);
+                }
+
                 // virtual debugging sensors are not added to mUserSensorList
                 registerVirtualSensor( new CorrectedGyroSensor(list, count) );
                 registerVirtualSensor( new GyroDriftSensor() );
             }
 
+            if (hasAccel && hasGyro) {
+                Sensor aSensor;
+
+                aSensor = registerVirtualSensor(
+                                new GravitySensor(list, count) );
+                if (virtualSensorsNeeds & (1<<SENSOR_TYPE_GRAVITY)) {
+                    mUserSensorList.add(aSensor);
+                }
+
+                aSensor = registerVirtualSensor(
+                                new GameRotationVectorSensor() );
+                if (virtualSensorsNeeds &
+                            (1<<SENSOR_TYPE_GAME_ROTATION_VECTOR)) {
+                    mUserSensorList.add(aSensor);
+                }
+            }
+
+            if (hasAccel && hasMag) {
+                Sensor aSensor;
+
+                aSensor = registerVirtualSensor(
+                                new GeoMagRotationVectorSensor() );
+                if (virtualSensorsNeeds &
+                        (1<<SENSOR_TYPE_GEOMAGNETIC_ROTATION_VECTOR)) {
+                    mUserSensorList.add(aSensor);
+                }
+            }
+
             // debugging sensor list
             mUserSensorListDebug = mSensorList;
 
diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h
index 9a573ae..7d81d6e 100644
--- a/services/sensorservice/SensorService.h
+++ b/services/sensorservice/SensorService.h
@@ -46,7 +46,7 @@
 #endif
 
 // ---------------------------------------------------------------------------
-
+#define IGNORE_HARDWARE_FUSION  false
 #define DEBUG_CONNECTIONS   false
 // Max size is 100 KB which is enough to accept a batch of about 1000 events.
 #define MAX_SOCKET_BUFFER_SIZE_BATCHED 100 * 1024
diff --git a/services/sensorservice/main_sensorservice.cpp b/services/sensorservice/main_sensorservice.cpp
index 0a96f42..01bb0e7 100644
--- a/services/sensorservice/main_sensorservice.cpp
+++ b/services/sensorservice/main_sensorservice.cpp
@@ -20,6 +20,7 @@
 using namespace android;
 
 int main(int /*argc*/, char** /*argv*/) {
+    signal(SIGPIPE, SIG_IGN);
     SensorService::publishAndJoinThreadPool();
     return 0;
 }
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 1eb2361..17ca10e 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -122,6 +122,8 @@
 LOCAL_CFLAGS := -DLOG_TAG=\"SurfaceFlinger\"
 LOCAL_CPPFLAGS := -std=c++11
 
+LOCAL_INIT_RC := surfaceflinger.rc
+
 LOCAL_SRC_FILES := \
     main_surfaceflinger.cpp
 
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index 2dad005..0859149 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -336,10 +336,20 @@
     HWC_DISPLAY_HEIGHT,
     HWC_DISPLAY_DPI_X,
     HWC_DISPLAY_DPI_Y,
+    HWC_DISPLAY_COLOR_TRANSFORM,
     HWC_DISPLAY_NO_ATTRIBUTE,
 };
 #define NUM_DISPLAY_ATTRIBUTES (sizeof(DISPLAY_ATTRIBUTES) / sizeof(DISPLAY_ATTRIBUTES)[0])
 
+static const uint32_t PRE_HWC15_DISPLAY_ATTRIBUTES[] = {
+    HWC_DISPLAY_VSYNC_PERIOD,
+    HWC_DISPLAY_WIDTH,
+    HWC_DISPLAY_HEIGHT,
+    HWC_DISPLAY_DPI_X,
+    HWC_DISPLAY_DPI_Y,
+    HWC_DISPLAY_NO_ATTRIBUTE,
+};
+
 status_t HWComposer::queryDisplayProperties(int disp) {
 
     LOG_ALWAYS_FATAL_IF(!mHwc || !hwcHasApiVersion(mHwc, HWC_DEVICE_API_VERSION_1_1));
@@ -362,6 +372,12 @@
     for (size_t c = 0; c < numConfigs; ++c) {
         err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
                 DISPLAY_ATTRIBUTES, values);
+        // If this is a pre-1.5 HWC, it may not know about color transform, so
+        // try again with a smaller set of attributes
+        if (err != NO_ERROR) {
+            err = mHwc->getDisplayAttributes(mHwc, disp, configs[c],
+                    PRE_HWC15_DISPLAY_ATTRIBUTES, values);
+        }
         if (err != NO_ERROR) {
             // we can't get this display's info. turn it off.
             mDisplayData[disp].connected = false;
@@ -386,6 +402,9 @@
                 case HWC_DISPLAY_DPI_Y:
                     config.ydpi = values[i] / 1000.0f;
                     break;
+                case HWC_DISPLAY_COLOR_TRANSFORM:
+                    config.colorTransform = values[i];
+                    break;
                 default:
                     ALOG_ASSERT(false, "unknown display attribute[%zu] %#x",
                             i, DISPLAY_ATTRIBUTES[i]);
@@ -1162,9 +1181,11 @@
             result.appendFormat("  Display[%zd] configurations (* current):\n", i);
             for (size_t c = 0; c < disp.configs.size(); ++c) {
                 const DisplayConfig& config(disp.configs[c]);
-                result.appendFormat("    %s%zd: %ux%u, xdpi=%f, ydpi=%f, refresh=%" PRId64 "\n",
-                        c == disp.currentConfig ? "* " : "", c, config.width, config.height,
-                        config.xdpi, config.ydpi, config.refresh);
+                result.appendFormat("    %s%zd: %ux%u, xdpi=%f, ydpi=%f"
+                        ", refresh=%" PRId64 ", colorTransform=%d\n",
+                        c == disp.currentConfig ? "* " : "", c,
+                        config.width, config.height, config.xdpi, config.ydpi,
+                        config.refresh, config.colorTransform);
             }
 
             if (disp.list) {
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.h b/services/surfaceflinger/DisplayHardware/HWComposer.h
index cc98b4c..5e0b3d8 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.h
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.h
@@ -257,6 +257,7 @@
         float xdpi;
         float ydpi;
         nsecs_t refresh;
+        int colorTransform;
     };
 
     // Query display parameters.  Pass in a display index (e.g.
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 470f153..b2ff8b4 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -282,8 +282,13 @@
     return NO_ERROR;
 }
 
-status_t VirtualDisplaySurface::setBufferCount(int bufferCount) {
-    return mSource[SOURCE_SINK]->setBufferCount(bufferCount);
+status_t VirtualDisplaySurface::setMaxDequeuedBufferCount(
+        int maxDequeuedBuffers) {
+    return mSource[SOURCE_SINK]->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
+status_t VirtualDisplaySurface::setAsyncMode(bool async) {
+    return mSource[SOURCE_SINK]->setAsyncMode(async);
 }
 
 status_t VirtualDisplaySurface::dequeueBuffer(Source source,
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
index 6298751..5807eb1 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.h
@@ -98,7 +98,8 @@
     // IGraphicBufferProducer interface, used by the GLES driver.
     //
     virtual status_t requestBuffer(int pslot, sp<GraphicBuffer>* outBuf);
-    virtual status_t setBufferCount(int bufferCount);
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+    virtual status_t setAsyncMode(bool async);
     virtual status_t dequeueBuffer(int* pslot, sp<Fence>* fence, bool async,
             uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
     virtual status_t detachBuffer(int slot);
diff --git a/services/surfaceflinger/MonitoredProducer.cpp b/services/surfaceflinger/MonitoredProducer.cpp
index fb7af97..85182d9 100644
--- a/services/surfaceflinger/MonitoredProducer.cpp
+++ b/services/surfaceflinger/MonitoredProducer.cpp
@@ -56,8 +56,13 @@
     return mProducer->requestBuffer(slot, buf);
 }
 
-status_t MonitoredProducer::setBufferCount(int bufferCount) {
-    return mProducer->setBufferCount(bufferCount);
+status_t MonitoredProducer::setMaxDequeuedBufferCount(
+        int maxDequeuedBuffers) {
+    return mProducer->setMaxDequeuedBufferCount(maxDequeuedBuffers);
+}
+
+status_t MonitoredProducer::setAsyncMode(bool async) {
+    return mProducer->setAsyncMode(async);
 }
 
 status_t MonitoredProducer::dequeueBuffer(int* slot, sp<Fence>* fence,
diff --git a/services/surfaceflinger/MonitoredProducer.h b/services/surfaceflinger/MonitoredProducer.h
index da95766..f5575ff 100644
--- a/services/surfaceflinger/MonitoredProducer.h
+++ b/services/surfaceflinger/MonitoredProducer.h
@@ -35,7 +35,8 @@
 
     // From IGraphicBufferProducer
     virtual status_t requestBuffer(int slot, sp<GraphicBuffer>* buf);
-    virtual status_t setBufferCount(int bufferCount);
+    virtual status_t setMaxDequeuedBufferCount(int maxDequeuedBuffers);
+    virtual status_t setAsyncMode(bool async);
     virtual status_t dequeueBuffer(int* slot, sp<Fence>* fence, bool async,
             uint32_t w, uint32_t h, PixelFormat format, uint32_t usage);
     virtual status_t detachBuffer(int slot);
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 063d735..285b829 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -635,6 +635,7 @@
         info.ydpi = ydpi;
         info.fps = float(1e9 / hwConfig.refresh);
         info.appVsyncOffset = VSYNC_EVENT_PHASE_OFFSET_NS;
+        info.colorTransform = hwConfig.colorTransform;
 
         // This is how far in advance a buffer must be queued for
         // presentation at a given time.  If you want a buffer to appear
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index a74bc4c..ca81aaa 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -26,6 +26,7 @@
 using namespace android;
 
 int main(int, char**) {
+    signal(SIGPIPE, SIG_IGN);
     // When SF is launched in its own process, limit the number of
     // binder threads to 4.
     ProcessState::self()->setThreadPoolMaxThreadCount(4);
diff --git a/services/surfaceflinger/surfaceflinger.rc b/services/surfaceflinger/surfaceflinger.rc
new file mode 100644
index 0000000..718b6b65
--- /dev/null
+++ b/services/surfaceflinger/surfaceflinger.rc
@@ -0,0 +1,5 @@
+service surfaceflinger /system/bin/surfaceflinger
+    class core
+    user system
+    group graphics drmrpc
+    onrestart restart zygote