Merge "atrace: add database tag"
diff --git a/cmds/atrace/atrace.cpp b/cmds/atrace/atrace.cpp
index 698ffb1..81c8967 100644
--- a/cmds/atrace/atrace.cpp
+++ b/cmds/atrace/atrace.cpp
@@ -26,6 +26,7 @@
 #include <string.h>
 #include <sys/sendfile.h>
 #include <time.h>
+#include <unistd.h>
 #include <zlib.h>
 
 #include <binder/IBinder.h>
@@ -212,6 +213,9 @@
 static const char* k_tracePath =
     "/sys/kernel/debug/tracing/trace";
 
+static const char* k_traceStreamPath =
+    "/sys/kernel/debug/tracing/trace_pipe";
+
 static const char* k_traceMarkerPath =
     "/sys/kernel/debug/tracing/trace_marker";
 
@@ -730,6 +734,31 @@
     setTracingEnabled(false);
 }
 
+// Read data from the tracing pipe and forward to stdout
+static void streamTrace()
+{
+    char trace_data[4096];
+    int traceFD = open(k_traceStreamPath, O_RDWR);
+    if (traceFD == -1) {
+        fprintf(stderr, "error opening %s: %s (%d)\n", k_traceStreamPath,
+                strerror(errno), errno);
+        return;
+    }
+    while (!g_traceAborted) {
+        ssize_t bytes_read = read(traceFD, trace_data, 4096);
+        if (bytes_read > 0) {
+            write(STDOUT_FILENO, trace_data, bytes_read);
+            fflush(stdout);
+        } else {
+            if (!g_traceAborted) {
+                fprintf(stderr, "read returned %zd bytes err %d (%s)\n",
+                        bytes_read, errno, strerror(errno));
+            }
+            break;
+        }
+    }
+}
+
 // Read the current kernel trace and write it to stdout.
 static void dumpTrace()
 {
@@ -876,6 +905,10 @@
                     "  --async_dump    dump the current contents of circular trace buffer\n"
                     "  --async_stop    stop tracing and dump the current contents of circular\n"
                     "                    trace buffer\n"
+                    "  --stream        stream trace to stdout as it enters the trace buffer\n"
+                    "                    Note: this can take significant CPU time, and is best\n"
+                    "                    used for measuring things that are not affected by\n"
+                    "                    CPU performance, like pagecache usage.\n"
                     "  --list_categories\n"
                     "                  list the available tracing categories\n"
             );
@@ -887,6 +920,7 @@
     bool traceStart = true;
     bool traceStop = true;
     bool traceDump = true;
+    bool traceStream = false;
 
     if (argc == 2 && 0 == strcmp(argv[1], "--help")) {
         showHelp(argv[0]);
@@ -901,6 +935,7 @@
             {"async_stop",      no_argument, 0,  0 },
             {"async_dump",      no_argument, 0,  0 },
             {"list_categories", no_argument, 0,  0 },
+            {"stream",          no_argument, 0,  0 },
             {           0,                0, 0,  0 }
         };
 
@@ -967,6 +1002,9 @@
                     async = true;
                     traceStart = false;
                     traceStop = false;
+                } else if (!strcmp(long_options[option_index].name, "stream")) {
+                    traceStream = true;
+                    traceDump = false;
                 } else if (!strcmp(long_options[option_index].name, "list_categories")) {
                     listSupportedCategories();
                     exit(0);
@@ -992,8 +1030,10 @@
     ok &= startTrace();
 
     if (ok && traceStart) {
-        printf("capturing trace...");
-        fflush(stdout);
+        if (!traceStream) {
+            printf("capturing trace...");
+            fflush(stdout);
+        }
 
         // We clear the trace after starting it because tracing gets enabled for
         // each CPU individually in the kernel. Having the beginning of the trace
@@ -1003,7 +1043,7 @@
         ok = clearTrace();
 
         writeClockSyncMarker();
-        if (ok && !async) {
+        if (ok && !async && !traceStream) {
             // Sleep to allow the trace to be captured.
             struct timespec timeLeft;
             timeLeft.tv_sec = g_traceDurationSeconds;
@@ -1014,6 +1054,10 @@
                 }
             } while (nanosleep(&timeLeft, &timeLeft) == -1 && errno == EINTR);
         }
+
+        if (traceStream) {
+            streamTrace();
+        }
     }
 
     // Stop the trace and restore the default settings.
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 81df92f..9d07b09 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -298,6 +298,7 @@
     dump_dev_files("TRUSTY VERSION", "/sys/bus/platform/drivers/trusty", "trusty_version");
     run_command("UPTIME", 10, "uptime", NULL);
     dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
+    dump_emmc_ecsd("/d/mmc0/mmc0:0001/ext_csd");
     dump_file("MEMORY INFO", "/proc/meminfo");
     run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-H", NULL);
     run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
@@ -339,11 +340,12 @@
                                                         "-v", "printable",
                                                         "-d",
                                                         "*:v", NULL);
-    timeout = logcat_timeout("events");
+    timeout = logcat_timeout("events") + logcat_timeout("security");
     if (timeout < 20000) {
         timeout = 20000;
     }
     run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
+                                                       "-b", "security",
                                                        "-v", "threadtime",
                                                        "-v", "printable",
                                                        "-d",
@@ -360,8 +362,7 @@
 
     run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
 
-    // raft disabled as per http://b/24159112
-    // run_command("RAFT LOGS", 300, SU_PATH, "root", "logcompressor", "-r", RAFT_DIR, NULL);
+    run_command("RAFT LOGS", 300, SU_PATH, "root", "logcompressor", "-r", RAFT_DIR, NULL);
 
     /* show the traces we collected in main(), if that was done */
     if (dump_traces_path != NULL) {
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index c5d3044..228f09c 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -84,4 +84,7 @@
 /* Implemented by libdumpstate_board to dump board-specific info */
 void dumpstate_board();
 
+/* dump eMMC Extended CSD data */
+void dump_emmc_ecsd(const char *ext_csd_path);
+
 #endif /* _DUMPSTATE_H_ */
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index cd5d6c4..4cd1803 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -1,3 +1,8 @@
+on boot
+    # Allow bugreports access to eMMC 5.0 stats
+    chown root mount /sys/kernel/debug/mmc0/mmc0:0001/ext_csd
+    chmod 0440 /sys/kernel/debug/mmc0/mmc0:0001/ext_csd
+
 service dumpstate /system/bin/dumpstate -s
     class main
     socket dumpstate stream 0660 shell log
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 0dd0c21..47acb63 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -778,3 +778,120 @@
     }
     fclose(fp);
 }
+
+void dump_emmc_ecsd(const char *ext_csd_path) {
+    static const size_t EXT_CSD_REV = 192;
+    static const size_t EXT_PRE_EOL_INFO = 267;
+    static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_A = 268;
+    static const size_t EXT_DEVICE_LIFE_TIME_EST_TYP_B = 269;
+    struct hex {
+        char str[2];
+    } buffer[512];
+    int fd, ext_csd_rev, ext_pre_eol_info;
+    ssize_t bytes_read;
+    static const char *ver_str[] = {
+        "4.0", "4.1", "4.2", "4.3", "Obsolete", "4.41", "4.5", "5.0"
+    };
+    static const char *eol_str[] = {
+        "Undefined",
+        "Normal",
+        "Warning (consumed 80% of reserve)",
+        "Urgent (consumed 90% of reserve)"
+    };
+
+    printf("------ %s Extended CSD ------\n", ext_csd_path);
+
+    fd = TEMP_FAILURE_RETRY(open(ext_csd_path,
+                                 O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+    if (fd < 0) {
+        printf("*** %s: %s\n\n", ext_csd_path, strerror(errno));
+        return;
+    }
+
+    bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+    close(fd);
+    if (bytes_read < 0) {
+        printf("*** %s: %s\n\n", ext_csd_path, strerror(errno));
+        return;
+    }
+    if (bytes_read < (ssize_t)(EXT_CSD_REV * sizeof(struct hex))) {
+        printf("*** %s: truncated content %zd\n\n", ext_csd_path, bytes_read);
+        return;
+    }
+
+    ext_csd_rev = 0;
+    if (sscanf(buffer[EXT_CSD_REV].str, "%02x", &ext_csd_rev) != 1) {
+        printf("*** %s: EXT_CSD_REV parse error \"%.2s\"\n\n",
+               ext_csd_path, buffer[EXT_CSD_REV].str);
+        return;
+    }
+
+    printf("rev 1.%d (MMC %s)\n",
+           ext_csd_rev,
+           (ext_csd_rev < (int)(sizeof(ver_str) / sizeof(ver_str[0]))) ?
+               ver_str[ext_csd_rev] :
+               "Unknown");
+    if (ext_csd_rev < 7) {
+        printf("\n");
+        return;
+    }
+
+    if (bytes_read < (ssize_t)(EXT_PRE_EOL_INFO * sizeof(struct hex))) {
+        printf("*** %s: truncated content %zd\n\n", ext_csd_path, bytes_read);
+        return;
+    }
+
+    ext_pre_eol_info = 0;
+    if (sscanf(buffer[EXT_PRE_EOL_INFO].str, "%02x", &ext_pre_eol_info) != 1) {
+        printf("*** %s: PRE_EOL_INFO parse error \"%.2s\"\n\n",
+               ext_csd_path, buffer[EXT_PRE_EOL_INFO].str);
+        return;
+    }
+    printf("PRE_EOL_INFO %d (MMC %s)\n",
+           ext_pre_eol_info,
+           eol_str[(ext_pre_eol_info < (int)
+                       (sizeof(eol_str) / sizeof(eol_str[0]))) ?
+                           ext_pre_eol_info : 0]);
+
+    for (size_t lifetime = EXT_DEVICE_LIFE_TIME_EST_TYP_A;
+            lifetime <= EXT_DEVICE_LIFE_TIME_EST_TYP_B;
+            ++lifetime) {
+        int ext_device_life_time_est;
+        static const char *est_str[] = {
+            "Undefined",
+            "0-10% of device lifetime used",
+            "10-20% of device lifetime used",
+            "20-30% of device lifetime used",
+            "30-40% of device lifetime used",
+            "40-50% of device lifetime used",
+            "50-60% of device lifetime used",
+            "60-70% of device lifetime used",
+            "70-80% of device lifetime used",
+            "80-90% of device lifetime used",
+            "90-100% of device lifetime used",
+            "Exceeded the maximum estimated device lifetime",
+        };
+
+        if (bytes_read < (ssize_t)(lifetime * sizeof(struct hex))) {
+            printf("*** %s: truncated content %zd\n", ext_csd_path, bytes_read);
+            break;
+        }
+
+        ext_device_life_time_est = 0;
+        if (sscanf(buffer[lifetime].str, "%02x", &ext_device_life_time_est) != 1) {
+            printf("*** %s: DEVICE_LIFE_TIME_EST_TYP_%c parse error \"%.2s\"\n",
+                   ext_csd_path,
+                   (unsigned)(lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) + 'A',
+                   buffer[lifetime].str);
+            continue;
+        }
+        printf("DEVICE_LIFE_TIME_EST_TYP_%c %d (MMC %s)\n",
+               (unsigned)(lifetime - EXT_DEVICE_LIFE_TIME_EST_TYP_A) + 'A',
+               ext_device_life_time_est,
+               est_str[(ext_device_life_time_est < (int)
+                           (sizeof(est_str) / sizeof(est_str[0]))) ?
+                               ext_device_life_time_est : 0]);
+    }
+
+    printf("\n");
+}
diff --git a/cmds/installd/commands.cpp b/cmds/installd/commands.cpp
index 757290f..1b99582 100644
--- a/cmds/installd/commands.cpp
+++ b/cmds/installd/commands.cpp
@@ -16,8 +16,8 @@
 
 #include "installd.h"
 
-#include <base/stringprintf.h>
-#include <base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/logging.h>
 #include <cutils/sched_policy.h>
 #include <diskusage/dirsize.h>
 #include <logwrap/logwrap.h>
diff --git a/cmds/installd/installd.cpp b/cmds/installd/installd.cpp
index 7a16150..30e4f8b 100644
--- a/cmds/installd/installd.cpp
+++ b/cmds/installd/installd.cpp
@@ -16,7 +16,7 @@
 
 #include "installd.h"
 
-#include <base/logging.h>
+#include <android-base/logging.h>
 
 #include <sys/capability.h>
 #include <sys/prctl.h>
diff --git a/cmds/installd/utils.cpp b/cmds/installd/utils.cpp
index abbd021..a98fec5 100644
--- a/cmds/installd/utils.cpp
+++ b/cmds/installd/utils.cpp
@@ -16,8 +16,8 @@
 
 #include "installd.h"
 
-#include <base/stringprintf.h>
-#include <base/logging.h>
+#include <android-base/stringprintf.h>
+#include <android-base/logging.h>
 
 #define CACHE_NOISY(x) //x
 
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index a12d68d..16a4790 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include <cutils/native_handle.h>
+#include <nativehelper/ScopedFd.h>
 #include <utils/Errors.h>
 #include <utils/RefBase.h>
 #include <utils/String16.h>
@@ -154,6 +155,17 @@
     // will be closed once the parcel is destroyed.
     status_t            writeDupFileDescriptor(int fd);
 
+    // Place a file descriptor into the parcel.  This will not affect the
+    // semantics of the smart file descriptor. A new descriptor will be
+    // created, and will be closed when the parcel is destroyed.
+    status_t            writeUniqueFileDescriptor(
+                            const ScopedFd& fd);
+
+    // Place a vector of file desciptors into the parcel. Each descriptor is
+    // dup'd as in writeDupFileDescriptor
+    status_t            writeUniqueFileDescriptorVector(
+                            const std::vector<ScopedFd>& val);
+
     // Writes a blob to the parcel.
     // If the blob is small, then it is stored in-place, otherwise it is
     // transferred by way of an anonymous shared memory region.  Prefer sending
@@ -250,6 +262,15 @@
     // in the parcel, which you do not own -- use dup() to get your own copy.
     int                 readFileDescriptor() const;
 
+    // Retrieve a smart file descriptor from the parcel.
+    status_t            readUniqueFileDescriptor(
+                            ScopedFd* val) const;
+
+
+    // Retrieve a vector of smart file descriptors from the parcel.
+    status_t            readUniqueFileDescriptorVector(
+                            std::vector<ScopedFd>* val) const;
+
     // Reads a blob from the parcel.
     // The caller should call release() on the blob after reading its contents.
     status_t            readBlob(size_t len, ReadableBlob* outBlob) const;
@@ -406,10 +427,12 @@
     };
 
 private:
-    size_t mBlobAshmemSize;
+    size_t mOpenAshmemSize;
 
 public:
+    // TODO: Remove once ABI can be changed.
     size_t getBlobAshmemSize() const;
+    size_t getOpenAshmemSize() const;
 };
 
 // ---------------------------------------------------------------------------
diff --git a/include/binder/Status.h b/include/binder/Status.h
index 04738f8..203a01e 100644
--- a/include/binder/Status.h
+++ b/include/binder/Status.h
@@ -60,31 +60,42 @@
         EX_ILLEGAL_STATE = -5,
         EX_NETWORK_MAIN_THREAD = -6,
         EX_UNSUPPORTED_OPERATION = -7,
-        EX_TRANSACTION_FAILED = -8,
+        EX_SERVICE_SPECIFIC = -8,
 
         // This is special and Java specific; see Parcel.java.
         EX_HAS_REPLY_HEADER = -128,
+        // This is special, and indicates to C++ binder proxies that the
+        // transaction has failed at a low level.
+        EX_TRANSACTION_FAILED = -129,
     };
 
-    // Allow authors to explicitly pick whether their integer is a status_t or
-    // exception code.
-    static Status fromExceptionCode(int32_t exception_code);
-    static Status fromStatusT(status_t status);
     // A more readable alias for the default constructor.
     static Status ok();
+    // Authors should explicitly pick whether their integer is:
+    //  - an exception code (EX_* above)
+    //  - service specific error code
+    //  - status_t
+    //
+    //  Prefer a generic exception code when possible, then a service specific
+    //  code, and finally a status_t for low level failures or legacy support.
+    //  Exception codes and service specific errors map to nicer exceptions for
+    //  Java clients.
+    static Status fromExceptionCode(int32_t exceptionCode);
+    static Status fromExceptionCode(int32_t exceptionCode,
+                                    const String8& message);
+    static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode);
+    static Status fromServiceSpecificError(int32_t serviceSpecificErrorCode,
+                                           const String8& message);
+    static Status fromStatusT(status_t status);
 
     Status() = default;
-    Status(int32_t exception_code, const String8& message);
-    Status(int32_t exception_code, const char* message);
-
+    ~Status() = default;
 
     // Status objects are copyable and contain just simple data.
     Status(const Status& status) = default;
     Status(Status&& status) = default;
     Status& operator=(const Status& status) = default;
 
-    ~Status() = default;
-
     // Bear in mind that if the client or service is a Java endpoint, this
     // is not the logic which will provide/interpret the data here.
     status_t readFromParcel(const Parcel& parcel);
@@ -92,16 +103,22 @@
 
     // Set one of the pre-defined exception types defined above.
     void setException(int32_t ex, const String8& message);
-    // A few of the status_t values map to exception codes, but most of them
-    // simply map to "transaction failed."
+    // Set a service specific exception with error code.
+    void setServiceSpecificError(int32_t errorCode, const String8& message);
+    // Setting a |status| != OK causes generated code to return |status|
+    // from Binder transactions, rather than writing an exception into the
+    // reply Parcel.  This is the least preferable way of reporting errors.
     void setFromStatusT(status_t status);
 
     // Get information about an exception.
-    // Any argument may be given as nullptr.
-    void getException(int32_t* returned_exception,
-                      String8* returned_message) const;
     int32_t exceptionCode() const  { return mException; }
     const String8& exceptionMessage() const { return mMessage; }
+    status_t transactionError() const {
+        return mException == EX_TRANSACTION_FAILED ? mErrorCode : OK;
+    }
+    int32_t serviceSpecificErrorCode() const {
+        return mException == EX_SERVICE_SPECIFIC ? mErrorCode : 0;
+    }
 
     bool isOk() const { return mException == EX_NONE; }
 
@@ -109,9 +126,18 @@
     String8 toString8() const;
 
 private:
-    // We always write |mException| to the parcel.
-    // If |mException| !=  EX_NONE, we write message as well.
+    Status(int32_t exceptionCode, int32_t errorCode);
+    Status(int32_t exceptionCode, int32_t errorCode, const String8& message);
+
+    // If |mException| == EX_TRANSACTION_FAILED, generated code will return
+    // |mErrorCode| as the result of the transaction rather than write an
+    // exception to the reply parcel.
+    //
+    // Otherwise, we always write |mException| to the parcel.
+    // If |mException| !=  EX_NONE, we write |mMessage| as well.
+    // If |mException| == EX_SERVICE_SPECIFIC we write |mErrorCode| as well.
     int32_t mException = EX_NONE;
+    int32_t mErrorCode = 0;
     String8 mMessage;
 };  // class Status
 
diff --git a/include/input/Input.h b/include/input/Input.h
index 093219a..3b1c86b 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -28,6 +28,7 @@
 #include <utils/String8.h>
 #include <utils/Timers.h>
 #include <utils/Vector.h>
+#include <stdint.h>
 
 /*
  * Additional private constants not defined in ndk/ui/input.h.
@@ -111,6 +112,11 @@
 #define MAX_POINTERS 16
 
 /*
+ * Maximum number of samples supported per motion event.
+ */
+#define MAX_SAMPLES UINT16_MAX
+
+/*
  * Maximum pointer id value supported in a motion event.
  * Smallest pointer id is 0.
  * (This is limited by our use of BitSet32 to track pointer assignments.)
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 111139b..eb5840e 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -124,6 +124,11 @@
      * the mapping in some way. */
     status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
 
+    /* Tries to find a replacement key code for a given key code and meta state
+     * in character map. */
+    void tryRemapKey(int32_t scanCode, int32_t metaState,
+            int32_t* outKeyCode, int32_t* outMetaState) const;
+
 #ifdef __ANDROID__
     /* Reads a key map from a parcel. */
     static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
@@ -151,6 +156,9 @@
 
         /* The fallback keycode if the key is not handled. */
         int32_t fallbackKeyCode;
+
+        /* The replacement keycode if the key has to be replaced outright. */
+        int32_t replacementKeyCode;
     };
 
     struct Key {
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 519bb22..d4903e9 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -88,6 +88,13 @@
 extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
 
 /**
+ * Normalizes the meta state such that if either the left or right modifier
+ * meta state bits are set then the result will also include the universal
+ * bit for that modifier.
+ */
+extern int32_t normalizeMetaState(int32_t oldMetaState);
+
+/**
  * Returns true if a key is a meta key like ALT or CAPS_LOCK.
  */
 extern bool isMetaKey(int32_t keyCode);
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 03348da..3abb44f 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -94,7 +94,7 @@
 };
 
 void acquire_object(const sp<ProcessState>& proc,
-    const flat_binder_object& obj, const void* who)
+    const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
 {
     switch (obj.type) {
         case BINDER_TYPE_BINDER:
@@ -121,8 +121,15 @@
             return;
         }
         case BINDER_TYPE_FD: {
-            // intentionally blank -- nothing to do to acquire this, but we do
-            // recognize it as a legitimate object type.
+            if (obj.cookie != 0) {
+                if (outAshmemSize != NULL) {
+                    // If we own an ashmem fd, keep track of how much memory it refers to.
+                    int size = ashmem_get_size_region(obj.handle);
+                    if (size > 0) {
+                        *outAshmemSize += size;
+                    }
+                }
+            }
             return;
         }
     }
@@ -130,9 +137,15 @@
     ALOGD("Invalid object type 0x%08x", obj.type);
 }
 
-void release_object(const sp<ProcessState>& proc,
+void acquire_object(const sp<ProcessState>& proc,
     const flat_binder_object& obj, const void* who)
 {
+    acquire_object(proc, obj, who, NULL);
+}
+
+static void release_object(const sp<ProcessState>& proc,
+    const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
+{
     switch (obj.type) {
         case BINDER_TYPE_BINDER:
             if (obj.binder) {
@@ -158,7 +171,16 @@
             return;
         }
         case BINDER_TYPE_FD: {
-            if (obj.cookie != 0) close(obj.handle);
+            if (outAshmemSize != NULL) {
+                if (obj.cookie != 0) {
+                    int size = ashmem_get_size_region(obj.handle);
+                    if (size > 0) {
+                        *outAshmemSize -= size;
+                    }
+
+                    close(obj.handle);
+                }
+            }
             return;
         }
     }
@@ -166,6 +188,12 @@
     ALOGE("Invalid object type 0x%08x", obj.type);
 }
 
+void release_object(const sp<ProcessState>& proc,
+    const flat_binder_object& obj, const void* who)
+{
+    release_object(proc, obj, who, NULL);
+}
+
 inline static status_t finish_flatten_binder(
     const sp<IBinder>& /*binder*/, const flat_binder_object& flat, Parcel* out)
 {
@@ -502,7 +530,7 @@
 
             flat_binder_object* flat
                 = reinterpret_cast<flat_binder_object*>(mData + off);
-            acquire_object(proc, *flat, this);
+            acquire_object(proc, *flat, this, &mOpenAshmemSize);
 
             if (flat->type == BINDER_TYPE_FD) {
                 // If this is a file descriptor, we need to dup it so the
@@ -980,12 +1008,20 @@
         return -errno;
     }
     status_t err = writeFileDescriptor(dupFd, true /*takeOwnership*/);
-    if (err) {
+    if (err != OK) {
         close(dupFd);
     }
     return err;
 }
 
+status_t Parcel::writeUniqueFileDescriptor(const ScopedFd& fd) {
+    return writeDupFileDescriptor(fd.get());
+}
+
+status_t Parcel::writeUniqueFileDescriptorVector(const std::vector<ScopedFd>& val) {
+    return writeTypedVector(val, &Parcel::writeUniqueFileDescriptor);
+}
+
 status_t Parcel::writeBlob(size_t len, bool mutableCopy, WritableBlob* outBlob)
 {
     if (len > INT32_MAX) {
@@ -1011,8 +1047,6 @@
     int fd = ashmem_create_region("Parcel Blob", len);
     if (fd < 0) return NO_MEMORY;
 
-    mBlobAshmemSize += len;
-
     int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE);
     if (result < 0) {
         status = result;
@@ -1114,7 +1148,7 @@
         // Need to write meta-data?
         if (nullMetaData || val.binder != 0) {
             mObjects[mObjectsSize] = mDataPos;
-            acquire_object(ProcessState::self(), val, this);
+            acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
             mObjectsSize++;
         }
 
@@ -1601,16 +1635,36 @@
 int Parcel::readFileDescriptor() const
 {
     const flat_binder_object* flat = readObject(true);
-    if (flat) {
-        switch (flat->type) {
-            case BINDER_TYPE_FD:
-                //ALOGI("Returning file descriptor %ld from parcel %p", flat->handle, this);
-                return flat->handle;
-        }
+
+    if (flat && flat->type == BINDER_TYPE_FD) {
+        return flat->handle;
     }
+
     return BAD_TYPE;
 }
 
+status_t Parcel::readUniqueFileDescriptor(ScopedFd* val) const
+{
+    int got = readFileDescriptor();
+
+    if (got == BAD_TYPE) {
+        return BAD_TYPE;
+    }
+
+    val->reset(dup(got));
+
+    if (val->get() < 0) {
+        return BAD_VALUE;
+    }
+
+    return OK;
+}
+
+
+status_t Parcel::readUniqueFileDescriptorVector(std::vector<ScopedFd>* val) const {
+    return readTypedVector(val, &Parcel::readUniqueFileDescriptor);
+}
+
 status_t Parcel::readBlob(size_t len, ReadableBlob* outBlob) const
 {
     int32_t blobType;
@@ -1844,7 +1898,7 @@
         i--;
         const flat_binder_object* flat
             = reinterpret_cast<flat_binder_object*>(data+objects[i]);
-        release_object(proc, *flat, this);
+        release_object(proc, *flat, this, &mOpenAshmemSize);
     }
 }
 
@@ -1858,7 +1912,7 @@
         i--;
         const flat_binder_object* flat
             = reinterpret_cast<flat_binder_object*>(data+objects[i]);
-        acquire_object(proc, *flat, this);
+        acquire_object(proc, *flat, this, &mOpenAshmemSize);
     }
 }
 
@@ -1935,6 +1989,9 @@
         pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
         gParcelGlobalAllocSize += desired;
         gParcelGlobalAllocSize -= mDataCapacity;
+        if (!mData) {
+            gParcelGlobalAllocCount++;
+        }
         pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
         mData = data;
         mDataCapacity = desired;
@@ -2046,7 +2103,7 @@
                     // will need to rescan because we may have lopped off the only FDs
                     mFdsKnown = false;
                 }
-                release_object(proc, *flat, this);
+                release_object(proc, *flat, this, &mOpenAshmemSize);
             }
             binder_size_t* objects =
                 (binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
@@ -2066,7 +2123,6 @@
                 pthread_mutex_lock(&gParcelGlobalAllocSizeLock);
                 gParcelGlobalAllocSize += desired;
                 gParcelGlobalAllocSize -= mDataCapacity;
-                gParcelGlobalAllocCount++;
                 pthread_mutex_unlock(&gParcelGlobalAllocSizeLock);
                 mData = data;
                 mDataCapacity = desired;
@@ -2132,7 +2188,7 @@
     mFdsKnown = true;
     mAllowFds = true;
     mOwner = NULL;
-    mBlobAshmemSize = 0;
+    mOpenAshmemSize = 0;
 }
 
 void Parcel::scanForFds() const
@@ -2152,7 +2208,15 @@
 
 size_t Parcel::getBlobAshmemSize() const
 {
-    return mBlobAshmemSize;
+    // This used to return the size of all blobs that were written to ashmem, now we're returning
+    // the ashmem currently referenced by this Parcel, which should be equivalent.
+    // TODO: Remove method once ABI can be changed.
+    return mOpenAshmemSize;
+}
+
+size_t Parcel::getOpenAshmemSize() const
+{
+    return mOpenAshmemSize;
 }
 
 // --- Parcel::Blob ---
diff --git a/libs/binder/Status.cpp b/libs/binder/Status.cpp
index 41fff3d..d3520d6 100644
--- a/libs/binder/Status.cpp
+++ b/libs/binder/Status.cpp
@@ -19,8 +19,26 @@
 namespace android {
 namespace binder {
 
-Status Status::fromExceptionCode(int32_t exception_code) {
-    return Status(exception_code, "");
+Status Status::ok() {
+    return Status();
+}
+
+Status Status::fromExceptionCode(int32_t exceptionCode) {
+    return Status(exceptionCode, OK);
+}
+
+Status Status::fromExceptionCode(int32_t exceptionCode,
+                                 const String8& message) {
+    return Status(exceptionCode, OK, message);
+}
+
+Status Status::fromServiceSpecificError(int32_t serviceSpecificErrorCode) {
+    return Status(EX_SERVICE_SPECIFIC, serviceSpecificErrorCode);
+}
+
+Status Status::fromServiceSpecificError(int32_t serviceSpecificErrorCode,
+                                        const String8& message) {
+    return Status(EX_SERVICE_SPECIFIC, serviceSpecificErrorCode, message);
 }
 
 Status Status::fromStatusT(status_t status) {
@@ -29,16 +47,13 @@
     return ret;
 }
 
-Status Status::ok() {
-    return Status();
-}
+Status::Status(int32_t exceptionCode, int32_t errorCode)
+    : mException(exceptionCode),
+      mErrorCode(errorCode) {}
 
-Status::Status(int32_t exception_code, const String8& message)
-    : mException(exception_code),
-      mMessage(message) {}
-
-Status::Status(int32_t exception_code, const char* message)
-    : mException(exception_code),
+Status::Status(int32_t exceptionCode, int32_t errorCode, const String8& message)
+    : mException(exceptionCode),
+      mErrorCode(errorCode),
       mMessage(message) {}
 
 status_t Status::readFromParcel(const Parcel& parcel) {
@@ -69,12 +84,32 @@
     }
 
     // The remote threw an exception.  Get the message back.
-    mMessage = String8(parcel.readString16());
+    String16 message;
+    status = parcel.readString16(&message);
+    if (status != OK) {
+        setFromStatusT(status);
+        return status;
+    }
+    mMessage = String8(message);
+
+    if (mException == EX_SERVICE_SPECIFIC) {
+        status = parcel.readInt32(&mErrorCode);
+    }
+    if (status != OK) {
+        setFromStatusT(status);
+        return status;
+    }
 
     return status;
 }
 
 status_t Status::writeToParcel(Parcel* parcel) const {
+    // Something really bad has happened, and we're not going to even
+    // try returning rich error data.
+    if (mException == EX_TRANSACTION_FAILED) {
+        return mErrorCode;
+    }
+
     status_t status = parcel->writeInt32(mException);
     if (status != OK) { return status; }
     if (mException == EX_NONE) {
@@ -82,39 +117,29 @@
         return status;
     }
     status = parcel->writeString16(String16(mMessage));
-    return status;
-}
-
-void Status::setFromStatusT(status_t status) {
-    switch (status) {
-        case NO_ERROR:
-            mException = EX_NONE;
-            mMessage.clear();
-            break;
-        case UNEXPECTED_NULL:
-            mException = EX_NULL_POINTER;
-            mMessage.setTo("Unexpected null reference in Parcel");
-            break;
-        default:
-            mException = EX_TRANSACTION_FAILED;
-            mMessage.setTo("Transaction failed");
-            break;
+    if (mException != EX_SERVICE_SPECIFIC) {
+        // We have no more information to write.
+        return status;
     }
+    status = parcel->writeInt32(mErrorCode);
+    return status;
 }
 
 void Status::setException(int32_t ex, const String8& message) {
     mException = ex;
+    mErrorCode = NO_ERROR;  // an exception, not a transaction failure.
     mMessage.setTo(message);
 }
 
-void Status::getException(int32_t* returned_exception,
-                          String8* returned_message) const {
-    if (returned_exception) {
-        *returned_exception = mException;
-    }
-    if (returned_message) {
-        returned_message->setTo(mMessage);
-    }
+void Status::setServiceSpecificError(int32_t errorCode, const String8& message) {
+    setException(EX_SERVICE_SPECIFIC, message);
+    mErrorCode = errorCode;
+}
+
+void Status::setFromStatusT(status_t status) {
+    mException = (status == NO_ERROR) ? EX_NONE : EX_TRANSACTION_FAILED;
+    mErrorCode = status;
+    mMessage.clear();
 }
 
 String8 Status::toString8() const {
@@ -123,6 +148,10 @@
         ret.append("No error");
     } else {
         ret.appendFormat("Status(%d): '", mException);
+        if (mException == EX_SERVICE_SPECIFIC ||
+            mException == EX_TRANSACTION_FAILED) {
+            ret.appendFormat("%d: ", mErrorCode);
+        }
         ret.append(String8(mMessage));
         ret.append("'");
     }
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index 87e5b4d..a941e2d 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -696,15 +696,6 @@
         mCore->validateConsistencyLocked();
     } // Autolock scope
 
-    // Wait without lock held
-    if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) {
-        // Waiting here allows for two full buffers to be queued but not a
-        // third. In the event that frames take varying time, this makes a
-        // small trade-off in favor of latency rather than throughput.
-        mLastQueueBufferFence->waitForever("Throttling EGL Production");
-        mLastQueueBufferFence = fence;
-    }
-
     // Don't send the GraphicBuffer through the callback, and don't send
     // the slot number, since the consumer shouldn't need it
     item.mGraphicBuffer.clear();
@@ -728,6 +719,15 @@
         mCallbackCondition.broadcast();
     }
 
+    // Wait without lock held
+    if (mCore->mConnectedApi == NATIVE_WINDOW_API_EGL) {
+        // Waiting here allows for two full buffers to be queued but not a
+        // third. In the event that frames take varying time, this makes a
+        // small trade-off in favor of latency rather than throughput.
+        mLastQueueBufferFence->waitForever("Throttling EGL Production");
+        mLastQueueBufferFence = fence;
+    }
+
     return NO_ERROR;
 }
 
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 4b3603e..235cbbd 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -245,6 +245,11 @@
         break;
     }
 
+    // Set DATA_INJECTION flag here. Defined in HAL 1_4.
+    if (halVersion >= SENSORS_DEVICE_API_VERSION_1_4) {
+        mFlags |= (hwSensor->flags & DATA_INJECTION_MASK);
+    }
+
     // For the newer HALs log errors if reporting mask flags are set incorrectly.
     if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
         // Wake-up flag is set here.
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 0155007..a624663 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -424,7 +424,8 @@
 status_t MotionEvent::readFromParcel(Parcel* parcel) {
     size_t pointerCount = parcel->readInt32();
     size_t sampleCount = parcel->readInt32();
-    if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
+    if (pointerCount == 0 || pointerCount > MAX_POINTERS ||
+            sampleCount == 0 || sampleCount > MAX_SAMPLES) {
         return BAD_VALUE;
     }
 
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 732ebd0..dd01a93 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -332,33 +332,75 @@
     if (usageCode) {
         ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
         if (index >= 0) {
-#if DEBUG_MAPPING
-    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
-            scanCode, usageCode, *outKeyCode);
-#endif
             *outKeyCode = mKeysByUsageCode.valueAt(index);
+#if DEBUG_MAPPING
+            ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+                    scanCode, usageCode, *outKeyCode);
+#endif
             return OK;
         }
     }
     if (scanCode) {
         ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
         if (index >= 0) {
-#if DEBUG_MAPPING
-    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
-            scanCode, usageCode, *outKeyCode);
-#endif
             *outKeyCode = mKeysByScanCode.valueAt(index);
+#if DEBUG_MAPPING
+            ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+                    scanCode, usageCode, *outKeyCode);
+#endif
             return OK;
         }
     }
 
 #if DEBUG_MAPPING
-        ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
+    ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
 #endif
     *outKeyCode = AKEYCODE_UNKNOWN;
     return NAME_NOT_FOUND;
 }
 
+void KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState,
+                                  int32_t *outKeyCode, int32_t *outMetaState) const {
+    *outKeyCode = keyCode;
+    *outMetaState = metaState;
+
+    const Key* key;
+    const Behavior* behavior;
+    if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+        if (behavior->replacementKeyCode) {
+            *outKeyCode = behavior->replacementKeyCode;
+            int32_t newMetaState = metaState & ~behavior->metaState;
+            // Reset dependent meta states.
+            if (behavior->metaState & AMETA_ALT_ON) {
+                newMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
+            }
+            if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
+                newMetaState &= ~AMETA_ALT_ON;
+            }
+            if (behavior->metaState & AMETA_CTRL_ON) {
+                newMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
+            }
+            if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
+                newMetaState &= ~AMETA_CTRL_ON;
+            }
+            if (behavior->metaState & AMETA_SHIFT_ON) {
+                newMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
+            }
+            if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
+                newMetaState &= ~AMETA_SHIFT_ON;
+            }
+            // ... and put universal bits back if needed
+            *outMetaState = normalizeMetaState(newMetaState);
+        }
+    }
+
+#if DEBUG_MAPPING
+    ALOGD("tryRemapKey: keyCode=%d, metaState=0x%08x ~ "
+            "replacement keyCode=%d, replacement metaState=0x%08x.",
+            keyCode, metaState, *outKeyCode, *outMetaState);
+#endif
+}
+
 bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
     ssize_t index = mKeys.indexOfKey(keyCode);
     if (index >= 0) {
@@ -584,6 +626,7 @@
             int32_t metaState = parcel->readInt32();
             char16_t character = parcel->readInt32();
             int32_t fallbackKeyCode = parcel->readInt32();
+            int32_t replacementKeyCode = parcel->readInt32();
             if (parcel->errorCheck()) {
                 return NULL;
             }
@@ -592,6 +635,7 @@
             behavior->metaState = metaState;
             behavior->character = character;
             behavior->fallbackKeyCode = fallbackKeyCode;
+            behavior->replacementKeyCode = replacementKeyCode;
             if (lastBehavior) {
                 lastBehavior->next = behavior;
             } else {
@@ -624,6 +668,7 @@
             parcel->writeInt32(behavior->metaState);
             parcel->writeInt32(behavior->character);
             parcel->writeInt32(behavior->fallbackKeyCode);
+            parcel->writeInt32(behavior->replacementKeyCode);
         }
         parcel->writeInt32(0);
     }
@@ -655,13 +700,14 @@
 // --- KeyCharacterMap::Behavior ---
 
 KeyCharacterMap::Behavior::Behavior() :
-        next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
+        next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
 }
 
 KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
         next(other.next ? new Behavior(*other.next) : NULL),
         metaState(other.metaState), character(other.character),
-        fallbackKeyCode(other.fallbackKeyCode) {
+        fallbackKeyCode(other.fallbackKeyCode),
+        replacementKeyCode(other.replacementKeyCode) {
 }
 
 
@@ -923,6 +969,7 @@
     Behavior behavior;
     bool haveCharacter = false;
     bool haveFallback = false;
+    bool haveReplacement = false;
 
     do {
         char ch = mTokenizer->peekChar();
@@ -939,6 +986,11 @@
                         mTokenizer->getLocation().string());
                 return BAD_VALUE;
             }
+            if (haveReplacement) {
+                ALOGE("%s: Cannot combine character literal with replace action.",
+                        mTokenizer->getLocation().string());
+                return BAD_VALUE;
+            }
             behavior.character = character;
             haveCharacter = true;
         } else {
@@ -949,6 +1001,11 @@
                             mTokenizer->getLocation().string());
                     return BAD_VALUE;
                 }
+                if (haveReplacement) {
+                    ALOGE("%s: Cannot combine 'none' with replace action.",
+                            mTokenizer->getLocation().string());
+                    return BAD_VALUE;
+                }
                 haveCharacter = true;
             } else if (token == "fallback") {
                 mTokenizer->skipDelimiters(WHITESPACE);
@@ -960,13 +1017,36 @@
                             token.string());
                     return BAD_VALUE;
                 }
-                if (haveFallback) {
-                    ALOGE("%s: Cannot combine multiple fallback key codes.",
+                if (haveFallback || haveReplacement) {
+                    ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
                             mTokenizer->getLocation().string());
                     return BAD_VALUE;
                 }
                 behavior.fallbackKeyCode = keyCode;
                 haveFallback = true;
+            } else if (token == "replace") {
+                mTokenizer->skipDelimiters(WHITESPACE);
+                token = mTokenizer->nextToken(WHITESPACE);
+                int32_t keyCode = getKeyCodeByLabel(token.string());
+                if (!keyCode) {
+                    ALOGE("%s: Invalid key code label for replace, got '%s'.",
+                            mTokenizer->getLocation().string(),
+                            token.string());
+                    return BAD_VALUE;
+                }
+                if (haveCharacter) {
+                    ALOGE("%s: Cannot combine character literal with replace action.",
+                            mTokenizer->getLocation().string());
+                    return BAD_VALUE;
+                }
+                if (haveFallback || haveReplacement) {
+                    ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
+                            mTokenizer->getLocation().string());
+                    return BAD_VALUE;
+                }
+                behavior.replacementKeyCode = keyCode;
+                haveReplacement = true;
+
             } else {
                 ALOGE("%s: Expected a key behavior after ':'.",
                         mTokenizer->getLocation().string());
@@ -1016,8 +1096,10 @@
             newBehavior->next = key->firstBehavior;
             key->firstBehavior = newBehavior;
 #if DEBUG_PARSER
-            ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
-                    newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
+            ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
+                    mKeyCode,
+                    newBehavior->metaState, newBehavior->character,
+                    newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode);
 #endif
             break;
         }
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index f4d9507..9a01395 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -176,6 +176,11 @@
                 ~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
     }
 
+    return normalizeMetaState(newMetaState);
+}
+
+int32_t normalizeMetaState(int32_t oldMetaState) {
+    int32_t newMetaState = oldMetaState;
     if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
         newMetaState |= AMETA_ALT_ON;
     }
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 7fb0f77..f389c94 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -103,11 +103,12 @@
 
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= 		\
-	GLES2/gl2.cpp.arm 	\
+LOCAL_SRC_FILES:= \
+	GLES2/gl2.cpp   \
 #
 
 LOCAL_CLANG := false
+LOCAL_ARM_MODE := arm
 LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
 LOCAL_MODULE:= libGLESv2
 
@@ -122,14 +123,32 @@
 # TODO: This is to work around b/20093774. Remove after root cause is fixed
 LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
 
-# Symlink libGLESv3.so -> libGLESv2.so
-# Platform modules should link against libGLESv2.so (-lGLESv2), but NDK apps
-# will be linked against libGLESv3.so.
-# Note we defer the evaluation of the LOCAL_POST_INSTALL_CMD,
-# so $(LOCAL_INSTALLED_MODULE) will be expanded to correct value,
-# even for both 32-bit and 64-bit installed files in multilib build.
-LOCAL_POST_INSTALL_CMD = \
-    $(hide) ln -sf $(notdir $(LOCAL_INSTALLED_MODULE)) $(dir $(LOCAL_INSTALLED_MODULE))libGLESv3.so
+include $(BUILD_SHARED_LIBRARY)
+
+###############################################################################
+# Build the wrapper OpenGL ES 3.x library (this is just different name for v2)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+	GLES2/gl2.cpp   \
+#
+
+LOCAL_CLANG := false
+LOCAL_ARM_MODE := arm
+LOCAL_SHARED_LIBRARIES += libcutils libutils liblog libEGL
+LOCAL_MODULE:= libGLESv3
+LOCAL_SHARED_LIBRARIES += libdl
+# we need to access the private Bionic header <bionic_tls.h>
+LOCAL_C_INCLUDES += bionic/libc/private
+
+LOCAL_CFLAGS += -DLOG_TAG=\"libGLESv3\"
+LOCAL_CFLAGS += -DGL_GLEXT_PROTOTYPES -DEGL_EGLEXT_PROTOTYPES
+LOCAL_CFLAGS += -fvisibility=hidden
+
+# TODO: This is to work around b/20093774. Remove after root cause is fixed
+LOCAL_LDFLAGS_arm += -Wl,--hash-style,both
 
 include $(BUILD_SHARED_LIBRARY)
 
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 8378907..cdec565 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -595,15 +595,6 @@
         return setError(EGL_BAD_SURFACE, EGL_FALSE);
 
     egl_surface_t * const s = get_surface(surface);
-    ANativeWindow* window = s->win.get();
-    if (window) {
-        int result = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
-        if (result != OK) {
-            ALOGE("eglDestroySurface: native_window_api_disconnect (win=%p) "
-                  "failed (%#x)",
-                  window, result);
-        }
-    }
     EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
     if (result == EGL_TRUE) {
         _s.terminate();
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 6b60c7c..5859606 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -438,10 +438,12 @@
     return false;
 }
 
-status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-        int32_t* outKeycode, uint32_t* outFlags) const {
+status_t EventHub::mapKey(int32_t deviceId,
+        int32_t scanCode, int32_t usageCode, int32_t metaState,
+        int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
     AutoMutex _l(mLock);
     Device* device = getDeviceLocked(deviceId);
+    status_t status = NAME_NOT_FOUND;
 
     if (device) {
         // Check the key character map first.
@@ -449,22 +451,34 @@
         if (kcm != NULL) {
             if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
                 *outFlags = 0;
-                return NO_ERROR;
+                status = NO_ERROR;
             }
         }
 
         // Check the key layout next.
-        if (device->keyMap.haveKeyLayout()) {
+        if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
             if (!device->keyMap.keyLayoutMap->mapKey(
                     scanCode, usageCode, outKeycode, outFlags)) {
-                return NO_ERROR;
+                status = NO_ERROR;
+            }
+        }
+
+        if (status == NO_ERROR) {
+            if (kcm != NULL) {
+                kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
+            } else {
+                *outMetaState = metaState;
             }
         }
     }
 
-    *outKeycode = 0;
-    *outFlags = 0;
-    return NAME_NOT_FOUND;
+    if (status != NO_ERROR) {
+        *outKeycode = 0;
+        *outFlags = 0;
+        *outMetaState = metaState;
+    }
+
+    return status;
 }
 
 status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 3ec4910..0f94c77 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -197,8 +197,9 @@
 
     virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
 
-    virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-            int32_t* outKeycode, uint32_t* outFlags) const = 0;
+    virtual status_t mapKey(int32_t deviceId,
+            int32_t scanCode, int32_t usageCode, int32_t metaState,
+            int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const = 0;
 
     virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
             AxisInfo* outAxisInfo) const = 0;
@@ -285,8 +286,9 @@
 
     virtual bool hasInputProperty(int32_t deviceId, int property) const;
 
-    virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-            int32_t* outKeycode, uint32_t* outFlags) const;
+    virtual status_t mapKey(int32_t deviceId,
+            int32_t scanCode, int32_t usageCode, int32_t metaState,
+            int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const;
 
     virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
             AxisInfo* outAxisInfo) const;
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 36095bf..b2cbfe8 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2177,13 +2177,7 @@
         mCurrentHidUsage = 0;
 
         if (isKeyboardOrGamepadKey(scanCode)) {
-            int32_t keyCode;
-            uint32_t flags;
-            if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {
-                keyCode = AKEYCODE_UNKNOWN;
-                flags = 0;
-            }
-            processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
+            processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
         }
         break;
     }
@@ -2208,8 +2202,18 @@
         || (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
 }
 
-void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
-        int32_t scanCode, uint32_t policyFlags) {
+void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
+        int32_t usageCode) {
+    int32_t keyCode;
+    int32_t keyMetaState;
+    uint32_t policyFlags;
+
+    if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
+                              &keyCode, &keyMetaState, &policyFlags)) {
+        keyCode = AKEYCODE_UNKNOWN;
+        keyMetaState = mMetaState;
+        policyFlags = 0;
+    }
 
     if (down) {
         // Rotate key codes according to orientation if needed.
@@ -2262,6 +2266,12 @@
     if (metaStateChanged) {
         mMetaState = newMetaState;
         updateLedState(false);
+
+        // If global meta state changed send it along with the key.
+        // If it has not changed then we'll use what keymap gave us,
+        // since key replacement logic might temporarily reset a few
+        // meta bits for given key.
+        keyMetaState = newMetaState;
     }
 
     nsecs_t downTime = mDownTime;
@@ -2289,7 +2299,7 @@
 
     NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
             down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
-            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
+            AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
     getListener()->notifyKey(&args);
 }
 
@@ -3543,8 +3553,10 @@
 
         virtualKey.scanCode = virtualKeyDefinition.scanCode;
         int32_t keyCode;
+        int32_t dummyKeyMetaState;
         uint32_t flags;
-        if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) {
+        if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0,
+                                  &keyCode, &dummyKeyMetaState, &flags)) {
             ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
                     virtualKey.scanCode);
             mVirtualKeys.pop(); // drop the key
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 7cb4680..30c84b1 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1154,8 +1154,7 @@
 
     bool isKeyboardOrGamepadKey(int32_t scanCode);
 
-    void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
-            uint32_t policyFlags);
+    void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
 
     ssize_t findKeyDown(int32_t scanCode);
 
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index f34b810..42bc865 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -518,8 +518,9 @@
         return false;
     }
 
-    virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
-            int32_t* outKeycode, uint32_t* outFlags) const {
+    virtual status_t mapKey(int32_t deviceId,
+            int32_t scanCode, int32_t usageCode, int32_t metaState,
+            int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const {
         Device* device = getDevice(deviceId);
         if (device) {
             const KeyInfo* key = getKey(device, scanCode, usageCode);
@@ -530,6 +531,9 @@
                 if (outFlags) {
                     *outFlags = key->flags;
                 }
+                if (outMetaState) {
+                    *outMetaState = metaState;
+                }
                 return OK;
             }
         }
diff --git a/services/surfaceflinger/DisplayDevice.cpp b/services/surfaceflinger/DisplayDevice.cpp
index 13d44f3..bdf8f74 100644
--- a/services/surfaceflinger/DisplayDevice.cpp
+++ b/services/surfaceflinger/DisplayDevice.cpp
@@ -88,21 +88,22 @@
       mPowerMode(HWC_POWER_MODE_OFF),
       mActiveConfig(0)
 {
-    mNativeWindow = new Surface(producer, false);
+    Surface* surface;
+    mNativeWindow = surface = new Surface(producer, false);
     ANativeWindow* const window = mNativeWindow.get();
 
     /*
      * Create our display's surface
      */
 
-    EGLSurface surface;
+    EGLSurface eglSurface;
     EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
     if (config == EGL_NO_CONFIG) {
         config = RenderEngine::chooseEglConfig(display, format);
     }
-    surface = eglCreateWindowSurface(display, config, window, NULL);
-    eglQuerySurface(display, surface, EGL_WIDTH,  &mDisplayWidth);
-    eglQuerySurface(display, surface, EGL_HEIGHT, &mDisplayHeight);
+    eglSurface = eglCreateWindowSurface(display, config, window, NULL);
+    eglQuerySurface(display, eglSurface, EGL_WIDTH,  &mDisplayWidth);
+    eglQuerySurface(display, eglSurface, EGL_HEIGHT, &mDisplayHeight);
 
     // Make sure that composition can never be stalled by a virtual display
     // consumer that isn't processing buffers fast enough. We have to do this
@@ -116,7 +117,7 @@
 
     mConfig = config;
     mDisplay = display;
-    mSurface = surface;
+    mSurface = eglSurface;
     mFormat  = format;
     mPageFlipCount = 0;
     mViewport.makeInvalid();
@@ -142,6 +143,10 @@
 
     // initialize the display orientation transform.
     setProjection(DisplayState::eOrientationDefault, mViewport, mFrame);
+
+#ifdef NUM_FRAMEBUFFER_SURFACE_BUFFERS
+    surface->allocateBuffers();
+#endif
 }
 
 DisplayDevice::~DisplayDevice() {