Merge "Add Color Layer to ASurfaceControl"
diff --git a/cmds/dumpstate/DumpstateService.cpp b/cmds/dumpstate/DumpstateService.cpp
index ba9a967..eb0d50d 100644
--- a/cmds/dumpstate/DumpstateService.cpp
+++ b/cmds/dumpstate/DumpstateService.cpp
@@ -44,7 +44,7 @@
 static void* callAndNotify(void* data) {
     Dumpstate& ds = *static_cast<Dumpstate*>(data);
     ds.Run();
-    MYLOGE("Finished Run()\n");
+    MYLOGD("Finished Run()\n");
     return nullptr;
 }
 
@@ -104,9 +104,6 @@
                                                 const android::base::unique_fd& screenshot_fd,
                                                 int bugreport_mode,
                                                 const sp<IDumpstateListener>& listener) {
-    // TODO(b/111441001):
-    // 1. check DUMP permission (again)?
-    // 2. check if primary user? If non primary user the consent service will reject anyway.
     MYLOGI("startBugreport() with mode: %d\n", bugreport_mode);
 
     if (bugreport_mode != Dumpstate::BugreportMode::BUGREPORT_FULL &&
@@ -143,6 +140,14 @@
     return binder::Status::ok();
 }
 
+binder::Status DumpstateService::cancelBugreport() {
+    // This is a no-op since the cancellation is done from java side via setting sys properties.
+    // See BugreportManagerServiceImpl.
+    // TODO(b/111441001): maybe make native and java sides use different binder interface
+    // to avoid these annoyances.
+    return binder::Status::ok();
+}
+
 status_t DumpstateService::dump(int fd, const Vector<String16>&) {
     std::string destination = ds_.options_->bugreport_fd.get() != -1
                                   ? StringPrintf("[fd:%d]", ds_.options_->bugreport_fd.get())
diff --git a/cmds/dumpstate/DumpstateService.h b/cmds/dumpstate/DumpstateService.h
index b6ba32d..faeea53 100644
--- a/cmds/dumpstate/DumpstateService.h
+++ b/cmds/dumpstate/DumpstateService.h
@@ -47,6 +47,9 @@
                                   const android::base::unique_fd& screenshot_fd, int bugreport_mode,
                                   const sp<IDumpstateListener>& listener) override;
 
+    // No-op
+    binder::Status cancelBugreport();
+
   private:
     Dumpstate& ds_;
     std::mutex lock_;
diff --git a/cmds/dumpstate/binder/android/os/IDumpstate.aidl b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
index 2635157..f58535e 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstate.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstate.aidl
@@ -79,4 +79,9 @@
     void startBugreport(int callingUid, @utf8InCpp String callingPackage,
                         FileDescriptor bugreportFd, FileDescriptor screenshotFd,
                         int bugreportMode, IDumpstateListener listener);
+
+    /*
+     * Cancels the bugreport currently in progress.
+     */
+    void cancelBugreport();
 }
diff --git a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
index bcd0cb7..8396acd 100644
--- a/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
+++ b/cmds/dumpstate/binder/android/os/IDumpstateListener.aidl
@@ -44,14 +44,9 @@
     oneway void onError(int errorCode);
 
     /**
-     * Called when taking bugreport finishes successfully
-     *
-     * @param durationMs time capturing bugreport took in milliseconds
-     * @param title title for the bugreport; helpful in reminding the user why they took it
-     * @param description detailed description for the bugreport
+     * Called when taking bugreport finishes successfully.
      */
-     oneway void onFinished(long durationMs, @utf8InCpp String title,
-                            @utf8InCpp String description);
+     oneway void onFinished();
 
     // TODO(b/111441001): Remove old methods when not used anymore.
     void onProgressUpdated(int progress);
diff --git a/cmds/dumpstate/dumpstate.cpp b/cmds/dumpstate/dumpstate.cpp
index 4634ecd..7958865 100644
--- a/cmds/dumpstate/dumpstate.cpp
+++ b/cmds/dumpstate/dumpstate.cpp
@@ -1660,6 +1660,7 @@
             "progress (requires -o and -B)\n"
             "  -R: take bugreport in remote mode (requires -o, -z, -d and -B, "
             "shouldn't be used with -P)\n"
+            "  -w: start binder service and make it wait for a call to startBugreport\n"
             "  -v: prints the dumpstate header and exit\n");
 }
 
@@ -2118,7 +2119,7 @@
 Dumpstate::RunStatus Dumpstate::DumpOptions::Initialize(int argc, char* argv[]) {
     RunStatus status = RunStatus::OK;
     int c;
-    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:")) != -1) {
+    while ((c = getopt(argc, argv, "dho:svqzpPBRSV:w")) != -1) {
         switch (c) {
             // clang-format off
             case 'd': do_add_date = true;            break;
@@ -2135,6 +2136,9 @@
             case 'R': is_remote_mode = true;         break;
             case 'B': do_broadcast = true;           break;
             case 'V':                                break;  // compatibility no-op
+            case 'w':
+                // This was already processed
+                break;
             case 'h':
                 status = RunStatus::HELP;
                 break;
@@ -2193,9 +2197,7 @@
     if (listener_ != nullptr) {
         switch (status) {
             case Dumpstate::RunStatus::OK:
-                // TODO(b/111441001): duration argument does not make sense. Remove.
-                listener_->onFinished(0 /* duration */, options_->notification_title,
-                                      options_->notification_description);
+                listener_->onFinished();
                 break;
             case Dumpstate::RunStatus::HELP:
                 break;
diff --git a/cmds/dumpstate/dumpstate.rc b/cmds/dumpstate/dumpstate.rc
index 2e72574..14937b8 100644
--- a/cmds/dumpstate/dumpstate.rc
+++ b/cmds/dumpstate/dumpstate.rc
@@ -17,3 +17,9 @@
     class main
     disabled
     oneshot
+
+# bugreportd starts dumpstate binder service and makes it wait for a listener to connect.
+service bugreportd /system/bin/dumpstate -w
+    class main
+    disabled
+    oneshot
diff --git a/cmds/dumpstate/main.cpp b/cmds/dumpstate/main.cpp
index 78aad11..68d3733 100644
--- a/cmds/dumpstate/main.cpp
+++ b/cmds/dumpstate/main.cpp
@@ -14,8 +14,55 @@
  * limitations under the License.
  */
 
+#define LOG_TAG "dumpstate"
+
+#include <binder/IPCThreadState.h>
+
+#include "DumpstateInternal.h"
+#include "DumpstateService.h"
 #include "dumpstate.h"
 
+namespace {
+
+// Returns true if we should start the service and wait for a listener
+// to bind with bugreport options.
+bool ShouldStartServiceAndWait(int argc, char* argv[]) {
+    bool do_wait = false;
+    int c;
+    // Keep flags in sync with Dumpstate::DumpOptions::Initialize.
+    while ((c = getopt(argc, argv, "wdho:svqzpPBRSV:")) != -1 && !do_wait) {
+        switch (c) {
+            case 'w':
+                do_wait = true;
+                break;
+            default:
+                // Ignore all other options
+                break;
+        }
+    }
+
+    // Reset next index used by getopt so getopt can be called called again in Dumpstate::Run to
+    // parse bugreport options.
+    optind = 1;
+    return do_wait;
+}
+
+}  // namespace
+
 int main(int argc, char* argv[]) {
-    return run_main(argc, argv);
+    if (ShouldStartServiceAndWait(argc, argv)) {
+        int ret;
+        if ((ret = android::os::DumpstateService::Start()) != android::OK) {
+            MYLOGE("Unable to start 'dumpstate' service: %d", ret);
+            exit(1);
+        }
+        MYLOGI("'dumpstate' service started and will wait for a call to startBugreport()");
+
+        // Waits forever for an incoming connection.
+        // TODO(b/111441001): should this time out?
+        android::IPCThreadState::self()->joinThreadPool();
+        return 0;
+    } else {
+        return run_main(argc, argv);
+    }
 }
diff --git a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
index c57775f..570c6c9 100644
--- a/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_smoke_test.cpp
@@ -61,9 +61,8 @@
         dprintf(outFd_, "\rError %d", error_code);
         return binder::Status::ok();
     }
-    binder::Status onFinished(int64_t duration_ms, const ::std::string&,
-                              const ::std::string&) override {
-        dprintf(outFd_, "\rFinished in %lld", (long long) duration_ms);
+    binder::Status onFinished() override {
+        dprintf(outFd_, "\rFinished");
         return binder::Status::ok();
     }
     binder::Status onProgressUpdated(int32_t progress) override {
diff --git a/cmds/dumpstate/tests/dumpstate_test.cpp b/cmds/dumpstate/tests/dumpstate_test.cpp
index 0302c46..eb73d41 100644
--- a/cmds/dumpstate/tests/dumpstate_test.cpp
+++ b/cmds/dumpstate/tests/dumpstate_test.cpp
@@ -61,8 +61,7 @@
   public:
     MOCK_METHOD1(onProgress, binder::Status(int32_t progress));
     MOCK_METHOD1(onError, binder::Status(int32_t error_code));
-    MOCK_METHOD3(onFinished, binder::Status(int64_t duration_ms, const ::std::string& title,
-                                            const ::std::string& description));
+    MOCK_METHOD0(onFinished, binder::Status());
     MOCK_METHOD1(onProgressUpdated, binder::Status(int32_t progress));
     MOCK_METHOD1(onMaxProgressUpdated, binder::Status(int32_t max_progress));
     MOCK_METHOD4(onSectionComplete, binder::Status(const ::std::string& name, int32_t status,
diff --git a/data/etc/android.software.secure_lock_screen.xml b/data/etc/android.software.secure_lock_screen.xml
new file mode 100644
index 0000000..3464487
--- /dev/null
+++ b/data/etc/android.software.secure_lock_screen.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2019 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.secure_lock_screen" />
+</permissions>
diff --git a/data/etc/car_core_hardware.xml b/data/etc/car_core_hardware.xml
index d6021c0..6cbe4ae 100644
--- a/data/etc/car_core_hardware.xml
+++ b/data/etc/car_core_hardware.xml
@@ -45,6 +45,7 @@
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/go_handheld_core_hardware.xml b/data/etc/go_handheld_core_hardware.xml
index 8b5a461..915e579 100644
--- a/data/etc/go_handheld_core_hardware.xml
+++ b/data/etc/go_handheld_core_hardware.xml
@@ -43,6 +43,7 @@
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/handheld_core_hardware.xml b/data/etc/handheld_core_hardware.xml
index 060a334..619d017 100644
--- a/data/etc/handheld_core_hardware.xml
+++ b/data/etc/handheld_core_hardware.xml
@@ -51,6 +51,7 @@
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/tablet_core_hardware.xml b/data/etc/tablet_core_hardware.xml
index 6db2627..52524ca 100644
--- a/data/etc/tablet_core_hardware.xml
+++ b/data/etc/tablet_core_hardware.xml
@@ -51,6 +51,7 @@
     <feature name="android.software.companion_device_setup" />
     <feature name="android.software.autofill" />
     <feature name="android.software.cant_save_state" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- Feature to specify if the device supports adding device admins. -->
     <feature name="android.software.device_admin" />
diff --git a/data/etc/wearable_core_hardware.xml b/data/etc/wearable_core_hardware.xml
index e2ab71a..0f364c1 100644
--- a/data/etc/wearable_core_hardware.xml
+++ b/data/etc/wearable_core_hardware.xml
@@ -35,6 +35,7 @@
 
     <!-- basic system services -->
     <feature name="android.software.home_screen" />
+    <feature name="android.software.secure_lock_screen" />
 
     <!-- input management and third-party input method editors -->
     <feature name="android.software.input_methods" />
diff --git a/libs/cputimeinstate/Android.bp b/libs/cputimeinstate/Android.bp
new file mode 100644
index 0000000..28cb138
--- /dev/null
+++ b/libs/cputimeinstate/Android.bp
@@ -0,0 +1,30 @@
+cc_library {
+    name: "libtimeinstate",
+    srcs: ["cputimeinstate.cpp"],
+    shared_libs: [
+        "libbase",
+        "libbpf",
+        "libbpf_android",
+        "liblog",
+        "libnetdutils"
+    ],
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wextra",
+    ],
+}
+
+cc_test {
+    name: "libtimeinstate_test",
+    srcs: ["testtimeinstate.cpp"],
+    shared_libs: [
+        "libtimeinstate",
+    ],
+    cflags: [
+        "-Werror",
+        "-Wall",
+        "-Wextra",
+    ],
+}
+
diff --git a/libs/cputimeinstate/cputimeinstate.cpp b/libs/cputimeinstate/cputimeinstate.cpp
new file mode 100644
index 0000000..4cddf94
--- /dev/null
+++ b/libs/cputimeinstate/cputimeinstate.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2019 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.
+ */
+
+#define LOG_TAG "libtimeinstate"
+
+#include "cputimeinstate.h"
+
+#include <dirent.h>
+#include <errno.h>
+#include <inttypes.h>
+
+#include <mutex>
+#include <set>
+#include <string>
+#include <unordered_map>
+#include <vector>
+
+#include <android-base/file.h>
+#include <android-base/parseint.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <bpf/BpfMap.h>
+#include <libbpf.h>
+#include <log/log.h>
+
+#define BPF_FS_PATH "/sys/fs/bpf/"
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+namespace android {
+namespace bpf {
+
+typedef struct {
+    uint32_t uid;
+    uint32_t freq;
+} time_key_t;
+
+typedef struct {
+    uint64_t ar[100];
+} val_t;
+
+static std::mutex gInitializedMutex;
+static bool gInitialized = false;
+static uint32_t gNPolicies = 0;
+static std::vector<std::vector<uint32_t>> gPolicyFreqs;
+static std::vector<std::vector<uint32_t>> gPolicyCpus;
+static std::set<uint32_t> gAllFreqs;
+static unique_fd gMapFd;
+
+static bool readNumbersFromFile(const std::string &path, std::vector<uint32_t> *out) {
+    std::string data;
+
+    if (!android::base::ReadFileToString(path, &data)) {
+        ALOGD("Failed to read file %s", path.c_str());
+        return false;
+    }
+
+    auto strings = android::base::Split(data, " \n");
+    for (const auto &s : strings) {
+        if (s.empty()) continue;
+        uint32_t n;
+        if (!android::base::ParseUint(s, &n)) {
+            ALOGD("Failed to parse file %s", path.c_str());
+            return false;
+        }
+        out->emplace_back(n);
+    }
+    return true;
+}
+
+static int isPolicyFile(const struct dirent *d) {
+    return android::base::StartsWith(d->d_name, "policy");
+}
+
+static int comparePolicyFiles(const struct dirent **d1, const struct dirent **d2) {
+    uint32_t policyN1, policyN2;
+    if (sscanf((*d1)->d_name, "policy%" SCNu32 "", &policyN1) != 1 ||
+        sscanf((*d2)->d_name, "policy%" SCNu32 "", &policyN2) != 1)
+        return 0;
+    return policyN1 - policyN2;
+}
+
+static bool initGlobals() {
+    std::lock_guard<std::mutex> guard(gInitializedMutex);
+    if (gInitialized) return true;
+
+    struct dirent **dirlist;
+    const char basepath[] = "/sys/devices/system/cpu/cpufreq";
+    int ret = scandir(basepath, &dirlist, isPolicyFile, comparePolicyFiles);
+    if (ret == -1) return false;
+    gNPolicies = ret;
+
+    std::vector<std::string> policyFileNames;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        policyFileNames.emplace_back(dirlist[i]->d_name);
+        free(dirlist[i]);
+    }
+    free(dirlist);
+
+    for (const auto &policy : policyFileNames) {
+        std::vector<uint32_t> freqs;
+        for (const auto &name : {"available", "boost"}) {
+            std::string path =
+                    StringPrintf("%s/%s/scaling_%s_frequencies", basepath, policy.c_str(), name);
+            if (!readNumbersFromFile(path, &freqs)) return false;
+        }
+        std::sort(freqs.begin(), freqs.end());
+        gPolicyFreqs.emplace_back(freqs);
+
+        for (auto freq : freqs) gAllFreqs.insert(freq);
+
+        std::vector<uint32_t> cpus;
+        std::string path = StringPrintf("%s/%s/%s", basepath, policy.c_str(), "related_cpus");
+        if (!readNumbersFromFile(path, &cpus)) return false;
+        gPolicyCpus.emplace_back(cpus);
+    }
+
+    gMapFd = unique_fd{bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times")};
+    if (gMapFd < 0) return false;
+
+    gInitialized = true;
+    return true;
+}
+
+static bool attachTracepointProgram(const std::string &eventType, const std::string &eventName) {
+    std::string path = StringPrintf(BPF_FS_PATH "prog_time_in_state_tracepoint_%s_%s",
+                                    eventType.c_str(), eventName.c_str());
+    int prog_fd = bpf_obj_get(path.c_str());
+    if (prog_fd < 0) {
+        ALOGD("bpf_obj_get() failed for program %s", path.c_str());
+        return false;
+    }
+    if (bpf_attach_tracepoint(prog_fd, eventType.c_str(), eventName.c_str()) < 0) {
+        ALOGD("Failed to attach bpf program to tracepoint %s/%s", eventType.c_str(),
+              eventName.c_str());
+        return false;
+    }
+    return true;
+}
+
+// Start tracking and aggregating data to be reported by getUidCpuFreqTimes and getUidsCpuFreqTimes.
+// Returns true on success, false otherwise.
+// Tracking is active only once a live process has successfully called this function; if the calling
+// process dies then it must be called again to resume tracking.
+// This function should *not* be called while tracking is already active; doing so is unnecessary
+// and can lead to accounting errors.
+bool startTrackingUidCpuFreqTimes() {
+    return attachTracepointProgram("sched", "sched_switch") &&
+            attachTracepointProgram("power", "cpu_frequency");
+}
+
+// Retrieve the times in ns that uid spent running at each CPU frequency and store in freqTimes.
+// Returns false on error. Otherwise, returns true and populates freqTimes with a vector of vectors
+// using the format:
+// [[t0_0, t0_1, ...],
+//  [t1_0, t1_1, ...], ...]
+// where ti_j is the ns that uid spent running on the ith cluster at that cluster's jth lowest freq.
+bool getUidCpuFreqTimes(uint32_t uid, std::vector<std::vector<uint64_t>> *freqTimes) {
+    if (!gInitialized && !initGlobals()) return false;
+    time_key_t key = {.uid = uid, .freq = 0};
+
+    freqTimes->clear();
+    freqTimes->resize(gNPolicies);
+    std::vector<uint32_t> idxs(gNPolicies, 0);
+
+    val_t value;
+    for (uint32_t freq : gAllFreqs) {
+        key.freq = freq;
+        int ret = findMapEntry(gMapFd, &key, &value);
+        if (ret) {
+            if (errno == ENOENT)
+                memset(&value.ar, 0, sizeof(value.ar));
+            else
+                return false;
+        }
+        for (uint32_t i = 0; i < gNPolicies; ++i) {
+            if (idxs[i] == gPolicyFreqs[i].size() || freq != gPolicyFreqs[i][idxs[i]]) continue;
+            uint64_t time = 0;
+            for (uint32_t cpu : gPolicyCpus[i]) time += value.ar[cpu];
+            idxs[i] += 1;
+            (*freqTimes)[i].emplace_back(time);
+        }
+    }
+
+    return true;
+}
+
+// Retrieve the times in ns that each uid spent running at each CPU freq and store in freqTimeMap.
+// Returns false on error. Otherwise, returns true and populates freqTimeMap with a map from uids to
+// vectors of vectors using the format:
+// { uid0 -> [[t0_0_0, t0_0_1, ...], [t0_1_0, t0_1_1, ...], ...],
+//   uid1 -> [[t1_0_0, t1_0_1, ...], [t1_1_0, t1_1_1, ...], ...], ... }
+// where ti_j_k is the ns uid i spent running on the jth cluster at the cluster's kth lowest freq.
+bool getUidsCpuFreqTimes(
+        std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *freqTimeMap) {
+    if (!gInitialized && !initGlobals()) return false;
+
+    int fd = bpf_obj_get(BPF_FS_PATH "map_time_in_state_uid_times");
+    if (fd < 0) return false;
+    BpfMap<time_key_t, val_t> m(fd);
+
+    std::vector<std::unordered_map<uint32_t, uint32_t>> policyFreqIdxs;
+    for (uint32_t i = 0; i < gNPolicies; ++i) {
+        std::unordered_map<uint32_t, uint32_t> freqIdxs;
+        for (size_t j = 0; j < gPolicyFreqs[i].size(); ++j) freqIdxs[gPolicyFreqs[i][j]] = j;
+        policyFreqIdxs.emplace_back(freqIdxs);
+    }
+
+    auto fn = [freqTimeMap, &policyFreqIdxs](const time_key_t &key, const val_t &val,
+                                             const BpfMap<time_key_t, val_t> &) {
+        if (freqTimeMap->find(key.uid) == freqTimeMap->end()) {
+            std::vector<std::vector<uint64_t>> v;
+            for (uint32_t i = 0; i < gNPolicies; ++i) {
+                std::vector<uint64_t> v2(gPolicyFreqs[i].size(), 0);
+                v.emplace_back(v2);
+            }
+            (*freqTimeMap)[key.uid] = v;
+        }
+
+        for (size_t policy = 0; policy < gNPolicies; ++policy) {
+            for (const auto &cpu : gPolicyCpus[policy]) {
+                uint32_t cpuTime = val.ar[cpu];
+                if (cpuTime == 0) continue;
+                auto freqIdx = policyFreqIdxs[policy][key.freq];
+                (*freqTimeMap)[key.uid][policy][freqIdx] += cpuTime;
+            }
+        }
+        return android::netdutils::status::ok;
+    };
+    return isOk(m.iterateWithValue(fn));
+}
+
+// Clear all time in state data for a given uid. Returns false on error, true otherwise.
+bool clearUidCpuFreqTimes(uint32_t uid) {
+    if (!gInitialized && !initGlobals()) return false;
+    time_key_t key = {.uid = uid, .freq = 0};
+
+    std::vector<uint32_t> idxs(gNPolicies, 0);
+    for (auto freq : gAllFreqs) {
+        key.freq = freq;
+        if (deleteMapEntry(gMapFd, &key) && errno != ENOENT) return false;
+    }
+    return true;
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/libs/cputimeinstate/cputimeinstate.h b/libs/cputimeinstate/cputimeinstate.h
new file mode 100644
index 0000000..0205452
--- /dev/null
+++ b/libs/cputimeinstate/cputimeinstate.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 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 <unordered_map>
+#include <vector>
+
+namespace android {
+namespace bpf {
+
+bool startTrackingUidCpuFreqTimes();
+bool getUidCpuFreqTimes(unsigned int uid, std::vector<std::vector<uint64_t>> *freqTimes);
+bool getUidsCpuFreqTimes(std::unordered_map<uint32_t, std::vector<std::vector<uint64_t>>> *tisMap);
+bool clearUidCpuFreqTimes(unsigned int uid);
+
+} // namespace bpf
+} // namespace android
diff --git a/libs/cputimeinstate/testtimeinstate.cpp b/libs/cputimeinstate/testtimeinstate.cpp
new file mode 100644
index 0000000..9837865
--- /dev/null
+++ b/libs/cputimeinstate/testtimeinstate.cpp
@@ -0,0 +1,58 @@
+
+#include <unordered_map>
+#include <vector>
+
+#include <gtest/gtest.h>
+
+#include <cputimeinstate.h>
+
+namespace android {
+namespace bpf {
+
+using std::vector;
+
+TEST(TimeInStateTest, SingleUid) {
+    vector<vector<uint64_t>> times;
+    ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
+    EXPECT_FALSE(times.empty());
+}
+
+TEST(TimeInStateTest, AllUid) {
+    vector<size_t> sizes;
+    std::unordered_map<uint32_t, vector<vector<uint64_t>>> map;
+    ASSERT_TRUE(getUidsCpuFreqTimes(&map));
+
+    ASSERT_FALSE(map.empty());
+
+    auto firstEntry = map.begin()->second;
+    for (const auto &subEntry : firstEntry) sizes.emplace_back(subEntry.size());
+
+    for (const auto &vec : map) {
+        ASSERT_EQ(vec.second.size(), sizes.size());
+        for (size_t i = 0; i < vec.second.size(); ++i) ASSERT_EQ(vec.second[i].size(), sizes[i]);
+    }
+}
+
+TEST(TimeInStateTest, RemoveUid) {
+    vector<vector<uint64_t>> times, times2;
+    ASSERT_TRUE(getUidCpuFreqTimes(0, &times));
+    ASSERT_FALSE(times.empty());
+
+    uint64_t sum = 0;
+    for (size_t i = 0; i < times.size(); ++i) {
+        for (auto x : times[i]) sum += x;
+    }
+    ASSERT_GT(sum, (uint64_t)0);
+
+    ASSERT_TRUE(clearUidCpuFreqTimes(0));
+
+    ASSERT_TRUE(getUidCpuFreqTimes(0, &times2));
+    ASSERT_EQ(times2.size(), times.size());
+    for (size_t i = 0; i < times.size(); ++i) {
+        ASSERT_EQ(times2[i].size(), times[i].size());
+        for (size_t j = 0; j < times[i].size(); ++j) ASSERT_LE(times2[i][j], times[i][j]);
+    }
+}
+
+} // namespace bpf
+} // namespace android
diff --git a/libs/gui/SurfaceComposerClient.cpp b/libs/gui/SurfaceComposerClient.cpp
index 7cc0ee5..6c1c52e 100644
--- a/libs/gui/SurfaceComposerClient.cpp
+++ b/libs/gui/SurfaceComposerClient.cpp
@@ -102,6 +102,27 @@
     mDeathObserver = nullptr;
 }
 
+class DefaultComposerClient: public Singleton<DefaultComposerClient> {
+    Mutex mLock;
+    sp<SurfaceComposerClient> mClient;
+    friend class Singleton<ComposerService>;
+public:
+    static sp<SurfaceComposerClient> getComposerClient() {
+        DefaultComposerClient& dc = DefaultComposerClient::getInstance();
+        Mutex::Autolock _l(dc.mLock);
+        if (dc.mClient == nullptr) {
+            dc.mClient = new SurfaceComposerClient;
+        }
+        return dc.mClient;
+    }
+};
+ANDROID_SINGLETON_STATIC_INSTANCE(DefaultComposerClient);
+
+
+sp<SurfaceComposerClient> SurfaceComposerClient::getDefault() {
+    return DefaultComposerClient::getComposerClient();
+}
+
 // ---------------------------------------------------------------------------
 
 // TransactionCompletedListener does not use ANDROID_SINGLETON_STATIC_INSTANCE because it needs
@@ -959,6 +980,54 @@
     return *this;
 }
 
+SurfaceComposerClient::Transaction& SurfaceComposerClient::Transaction::setGeometry(
+        const sp<SurfaceControl>& sc, const Rect& source, const Rect& dst, int transform) {
+    setCrop_legacy(sc, source);
+
+    int x = dst.left;
+    int y = dst.top;
+    float xScale = dst.getWidth() / static_cast<float>(source.getWidth());
+    float yScale = dst.getHeight() / static_cast<float>(source.getHeight());
+    float matrix[4] = {1, 0, 0, 1};
+
+    switch (transform) {
+        case NATIVE_WINDOW_TRANSFORM_FLIP_H:
+            matrix[0] = -xScale; matrix[1] = 0;
+            matrix[2] = 0; matrix[3] = yScale;
+            x += source.getWidth();
+            break;
+        case NATIVE_WINDOW_TRANSFORM_FLIP_V:
+            matrix[0] = xScale; matrix[1] = 0;
+            matrix[2] = 0; matrix[3] = -yScale;
+            y += source.getHeight();
+            break;
+        case NATIVE_WINDOW_TRANSFORM_ROT_90:
+            matrix[0] = 0; matrix[1] = -yScale;
+            matrix[2] = xScale; matrix[3] = 0;
+            x += source.getHeight();
+            break;
+        case NATIVE_WINDOW_TRANSFORM_ROT_180:
+            matrix[0] = -xScale; matrix[1] = 0;
+            matrix[2] = 0; matrix[3] = -yScale;
+            x += source.getWidth();
+            y += source.getHeight();
+            break;
+        case NATIVE_WINDOW_TRANSFORM_ROT_270:
+            matrix[0] = 0; matrix[1] = yScale;
+            matrix[2] = -xScale; matrix[3] = 0;
+            y += source.getWidth();
+            break;
+        default:
+            matrix[0] = xScale; matrix[1] = 0;
+            matrix[2] = 0; matrix[3] = yScale;
+            break;
+    }
+    setMatrix(sc, matrix[0], matrix[1], matrix[2], matrix[3]);
+    setPosition(sc, x, y);
+
+    return *this;
+}
+
 // ---------------------------------------------------------------------------
 
 DisplayState& SurfaceComposerClient::Transaction::getDisplayState(const sp<IBinder>& token) {
diff --git a/libs/gui/include/gui/SurfaceComposerClient.h b/libs/gui/include/gui/SurfaceComposerClient.h
index 2563351..24b656b 100644
--- a/libs/gui/include/gui/SurfaceComposerClient.h
+++ b/libs/gui/include/gui/SurfaceComposerClient.h
@@ -156,6 +156,8 @@
     // ------------------------------------------------------------------------
     // surface creation / destruction
 
+    static sp<SurfaceComposerClient> getDefault();
+
     //! Create a surface
     sp<SurfaceControl> createSurface(
             const String8& name,// name of the surface
@@ -382,6 +384,9 @@
         Transaction& setColorTransform(const sp<SurfaceControl>& sc, const mat3& matrix,
                                        const vec3& translation);
 
+        Transaction& setGeometry(const sp<SurfaceControl>& sc,
+                const Rect& source, const Rect& dst, int transform);
+
         status_t setDisplaySurface(const sp<IBinder>& token,
                 const sp<IGraphicBufferProducer>& bufferProducer);
 
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index f57bf9c..c5a9942 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -608,7 +608,17 @@
 }
 
 status_t GLESRenderEngine::bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer,
-                                                     sp<Fence> bufferFence) {
+                                                     sp<Fence> bufferFence, bool readCache,
+                                                     bool persistCache) {
+    if (readCache) {
+        auto cachedImage = mImageCache.find(buffer->getId());
+
+        if (cachedImage != mImageCache.end()) {
+            bindExternalTextureImage(texName, *cachedImage->second);
+            return NO_ERROR;
+        }
+    }
+
     std::unique_ptr<Image> newImage = createImage();
 
     bool created = newImage->setNativeWindowBuffer(buffer->getNativeBuffer(),
@@ -644,9 +654,35 @@
         }
     }
 
+    // We don't always want to persist to the cache, e.g. on older devices we
+    // might bind for synchronization purpoeses, but that might leak if we never
+    // call drawLayers again, so it's just better to recreate the image again
+    // if needed when we draw.
+    if (persistCache) {
+        mImageCache.insert(std::make_pair(buffer->getId(), std::move(newImage)));
+    }
+
     return NO_ERROR;
 }
 
+void GLESRenderEngine::evictImages(const std::vector<LayerSettings>& layers) {
+    // destroy old image references that we're not going to draw with.
+    std::unordered_set<uint64_t> bufIds;
+    for (auto layer : layers) {
+        if (layer.source.buffer.buffer != nullptr) {
+            bufIds.emplace(layer.source.buffer.buffer->getId());
+        }
+    }
+
+    for (auto it = mImageCache.begin(); it != mImageCache.end();) {
+        if (bufIds.count(it->first) == 0) {
+            it = mImageCache.erase(it);
+        } else {
+            it++;
+        }
+    }
+}
+
 FloatRect GLESRenderEngine::setupLayerCropping(const LayerSettings& layer, Mesh& mesh) {
     // Translate win by the rounded corners rect coordinates, to have all values in
     // layer coordinate space.
@@ -748,6 +784,8 @@
         return fbo.getStatus();
     }
 
+    evictImages(layers);
+
     setViewportAndProjection(display.physicalDisplay, display.clip);
 
     setOutputDataSpace(display.outputDataspace);
@@ -781,8 +819,9 @@
 
             sp<GraphicBuffer> gBuf = layer.source.buffer.buffer;
 
+            bool readCache = layer.source.buffer.cacheHint == Buffer::CachingHint::USE_CACHE;
             bindExternalTextureBuffer(layer.source.buffer.textureName, gBuf,
-                                      layer.source.buffer.fence);
+                                      layer.source.buffer.fence, readCache, /*persistCache=*/true);
 
             usePremultipliedAlpha = layer.source.buffer.usePremultipliedAlpha;
             Texture texture(Texture::TEXTURE_EXTERNAL, layer.source.buffer.textureName);
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index b596242..e094860 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -30,6 +30,7 @@
 #include <GLES2/gl2.h>
 #include <renderengine/RenderEngine.h>
 #include <renderengine/private/Description.h>
+#include <unordered_map>
 
 #define EGL_NO_CONFIG ((EGLConfig)0)
 
@@ -133,7 +134,10 @@
     // Defines the viewport, and sets the projection matrix to the projection
     // defined by the clip.
     void setViewportAndProjection(Rect viewport, Rect clip);
-    status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence);
+    status_t bindExternalTextureBuffer(uint32_t texName, sp<GraphicBuffer> buffer, sp<Fence> fence,
+                                       bool readCache, bool persistCache);
+    // Evicts stale images from the buffer cache.
+    void evictImages(const std::vector<LayerSettings>& layers);
     // Computes the cropping window for the layer and sets up cropping
     // coordinates for the mesh.
     FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh);
@@ -179,6 +183,9 @@
     // supports sRGB, DisplayP3 color spaces.
     const bool mUseColorManagement = false;
 
+    // Cache of GL images that we'll store per GraphicBuffer ID
+    std::unordered_map<uint64_t, std::unique_ptr<Image>> mImageCache;
+
     class FlushTracer {
     public:
         FlushTracer(GLESRenderEngine* engine);
diff --git a/libs/renderengine/include/renderengine/LayerSettings.h b/libs/renderengine/include/renderengine/LayerSettings.h
index 4d53205..56ac714 100644
--- a/libs/renderengine/include/renderengine/LayerSettings.h
+++ b/libs/renderengine/include/renderengine/LayerSettings.h
@@ -32,6 +32,16 @@
 
 // Metadata describing the input buffer to render from.
 struct Buffer {
+    // Hint for whether to use the Image cache or not.
+    // If NO_CACHE is specified, then upload the contents of the GraphicBuffer
+    // to the GPU, without checking against any implementation defined cache.
+    // If USE_CACHE is specified, then check against an implementation defined
+    // cache first. If there is an Image cached for the given GraphicBuffer id,
+    // then use that instead of the provided buffer contents. If there is no
+    // cached image or the RenderEngine implementation does not support caching,
+    // then use the GraphicBuffer contents.
+    enum class CachingHint { NO_CACHE, USE_CACHE };
+
     // Buffer containing the image that we will render.
     // If buffer == nullptr, then the rest of the fields in this struct will be
     // ignored.
@@ -40,6 +50,9 @@
     // Fence that will fire when the buffer is ready to be bound.
     sp<Fence> fence = nullptr;
 
+    // Caching hint to use when uploading buffer contents.
+    CachingHint cacheHint = CachingHint::NO_CACHE;
+
     // Texture identifier to bind the external texture to.
     // TODO(alecmouri): This is GL-specific...make the type backend-agnostic.
     uint32_t textureName = 0;
diff --git a/libs/ui/Gralloc2.cpp b/libs/ui/Gralloc2.cpp
index ea7321e..2c4b5f3 100644
--- a/libs/ui/Gralloc2.cpp
+++ b/libs/ui/Gralloc2.cpp
@@ -227,7 +227,14 @@
 }
 
 status_t Gralloc2Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
-                              int acquireFence, void** outData) const {
+                              int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                              int32_t* outBytesPerStride) const {
+    if (outBytesPerPixel) {
+        *outBytesPerPixel = -1;
+    }
+    if (outBytesPerStride) {
+        *outBytesPerStride = -1;
+    }
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
 
     IMapper::Rect accessRegion = sGralloc2Rect(bounds);
diff --git a/libs/ui/Gralloc3.cpp b/libs/ui/Gralloc3.cpp
index 128200e..acb6b01 100644
--- a/libs/ui/Gralloc3.cpp
+++ b/libs/ui/Gralloc3.cpp
@@ -192,7 +192,8 @@
 }
 
 status_t Gralloc3Mapper::lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
-                              int acquireFence, void** outData) const {
+                              int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                              int32_t* outBytesPerStride) const {
     auto buffer = const_cast<native_handle_t*>(bufferHandle);
 
     IMapper::Rect accessRegion = sGralloc3Rect(bounds);
@@ -208,12 +209,19 @@
 
     Error error;
     auto ret = mMapper->lock(buffer, usage, accessRegion, acquireFenceHandle,
-                             [&](const auto& tmpError, const auto& tmpData) {
+                             [&](const auto& tmpError, const auto& tmpData,
+                                 const auto& tmpBytesPerPixel, const auto& tmpBytesPerStride) {
                                  error = tmpError;
                                  if (error != Error::NONE) {
                                      return;
                                  }
                                  *outData = tmpData;
+                                 if (outBytesPerPixel) {
+                                     *outBytesPerPixel = tmpBytesPerPixel;
+                                 }
+                                 if (outBytesPerStride) {
+                                     *outBytesPerStride = tmpBytesPerStride;
+                                 }
                              });
 
     // we own acquireFence even on errors
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index f408fcb..da24cf1 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -252,7 +252,10 @@
                 width, height);
         return BAD_VALUE;
     }
-    status_t res = getBufferMapper().lock(handle, inUsage, rect, vaddr);
+    int32_t bytesPerPixel, bytesPerStride;
+
+    status_t res =
+            getBufferMapper().lock(handle, inUsage, rect, vaddr, &bytesPerPixel, &bytesPerStride);
     return res;
 }
 
@@ -306,8 +309,10 @@
                 width, height);
         return BAD_VALUE;
     }
-    status_t res = getBufferMapper().lockAsync(handle, inProducerUsage,
-            inConsumerUsage, rect, vaddr, fenceFd);
+
+    int32_t bytesPerPixel, bytesPerStride;
+    status_t res = getBufferMapper().lockAsync(handle, inProducerUsage, inConsumerUsage, rect,
+                                               vaddr, fenceFd, &bytesPerPixel, &bytesPerStride);
     return res;
 }
 
diff --git a/libs/ui/GraphicBufferMapper.cpp b/libs/ui/GraphicBufferMapper.cpp
index b049329..9e36377 100644
--- a/libs/ui/GraphicBufferMapper.cpp
+++ b/libs/ui/GraphicBufferMapper.cpp
@@ -102,10 +102,10 @@
     return NO_ERROR;
 }
 
-status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage,
-        const Rect& bounds, void** vaddr)
-{
-    return lockAsync(handle, usage, bounds, vaddr, -1);
+status_t GraphicBufferMapper::lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+                                   void** vaddr, int32_t* outBytesPerPixel,
+                                   int32_t* outBytesPerStride) {
+    return lockAsync(handle, usage, bounds, vaddr, -1, outBytesPerPixel, outBytesPerStride);
 }
 
 status_t GraphicBufferMapper::lockYCbCr(buffer_handle_t handle, uint32_t usage,
@@ -125,21 +125,23 @@
     return error;
 }
 
-status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
-        uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd)
-{
-    return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd);
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds,
+                                        void** vaddr, int fenceFd, int32_t* outBytesPerPixel,
+                                        int32_t* outBytesPerStride) {
+    return lockAsync(handle, usage, usage, bounds, vaddr, fenceFd, outBytesPerPixel,
+                     outBytesPerStride);
 }
 
-status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle,
-        uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
-        void** vaddr, int fenceFd)
-{
+status_t GraphicBufferMapper::lockAsync(buffer_handle_t handle, uint64_t producerUsage,
+                                        uint64_t consumerUsage, const Rect& bounds, void** vaddr,
+                                        int fenceFd, int32_t* outBytesPerPixel,
+                                        int32_t* outBytesPerStride) {
     ATRACE_CALL();
 
     const uint64_t usage = static_cast<uint64_t>(
             android_convertGralloc1To0Usage(producerUsage, consumerUsage));
-    return mMapper->lock(handle, usage, bounds, fenceFd, vaddr);
+    return mMapper->lock(handle, usage, bounds, fenceFd, vaddr, outBytesPerPixel,
+                         outBytesPerStride);
 }
 
 status_t GraphicBufferMapper::lockAsyncYCbCr(buffer_handle_t handle,
diff --git a/libs/ui/include/ui/Gralloc.h b/libs/ui/include/ui/Gralloc.h
index 92bf043..a484bce 100644
--- a/libs/ui/include/ui/Gralloc.h
+++ b/libs/ui/include/ui/Gralloc.h
@@ -56,7 +56,8 @@
     // The ownership of acquireFence is always transferred to the callee, even
     // on errors.
     virtual status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
-                          int acquireFence, void** outData) const = 0;
+                          int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                          int32_t* outBytesPerStride) const = 0;
 
     // The ownership of acquireFence is always transferred to the callee, even
     // on errors.
diff --git a/libs/ui/include/ui/Gralloc2.h b/libs/ui/include/ui/Gralloc2.h
index e03cb43..b23d8f7 100644
--- a/libs/ui/include/ui/Gralloc2.h
+++ b/libs/ui/include/ui/Gralloc2.h
@@ -53,7 +53,8 @@
                           uint32_t* outNumInts) const override;
 
     status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
-                  int acquireFence, void** outData) const override;
+                  int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                  int32_t* outBytesPerStride) const override;
 
     status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
                   int acquireFence, android_ycbcr* ycbcr) const override;
diff --git a/libs/ui/include/ui/Gralloc3.h b/libs/ui/include/ui/Gralloc3.h
index 510ce4a..b0cbcc1 100644
--- a/libs/ui/include/ui/Gralloc3.h
+++ b/libs/ui/include/ui/Gralloc3.h
@@ -52,7 +52,8 @@
                           uint32_t* outNumInts) const override;
 
     status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
-                  int acquireFence, void** outData) const override;
+                  int acquireFence, void** outData, int32_t* outBytesPerPixel,
+                  int32_t* outBytesPerStride) const override;
 
     status_t lock(buffer_handle_t bufferHandle, uint64_t usage, const Rect& bounds,
                   int acquireFence, android_ycbcr* ycbcr) const override;
diff --git a/libs/ui/include/ui/GraphicBufferMapper.h b/libs/ui/include/ui/GraphicBufferMapper.h
index 156bd7a..072926f 100644
--- a/libs/ui/include/ui/GraphicBufferMapper.h
+++ b/libs/ui/include/ui/GraphicBufferMapper.h
@@ -56,20 +56,21 @@
     void getTransportSize(buffer_handle_t handle,
             uint32_t* outTransportNumFds, uint32_t* outTransportNumInts);
 
-    status_t lock(buffer_handle_t handle,
-            uint32_t usage, const Rect& bounds, void** vaddr);
+    status_t lock(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr,
+                  int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
 
     status_t lockYCbCr(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr);
 
     status_t unlock(buffer_handle_t handle);
 
-    status_t lockAsync(buffer_handle_t handle,
-            uint32_t usage, const Rect& bounds, void** vaddr, int fenceFd);
+    status_t lockAsync(buffer_handle_t handle, uint32_t usage, const Rect& bounds, void** vaddr,
+                       int fenceFd, int32_t* outBytesPerPixel = nullptr,
+                       int32_t* outBytesPerStride = nullptr);
 
-    status_t lockAsync(buffer_handle_t handle,
-            uint64_t producerUsage, uint64_t consumerUsage, const Rect& bounds,
-            void** vaddr, int fenceFd);
+    status_t lockAsync(buffer_handle_t handle, uint64_t producerUsage, uint64_t consumerUsage,
+                       const Rect& bounds, void** vaddr, int fenceFd,
+                       int32_t* outBytesPerPixel = nullptr, int32_t* outBytesPerStride = nullptr);
 
     status_t lockAsyncYCbCr(buffer_handle_t handle,
             uint32_t usage, const Rect& bounds, android_ycbcr *ycbcr,
diff --git a/services/inputflinger/Android.bp b/services/inputflinger/Android.bp
index 843eb37..e3a237e 100644
--- a/services/inputflinger/Android.bp
+++ b/services/inputflinger/Android.bp
@@ -76,7 +76,8 @@
         "libutils",
         "libui",
         "libhardware_legacy",
-        "libutils"
+        "libstatslog",
+        "libutils",
     ],
 
     header_libs: [
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 2b31f6e..64070e3 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -57,6 +57,7 @@
 #include <android-base/stringprintf.h>
 #include <input/Keyboard.h>
 #include <input/VirtualKeyMap.h>
+#include <statslog.h>
 
 #define INDENT "  "
 #define INDENT2 "    "
@@ -71,18 +72,21 @@
 // --- Constants ---
 
 // Maximum number of slots supported when using the slot-based Multitouch Protocol B.
-static const size_t MAX_SLOTS = 32;
+static constexpr size_t MAX_SLOTS = 32;
 
 // Maximum amount of latency to add to touch events while waiting for data from an
 // external stylus.
-static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
+static constexpr nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72);
 
 // Maximum amount of time to wait on touch data before pushing out new pressure data.
-static const nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
+static constexpr nsecs_t TOUCH_DATA_TIMEOUT = ms2ns(20);
 
 // Artificial latency on synthetic events created from stylus data without corresponding touch
 // data.
-static const nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
+static constexpr nsecs_t STYLUS_DATA_LATENCY = ms2ns(10);
+
+// How often to report input event statistics
+static constexpr nsecs_t STATISTICS_REPORT_FREQUENCY = seconds_to_nanoseconds(5 * 60);
 
 // --- Static Functions ---
 
@@ -4287,12 +4291,25 @@
     mExternalStylusFusionTimeout = LLONG_MAX;
 }
 
+void TouchInputMapper::reportEventForStatistics(nsecs_t evdevTime) {
+    nsecs_t now = systemTime(CLOCK_MONOTONIC);
+    nsecs_t latency = now - evdevTime;
+    mStatistics.addValue(nanoseconds_to_microseconds(latency));
+    nsecs_t timeSinceLastReport = now - mStatistics.lastReportTime;
+    if (timeSinceLastReport > STATISTICS_REPORT_FREQUENCY) {
+        android::util::stats_write(android::util::TOUCH_EVENT_REPORTED,
+                mStatistics.min, mStatistics.max, mStatistics.mean(), mStatistics.stdev());
+        mStatistics.reset(now);
+    }
+}
+
 void TouchInputMapper::process(const RawEvent* rawEvent) {
     mCursorButtonAccumulator.process(rawEvent);
     mCursorScrollAccumulator.process(rawEvent);
     mTouchButtonAccumulator.process(rawEvent);
 
     if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) {
+        reportEventForStatistics(rawEvent->when);
         sync(rawEvent->when);
     }
 }
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 35f3c23..aaffce2 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -567,6 +567,69 @@
     }
 };
 
+/**
+ * Basic statistics information.
+ * Keep track of min, max, average, and standard deviation of the received samples.
+ * Used to report latency information about input events.
+ */
+struct LatencyStatistics {
+    float min;
+    float max;
+    // Sum of all samples
+    float sum;
+    // Sum of squares of all samples
+    float sum2;
+    // The number of samples
+    size_t count;
+    // The last time statistics were reported.
+    nsecs_t lastReportTime;
+
+    LatencyStatistics() {
+        reset(systemTime(SYSTEM_TIME_MONOTONIC));
+    }
+
+    inline void addValue(float x) {
+        if (x < min) {
+            min = x;
+        }
+        if (x > max) {
+            max = x;
+        }
+        sum += x;
+        sum2 += x * x;
+        count++;
+    }
+
+    // Get the average value. Should not be called if no samples have been added.
+    inline float mean() {
+        if (count == 0) {
+            return 0;
+        }
+        return sum / count;
+    }
+
+    // Get the standard deviation. Should not be called if no samples have been added.
+    inline float stdev() {
+        if (count == 0) {
+            return 0;
+        }
+        float average = mean();
+        return sqrt(sum2 / count - average * average);
+    }
+
+    /**
+     * Reset internal state. The variable 'when' is the time when the data collection started.
+     * Call this to start a new data collection window.
+     */
+    inline void reset(nsecs_t when) {
+        max = 0;
+        min = std::numeric_limits<float>::max();
+        sum = 0;
+        sum2 = 0;
+        count = 0;
+        lastReportTime = when;
+    }
+};
 
 /* Keeps track of the state of single-touch protocol. */
 class SingleTouchMotionAccumulator {
@@ -1511,6 +1574,9 @@
     VelocityControl mWheelXVelocityControl;
     VelocityControl mWheelYVelocityControl;
 
+    // Latency statistics for touch events
+    struct LatencyStatistics mStatistics;
+
     std::optional<DisplayViewport> findViewport();
 
     void resetExternalStylus();
@@ -1580,6 +1646,8 @@
 
     static void assignPointerIds(const RawState* last, RawState* current);
 
+    void reportEventForStatistics(nsecs_t evdevTime);
+
     const char* modeToString(DeviceMode deviceMode);
 };
 
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
new file mode 100644
index 0000000..ce1637a
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <algorithm>
+#include <numeric>
+
+#include "Scheduler/SchedulerUtils.h"
+#include "android-base/stringprintf.h"
+
+namespace android {
+namespace scheduler {
+
+/**
+ * This class is used to encapsulate configuration for refresh rates. It holds infomation
+ * about available refresh rates on the device, and the mapping between the numbers and human
+ * readable names.
+ */
+class RefreshRateConfigs {
+public:
+    // Enum to indicate which vsync rate to run at. Power saving is intended to be the lowest
+    // (eg. when the screen is in AOD mode or off), default is the old 60Hz, and performance
+    // is the new 90Hz. Eventually we want to have a way for vendors to map these in the configs.
+    enum class RefreshRateType { POWER_SAVING, DEFAULT, PERFORMANCE };
+
+    struct RefreshRate {
+        // Type of the refresh rate.
+        RefreshRateType type;
+        // This config ID corresponds to the position of the config in the vector that is stored
+        // on the device.
+        int configId;
+        // Human readable name of the refresh rate.
+        std::string name;
+    };
+
+    // TODO(b/122916473): Get this information from configs prepared by vendors, instead of
+    // baking them in.
+    explicit RefreshRateConfigs(
+            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
+        // This is the rate that HWC encapsulates right now when the screen is off.
+        RefreshRate rate;
+        rate.type = RefreshRateType::POWER_SAVING;
+        rate.configId = SCREEN_OFF_CONFIG_ID;
+        rate.name = "ScreenOff";
+        mRefreshRates.push_back(rate);
+
+        if (configs.size() < 1) {
+            return;
+        }
+
+        std::vector<std::pair<int, nsecs_t>> configIdToVsyncPeriod;
+        for (int i = 0; i < configs.size(); ++i) {
+            configIdToVsyncPeriod.push_back(std::make_pair(i, configs.at(i)->getVsyncPeriod()));
+        }
+        std::sort(configIdToVsyncPeriod.begin(), configIdToVsyncPeriod.end(),
+                  [](const std::pair<int, nsecs_t>& a, const std::pair<int, nsecs_t>& b) {
+                      return a.second > b.second;
+                  });
+
+        nsecs_t vsyncPeriod = configIdToVsyncPeriod.at(0).second;
+        if (vsyncPeriod != 0) {
+            const float fps = std::chrono::nanoseconds(1).count() / vsyncPeriod;
+            rate.type = RefreshRateType::DEFAULT;
+            rate.configId = configIdToVsyncPeriod.at(0).first;
+            rate.name = base::StringPrintf("%2.ffps", fps);
+            mRefreshRates.push_back(rate);
+        }
+        if (configs.size() < 2) {
+            return;
+        }
+
+        vsyncPeriod = configIdToVsyncPeriod.at(1).second;
+        if (vsyncPeriod != 0) {
+            const float fps = std::chrono::nanoseconds(1).count() / vsyncPeriod;
+            rate.type = RefreshRateType::PERFORMANCE;
+            rate.configId = configIdToVsyncPeriod.at(1).first;
+            rate.name = base::StringPrintf("%2.ffps", fps);
+            mRefreshRates.push_back(rate);
+        }
+
+        for (auto refreshRate : mRefreshRates) {
+            ALOGV("type: %d, id: %d, name: %s", refreshRate.type, refreshRate.configId,
+                  refreshRate.name.c_str());
+        }
+    }
+    ~RefreshRateConfigs() = default;
+
+    const std::vector<RefreshRate>& getRefreshRates() { return mRefreshRates; }
+
+private:
+    std::vector<RefreshRate> mRefreshRates;
+};
+
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
new file mode 100644
index 0000000..cd81e4d
--- /dev/null
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -0,0 +1,146 @@
+/*
+ * Copyright 2019 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.
+ */
+
+#pragma once
+
+#include <numeric>
+
+#include "Scheduler/RefreshRateConfigs.h"
+#include "Scheduler/SchedulerUtils.h"
+
+#include "android-base/stringprintf.h"
+#include "utils/Timers.h"
+
+namespace android {
+namespace scheduler {
+
+/**
+ * Class to encapsulate statistics about refresh rates that the display is using. When the power
+ * mode is set to HWC_POWER_MODE_NORMAL, SF is switching between refresh rates that are stored in
+ * the device's configs. Otherwise, we assume the HWC is running in power saving mode under the
+ * hood (eg. the device is in DOZE, or screen off mode).
+ */
+class RefreshRateStats {
+    static constexpr int64_t MS_PER_S = 1000;
+    static constexpr int64_t MS_PER_MIN = 60 * MS_PER_S;
+    static constexpr int64_t MS_PER_HOUR = 60 * MS_PER_MIN;
+    static constexpr int64_t MS_PER_DAY = 24 * MS_PER_HOUR;
+
+public:
+    explicit RefreshRateStats(
+            const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs)
+          : mRefreshRateConfigs(std::make_unique<RefreshRateConfigs>(configs)),
+            mPreviousRecordedTime(systemTime()) {}
+    ~RefreshRateStats() = default;
+
+    // Sets power mode. We only collect the information when the power mode is not
+    // HWC_POWER_MODE_NORMAL. When power mode is HWC_POWER_MODE_NORMAL, we collect the stats based
+    // on config mode.
+    void setPowerMode(int mode) {
+        if (mCurrentPowerMode == mode) {
+            return;
+        }
+        // If power mode is normal, the time is going to be recorded under config modes.
+        if (mode == HWC_POWER_MODE_NORMAL) {
+            mCurrentPowerMode = mode;
+            return;
+        }
+        flushTime();
+        mCurrentPowerMode = mode;
+    }
+
+    // Sets config mode. If the mode has changed, it records how much time was spent in the previous
+    // mode.
+    void setConfigMode(int mode) {
+        if (mCurrentConfigMode == mode) {
+            return;
+        }
+        flushTime();
+        mCurrentConfigMode = mode;
+    }
+
+    // Returns a map between human readable refresh rate and number of seconds the device spent in
+    // that mode.
+    std::unordered_map<std::string, int64_t> getTotalTimes() {
+        // If the power mode is on, then we are probably switching between the config modes. If
+        // it's not then the screen is probably off. Make sure to flush times before printing
+        // them.
+        flushTime();
+
+        std::unordered_map<std::string, int64_t> totalTime;
+        for (auto config : mRefreshRateConfigs->getRefreshRates()) {
+            if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
+                totalTime[config.name] = mConfigModesTotalTime.at(config.configId);
+            }
+        }
+        return totalTime;
+    }
+
+    // Traverses through the map of config modes and returns how long they've been running in easy
+    // to read format.
+    std::string doDump() {
+        std::ostringstream stream;
+        stream << "+  Refresh rate: running time in seconds\n";
+        for (auto stats : getTotalTimes()) {
+            stream << stats.first.c_str() << ": " << getDateFormatFromMs(stats.second) << "\n";
+        }
+        return stream.str();
+    }
+
+private:
+    void flushTime() {
+        // Normal power mode is counted under different config modes.
+        if (mCurrentPowerMode == HWC_POWER_MODE_NORMAL) {
+            flushTimeForMode(mCurrentConfigMode);
+        } else {
+            flushTimeForMode(SCREEN_OFF_CONFIG_ID);
+        }
+    }
+
+    // Calculates the time that passed in ms between the last time we recorded time and the time
+    // this method was called.
+    void flushTimeForMode(int mode) {
+        nsecs_t currentTime = systemTime();
+        int64_t timeElapsedMs = ns2ms(currentTime - mPreviousRecordedTime);
+        mPreviousRecordedTime = currentTime;
+
+        mConfigModesTotalTime[mode] += timeElapsedMs;
+    }
+
+    // Formats the time in milliseconds into easy to read format.
+    static std::string getDateFormatFromMs(int64_t timeMs) {
+        auto [days, dayRemainderMs] = std::div(timeMs, MS_PER_DAY);
+        auto [hours, hourRemainderMs] = std::div(dayRemainderMs, MS_PER_HOUR);
+        auto [mins, minsRemainderMs] = std::div(hourRemainderMs, MS_PER_MIN);
+        auto [sec, secRemainderMs] = std::div(minsRemainderMs, MS_PER_S);
+        return base::StringPrintf("%" PRId64 "d%02" PRId64 ":%02" PRId64 ":%02" PRId64
+                                  ".%03" PRId64,
+                                  days, hours, mins, sec, secRemainderMs);
+    }
+
+    // Keeps information about refresh rate configs that device has.
+    std::unique_ptr<RefreshRateConfigs> mRefreshRateConfigs;
+
+    int64_t mCurrentConfigMode = 0;
+    int32_t mCurrentPowerMode = HWC_POWER_MODE_OFF;
+
+    std::unordered_map<int /* power mode */, int64_t /* duration in ms */> mConfigModesTotalTime;
+
+    nsecs_t mPreviousRecordedTime;
+};
+
+} // namespace scheduler
+} // namespace android
\ No newline at end of file
diff --git a/services/surfaceflinger/Scheduler/Scheduler.cpp b/services/surfaceflinger/Scheduler/Scheduler.cpp
index 0d587dd..f4191e6 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.cpp
+++ b/services/surfaceflinger/Scheduler/Scheduler.cpp
@@ -352,4 +352,10 @@
     }
 }
 
+std::string Scheduler::doDump() {
+    std::ostringstream stream;
+    stream << "+  Idle timer interval: " << mSetIdleTimerMs << " ms" << std::endl;
+    return stream.str();
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/Scheduler/Scheduler.h b/services/surfaceflinger/Scheduler/Scheduler.h
index ba18d21..435fd14 100644
--- a/services/surfaceflinger/Scheduler/Scheduler.h
+++ b/services/surfaceflinger/Scheduler/Scheduler.h
@@ -118,6 +118,8 @@
     void setExpiredIdleTimerCallback(const ExpiredIdleTimerCallback& expiredTimerCallback);
     // Callback that gets invoked once the idle timer is reset.
     void setResetIdleTimerCallback(const ResetIdleTimerCallback& resetTimerCallback);
+    // Returns relevant information about Scheduler for dumpsys purposes.
+    std::string doDump();
 
 protected:
     virtual std::unique_ptr<EventThread> makeEventThread(
diff --git a/services/surfaceflinger/Scheduler/SchedulerUtils.h b/services/surfaceflinger/Scheduler/SchedulerUtils.h
index 17c57db..edd23de 100644
--- a/services/surfaceflinger/Scheduler/SchedulerUtils.h
+++ b/services/surfaceflinger/Scheduler/SchedulerUtils.h
@@ -26,6 +26,11 @@
 // about layers.
 static constexpr size_t ARRAY_SIZE = 30;
 
+// This number is used to have a place holder for when the screen is not NORMAL/ON. Currently
+// the config is not visible to SF, and is completely maintained by HWC. However, we would
+// still like to keep track of time when the device is in this config.
+static constexpr int SCREEN_OFF_CONFIG_ID = -1;
+
 // Calculates the statistical mean (average) in the data structure (array, vector). The
 // function does not modify the contents of the array.
 template <typename T>
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 709b1ef..8746a68 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -737,6 +737,8 @@
     if (mUseScheduler) {
         mScheduler->setExpiredIdleTimerCallback([this]() { setRefreshRateTo(60.f /* fps */); });
         mScheduler->setResetIdleTimerCallback([this]() { setRefreshRateTo(90.f /* fps */); });
+        mRefreshRateStats = std::make_unique<scheduler::RefreshRateStats>(
+                getHwComposer().getConfigs(*display->getId()));
     }
 
     ALOGV("Done initializing");
@@ -987,6 +989,9 @@
         // Don't update config if we are already running in the desired mode.
         return;
     }
+    if (mUseScheduler) {
+        mRefreshRateStats->setConfigMode(mode);
+    }
 
     const auto displayId = display->getId();
     LOG_ALWAYS_FATAL_IF(!displayId);
@@ -4333,6 +4338,10 @@
 
     if (display->isPrimary()) {
         mTimeStats->setPowerMode(mode);
+        if (mUseScheduler) {
+            // Update refresh rate stats.
+            mRefreshRateStats->setPowerMode(mode);
+        }
     }
 
     ALOGD("Finished setting power mode %d on display %s", mode, to_string(*displayId).c_str());
@@ -4958,6 +4967,15 @@
         result.append(mVrFlinger->Dump());
         result.append("\n");
     }
+
+    /**
+     * Scheduler dump state.
+     */
+    if (mUseScheduler) {
+        result.append("\nScheduler state:\n");
+        result.append(mScheduler->doDump() + "\n");
+        result.append(mRefreshRateStats->doDump() + "\n");
+    }
 }
 
 const Vector<sp<Layer>>& SurfaceFlinger::getLayerSortedByZForHwcDisplay(DisplayId displayId) {
diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h
index 499ebcd..28ed004 100644
--- a/services/surfaceflinger/SurfaceFlinger.h
+++ b/services/surfaceflinger/SurfaceFlinger.h
@@ -59,6 +59,7 @@
 #include "Scheduler/DispSync.h"
 #include "Scheduler/EventThread.h"
 #include "Scheduler/MessageQueue.h"
+#include "Scheduler/RefreshRateStats.h"
 #include "Scheduler/Scheduler.h"
 #include "Scheduler/VSyncModulator.h"
 #include "SurfaceFlingerFactory.h"
@@ -1037,11 +1038,16 @@
     SurfaceFlingerBE mBE;
     std::unique_ptr<compositionengine::CompositionEngine> mCompositionEngine;
 
+    /* ------------------------------------------------------------------------
+     * Scheduler
+     */
     bool mUseScheduler = false;
     std::unique_ptr<Scheduler> mScheduler;
     sp<Scheduler::ConnectionHandle> mAppConnectionHandle;
     sp<Scheduler::ConnectionHandle> mSfConnectionHandle;
+    std::unique_ptr<scheduler::RefreshRateStats> mRefreshRateStats;
 
+    /* ------------------------------------------------------------------------ */
     sp<IInputFlinger> mInputFlinger;
 
     InputWindowCommands mInputWindowCommands;