Merge "Add RGBA8888 to OMX_COLOR_FORMATTYPE"
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 342dc89..ffc8714 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -378,8 +378,8 @@
 }
 
 static void sigpipe_handler(int n) {
-    (void)n;
-    exit(EXIT_FAILURE);
+    // don't complain to stderr or stdout
+    _exit(EXIT_FAILURE);
 }
 
 int main(int argc, char *argv[]) {
@@ -404,10 +404,12 @@
     }
     ALOGI("begin\n");
 
+
     memset(&sigact, 0, sizeof(sigact));
     sigact.sa_handler = sigpipe_handler;
     sigaction(SIGPIPE, &sigact, NULL);
 
+
     /* set as high priority, and protect from OOM killer */
     setpriority(PRIO_PROCESS, 0, -20);
     FILE *oom_adj = fopen("/proc/self/oom_adj", "w");
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index a6d9ef6..85c353e 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -313,6 +313,12 @@
         /* make sure the child dies when dumpstate dies */
         prctl(PR_SET_PDEATHSIG, SIGKILL);
 
+        /* just ignore SIGPIPE, will go down with parent's */
+        struct sigaction sigact;
+        memset(&sigact, 0, sizeof(sigact));
+        sigact.sa_handler = SIG_IGN;
+        sigaction(SIGPIPE, &sigact, NULL);
+
         va_list ap;
         va_start(ap, command);
         if (title) printf("------ %s (%s", title, command);
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 23cb816..e06cddd 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -177,10 +177,6 @@
     return 0;
 }
 
-static int lib_dir_matcher(const char* file_name, const int is_dir) {
-  return is_dir && !strcmp(file_name, "lib");
-}
-
 int delete_user_data(const char *pkgname, userid_t userid)
 {
     char pkgdir[PKG_PATH_MAX];
@@ -188,8 +184,7 @@
     if (create_pkg_path(pkgdir, pkgname, PKG_DIR_POSTFIX, userid))
         return -1;
 
-    /* delete contents, excluding "lib", but not the directory itself */
-    return delete_dir_contents(pkgdir, 0, &lib_dir_matcher);
+    return delete_dir_contents(pkgdir, 0, NULL);
 }
 
 int make_user_data(const char *pkgname, uid_t uid, userid_t userid, const char* seinfo)
@@ -637,7 +632,7 @@
     const char* output_file_name, const char *pkgname, const char *instruction_set)
 {
     static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 32;
+    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
 
     static const char* PATCHOAT_BIN = "/system/bin/patchoat";
     if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
@@ -674,8 +669,17 @@
 }
 
 static void run_dex2oat(int zip_fd, int oat_fd, const char* input_file_name,
-    const char* output_file_name, const char *pkgname, const char *instruction_set)
+    const char* output_file_name, const char *pkgname, const char *instruction_set,
+    bool vm_safe_mode)
 {
+    static const unsigned int MAX_INSTRUCTION_SET_LEN = 7;
+
+    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
+        ALOGE("Instruction set %s longer than max length of %d",
+              instruction_set, MAX_INSTRUCTION_SET_LEN);
+        return;
+    }
+
     char prop_buf[PROPERTY_VALUE_MAX];
     bool profiler = (property_get("dalvik.vm.profiler", prop_buf, "0") > 0) && (prop_buf[0] == '1');
 
@@ -689,6 +693,12 @@
     bool have_dex2oat_compiler_filter_flag = property_get("dalvik.vm.dex2oat-filter",
                                                           dex2oat_compiler_filter_flag, NULL) > 0;
 
+    char dex2oat_isa_features_key[PROPERTY_KEY_MAX];
+    sprintf(dex2oat_isa_features_key, "dalvik.vm.isa.%s.features", instruction_set);
+    char dex2oat_isa_features[PROPERTY_VALUE_MAX];
+    bool have_dex2oat_isa_features = property_get(dex2oat_isa_features_key,
+                                                  dex2oat_isa_features, NULL) > 0;
+
     char dex2oat_flags[PROPERTY_VALUE_MAX];
     bool have_dex2oat_flags = property_get("dalvik.vm.dex2oat-flags", dex2oat_flags, NULL) > 0;
     ALOGV("dalvik.vm.dex2oat-flags=%s\n", dex2oat_flags);
@@ -705,19 +715,13 @@
     static const char* RUNTIME_ARG = "--runtime-arg";
 
     static const int MAX_INT_LEN = 12;      // '-'+10dig+'\0' -OR- 0x+8dig
-    static const unsigned int MAX_INSTRUCTION_SET_LEN = 32;
-
-    if (strlen(instruction_set) >= MAX_INSTRUCTION_SET_LEN) {
-        ALOGE("Instruction set %s longer than max length of %d",
-              instruction_set, MAX_INSTRUCTION_SET_LEN);
-        return;
-    }
 
     char zip_fd_arg[strlen("--zip-fd=") + MAX_INT_LEN];
     char zip_location_arg[strlen("--zip-location=") + PKG_PATH_MAX];
     char oat_fd_arg[strlen("--oat-fd=") + MAX_INT_LEN];
     char oat_location_arg[strlen("--oat-location=") + PKG_PATH_MAX];
     char instruction_set_arg[strlen("--instruction-set=") + MAX_INSTRUCTION_SET_LEN];
+    char instruction_set_features_arg[strlen("--instruction-set-features=") + PROPERTY_VALUE_MAX];
     char profile_file_arg[strlen("--profile-file=") + PKG_PATH_MAX];
     char top_k_profile_threshold_arg[strlen("--top-k-profile-threshold=") + PROPERTY_VALUE_MAX];
     char dex2oat_Xms_arg[strlen("-Xms") + PROPERTY_VALUE_MAX];
@@ -729,6 +733,7 @@
     sprintf(oat_fd_arg, "--oat-fd=%d", oat_fd);
     sprintf(oat_location_arg, "--oat-location=%s", output_file_name);
     sprintf(instruction_set_arg, "--instruction-set=%s", instruction_set);
+    sprintf(instruction_set_features_arg, "--instruction-set-features=%s", dex2oat_isa_features);
 
     bool have_profile_file = false;
     bool have_top_k_profile_threshold = false;
@@ -757,6 +762,9 @@
     if (skip_compilation) {
         strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=verify-none");
         have_dex2oat_compiler_filter_flag = true;
+    } else if (vm_safe_mode) {
+        strcpy(dex2oat_compiler_filter_arg, "--compiler-filter=interpret-only");
+        have_dex2oat_compiler_filter_flag = true;
     } else if (have_dex2oat_compiler_filter_flag) {
         sprintf(dex2oat_compiler_filter_arg, "--compiler-filter=%s", dex2oat_compiler_filter_flag);
     }
@@ -764,6 +772,7 @@
     ALOGV("Running %s in=%s out=%s\n", DEX2OAT_BIN, input_file_name, output_file_name);
 
     char* argv[7  // program name, mandatory arguments and the final NULL
+               + (have_dex2oat_isa_features ? 1 : 0)
                + (have_profile_file ? 1 : 0)
                + (have_top_k_profile_threshold ? 1 : 0)
                + (have_dex2oat_Xms_flag ? 2 : 0)
@@ -777,6 +786,9 @@
     argv[i++] = oat_fd_arg;
     argv[i++] = oat_location_arg;
     argv[i++] = instruction_set_arg;
+    if (have_dex2oat_isa_features) {
+        argv[i++] = instruction_set_features_arg;
+    }
     if (have_profile_file) {
         argv[i++] = profile_file_arg;
     }
@@ -830,9 +842,9 @@
     }
 }
 
-int dexopt(const char *apk_path, uid_t uid, int is_public,
+int dexopt(const char *apk_path, uid_t uid, bool is_public,
            const char *pkgname, const char *instruction_set,
-           int is_patchoat)
+           bool vm_safe_mode, bool is_patchoat)
 {
     struct utimbuf ut;
     struct stat input_stat, dex_stat;
@@ -966,7 +978,8 @@
             if (is_patchoat) {
                 run_patchoat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
             } else {
-                run_dex2oat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set);
+                run_dex2oat(input_fd, out_fd, input_file, out_path, pkgname, instruction_set,
+                            vm_safe_mode);
             }
         } else {
             exit(69);   /* Unexpected persist.sys.dalvik.vm.lib value */
@@ -1524,50 +1537,3 @@
     return ret;
 }
 
-static int prune_dex_exclusion_predicate(const char *file_name, const int is_dir)
-{
-    // Exclude all directories. The top level command will be
-    // given a list of ISA specific directories that are assumed
-    // to be flat.
-    if (is_dir) {
-      return 1;
-    }
-
-
-    // Don't exclude regular files that start with the list
-    // of prefixes.
-    static const char data_app_prefix[] = "data@app@";
-    static const char data_priv_app_prefix[] = "data@priv-app@";
-    if (!strncmp(file_name, data_app_prefix, sizeof(data_app_prefix) - 1) ||
-        !strncmp(file_name, data_priv_app_prefix, sizeof(data_priv_app_prefix) - 1)) {
-      return 0;
-    }
-
-    // Exclude all regular files that don't start with the prefix "data@app@" or
-    // "data@priv-app@".
-    return 1;
-}
-
-int prune_dex_cache(const char* subdir) {
-    // "." is handled as a special case, and refers to
-    // DALVIK_CACHE_PREFIX (usually /data/dalvik-cache).
-    const bool is_dalvik_cache_root = !strcmp(subdir, ".");
-
-    // Don't allow the path to contain "." or ".." except for the
-    // special case above. This is much stricter than we need to be,
-    // but there's no good reason to support them.
-    if (strchr(subdir, '.' ) != NULL && !is_dalvik_cache_root) {
-        return -1;
-    }
-
-    if (!is_dalvik_cache_root) {
-        char full_path[PKG_PATH_MAX];
-        snprintf(full_path, sizeof(full_path), "%s%s", DALVIK_CACHE_PREFIX, subdir);
-        return delete_dir_contents(full_path, 0, &prune_dex_exclusion_predicate);
-    }
-
-
-    // When subdir == ".", clean the contents of the top level
-    // dalvik-cache directory.
-    return delete_dir_contents(DALVIK_CACHE_PREFIX, 0, &prune_dex_exclusion_predicate);
-}
diff --git a/cmds/installd/installd.c b/cmds/installd/installd.c
index 746ce57..c7fdf7a 100644
--- a/cmds/installd/installd.c
+++ b/cmds/installd/installd.c
@@ -38,8 +38,8 @@
 
 static int do_dexopt(char **arg, char reply[REPLY_MAX])
 {
-        /* apk_path, uid, is_public, pkgname, instruction_set */
-    return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], 0);
+    /* apk_path, uid, is_public, pkgname, instruction_set, vm_safe_mode, should_relocate */
+    return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], atoi(arg[5]), 0);
 }
 
 static int do_move_dex(char **arg, char reply[REPLY_MAX])
@@ -145,14 +145,9 @@
                              /* pkgName, seinfo, uid*/
 }
 
-static int do_prune_dex_cache(char **arg __attribute__((unused)),
-                              char reply[REPLY_MAX] __attribute__((unused)))
-{
-    return prune_dex_cache(arg[0] /* subdirectory name */);
-}
-
 static int do_patchoat(char **arg, char reply[REPLY_MAX]) {
-    return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], 1);
+    /* apk_path, uid, is_public, pkgname, instruction_set, vm_safe_mode, should_relocate */
+    return dexopt(arg[0], atoi(arg[1]), atoi(arg[2]), arg[3], arg[4], 0, 1);
 }
 
 struct cmdinfo {
@@ -164,7 +159,7 @@
 struct cmdinfo cmds[] = {
     { "ping",                 0, do_ping },
     { "install",              4, do_install },
-    { "dexopt",               5, do_dexopt },
+    { "dexopt",               6, do_dexopt },
     { "movedex",              3, do_move_dex },
     { "rmdex",                2, do_rm_dex },
     { "remove",               2, do_remove },
@@ -182,7 +177,6 @@
     { "rmuser",               1, do_rm_user },
     { "idmap",                3, do_idmap },
     { "restorecondata",       3, do_restorecon_data },
-    { "prunedexcache",        1, do_prune_dex_cache },
     { "patchoat",             5, do_patchoat },
 };
 
diff --git a/cmds/installd/installd.h b/cmds/installd/installd.h
index 9d420bd..99f037c 100644
--- a/cmds/installd/installd.h
+++ b/cmds/installd/installd.h
@@ -216,10 +216,9 @@
              const char *fwdlock_apkpath, const char *asecpath, const char *instruction_set,
              int64_t *codesize, int64_t *datasize, int64_t *cachesize, int64_t *asecsize);
 int free_cache(int64_t free_size);
-int dexopt(const char *apk_path, uid_t uid, int is_public, const char *pkgName,
-           const char *instruction_set, int should_relocate);
+int dexopt(const char *apk_path, uid_t uid, bool is_public, const char *pkgName,
+           const char *instruction_set, bool vm_safe_mode, bool should_relocate);
 int movefiles();
 int linklib(const char* target, const char* source, int userId);
 int idmap(const char *target_path, const char *overlay_path, uid_t uid);
 int restorecon_data();
-int prune_dex_cache(const char* subdir);
diff --git a/data/etc/android.software.live_tv.xml b/data/etc/android.software.live_tv.xml
new file mode 100644
index 0000000..431acb0
--- /dev/null
+++ b/data/etc/android.software.live_tv.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2014 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.
+-->
+
+<permissions>
+    <feature name="android.software.live_tv" />
+</permissions>
diff --git a/include/android/configuration.h b/include/android/configuration.h
index 97d4c42..be00066 100644
--- a/include/android/configuration.h
+++ b/include/android/configuration.h
@@ -45,6 +45,7 @@
     ACONFIGURATION_DENSITY_XHIGH = 320,
     ACONFIGURATION_DENSITY_XXHIGH = 480,
     ACONFIGURATION_DENSITY_XXXHIGH = 640,
+    ACONFIGURATION_DENSITY_ANY = 0xfffe,
     ACONFIGURATION_DENSITY_NONE = 0xffff,
 
     ACONFIGURATION_KEYBOARD_ANY  = 0x0000,
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index 813d411..75d0ab6 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -274,7 +274,35 @@
     AKEYCODE_12              = 228,
     AKEYCODE_LAST_CHANNEL    = 229,
     AKEYCODE_TV_DATA_SERVICE = 230,
-    AKEYCODE_VOICE_ASSIST    = 231
+    AKEYCODE_VOICE_ASSIST    = 231,
+    AKEYCODE_TV_RADIO_SERVICE = 232,
+    AKEYCODE_TV_TELETEXT     = 233,
+    AKEYCODE_TV_NUMBER_ENTRY = 234,
+    AKEYCODE_TV_TERRESTRIAL_ANALOG = 235,
+    AKEYCODE_TV_TERRESTRIAL_DIGITAL = 236,
+    AKEYCODE_TV_SATELLITE    = 237,
+    AKEYCODE_TV_SATELLITE_BS = 238,
+    AKEYCODE_TV_SATELLITE_CS = 239,
+    AKEYCODE_TV_SATELLITE_SERVICE = 240,
+    AKEYCODE_TV_NETWORK      = 241,
+    AKEYCODE_TV_ANTENNA_CABLE = 242,
+    AKEYCODE_TV_INPUT_HDMI_1 = 243,
+    AKEYCODE_TV_INPUT_HDMI_2 = 244,
+    AKEYCODE_TV_INPUT_HDMI_3 = 245,
+    AKEYCODE_TV_INPUT_HDMI_4 = 246,
+    AKEYCODE_TV_INPUT_COMPOSITE_1 = 247,
+    AKEYCODE_TV_INPUT_COMPOSITE_2 = 248,
+    AKEYCODE_TV_INPUT_COMPONENT_1 = 249,
+    AKEYCODE_TV_INPUT_COMPONENT_2 = 250,
+    AKEYCODE_TV_INPUT_VGA_1  = 251,
+    AKEYCODE_TV_AUDIO_DESCRIPTION = 252,
+    AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_UP = 253,
+    AKEYCODE_TV_AUDIO_DESCRIPTION_MIX_DOWN = 254,
+    AKEYCODE_TV_ZOOM_MODE    = 255,
+    AKEYCODE_TV_CONTENTS_MENU = 256,
+    AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257,
+    AKEYCODE_TV_TIMER_PROGRAMMING = 258,
+    AKEYCODE_HELP            = 259
 
     // 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/gui/GLConsumer.h b/include/gui/GLConsumer.h
index 37530db..f91fe46 100644
--- a/include/gui/GLConsumer.h
+++ b/include/gui/GLConsumer.h
@@ -287,7 +287,9 @@
 
         // createIfNeeded creates an EGLImage if required (we haven't created
         // one yet, or the EGLDisplay or crop-rect has changed).
-        status_t createIfNeeded(EGLDisplay display, const Rect& cropRect);
+        status_t createIfNeeded(EGLDisplay display,
+                                const Rect& cropRect,
+                                bool forceCreate = false);
 
         // This calls glEGLImageTargetTexture2DOES to bind the image to the
         // texture in the specified texture target.
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index 279ac40..df50237 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -271,6 +271,34 @@
     DEFINE_KEYCODE(LAST_CHANNEL),
     DEFINE_KEYCODE(TV_DATA_SERVICE),
     DEFINE_KEYCODE(VOICE_ASSIST),
+    DEFINE_KEYCODE(TV_RADIO_SERVICE),
+    DEFINE_KEYCODE(TV_TELETEXT),
+    DEFINE_KEYCODE(TV_NUMBER_ENTRY),
+    DEFINE_KEYCODE(TV_TERRESTRIAL_ANALOG),
+    DEFINE_KEYCODE(TV_TERRESTRIAL_DIGITAL),
+    DEFINE_KEYCODE(TV_SATELLITE),
+    DEFINE_KEYCODE(TV_SATELLITE_BS),
+    DEFINE_KEYCODE(TV_SATELLITE_CS),
+    DEFINE_KEYCODE(TV_SATELLITE_SERVICE),
+    DEFINE_KEYCODE(TV_NETWORK),
+    DEFINE_KEYCODE(TV_ANTENNA_CABLE),
+    DEFINE_KEYCODE(TV_INPUT_HDMI_1),
+    DEFINE_KEYCODE(TV_INPUT_HDMI_2),
+    DEFINE_KEYCODE(TV_INPUT_HDMI_3),
+    DEFINE_KEYCODE(TV_INPUT_HDMI_4),
+    DEFINE_KEYCODE(TV_INPUT_COMPOSITE_1),
+    DEFINE_KEYCODE(TV_INPUT_COMPOSITE_2),
+    DEFINE_KEYCODE(TV_INPUT_COMPONENT_1),
+    DEFINE_KEYCODE(TV_INPUT_COMPONENT_2),
+    DEFINE_KEYCODE(TV_INPUT_VGA_1),
+    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION),
+    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_UP),
+    DEFINE_KEYCODE(TV_AUDIO_DESCRIPTION_MIX_DOWN),
+    DEFINE_KEYCODE(TV_ZOOM_MODE),
+    DEFINE_KEYCODE(TV_CONTENTS_MENU),
+    DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU),
+    DEFINE_KEYCODE(TV_TIMER_PROGRAMMING),
+    DEFINE_KEYCODE(HELP),
 
     { NULL, 0 }
 };
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 939c4a9..ccafe81 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -462,24 +462,37 @@
     }
 
     status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
-                                                      mCurrentCrop);
-
+                                                        mCurrentCrop);
     if (err != NO_ERROR) {
         ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
                 mEglDisplay, mCurrentTexture);
         return UNKNOWN_ERROR;
     }
-
     mCurrentTextureImage->bindToTextureTarget(mTexTarget);
 
-    while ((error = glGetError()) != GL_NO_ERROR) {
-        ST_LOGE("bindTextureImage: error binding external image: %#04x", error);
-        return UNKNOWN_ERROR;
+    // In the rare case that the display is terminated and then initialized
+    // again, we can't detect that the display changed (it didn't), but the
+    // image is invalid. In this case, repeat the exact same steps while
+    // forcing the creation of a new image.
+    if ((error = glGetError()) != GL_NO_ERROR) {
+        glBindTexture(mTexTarget, mTexName);
+        status_t err = mCurrentTextureImage->createIfNeeded(mEglDisplay,
+                                                            mCurrentCrop,
+                                                            true);
+        if (err != NO_ERROR) {
+            ST_LOGW("bindTextureImage: can't create image on display=%p slot=%d",
+                    mEglDisplay, mCurrentTexture);
+            return UNKNOWN_ERROR;
+        }
+        mCurrentTextureImage->bindToTextureTarget(mTexTarget);
+        if ((error = glGetError()) != GL_NO_ERROR) {
+            ST_LOGE("bindTextureImage: error binding external image: %#04x", error);
+            return UNKNOWN_ERROR;
+        }
     }
 
     // Wait for the new buffer to be ready.
     return doGLFenceWaitLocked();
-
 }
 
 status_t GLConsumer::checkAndUpdateEglStateLocked(bool contextCheck) {
@@ -1056,12 +1069,13 @@
 }
 
 status_t GLConsumer::EglImage::createIfNeeded(EGLDisplay eglDisplay,
-                                              const Rect& cropRect) {
+                                              const Rect& cropRect,
+                                              bool forceCreation) {
     // If there's an image and it's no longer valid, destroy it.
     bool haveImage = mEglImage != EGL_NO_IMAGE_KHR;
     bool displayInvalid = mEglDisplay != eglDisplay;
     bool cropInvalid = hasEglAndroidImageCrop() && mCropRect != cropRect;
-    if (haveImage && (displayInvalid || cropInvalid)) {
+    if (haveImage && (displayInvalid || cropInvalid || forceCreation)) {
         if (!eglDestroyImageKHR(mEglDisplay, mEglImage)) {
            ALOGE("createIfNeeded: eglDestroyImageKHR failed");
         }
diff --git a/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp b/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
index 115a47d..1cd101e 100644
--- a/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureMultiContextGL_test.cpp
@@ -386,4 +386,59 @@
     ASSERT_EQ(OK, mST->updateTexImage());
 }
 
+TEST_F(SurfaceTextureMultiContextGLTest,
+       AttachAfterDisplayTerminatedSucceeds) {
+    ASSERT_EQ(NO_ERROR, mST->setDefaultMaxBufferCount(2));
+
+    // produce two frames and consume them both on the primary context
+    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
+    mFW->waitForFrame();
+    ASSERT_EQ(OK, mST->updateTexImage());
+
+    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
+    mFW->waitForFrame();
+    ASSERT_EQ(OK, mST->updateTexImage());
+
+    // produce one more frame
+    ASSERT_NO_FATAL_FAILURE(produceOneRGBA8Frame(mANW));
+
+    // Detach from the primary context.
+    ASSERT_EQ(OK, mST->releaseTexImage());
+    ASSERT_EQ(OK, mST->detachFromContext());
+
+    // Terminate and then initialize the display. All contexts, surfaces
+    // and images are invalid at this point.
+    EGLDisplay display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    ASSERT_NE(EGL_NO_DISPLAY, mEglDisplay);
+    EGLint majorVersion = 0;
+    EGLint minorVersion = 0;
+    EXPECT_TRUE(eglTerminate(display));
+    EXPECT_TRUE(eglInitialize(mEglDisplay, &majorVersion, &minorVersion));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    // The surface is invalid so create it again.
+    EGLint pbufferAttribs[] = {
+        EGL_WIDTH, 64,
+        EGL_HEIGHT, 64,
+        EGL_NONE };
+    mEglSurface = eglCreatePbufferSurface(mEglDisplay, mGlConfig,
+            pbufferAttribs);
+
+    // The second context is invalid so create it again.
+    mSecondEglContext = eglCreateContext(mEglDisplay, mGlConfig,
+            EGL_NO_CONTEXT, getContextAttribs());
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+    ASSERT_NE(EGL_NO_CONTEXT, mSecondEglContext);
+
+    ASSERT_TRUE(eglMakeCurrent(mEglDisplay, mEglSurface, mEglSurface,
+            mSecondEglContext));
+    ASSERT_EQ(EGL_SUCCESS, eglGetError());
+
+    // Now attach to and consume final frame on secondary context.
+    ASSERT_EQ(OK, mST->attachToContext(SECOND_TEX_ID));
+    mFW->waitForFrame();
+    ASSERT_EQ(OK, mST->updateTexImage());
+}
+
+
 } // namespace android
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 8295c4c..b7c7ff4 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -1815,7 +1815,7 @@
 // --- SwitchInputMapper ---
 
 SwitchInputMapper::SwitchInputMapper(InputDevice* device) :
-        InputMapper(device), mUpdatedSwitchValues(0), mUpdatedSwitchMask(0) {
+        InputMapper(device), mSwitchValues(0), mUpdatedSwitchMask(0) {
 }
 
 SwitchInputMapper::~SwitchInputMapper() {
@@ -1841,7 +1841,9 @@
 void SwitchInputMapper::processSwitch(int32_t switchCode, int32_t switchValue) {
     if (switchCode >= 0 && switchCode < 32) {
         if (switchValue) {
-            mUpdatedSwitchValues |= 1 << switchCode;
+            mSwitchValues |= 1 << switchCode;
+        } else {
+            mSwitchValues &= ~(1 << switchCode);
         }
         mUpdatedSwitchMask |= 1 << switchCode;
     }
@@ -1849,10 +1851,10 @@
 
 void SwitchInputMapper::sync(nsecs_t when) {
     if (mUpdatedSwitchMask) {
-        NotifySwitchArgs args(when, 0, mUpdatedSwitchValues, mUpdatedSwitchMask);
+        int32_t updatedSwitchValues = mSwitchValues & mUpdatedSwitchMask;
+        NotifySwitchArgs args(when, 0, updatedSwitchValues, mUpdatedSwitchMask);
         getListener()->notifySwitch(&args);
 
-        mUpdatedSwitchValues = 0;
         mUpdatedSwitchMask = 0;
     }
 }
@@ -1861,6 +1863,10 @@
     return getEventHub()->getSwitchState(getDeviceId(), switchCode);
 }
 
+void SwitchInputMapper::dump(String8& dump) {
+    dump.append(INDENT2 "Switch Input Mapper:\n");
+    dump.appendFormat(INDENT3 "SwitchValues: %x\n", mSwitchValues);
+}
 
 // --- VibratorInputMapper ---
 
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 9e36e35..c5896d4 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -999,9 +999,10 @@
     virtual void process(const RawEvent* rawEvent);
 
     virtual int32_t getSwitchState(uint32_t sourceMask, int32_t switchCode);
+    virtual void dump(String8& dump);
 
 private:
-    uint32_t mUpdatedSwitchValues;
+    uint32_t mSwitchValues;
     uint32_t mUpdatedSwitchMask;
 
     void processSwitch(int32_t switchCode, int32_t switchValue);
diff --git a/services/surfaceflinger/DisplayHardware/HWComposer.cpp b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
index a8dcf98..6302053 100644
--- a/services/surfaceflinger/DisplayHardware/HWComposer.cpp
+++ b/services/surfaceflinger/DisplayHardware/HWComposer.cpp
@@ -524,6 +524,10 @@
             if (!err) {
                 int32_t& events(mDisplayData[disp].events);
                 events = (events & ~eventBit) | newValue;
+
+                char tag[16];
+                snprintf(tag, sizeof(tag), "HW_VSYNC_ON_%1u", disp);
+                ATRACE_INT(tag, enabled);
             }
         }
         // error here should not happen -- not sure what we should