Merge "drm: add event for resource manager."
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 5d236d7..0cad9d8 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -64,7 +64,8 @@
     time_t thirty_minutes_ago = time(NULL) - 60*30;
     for (size_t i = 0; i < NUM_TOMBSTONES; i++) {
         snprintf(data[i].name, sizeof(data[i].name), "%s%02zu", TOMBSTONE_FILE_PREFIX, i);
-        int fd = open(data[i].name, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+        int fd = TEMP_FAILURE_RETRY(open(data[i].name,
+                                         O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
         struct stat st;
         if (fstat(fd, &st) == 0 && S_ISREG(st.st_mode) &&
                 (time_t) st.st_mtime >= thirty_minutes_ago) {
@@ -184,7 +185,8 @@
     if (!anr_traces_path[0]) {
         printf("*** NO VM TRACES FILE DEFINED (dalvik.vm.stack-trace-file)\n\n");
     } else {
-      int fd = open(anr_traces_path, O_RDONLY | O_CLOEXEC | O_NOFOLLOW);
+      int fd = TEMP_FAILURE_RETRY(open(anr_traces_path,
+                                       O_RDONLY | O_CLOEXEC | O_NOFOLLOW | O_NONBLOCK));
       if (fd < 0) {
           printf("*** NO ANR VM TRACES FILE (%s): %s\n\n", anr_traces_path, strerror(errno));
       } else {
@@ -239,7 +241,9 @@
     dump_file("LAST PANIC CONSOLE", "/data/dontpanic/apanic_console");
     dump_file("LAST PANIC THREADS", "/data/dontpanic/apanic_threads");
 
-    for_each_userid(do_dump_settings, NULL);
+    /* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
+    run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime",
+                                             "-b", "all", "-d", "*:v", NULL);
 
     /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
 
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 2be340b..8335e26 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -26,12 +26,13 @@
 
 typedef void (for_each_pid_func)(int, const char *);
 typedef void (for_each_tid_func)(int, int, const char *);
-typedef void (for_each_userid_func)(int);
 
 /* prints the contents of a file */
 int dump_file(const char *title, const char *path);
 
-/* prints the contents of the fd */
+/* prints the contents of the fd
+ * fd must have been opened with the flag O_NONBLOCK.
+ */
 int dump_file_from_fd(const char *title, const char *path, int fd);
 
 /* forks a command and waits for it to finish -- terminate args with NULL */
@@ -55,9 +56,6 @@
 /* for each thread in the system, run the specified function */
 void for_each_tid(for_each_tid_func func, const char *header);
 
-/* for each user id in the system, run the specified function */
-void for_each_userid(for_each_userid_func func, const char *header);
-
 /* Displays a blocked processes in-kernel wait channel */
 void show_wchan(int pid, int tid, const char *name);
 
@@ -67,9 +65,6 @@
 /* Gets the dmesg output for the kernel */
 void do_dmesg();
 
-/* Dumps settings for a given user id */
-void do_dump_settings(int userid);
-
 /* Prints the contents of all the routing tables, both IPv4 and IPv6. */
 void dump_route_tables();
 
diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c
index 7ad9cf0..48f59e1 100644
--- a/cmds/dumpstate/utils.c
+++ b/cmds/dumpstate/utils.c
@@ -53,6 +53,12 @@
         NULL,
 };
 
+static uint64_t nanotime() {
+    struct timespec ts;
+    clock_gettime(CLOCK_MONOTONIC, &ts);
+    return (uint64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
+}
+
 void for_each_userid(void (*func)(int), const char *header) {
     DIR *d;
     struct dirent *de;
@@ -98,7 +104,7 @@
 
         sprintf(cmdpath,"/proc/%d/cmdline", pid);
         memset(cmdline, 0, sizeof(cmdline));
-        if ((fd = open(cmdpath, O_RDONLY)) < 0) {
+        if ((fd = TEMP_FAILURE_RETRY(open(cmdpath, O_RDONLY))) < 0) {
             strcpy(cmdline, "N/A");
         } else {
             read(fd, cmdline, sizeof(cmdline) - 1);
@@ -149,7 +155,7 @@
 
         sprintf(commpath,"/proc/%d/comm", tid);
         memset(comm, 0, sizeof(comm));
-        if ((fd = open(commpath, O_RDONLY)) < 0) {
+        if ((fd = TEMP_FAILURE_RETRY(open(commpath, O_RDONLY))) < 0) {
             strcpy(comm, "N/A");
         } else {
             char *c;
@@ -180,7 +186,7 @@
     memset(buffer, 0, sizeof(buffer));
 
     sprintf(path, "/proc/%d/wchan", tid);
-    if ((fd = open(path, O_RDONLY)) < 0) {
+    if ((fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY))) < 0) {
         printf("Failed to open '%s' (%s)\n", path, strerror(errno));
         return;
     }
@@ -200,22 +206,6 @@
     return;
 }
 
-void do_dump_settings(int userid) {
-    char title[255];
-    char dbpath[255];
-    char sql[255];
-    sprintf(title, "SYSTEM SETTINGS (user %d)", userid);
-    if (userid == 0) {
-        strcpy(dbpath, "/data/data/com.android.providers.settings/databases/settings.db");
-        strcpy(sql, "pragma user_version; select * from system; select * from secure; select * from global;");
-    } else {
-        sprintf(dbpath, "/data/system/users/%d/settings.db", userid);
-        strcpy(sql, "pragma user_version; select * from system; select * from secure;");
-    }
-    run_command(title, 20, SU_PATH, "root", "sqlite3", dbpath, sql, NULL);
-    return;
-}
-
 void do_dmesg() {
     printf("------ KERNEL LOG (dmesg) ------\n");
     /* Get size of kernel buffer */
@@ -250,22 +240,7 @@
     run_command(title, 10, SU_PATH, "root", "showmap", arg, NULL);
 }
 
-/* prints the contents of a file */
-int dump_file(const char *title, const char *path) {
-    int fd = open(path, O_RDONLY);
-    if (fd < 0) {
-        int err = errno;
-        if (title) printf("------ %s (%s) ------\n", title, path);
-        printf("*** %s: %s\n", path, strerror(err));
-        if (title) printf("\n");
-        return -1;
-    }
-    return dump_file_from_fd(title, path, fd);
-}
-
-int dump_file_from_fd(const char *title, const char *path, int fd) {
-    char buffer[32768];
-
+static int _dump_file_from_fd(const char *title, const char *path, int fd) {
     if (title) printf("------ %s (%s", title, path);
 
     if (title) {
@@ -279,26 +254,76 @@
         printf(") ------\n");
     }
 
-    int newline = 0;
-    for (;;) {
-        int ret = read(fd, buffer, sizeof(buffer));
-        if (ret > 0) {
-            newline = (buffer[ret - 1] == '\n');
-            ret = fwrite(buffer, ret, 1, stdout);
+    bool newline = false;
+    fd_set read_set;
+    struct timeval tm;
+    while (1) {
+        FD_ZERO(&read_set);
+        FD_SET(fd, &read_set);
+        /* Timeout if no data is read for 30 seconds. */
+        tm.tv_sec = 30;
+        tm.tv_usec = 0;
+        uint64_t elapsed = nanotime();
+        int ret = TEMP_FAILURE_RETRY(select(fd + 1, &read_set, NULL, NULL, &tm));
+        if (ret == -1) {
+            printf("*** %s: select failed: %s\n", path, strerror(errno));
+            newline = true;
+            break;
+        } else if (ret == 0) {
+            elapsed = nanotime() - elapsed;
+            printf("*** %s: Timed out after %.3fs\n", path,
+                   (float) elapsed / NANOS_PER_SEC);
+            newline = true;
+            break;
+        } else {
+            char buffer[65536];
+            ssize_t bytes_read = TEMP_FAILURE_RETRY(read(fd, buffer, sizeof(buffer)));
+            if (bytes_read > 0) {
+                fwrite(buffer, bytes_read, 1, stdout);
+                newline = (buffer[bytes_read-1] == '\n');
+            } else {
+                if (bytes_read == -1) {
+                    printf("*** %s: Failed to read from fd: %s", path, strerror(errno));
+                    newline = true;
+                }
+                break;
+            }
         }
-        if (ret <= 0) break;
     }
-    close(fd);
+    TEMP_FAILURE_RETRY(close(fd));
 
     if (!newline) printf("\n");
     if (title) printf("\n");
     return 0;
 }
 
-static int64_t nanotime() {
-    struct timespec ts;
-    clock_gettime(CLOCK_MONOTONIC, &ts);
-    return (int64_t)ts.tv_sec * NANOS_PER_SEC + ts.tv_nsec;
+/* prints the contents of a file */
+int dump_file(const char *title, const char *path) {
+    int fd = TEMP_FAILURE_RETRY(open(path, O_RDONLY | O_NONBLOCK | O_CLOEXEC));
+    if (fd < 0) {
+        int err = errno;
+        if (title) printf("------ %s (%s) ------\n", title, path);
+        printf("*** %s: %s\n", path, strerror(err));
+        if (title) printf("\n");
+        return -1;
+    }
+    return _dump_file_from_fd(title, path, fd);
+}
+
+/* fd must have been opened with the flag O_NONBLOCK. With this flag set,
+ * it's possible to avoid issues where opening the file itself can get
+ * stuck.
+ */
+int dump_file_from_fd(const char *title, const char *path, int fd) {
+    int flags = fcntl(fd, F_GETFL);
+    if (flags == -1) {
+        printf("*** %s: failed to get flags on fd %d: %s\n", path, fd, strerror(errno));
+        return -1;
+    } else if (!(flags & O_NONBLOCK)) {
+        printf("*** %s: fd must have O_NONBLOCK set.\n", path);
+        return -1;
+    }
+    return _dump_file_from_fd(title, path, fd);
 }
 
 bool waitpid_with_timeout(pid_t pid, int timeout_seconds, int* status) {
@@ -348,7 +373,7 @@
 /* forks a command and waits for it to finish */
 int run_command(const char *title, int timeout_seconds, const char *command, ...) {
     fflush(stdout);
-    int64_t start = nanotime();
+    uint64_t start = nanotime();
     pid_t pid = fork();
 
     /* handle error case */
@@ -550,7 +575,8 @@
     }
 
     /* create a new, empty traces.txt file to receive stack dumps */
-    int fd = open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW, 0666);  /* -rw-rw-rw- */
+    int fd = TEMP_FAILURE_RETRY(open(traces_path, O_CREAT | O_WRONLY | O_TRUNC | O_NOFOLLOW,
+                                     0666));  /* -rw-rw-rw- */
     if (fd < 0) {
         fprintf(stderr, "%s: %s\n", traces_path, strerror(errno));
         return NULL;
@@ -600,7 +626,7 @@
         if (!strncmp(data, "/system/bin/app_process", strlen("/system/bin/app_process"))) {
             /* skip zygote -- it won't dump its stack anyway */
             snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
-            int cfd = open(path, O_RDONLY);
+            int cfd = TEMP_FAILURE_RETRY(open(path, O_RDONLY));
             len = read(cfd, data, sizeof(data) - 1);
             close(cfd);
             if (len <= 0) {
@@ -612,7 +638,7 @@
             }
 
             ++dalvik_found;
-            int64_t start = nanotime();
+            uint64_t start = nanotime();
             if (kill(pid, SIGQUIT)) {
                 fprintf(stderr, "kill(%d, SIGQUIT): %s\n", pid, strerror(errno));
                 continue;
@@ -642,7 +668,7 @@
                 fprintf(stderr, "lseek: %s\n", strerror(errno));
             } else {
                 static uint16_t timeout_failures = 0;
-                int64_t start = nanotime();
+                uint64_t start = nanotime();
 
                 /* If 3 backtrace dumps fail in a row, consider debuggerd dead. */
                 if (timeout_failures == 3) {
diff --git a/cmds/installd/commands.c b/cmds/installd/commands.c
index 42422e7..44c4988 100644
--- a/cmds/installd/commands.c
+++ b/cmds/installd/commands.c
@@ -16,6 +16,7 @@
 
 #include <inttypes.h>
 #include <sys/capability.h>
+#include <sys/file.h>
 #include "installd.h"
 #include <cutils/sched_policy.h>
 #include <diskusage/dirsize.h>
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index f37427a..df46a60 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -169,28 +169,26 @@
 
 uint32_t do_find_service(struct binder_state *bs, const uint16_t *s, size_t len, uid_t uid, pid_t spid)
 {
-    struct svcinfo *si;
+    struct svcinfo *si = find_svc(s, len);
+
+    if (!si || !si->handle) {
+        return 0;
+    }
+
+    if (!si->allow_isolated) {
+        // If this service doesn't allow access from isolated processes,
+        // then check the uid to see if it is isolated.
+        uid_t appid = uid % AID_USER;
+        if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
+            return 0;
+        }
+    }
 
     if (!svc_can_find(s, len, spid)) {
-        ALOGE("find_service('%s') uid=%d - PERMISSION DENIED\n",
-             str8(s, len), uid);
         return 0;
     }
-    si = find_svc(s, len);
-    //ALOGI("check_service('%s') handle = %x\n", str8(s, len), si ? si->handle : 0);
-    if (si && si->handle) {
-        if (!si->allow_isolated) {
-            // If this service doesn't allow access from isolated processes,
-            // then check the uid to see if it is isolated.
-            uid_t appid = uid % AID_USER;
-            if (appid >= AID_ISOLATED_START && appid <= AID_ISOLATED_END) {
-                return 0;
-            }
-        }
-        return si->handle;
-    } else {
-        return 0;
-    }
+
+    return si->handle;
 }
 
 int do_add_service(struct binder_state *bs,
diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h
index 79ff12a..629310f 100644
--- a/include/input/IInputFlinger.h
+++ b/include/input/IInputFlinger.h
@@ -31,8 +31,6 @@
 class IInputFlinger : public IInterface {
 public:
     DECLARE_META_INTERFACE(InputFlinger);
-
-    virtual status_t doSomething() = 0;
 };
 
 
diff --git a/include/input/Input.h b/include/input/Input.h
index 96b6885..c360f63 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -149,10 +149,22 @@
      * NOTE: If you want a flag to be able to set in a keylayout file, then you must add it to
      * InputEventLabels.h as well. */
 
+    // Indicates that the event should wake the device.
     POLICY_FLAG_WAKE = 0x00000001,
+
+    // Indicates that the key is virtual, such as a capacitive button, and should
+    // generate haptic feedback.  Virtual keys may be suppressed for some time
+    // after a recent touch to prevent accidental activation of virtual keys adjacent
+    // to the touch screen during an edge swipe.
     POLICY_FLAG_VIRTUAL = 0x00000002,
+
+    // Indicates that the key is the special function modifier.
     POLICY_FLAG_FUNCTION = 0x00000004,
 
+    // Indicates that the key represents a special gesture that has been detected by
+    // the touch firmware or driver.  Causes touch events from the same device to be canceled.
+    POLICY_FLAG_GESTURE = 0x00000008,
+
     POLICY_FLAG_RAW_MASK = 0x0000ffff,
 
     /* These flags are set by the input dispatcher. */
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index df50237..9aa7425 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -376,6 +376,7 @@
 static const InputEventLabel FLAGS[] = {
     DEFINE_FLAG(VIRTUAL),
     DEFINE_FLAG(FUNCTION),
+    DEFINE_FLAG(GESTURE),
 
     { NULL, 0 }
 };
diff --git a/libs/diskusage/dirsize.c b/libs/diskusage/dirsize.c
index 24e5af0..7576994 100644
--- a/libs/diskusage/dirsize.c
+++ b/libs/diskusage/dirsize.c
@@ -18,6 +18,7 @@
 #include <dirent.h>
 #include <fcntl.h>
 #include <sys/stat.h>
+#include <unistd.h>
 
 #include <diskusage/dirsize.h>
 
diff --git a/libs/gui/GLConsumer.cpp b/libs/gui/GLConsumer.cpp
index 065345c..a0f68b4 100644
--- a/libs/gui/GLConsumer.cpp
+++ b/libs/gui/GLConsumer.cpp
@@ -899,14 +899,14 @@
 
         // The crop is too wide
         if (newWidth < currentWidth) {
-            uint32_t dw = (newWidth - currentWidth) / 2;
-            outCrop.left -=dw;
-            outCrop.right += dw;
+            uint32_t dw = (currentWidth - newWidth) / 2;
+            outCrop.left += dw;
+            outCrop.right -= dw;
         // The crop is too tall
         } else if (newHeight < currentHeight) {
-            uint32_t dh = (newHeight - currentHeight) / 2;
-            outCrop.top -= dh;
-            outCrop.bottom += dh;
+            uint32_t dh = (currentHeight - newHeight) / 2;
+            outCrop.top += dh;
+            outCrop.bottom -= dh;
         }
 
         GLC_LOGV("getCurrentCrop final crop [%d,%d,%d,%d]",
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 425df38..638ac62 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -323,7 +323,11 @@
     const size_t numFds  = static_cast<size_t>(buf[8]);
     const size_t numInts = static_cast<size_t>(buf[9]);
 
-    const size_t maxNumber = UINT_MAX / sizeof(int);
+    // Limit the maxNumber to be relatively small. The number of fds or ints
+    // should not come close to this number, and the number itself was simply
+    // chosen to be high enough to not cause issues and low enough to prevent
+    // overflow problems.
+    const size_t maxNumber = 4096;
     if (numFds >= maxNumber || numInts >= (maxNumber - 10)) {
         width = height = stride = format = usage = 0;
         handle = NULL;
diff --git a/opengl/libs/Android.mk b/opengl/libs/Android.mk
index 2c66f3d..4da9f92 100644
--- a/opengl/libs/Android.mk
+++ b/opengl/libs/Android.mk
@@ -47,9 +47,6 @@
 ifeq ($(BOARD_ALLOW_EGL_HIBERNATION),true)
   LOCAL_CFLAGS += -DBOARD_ALLOW_EGL_HIBERNATION
 endif
-ifeq ($(TARGET_BOARD_PLATFORM), omap4)
-  LOCAL_CFLAGS += -DWORKAROUND_BUG_10194508=1
-endif
 ifneq ($(MAX_EGL_CACHE_ENTRY_SIZE),)
   LOCAL_CFLAGS += -DMAX_EGL_CACHE_ENTRY_SIZE=$(MAX_EGL_CACHE_ENTRY_SIZE)
 endif
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 6e77e45..ff08a6b 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -421,35 +421,7 @@
         // of our native format. So if sRGB gamma is requested, we have to
         // modify the EGLconfig's format before setting the native window's
         // format.
-#if WORKAROUND_BUG_10194508
-#warning "WORKAROUND_10194508 enabled"
-        EGLint format;
-        if (!cnx->egl.eglGetConfigAttrib(iDpy, config, EGL_NATIVE_VISUAL_ID,
-                &format)) {
-            ALOGE("eglGetConfigAttrib(EGL_NATIVE_VISUAL_ID) failed: %#x",
-                    eglGetError());
-            format = 0;
-        }
-        if (attrib_list) {
-            for (const EGLint* attr = attrib_list; *attr != EGL_NONE;
-                    attr += 2) {
-                if (*attr == EGL_GL_COLORSPACE_KHR &&
-                        dp->haveExtension("EGL_KHR_gl_colorspace")) {
-                    if (ENABLE_EGL_KHR_GL_COLORSPACE) {
-                        format = modifyFormatColorspace(format, *(attr+1));
-                    } else {
-                        // Normally we'd pass through unhandled attributes to
-                        // the driver. But in case the driver implements this
-                        // extension but we're disabling it, we want to prevent
-                        // it getting through -- support will be broken without
-                        // our help.
-                        ALOGE("sRGB window surfaces not supported");
-                        return setError(EGL_BAD_ATTRIBUTE, EGL_NO_SURFACE);
-                    }
-                }
-            }
-        }
-#else
+
         // by default, just pick RGBA_8888
         EGLint format = HAL_PIXEL_FORMAT_RGBA_8888;
 
@@ -490,7 +462,7 @@
                 }
             }
         }
-#endif
+
         if (format != 0) {
             int err = native_window_set_buffers_format(window, format);
             if (err != 0) {
diff --git a/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp b/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp
index 003efd3..2abc916 100755
--- a/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp
+++ b/opengl/tools/glgen/stubs/egl/eglGetDisplay.cpp
@@ -14,7 +14,8 @@
 android_eglGetDisplayInt
   (JNIEnv *_env, jobject _this, jint display_id) {
 
-    if ((EGLNativeDisplayType)display_id != EGL_DEFAULT_DISPLAY) {
+    if (static_cast<uintptr_t>(display_id) !=
+        reinterpret_cast<uintptr_t>(EGL_DEFAULT_DISPLAY)) {
         jniThrowException(_env, "java/lang/UnsupportedOperationException", "eglGetDisplay");
         return 0;
     }
diff --git a/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp b/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
index 41df486..d844152 100644
--- a/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glDrawElementsInstanced.cpp
@@ -32,7 +32,7 @@
         (GLenum)mode,
         (GLsizei)count,
         (GLenum)type,
-        (GLvoid *)indicesOffset,
+        (GLvoid *)static_cast<uintptr_t>(indicesOffset),
         (GLsizei)instanceCount
     );
 }
diff --git a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
index 0514fe9..a977693 100644
--- a/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
+++ b/opengl/tools/glgen/stubs/gles11/glGetTransformFeedbackVarying.cpp
@@ -157,7 +157,11 @@
         (GLsizei *)length,
         (GLint *)size,
         (GLenum *)type,
-        (char *)name
+        // The cast below is incorrect. The driver will end up writing to the
+        // address specified by name, which will always crash the process since
+        // it is guaranteed to be in low memory. The additional static_cast
+        // suppresses the warning for now. http://b/19478262
+        (char *)static_cast<uintptr_t>(name)
     );
     if (_typeArray) {
         releasePointer(_env, _typeArray, type, JNI_TRUE);
diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk
index add5108..ed867d8 100644
--- a/services/inputflinger/Android.mk
+++ b/services/inputflinger/Android.mk
@@ -22,8 +22,7 @@
     InputListener.cpp \
     InputManager.cpp \
     InputReader.cpp \
-    InputWindow.cpp \
-    InputFlinger.cpp
+    InputWindow.cpp
 
 LOCAL_SHARED_LIBRARIES := \
     libbinder \
@@ -47,18 +46,4 @@
 
 include $(BUILD_SHARED_LIBRARY)
 
-########################################################################
-# build input flinger executable
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES:= \
-	main.cpp
-
-LOCAL_SHARED_LIBRARIES := \
-	libbinder \
-	libinputflinger \
-	libutils
-
-LOCAL_MODULE := inputflinger
-
-include $(BUILD_EXECUTABLE)
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 8634e42..ccf8ced 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -1078,6 +1078,14 @@
     }
 }
 
+void InputDevice::cancelTouch(nsecs_t when) {
+    size_t numMappers = mMappers.size();
+    for (size_t i = 0; i < numMappers; i++) {
+        InputMapper* mapper = mMappers[i];
+        mapper->cancelTouch(when);
+    }
+}
+
 int32_t InputDevice::getMetaState() {
     int32_t result = 0;
     size_t numMappers = mMappers.size();
@@ -1786,6 +1794,9 @@
 void InputMapper::cancelVibrate(int32_t token) {
 }
 
+void InputMapper::cancelTouch(nsecs_t when) {
+}
+
 int32_t InputMapper::getMetaState() {
     return 0;
 }
@@ -2134,6 +2145,9 @@
                             getDevice(), keyCode, scanCode)) {
                 return;
             }
+            if (policyFlags & POLICY_FLAG_GESTURE) {
+                mDevice->cancelTouch(when);
+            }
 
             mKeyDowns.push();
             KeyDown& keyDown = mKeyDowns.editTop();
@@ -5717,6 +5731,10 @@
     }
 }
 
+void TouchInputMapper::cancelTouch(nsecs_t when) {
+    abortPointerUsage(when, 0 /*policyFlags*/);
+}
+
 bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) {
     return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue
             && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue;
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index c5896d4..34f20af 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -572,6 +572,7 @@
             const int32_t* keyCodes, uint8_t* outFlags);
     void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token);
     void cancelVibrate(int32_t token);
+    void cancelTouch(nsecs_t when);
 
     int32_t getMetaState();
 
@@ -973,6 +974,7 @@
     virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat,
             int32_t token);
     virtual void cancelVibrate(int32_t token);
+    virtual void cancelTouch(nsecs_t when);
 
     virtual int32_t getMetaState();
 
@@ -1191,6 +1193,7 @@
             const int32_t* keyCodes, uint8_t* outFlags);
 
     virtual void fadePointer();
+    virtual void cancelTouch(nsecs_t when);
     virtual void timeoutExpired(nsecs_t when);
 
 protected:
diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk
new file mode 100644
index 0000000..b828175
--- /dev/null
+++ b/services/inputflinger/host/Android.mk
@@ -0,0 +1,62 @@
+# 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.
+
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES:= \
+    InputFlinger.cpp \
+    InputDriver.cpp \
+    InputHost.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+    libbinder \
+    libcrypto \
+    libcutils \
+    libinput \
+    liblog \
+    libutils \
+    libhardware
+
+
+# TODO: Move inputflinger to its own process and mark it hidden
+#LOCAL_CFLAGS += -fvisibility=hidden
+
+LOCAL_CFLAGS += -Wno-unused-parameter
+
+LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
+
+LOCAL_MODULE := libinputflingerhost
+
+include $(BUILD_SHARED_LIBRARY)
+
+########################################################################
+# build input flinger executable
+include $(CLEAR_VARS)
+
+LOCAL_CLANG := true
+
+LOCAL_SRC_FILES:= \
+	main.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+	libbinder \
+	libinputflingerhost \
+	libutils
+
+LOCAL_MODULE := inputflinger
+
+include $(BUILD_EXECUTABLE)
diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp
new file mode 100644
index 0000000..ce84a6a
--- /dev/null
+++ b/services/inputflinger/host/InputDriver.cpp
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#define LOG_TAG "InputDriver"
+
+#define LOG_NDEBUG 0
+
+#include "InputDriver.h"
+#include "InputHost.h"
+
+#include <hardware/input.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define INDENT2 "    "
+
+namespace android {
+
+static input_host_callbacks_t kCallbacks = {
+    .create_device_identifier = create_device_identifier,
+    .create_device_definition = create_device_definition,
+    .create_input_report_definition = create_input_report_definition,
+    .create_output_report_definition = create_output_report_definition,
+    .input_device_definition_add_report = input_device_definition_add_report,
+    .input_report_definition_add_collection = input_report_definition_add_collection,
+    .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int,
+    .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool,
+    .register_device = register_device,
+    .input_allocate_report = input_allocate_report,
+    .report_event = report_event,
+};
+
+InputDriver::InputDriver(const char* name) : mName(String8(name)) {
+    const hw_module_t* module;
+    int err = input_open(&module, name);
+    LOG_ALWAYS_FATAL_IF(err != 0, "Input module %s not found", name);
+    mHal = reinterpret_cast<const input_module_t*>(module);
+}
+
+void InputDriver::init(InputHostInterface* host) {
+    mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks);
+}
+
+void InputDriver::dump(String8& result) {
+    result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string());
+}
+
+
+// HAL wrapper functions
+
+input_device_identifier_t* create_device_identifier(input_host_t* host,
+        const char* name, int32_t product_id, int32_t vendor_id,
+        input_bus_t bus, const char* unique_id) {
+    return nullptr;
+}
+
+input_device_definition_t* create_device_definition(input_host_t* host) {
+    return nullptr;
+}
+
+input_report_definition_t* create_input_report_definition(input_host_t* host) {
+    return nullptr;
+}
+
+input_report_definition_t* create_output_report_definition(input_host_t* host) {
+    return nullptr;
+}
+
+void input_device_definition_add_report(input_host_t* host,
+        input_device_definition_t* d, input_report_definition_t* r) { }
+
+void input_report_definition_add_collection(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id, int32_t arity) { }
+
+void input_report_definition_declare_usage_int(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id,
+        input_usage_t usage, int32_t min, int32_t max, float resolution) { }
+
+void input_report_definition_declare_usages_bool(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id,
+        input_usage_t* usage, size_t usage_count) { }
+
+
+input_device_handle_t* register_device(input_host_t* host,
+        input_device_identifier_t* id, input_device_definition_t* d) {
+    return nullptr;
+}
+
+input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) {
+    return nullptr;
+}
+
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { }
+
+
+} // namespace android
diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h
new file mode 100644
index 0000000..c2268e2
--- /dev/null
+++ b/services/inputflinger/host/InputDriver.h
@@ -0,0 +1,98 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INPUT_DRIVER_H
+#define ANDROID_INPUT_DRIVER_H
+
+#include <stdint.h>
+#include <sys/types.h>
+
+#include "InputHost.h"
+
+#include <hardware/input.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+
+namespace android {
+
+class InputHostInterface;
+
+class InputDriverInterface : public virtual RefBase {
+protected:
+    InputDriverInterface() = default;
+    virtual ~InputDriverInterface() = default;
+
+public:
+    virtual void init(InputHostInterface* host) = 0;
+
+    virtual void dump(String8& result) = 0;
+};
+
+class InputDriver : public InputDriverInterface {
+public:
+    InputDriver(const char* name);
+    virtual ~InputDriver() = default;
+
+    virtual void init(InputHostInterface* host) override;
+
+    virtual void dump(String8& result) override;
+
+private:
+    String8 mName;
+    const input_module_t* mHal;
+};
+
+
+extern "C" {
+
+input_device_identifier_t* create_device_identifier(input_host_t* host,
+        const char* name, int32_t product_id, int32_t vendor_id,
+        input_bus_t bus, const char* unique_id);
+
+input_device_definition_t* create_device_definition(input_host_t* host);
+
+input_report_definition_t* create_input_report_definition(input_host_t* host);
+
+input_report_definition_t* create_output_report_definition(input_host_t* host);
+
+void input_device_definition_add_report(input_host_t* host,
+        input_device_definition_t* d, input_report_definition_t* r);
+
+void input_report_definition_add_collection(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id, int32_t arity);
+
+void input_report_definition_declare_usage_int(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id,
+        input_usage_t usage, int32_t min, int32_t max, float resolution);
+
+void input_report_definition_declare_usages_bool(input_host_t* host,
+        input_report_definition_t* report, input_collection_id_t id,
+        input_usage_t* usage, size_t usage_count);
+
+
+input_device_handle_t* register_device(input_host_t* host,
+        input_device_identifier_t* id, input_device_definition_t* d);
+
+void unregister_device(input_host_t* host, input_device_handle_t* handle);
+
+input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r);
+
+void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report);
+
+}
+
+} // namespace android
+#endif // ANDROID_INPUT_DRIVER_H
diff --git a/services/inputflinger/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp
similarity index 70%
rename from services/inputflinger/InputFlinger.cpp
rename to services/inputflinger/host/InputFlinger.cpp
index 9ea6ce5..859c3b8 100644
--- a/services/inputflinger/InputFlinger.cpp
+++ b/services/inputflinger/host/InputFlinger.cpp
@@ -16,15 +16,18 @@
 
 #define LOG_TAG "InputFlinger"
 
-#include "InputFlinger.h"
 
 #include <stdint.h>
 #include <unistd.h>
 
 #include <sys/types.h>
 
+#include "InputFlinger.h"
+#include "InputDriver.h"
+
 #include <binder/IPCThreadState.h>
 #include <binder/PermissionCache.h>
+#include <hardware/input.h>
 #include <cutils/log.h>
 #include <private/android_filesystem_config.h>
 
@@ -37,29 +40,13 @@
 InputFlinger::InputFlinger() :
         BnInputFlinger() {
     ALOGI("InputFlinger is starting");
+    mHost = new InputHost();
+    mHost->registerInputDriver(new InputDriver(INPUT_INSTANCE_EVDEV));
 }
 
 InputFlinger::~InputFlinger() {
 }
 
-status_t InputFlinger::onTransact(
-        uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) {
-    switch (code) {
-    case DO_SOMETHING_TRANSACTION:
-        const IPCThreadState* ipc = IPCThreadState::self();
-        const int pid = ipc->getCallingPid();
-        const int uid = ipc->getCallingUid();
-        if (!PermissionCache::checkPermission(sAccessInputFlingerPermission, pid, uid)) {
-            ALOGE("Permission Denial: "
-                    "can't access InputFlinger from pid=%d, uid=%d", pid, uid);
-            return PERMISSION_DENIED;
-        }
-        break;
-    }
-
-    return BnInputFlinger::onTransact(code, data, reply, flags);
-}
-
 status_t InputFlinger::dump(int fd, const Vector<String16>& args) {
     String8 result;
     const IPCThreadState* ipc = IPCThreadState::self();
@@ -78,12 +65,7 @@
 
 void InputFlinger::dumpInternal(String8& result) {
     result.append("INPUT FLINGER (dumpsys inputflinger)\n");
-    result.append("... nothing here yet...\n");
-}
-
-status_t InputFlinger::doSomething() {
-    ALOGI("Did something...");
-    return OK;
+    mHost->dump(result);
 }
 
 }; // namespace android
diff --git a/services/inputflinger/InputFlinger.h b/services/inputflinger/host/InputFlinger.h
similarity index 85%
rename from services/inputflinger/InputFlinger.h
rename to services/inputflinger/host/InputFlinger.h
index 731ab17..39e69e5 100644
--- a/services/inputflinger/InputFlinger.h
+++ b/services/inputflinger/host/InputFlinger.h
@@ -20,10 +20,13 @@
 #include <stdint.h>
 #include <sys/types.h>
 
+#include "InputHost.h"
+
 #include <cutils/compiler.h>
 #include <input/IInputFlinger.h>
 #include <utils/String8.h>
 #include <utils/String16.h>
+#include <utils/StrongPointer.h>
 
 namespace android {
 
@@ -35,18 +38,14 @@
 
     InputFlinger() ANDROID_API;
 
-    // IBinder interface
-    virtual status_t onTransact(uint32_t code,
-            const Parcel& data, Parcel* reply, uint32_t flags);
     virtual status_t dump(int fd, const Vector<String16>& args);
 
-    // IInputFlinger interface
-    virtual status_t doSomething();
-
 private:
     virtual ~InputFlinger();
 
     void dumpInternal(String8& result);
+
+    sp<InputHostInterface> mHost;
 };
 
 } // namespace android
diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp
new file mode 100644
index 0000000..51d3e6b
--- /dev/null
+++ b/services/inputflinger/host/InputHost.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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.
+ */
+
+#include <vector>
+
+#include "InputDriver.h"
+#include "InputHost.h"
+
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+#define INDENT "  "
+
+namespace android {
+
+void InputHost::registerInputDriver(InputDriverInterface* driver) {
+    LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!");
+    driver->init(this);
+    mDrivers.push_back(driver);
+}
+
+void InputHost::dump(String8& result) {
+    result.append(INDENT "Input Drivers:\n");
+    for (size_t i = 0; i < mDrivers.size(); i++) {
+        mDrivers[i]->dump(result);
+    }
+}
+
+} // namespace android
diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h
new file mode 100644
index 0000000..42a66e0
--- /dev/null
+++ b/services/inputflinger/host/InputHost.h
@@ -0,0 +1,62 @@
+/*
+ * 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.
+ */
+
+#ifndef ANDROID_INPUT_HOST_H
+#define ANDROID_INPUT_HOST_H
+
+#include <vector>
+
+#include <hardware/input.h>
+#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include <utils/StrongPointer.h>
+
+#include "InputDriver.h"
+
+// Declare a concrete type for the HAL
+struct input_host {
+};
+
+namespace android {
+
+class InputDriverInterface;
+
+class InputHostInterface : public input_host_t, public virtual RefBase {
+protected:
+    InputHostInterface() = default;
+    virtual ~InputHostInterface() = default;
+
+public:
+
+    virtual void registerInputDriver(InputDriverInterface* driver) = 0;
+
+    virtual void dump(String8& result) = 0;
+};
+
+class InputHost : public InputHostInterface {
+public:
+    InputHost() = default;
+
+    virtual void registerInputDriver(InputDriverInterface* driver) override;
+
+    virtual void dump(String8& result) override;
+
+private:
+    std::vector<sp<InputDriverInterface>> mDrivers;
+};
+
+} // namespace android
+#endif // ANDRIOD_INPUT_HOST_H
diff --git a/services/inputflinger/main.cpp b/services/inputflinger/host/main.cpp
similarity index 100%
rename from services/inputflinger/main.cpp
rename to services/inputflinger/host/main.cpp
diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk
index 0742a08..4c43392 100644
--- a/services/inputflinger/tests/Android.mk
+++ b/services/inputflinger/tests/Android.mk
@@ -10,7 +10,6 @@
 shared_libraries := \
     libcutils \
     liblog \
-    libandroidfw \
     libutils \
     libhardware \
     libhardware_legacy \
@@ -24,7 +23,7 @@
     external/skia/include/core
 
 
-module_tags := eng tests
+module_tags := tests
 
 $(foreach file,$(test_src_files), \
     $(eval include $(CLEAR_VARS)) \
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 3419295..d01b945 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -148,7 +148,11 @@
         mPrimaryHWVsyncEnabled(false),
         mHWVsyncAvailable(false),
         mDaltonize(false),
-        mHasColorMatrix(false)
+        mHasColorMatrix(false),
+        mHasPoweredOff(false),
+        mFrameBuckets(),
+        mTotalTime(0),
+        mLastSwapTime(0)
 {
     ALOGI("SurfaceFlinger is starting");
 
@@ -949,8 +953,8 @@
         }
     }
 
+    const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
     if (kIgnorePresentFences) {
-        const sp<const DisplayDevice> hw(getDefaultDisplayDevice());
         if (hw->isDisplayOn()) {
             enableHardwareVsync();
         }
@@ -969,6 +973,26 @@
         }
         mAnimFrameTracker.advanceFrame();
     }
+
+    if (hw->getPowerMode() == HWC_POWER_MODE_OFF) {
+        return;
+    }
+
+    nsecs_t currentTime = systemTime();
+    if (mHasPoweredOff) {
+        mHasPoweredOff = false;
+    } else {
+        nsecs_t period = mPrimaryDispSync.getPeriod();
+        nsecs_t elapsedTime = currentTime - mLastSwapTime;
+        size_t numPeriods = static_cast<size_t>(elapsedTime / period);
+        if (numPeriods < NUM_BUCKETS - 1) {
+            mFrameBuckets[numPeriods] += elapsedTime;
+        } else {
+            mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime;
+        }
+        mTotalTime += elapsedTime;
+    }
+    mLastSwapTime = currentTime;
 }
 
 void SurfaceFlinger::rebuildLayerStacks() {
@@ -2345,6 +2369,7 @@
         }
 
         mVisibleRegionsDirty = true;
+        mHasPoweredOff = true;
         repaintEverything();
     } else if (mode == HWC_POWER_MODE_OFF) {
         if (type == DisplayDevice::DISPLAY_PRIMARY) {
@@ -2445,6 +2470,13 @@
                 mPrimaryDispSync.dump(result);
                 dumpAll = false;
             }
+
+            if ((index < numArgs) &&
+                    (args[index] == String16("--static-screen"))) {
+                index++;
+                dumpStaticScreenStats(result);
+                dumpAll = false;
+            }
         }
 
         if (dumpAll) {
@@ -2548,6 +2580,23 @@
     result.append(config);
 }
 
+void SurfaceFlinger::dumpStaticScreenStats(String8& result) const
+{
+    result.appendFormat("Static screen stats:\n");
+    for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) {
+        float bucketTimeSec = mFrameBuckets[b] / 1e9;
+        float percent = 100.0f *
+                static_cast<float>(mFrameBuckets[b]) / mTotalTime;
+        result.appendFormat("  < %zd frames: %.3f s (%.1f%%)\n",
+                b + 1, bucketTimeSec, percent);
+    }
+    float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9;
+    float percent = 100.0f *
+            static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime;
+    result.appendFormat("  %zd+ frames: %.3f s (%.1f%%)\n",
+            NUM_BUCKETS - 1, bucketTimeSec, percent);
+}
+
 void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index,
         String8& result) const
 {
@@ -2594,6 +2643,11 @@
         mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY));
     result.append("\n");
 
+    // Dump static screen stats
+    result.append("\n");
+    dumpStaticScreenStats(result);
+    result.append("\n");
+
     /*
      * Dump the visible layer list
      */
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 4deb815..34f0aaa 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -416,6 +416,8 @@
 
     void logFrameStats();
 
+    void dumpStaticScreenStats(String8& result) const;
+
     /* ------------------------------------------------------------------------
      * Attributes
      */
@@ -493,6 +495,13 @@
 
     mat4 mColorMatrix;
     bool mHasColorMatrix;
+
+    // Static screen stats
+    bool mHasPoweredOff;
+    static const size_t NUM_BUCKETS = 8; // < 1-7, 7+
+    nsecs_t mFrameBuckets[NUM_BUCKETS];
+    nsecs_t mTotalTime;
+    nsecs_t mLastSwapTime;
 };
 
 }; // namespace android
diff --git a/services/surfaceflinger/tests/vsync/vsync.cpp b/services/surfaceflinger/tests/vsync/vsync.cpp
index b0d54c4..aa72c79 100644
--- a/services/surfaceflinger/tests/vsync/vsync.cpp
+++ b/services/surfaceflinger/tests/vsync/vsync.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <android/looper.h>
 #include <gui/DisplayEventReceiver.h>
 #include <utils/Looper.h>
 
diff --git a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
index 279b88b..b88b04a 100644
--- a/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
+++ b/services/surfaceflinger/tests/waitforvsync/waitforvsync.cpp
@@ -23,6 +23,7 @@
 #include <errno.h>
 #include <string.h>
 #include <stdio.h>
+#include <unistd.h>
 
 #ifndef FBIO_WAITFORVSYNC
 #define FBIO_WAITFORVSYNC   _IOW('F', 0x20, __u32)