Merge "Tune SensorService thread priority, lower sensor event latency" into nyc-mr1-dev
diff --git a/cmds/bugreportz/.clang-format b/cmds/bugreportz/.clang-format
new file mode 100644
index 0000000..fc4eb1b
--- /dev/null
+++ b/cmds/bugreportz/.clang-format
@@ -0,0 +1,13 @@
+BasedOnStyle: Google
+AllowShortBlocksOnASingleLine: false
+AllowShortFunctionsOnASingleLine: false
+
+AccessModifierOffset: -2
+ColumnLimit: 100
+CommentPragmas: NOLINT:.*
+DerivePointerAlignment: false
+IndentWidth: 4
+PointerAlignment: Left
+TabWidth: 4
+UseTab: Never
+PenaltyExcessCharacter: 32
diff --git a/cmds/bugreportz/Android.mk b/cmds/bugreportz/Android.mk
index 14ba225..880bc75 100644
--- a/cmds/bugreportz/Android.mk
+++ b/cmds/bugreportz/Android.mk
@@ -1,12 +1,43 @@
 LOCAL_PATH:= $(call my-dir)
+
+# bugreportz
+# ==========
+
 include $(CLEAR_VARS)
 
-LOCAL_SRC_FILES:= bugreportz.cpp
+LOCAL_SRC_FILES:= \
+   bugreportz.cpp \
+   main.cpp \
 
 LOCAL_MODULE:= bugreportz
 
-LOCAL_CFLAGS := -Wall
+LOCAL_CFLAGS := -Werror -Wall
 
-LOCAL_SHARED_LIBRARIES := libcutils
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libcutils \
 
 include $(BUILD_EXECUTABLE)
+
+# bugreportz_test
+# ===============
+
+include $(CLEAR_VARS)
+
+LOCAL_MODULE := bugreportz_test
+LOCAL_MODULE_TAGS := tests
+
+LOCAL_CFLAGS := -Werror -Wall
+
+LOCAL_SRC_FILES := \
+    bugreportz.cpp \
+    bugreportz_test.cpp \
+
+LOCAL_STATIC_LIBRARIES := \
+    libgmock \
+
+LOCAL_SHARED_LIBRARIES := \
+    libbase \
+    libutils \
+
+include $(BUILD_NATIVE_TEST)
diff --git a/cmds/bugreportz/bugreportz.cpp b/cmds/bugreportz/bugreportz.cpp
index 312dceb..75855cf 100644
--- a/cmds/bugreportz/bugreportz.cpp
+++ b/cmds/bugreportz/bugreportz.cpp
@@ -15,89 +15,38 @@
  */
 
 #include <errno.h>
-#include <getopt.h>
 #include <stdio.h>
-#include <sys/socket.h>
-#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
 #include <unistd.h>
 
-#include <cutils/properties.h>
-#include <cutils/sockets.h>
+#include <string>
 
-static constexpr char VERSION[] = "1.0";
+#include <android-base/file.h>
+#include <android-base/strings.h>
 
-static void show_usage() {
-  fprintf(stderr,
-          "usage: bugreportz [-h | -v]\n"
-          "  -h: to display this help message\n"
-          "  -v: to display the version\n"
-          "  or no arguments to generate a zipped bugreport\n");
+#include "bugreportz.h"
+
+static constexpr char BEGIN_PREFIX[] = "BEGIN:";
+static constexpr char PROGRESS_PREFIX[] = "PROGRESS:";
+
+static void write_line(const std::string& line, bool show_progress) {
+    if (line.empty()) return;
+
+    // When not invoked with the -p option, it must skip BEGIN and PROGRESS lines otherwise it
+    // will break adb (which is expecting either OK or FAIL).
+    if (!show_progress && (android::base::StartsWith(line, PROGRESS_PREFIX) ||
+                           android::base::StartsWith(line, BEGIN_PREFIX)))
+        return;
+
+    android::base::WriteStringToFd(line, STDOUT_FILENO);
 }
 
-static void show_version() {
-  fprintf(stderr, "%s\n", VERSION);
-}
-
-int main(int argc, char *argv[]) {
-
-    if (argc > 1) {
-        /* parse arguments */
-        int c;
-        while ((c = getopt(argc, argv, "vh")) != -1) {
-            switch (c) {
-                case 'h':
-                    show_usage();
-                    return EXIT_SUCCESS;
-                case 'v':
-                    show_version();
-                    return EXIT_SUCCESS;
-                default:
-                    show_usage();
-                    return EXIT_FAILURE;
-            }
-        }
-        // passed an argument not starting with -
-        if (optind > 1 || argv[optind] != nullptr) {
-            show_usage();
-            return EXIT_FAILURE;
-        }
-    }
-
-    // TODO: code below was copy-and-pasted from bugreport.cpp (except by the timeout value);
-    // should be reused instead.
-
-    // Start the dumpstatez service.
-    property_set("ctl.start", "dumpstatez");
-
-    // Socket will not be available until service starts.
-    int s;
-    for (int i = 0; i < 20; i++) {
-        s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
-        if (s >= 0)
-            break;
-        // Try again in 1 second.
-        sleep(1);
-    }
-
-    if (s == -1) {
-        printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
-        return EXIT_SUCCESS;
-    }
-
-    // Set a timeout so that if nothing is read in 10 minutes, we'll stop
-    // reading and quit. No timeout in dumpstate is longer than 60 seconds,
-    // so this gives lots of leeway in case of unforeseen time outs.
-    struct timeval tv;
-    tv.tv_sec = 10 * 60;
-    tv.tv_usec = 0;
-    if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
-        fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
-    }
-
+int bugreportz(int s, bool show_progress) {
+    std::string line;
     while (1) {
         char buffer[65536];
-        ssize_t bytes_read = TEMP_FAILURE_RETRY(
-                read(s, buffer, sizeof(buffer)));
+        ssize_t bytes_read = TEMP_FAILURE_RETRY(read(s, buffer, sizeof(buffer)));
         if (bytes_read == 0) {
             break;
         } else if (bytes_read == -1) {
@@ -109,21 +58,18 @@
             break;
         }
 
-        ssize_t bytes_to_send = bytes_read;
-        ssize_t bytes_written;
-        do {
-            bytes_written = TEMP_FAILURE_RETRY(
-                    write(STDOUT_FILENO, buffer + bytes_read - bytes_to_send,
-                            bytes_to_send));
-            if (bytes_written == -1) {
-                fprintf(stderr,
-                        "Failed to write data to stdout: read %zd, trying to send %zd (%s)\n",
-                        bytes_read, bytes_to_send, strerror(errno));
-                break;
+        // Writes line by line.
+        for (int i = 0; i < bytes_read; i++) {
+            char c = buffer[i];
+            line.append(1, c);
+            if (c == '\n') {
+                write_line(line, show_progress);
+                line.clear();
             }
-            bytes_to_send -= bytes_written;
-        } while (bytes_written != 0 && bytes_to_send > 0);
+        }
     }
+    // Process final line, in case it didn't finish with newline
+    write_line(line, show_progress);
 
     if (close(s) == -1) {
         fprintf(stderr, "WARNING: error closing socket: %s\n", strerror(errno));
diff --git a/cmds/bugreportz/bugreportz.h b/cmds/bugreportz/bugreportz.h
new file mode 100644
index 0000000..304e4b3
--- /dev/null
+++ b/cmds/bugreportz/bugreportz.h
@@ -0,0 +1,21 @@
+// Copyright 2016 Google Inc. All Rights Reserved.
+//
+// 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 BUGREPORTZ_H
+#define BUGREPORTZ_H
+
+// Calls dumpstate using the given socket and output its result to stdout.
+int bugreportz(int s, bool show_progress);
+
+#endif  // BUGREPORTZ_H
diff --git a/cmds/bugreportz/bugreportz_test.cpp b/cmds/bugreportz/bugreportz_test.cpp
new file mode 100644
index 0000000..58b23d1
--- /dev/null
+++ b/cmds/bugreportz/bugreportz_test.cpp
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) 2016 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 <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+#include <stdio.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <string>
+
+#include "bugreportz.h"
+
+using ::testing::StrEq;
+using ::testing::internal::CaptureStdout;
+using ::testing::internal::GetCapturedStdout;
+
+class BugreportzTest : public ::testing::Test {
+  public:
+    // Creates the pipe used to communicate with bugreportz()
+    void SetUp() {
+        int fds[2];
+        ASSERT_EQ(0, pipe(fds));
+        read_fd_ = fds[0];
+        write_fd_ = fds[1];
+    }
+
+    // Closes the pipe FDs.
+    // If a FD is closed manually during a test, set it to -1 to prevent TearDown() trying to close
+    // it again.
+    void TearDown() {
+        for (int fd : {read_fd_, write_fd_}) {
+            if (fd >= 0) {
+                close(fd);
+            }
+        }
+    }
+
+    // Emulates dumpstate output by writing to the socket passed to bugreportz()
+    void WriteToSocket(const std::string& data) {
+        if (write_fd_ < 0) {
+            ADD_FAILURE() << "cannot write '" << data << "' because socket is already closed";
+            return;
+        }
+        int expected = data.length();
+        int actual = write(write_fd_, data.data(), data.length());
+        ASSERT_EQ(expected, actual) << "wrong number of bytes written to socket";
+    }
+
+    void AssertStdoutEquals(const std::string& expected) {
+        ASSERT_THAT(stdout_, StrEq(expected)) << "wrong stdout output";
+    }
+
+    // Calls bugreportz() using the internal pipe.
+    //
+    // Tests must call WriteToSocket() to set what's written prior to calling it, since the writing
+    // end of the pipe will be closed before calling bugreportz() (otherwise that function would
+    // hang).
+    void Bugreportz(bool show_progress) {
+        close(write_fd_);
+        write_fd_ = -1;
+
+        CaptureStdout();
+        int status = bugreportz(read_fd_, show_progress);
+
+        close(read_fd_);
+        read_fd_ = -1;
+        stdout_ = GetCapturedStdout();
+
+        ASSERT_EQ(0, status) << "bugrepotz() call failed (stdout: " << stdout_ << ")";
+    }
+
+  private:
+    int read_fd_;
+    int write_fd_;
+    std::string stdout_;
+};
+
+// Tests 'bugreportz', without any argument - it will ignore progress lines.
+TEST_F(BugreportzTest, NoArgument) {
+    WriteToSocket("BEGIN:THE IGNORED PATH WARS HAS!\n");  // Should be ommited.
+    WriteToSocket("What happens on 'dumpstate',");
+    WriteToSocket("stays on 'bugreportz'.\n");
+    WriteToSocket("PROGRESS:Y U NO OMITTED?\n");  // Should be ommited.
+    WriteToSocket("But ");
+    WriteToSocket("PROGRESS IN THE MIDDLE");  // Ok - not starting a line.
+    WriteToSocket(" is accepted\n");
+
+    Bugreportz(false);
+
+    AssertStdoutEquals(
+        "What happens on 'dumpstate',stays on 'bugreportz'.\n"
+        "But PROGRESS IN THE MIDDLE is accepted\n");
+}
+
+// Tests 'bugreportz -p' - it will just echo dumpstate's output to stdout
+TEST_F(BugreportzTest, WithProgress) {
+    WriteToSocket("BEGIN:I AM YOUR PATH\n");
+    WriteToSocket("What happens on 'dumpstate',");
+    WriteToSocket("stays on 'bugreportz'.\n");
+    WriteToSocket("PROGRESS:IS INEVITABLE\n");
+    WriteToSocket("PROG");
+    WriteToSocket("RESS:IS NOT AUTOMATIC\n");
+    WriteToSocket("Newline is optional");
+
+    Bugreportz(true);
+
+    AssertStdoutEquals(
+        "BEGIN:I AM YOUR PATH\n"
+        "What happens on 'dumpstate',stays on 'bugreportz'.\n"
+        "PROGRESS:IS INEVITABLE\n"
+        "PROGRESS:IS NOT AUTOMATIC\n"
+        "Newline is optional");
+}
diff --git a/cmds/bugreportz/main.cpp b/cmds/bugreportz/main.cpp
new file mode 100644
index 0000000..a3ae1ff
--- /dev/null
+++ b/cmds/bugreportz/main.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2016 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 <errno.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <cutils/properties.h>
+#include <cutils/sockets.h>
+
+#include "bugreportz.h"
+
+static constexpr char VERSION[] = "1.1";
+
+static void show_usage() {
+    fprintf(stderr,
+            "usage: bugreportz [-h | -v]\n"
+            "  -h: to display this help message\n"
+            "  -p: display progress\n"
+            "  -v: to display the version\n"
+            "  or no arguments to generate a zipped bugreport\n");
+}
+
+static void show_version() {
+    fprintf(stderr, "%s\n", VERSION);
+}
+
+int main(int argc, char* argv[]) {
+    bool show_progress = false;
+    if (argc > 1) {
+        /* parse arguments */
+        int c;
+        while ((c = getopt(argc, argv, "hpv")) != -1) {
+            switch (c) {
+                case 'h':
+                    show_usage();
+                    return EXIT_SUCCESS;
+                case 'p':
+                    show_progress = true;
+                    break;
+                case 'v':
+                    show_version();
+                    return EXIT_SUCCESS;
+                default:
+                    show_usage();
+                    return EXIT_FAILURE;
+            }
+        }
+    }
+
+    // TODO: code below was copy-and-pasted from bugreport.cpp (except by the
+    // timeout value);
+    // should be reused instead.
+
+    // Start the dumpstatez service.
+    property_set("ctl.start", "dumpstatez");
+
+    // Socket will not be available until service starts.
+    int s;
+    for (int i = 0; i < 20; i++) {
+        s = socket_local_client("dumpstate", ANDROID_SOCKET_NAMESPACE_RESERVED, SOCK_STREAM);
+        if (s >= 0) break;
+        // Try again in 1 second.
+        sleep(1);
+    }
+
+    if (s == -1) {
+        printf("FAIL:Failed to connect to dumpstatez service: %s\n", strerror(errno));
+        return EXIT_SUCCESS;
+    }
+
+    // Set a timeout so that if nothing is read in 10 minutes, we'll stop
+    // reading and quit. No timeout in dumpstate is longer than 60 seconds,
+    // so this gives lots of leeway in case of unforeseen time outs.
+    struct timeval tv;
+    tv.tv_sec = 10 * 60;
+    tv.tv_usec = 0;
+    if (setsockopt(s, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)) == -1) {
+        fprintf(stderr, "WARNING: Cannot set socket timeout: %s\n", strerror(errno));
+    }
+
+    bugreportz(s, show_progress);
+}
diff --git a/cmds/bugreportz/readme.md b/cmds/bugreportz/readme.md
index 85aafce..2697f09 100644
--- a/cmds/bugreportz/readme.md
+++ b/cmds/bugreportz/readme.md
@@ -3,6 +3,13 @@
 `bugreportz` is used to generate a zippped bugreport whose path is passed back to `adb`, using
 the simple protocol defined below.
 
+# Version 1.1
+On version 1.1, in addition to the `OK` and `FAILURE` lines, when `bugreportz` is invoked with
+`-p`, it outputs the following lines:
+
+- `BEGIN:<path_to_bugreport_file>` right away.
+- `PROGRESS:<progress>/<total>` as `dumpstate` progresses (where `<progress>` is the current
+progress units out of a max of `<total>`).
 
 ## Version 1.0
 On version 1.0, `bugreportz` does not generate any output on `stdout` until the bugreport is
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 279c010..e9f9e57 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -61,7 +61,7 @@
 static std::unique_ptr<ZipWriter> zip_writer;
 static std::set<std::string> mount_points;
 void add_mountinfo();
-static int control_socket_fd;
+int control_socket_fd = -1;
 /* suffix of the bugreport files - it's typically the date (when invoked with -d),
  * although it could be changed by the user using a system property */
 static std::string suffix;
@@ -1196,6 +1196,7 @@
     if (use_control_socket) {
         MYLOGD("Opening control socket\n");
         control_socket_fd = open_socket("dumpstate");
+        do_update_progress = 1;
     }
 
     /* full path of the temporary file containing the bugreport */
@@ -1269,14 +1270,21 @@
         }
 
         if (do_update_progress) {
-            std::vector<std::string> am_args = {
-                 "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
-                 "--es", "android.intent.extra.NAME", suffix,
-                 "--ei", "android.intent.extra.ID", std::to_string(id),
-                 "--ei", "android.intent.extra.PID", std::to_string(getpid()),
-                 "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
-            };
-            send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
+            if (do_broadcast) {
+                // clang-format off
+                std::vector<std::string> am_args = {
+                     "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
+                     "--es", "android.intent.extra.NAME", suffix,
+                     "--ei", "android.intent.extra.ID", std::to_string(id),
+                     "--ei", "android.intent.extra.PID", std::to_string(getpid()),
+                     "--ei", "android.intent.extra.MAX", std::to_string(WEIGHT_TOTAL),
+                };
+                // clang-format on
+                send_broadcast("android.intent.action.BUGREPORT_STARTED", am_args);
+            }
+            if (use_control_socket) {
+                dprintf(control_socket_fd, "BEGIN:%s\n", path.c_str());
+            }
         }
     }
 
@@ -1459,6 +1467,7 @@
     if (do_broadcast) {
         if (!path.empty()) {
             MYLOGI("Final bugreport path: %s\n", path.c_str());
+            // clang-format off
             std::vector<std::string> am_args = {
                  "--receiver-permission", "android.permission.DUMP", "--receiver-foreground",
                  "--ei", "android.intent.extra.ID", std::to_string(id),
@@ -1467,6 +1476,7 @@
                  "--es", "android.intent.extra.BUGREPORT", path,
                  "--es", "android.intent.extra.DUMPSTATE_LOG", log_path
             };
+            // clang-format on
             if (do_fb) {
                 am_args.push_back("--es");
                 am_args.push_back("android.intent.extra.SCREENSHOT");
@@ -1492,9 +1502,9 @@
         fclose(stderr);
     }
 
-    if (use_control_socket && control_socket_fd >= 0) {
-        MYLOGD("Closing control socket\n");
-        close(control_socket_fd);
+    if (use_control_socket && control_socket_fd != -1) {
+      MYLOGD("Closing control socket\n");
+      close(control_socket_fd);
     }
 
     return 0;
diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h
index 4769974..5e083cc 100644
--- a/cmds/dumpstate/dumpstate.h
+++ b/cmds/dumpstate/dumpstate.h
@@ -79,7 +79,7 @@
  * It would be better to take advantage of the C++ migration and encapsulate the state in an object,
  * but that will be better handled in a major C++ refactoring, which would also get rid of other C
  * idioms (like using std::string instead of char*, removing varargs, etc...) */
-extern int do_update_progress, progress, weight_total;
+extern int do_update_progress, progress, weight_total, control_socket_fd;
 
 /* full path of the directory where the bugreport files will be written */
 extern std::string bugreport_dir;
diff --git a/cmds/dumpstate/utils.cpp b/cmds/dumpstate/utils.cpp
index 3c39129..fd6413d 100644
--- a/cmds/dumpstate/utils.cpp
+++ b/cmds/dumpstate/utils.cpp
@@ -1214,6 +1214,11 @@
         fprintf(stderr, "Setting progress (%s): %s/%d\n", key, value, weight_total);
     }
 
+    if (control_socket_fd >= 0) {
+        dprintf(control_socket_fd, "PROGRESS:%d/%d\n", progress, weight_total);
+        fsync(control_socket_fd);
+    }
+
     int status = property_set(key, value);
     if (status) {
         MYLOGE("Could not update progress by setting system property %s to %s: %d\n",
diff --git a/cmds/dumpsys/dumpsys.cpp b/cmds/dumpsys/dumpsys.cpp
index 957a449..d19e98a 100644
--- a/cmds/dumpsys/dumpsys.cpp
+++ b/cmds/dumpsys/dumpsys.cpp
@@ -274,9 +274,8 @@
             if (N > 1) {
               std::chrono::duration<double> elapsed_seconds =
                   std::chrono::steady_clock::now() - start;
-              aout << StringPrintf("------ %.3fs was the duration of '", elapsed_seconds.count()).
-                  c_str();
-              aout << service_name << "' ------" << endl;
+              aout << StringPrintf("--------- %.3fs ", elapsed_seconds.count()).c_str()
+                   << "was the duration of dumpsys " << service_name << endl;
             }
         } else {
             aerr << "Can't find service: " << service_name << endl;
diff --git a/services/surfaceflinger/Android.mk b/services/surfaceflinger/Android.mk
index 2a8fa4a..dc5e97b 100644
--- a/services/surfaceflinger/Android.mk
+++ b/services/surfaceflinger/Android.mk
@@ -146,6 +146,10 @@
     LOCAL_CFLAGS += -DENABLE_CPUSETS
 endif
 
+ifeq ($(TARGET_USES_HWC2),true)
+    LOCAL_CFLAGS += -DUSE_HWC2
+endif
+
 LOCAL_SRC_FILES := \
     main_surfaceflinger.cpp
 
diff --git a/services/surfaceflinger/DispSync.cpp b/services/surfaceflinger/DispSync.cpp
index 37b6420..c67feb3 100644
--- a/services/surfaceflinger/DispSync.cpp
+++ b/services/surfaceflinger/DispSync.cpp
@@ -383,6 +383,13 @@
         mThread(new DispSyncThread(name)) {
 
     mThread->run("DispSync", PRIORITY_URGENT_DISPLAY + PRIORITY_MORE_FAVORABLE);
+    // set DispSync to SCHED_FIFO to minimize jitter
+    struct sched_param param = {0};
+    param.sched_priority = 1;
+    if (sched_setscheduler(mThread->getTid(), SCHED_FIFO, &param) != 0) {
+        ALOGE("Couldn't set SCHED_FIFO for DispSyncThread");
+    }
+
 
     reset();
     beginResync();
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index e78da96..2b89939 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -559,7 +559,7 @@
 #endif
             activeCrop.clear();
         }
-        activeCrop = s.active.transform.inverse().transform(activeCrop);
+        activeCrop = s.active.transform.inverse().transform(activeCrop, true);
         // This needs to be here as transform.transform(Rect) computes the
         // transformed rect and then takes the bounding box of the result before
         // returning. This means
@@ -732,11 +732,22 @@
     // SolidColor layers
     if (mActiveBuffer == nullptr) {
         setCompositionType(hwcId, HWC2::Composition::SolidColor);
+
+        // For now, we only support black for DimLayer
         error = hwcLayer->setColor({0, 0, 0, 255});
         if (error != HWC2::Error::None) {
             ALOGE("[%s] Failed to set color: %s (%d)", mName.string(),
                     to_string(error).c_str(), static_cast<int32_t>(error));
         }
+
+        // Clear out the transform, because it doesn't make sense absent a
+        // source buffer
+        error = hwcLayer->setTransform(HWC2::Transform::None);
+        if (error != HWC2::Error::None) {
+            ALOGE("[%s] Failed to clear transform: %s (%d)", mName.string(),
+                    to_string(error).c_str(), static_cast<int32_t>(error));
+        }
+
         return;
     }
 
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.cpp b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
index 27357b9..d6a032f 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.cpp
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.cpp
@@ -436,6 +436,13 @@
     return config;
 }
 
+
+void RenderEngine::primeCache() const {
+    // Getting the ProgramCache instance causes it to prime its shader cache,
+    // which is performed in its constructor
+    ProgramCache::getInstance();
+}
+
 // ---------------------------------------------------------------------------
 }; // namespace android
 // ---------------------------------------------------------------------------
diff --git a/services/surfaceflinger/RenderEngine/RenderEngine.h b/services/surfaceflinger/RenderEngine/RenderEngine.h
index 9cc1ed7..0259881 100644
--- a/services/surfaceflinger/RenderEngine/RenderEngine.h
+++ b/services/surfaceflinger/RenderEngine/RenderEngine.h
@@ -63,6 +63,8 @@
 
     static EGLConfig chooseEglConfig(EGLDisplay display, int format);
 
+    void primeCache() const;
+
     // dump the extension strings. always call the base class.
     virtual void dump(String8& result);
 
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index e2bd19f..820c332 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -465,18 +465,13 @@
         mSFEventThread = new EventThread(sfVsyncSrc, *this);
         mEventQueue.setEventThread(mSFEventThread);
 
-        // set EventThread and SFEventThread to SCHED_FIFO for minimum jitter
+        // set SFEventThread to SCHED_FIFO to minimize jitter
         struct sched_param param = {0};
         param.sched_priority = 1;
-        if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-            ALOGE("Couldn't set SCHED_FIFO for EventThread");
-        }
-
         if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
             ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
         }
 
-
         // Get a RenderEngine for the given display / config (can't fail)
         mRenderEngine = RenderEngine::create(mEGLDisplay,
                 HAL_PIXEL_FORMAT_RGBA_8888);
@@ -509,6 +504,8 @@
     // set initial conditions (e.g. unblank default device)
     initializeDisplays();
 
+    mRenderEngine->primeCache();
+
     // start boot animation
     startBootAnim();
 
@@ -2616,6 +2613,7 @@
     }
 
     if (currentMode == HWC_POWER_MODE_OFF) {
+        // Turn on the display
         getHwComposer().setPowerMode(type, mode);
         if (type == DisplayDevice::DISPLAY_PRIMARY) {
             // FIXME: eventthread only knows about the main display right now
@@ -2626,7 +2624,19 @@
         mVisibleRegionsDirty = true;
         mHasPoweredOff = true;
         repaintEverything();
+
+        struct sched_param param = {0};
+        param.sched_priority = 1;
+        if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
+            ALOGW("Couldn't set SCHED_FIFO on display on");
+        }
     } else if (mode == HWC_POWER_MODE_OFF) {
+        // Turn off the display
+        struct sched_param param = {0};
+        if (sched_setscheduler(0, SCHED_OTHER, &param) != 0) {
+            ALOGW("Couldn't set SCHED_OTHER on display off");
+        }
+
         if (type == DisplayDevice::DISPLAY_PRIMARY) {
             disableHardwareVsync(true); // also cancels any in-progress resync
 
diff --git a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
index 6fe2358..34240b4 100644
--- a/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
+++ b/services/surfaceflinger/SurfaceFlinger_hwc1.cpp
@@ -461,13 +461,9 @@
     mSFEventThread = new EventThread(sfVsyncSrc, *this);
     mEventQueue.setEventThread(mSFEventThread);
 
-    // set EventThread and SFEventThread to SCHED_FIFO for minimum jitter
+    // set SFEventThread to SCHED_FIFO to minimize jitter
     struct sched_param param = {0};
     param.sched_priority = 1;
-    if (sched_setscheduler(mEventThread->getTid(), SCHED_FIFO, &param) != 0) {
-        ALOGE("Couldn't set SCHED_FIFO for EventThread");
-    }
-
     if (sched_setscheduler(mSFEventThread->getTid(), SCHED_FIFO, &param) != 0) {
         ALOGE("Couldn't set SCHED_FIFO for SFEventThread");
     }
@@ -538,6 +534,8 @@
     // set initial conditions (e.g. unblank default device)
     initializeDisplays();
 
+    mRenderEngine->primeCache();
+
     // start boot animation
     startBootAnim();
 }
@@ -2532,6 +2530,7 @@
     }
 
     if (currentMode == HWC_POWER_MODE_OFF) {
+        // Turn on the display
         getHwComposer().setPowerMode(type, mode);
         if (type == DisplayDevice::DISPLAY_PRIMARY) {
             // FIXME: eventthread only knows about the main display right now
@@ -2542,7 +2541,19 @@
         mVisibleRegionsDirty = true;
         mHasPoweredOff = true;
         repaintEverything();
+
+        struct sched_param param = {0};
+        param.sched_priority = 1;
+        if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
+            ALOGW("Couldn't set SCHED_FIFO on display on");
+        }
     } else if (mode == HWC_POWER_MODE_OFF) {
+        // Turn off the display
+        struct sched_param param = {0};
+        if (sched_setscheduler(0, SCHED_OTHER, &param) != 0) {
+            ALOGW("Couldn't set SCHED_OTHER on display off");
+        }
+
         if (type == DisplayDevice::DISPLAY_PRIMARY) {
             disableHardwareVsync(true); // also cancels any in-progress resync
 
diff --git a/services/surfaceflinger/Transform.cpp b/services/surfaceflinger/Transform.cpp
index c2be91d..6be9ae2 100644
--- a/services/surfaceflinger/Transform.cpp
+++ b/services/surfaceflinger/Transform.cpp
@@ -196,7 +196,7 @@
     return transform( Rect(w, h) );
 }
 
-Rect Transform::transform(const Rect& bounds) const
+Rect Transform::transform(const Rect& bounds, bool roundOutwards) const
 {
     Rect r;
     vec2 lt( bounds.left,  bounds.top    );
@@ -209,10 +209,17 @@
     lb = transform(lb);
     rb = transform(rb);
 
-    r.left   = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
-    r.top    = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
-    r.right  = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
-    r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
+    if (roundOutwards) {
+        r.left   = floorf(min(lt[0], rt[0], lb[0], rb[0]));
+        r.top    = floorf(min(lt[1], rt[1], lb[1], rb[1]));
+        r.right  = ceilf(max(lt[0], rt[0], lb[0], rb[0]));
+        r.bottom = ceilf(max(lt[1], rt[1], lb[1], rb[1]));
+    } else {
+        r.left   = floorf(min(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
+        r.top    = floorf(min(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
+        r.right  = floorf(max(lt[0], rt[0], lb[0], rb[0]) + 0.5f);
+        r.bottom = floorf(max(lt[1], rt[1], lb[1], rb[1]) + 0.5f);
+    }
 
     return r;
 }
diff --git a/services/surfaceflinger/Transform.h b/services/surfaceflinger/Transform.h
index 90855da..66463a0 100644
--- a/services/surfaceflinger/Transform.h
+++ b/services/surfaceflinger/Transform.h
@@ -78,7 +78,8 @@
             Rect    makeBounds(int w, int h) const;
             vec2    transform(int x, int y) const;
             Region  transform(const Region& reg) const;
-            Rect    transform(const Rect& bounds) const;
+            Rect    transform(const Rect& bounds,
+                    bool roundOutwards = false) const;
             Transform operator * (const Transform& rhs) const;
             // assumes the last row is < 0 , 0 , 1 >
             vec2 transform(const vec2& v) const;
diff --git a/services/surfaceflinger/main_surfaceflinger.cpp b/services/surfaceflinger/main_surfaceflinger.cpp
index 543d0c7..53a63bd 100644
--- a/services/surfaceflinger/main_surfaceflinger.cpp
+++ b/services/surfaceflinger/main_surfaceflinger.cpp
@@ -64,7 +64,7 @@
     sm->addService(String16(GpuService::SERVICE_NAME), gpuservice, false);
 
     struct sched_param param = {0};
-    param.sched_priority = 1;
+    param.sched_priority = 2;
     if (sched_setscheduler(0, SCHED_FIFO, &param) != 0) {
         ALOGE("Couldn't set SCHED_FIFO");
     }