Merge "Reallocate GraphicBuffer as long as the protected bit is different."
diff --git a/cmds/installd/InstalldNativeService.cpp b/cmds/installd/InstalldNativeService.cpp
index 92fac66..c730ab9 100644
--- a/cmds/installd/InstalldNativeService.cpp
+++ b/cmds/installd/InstalldNativeService.cpp
@@ -171,7 +171,7 @@
 }
 
 binder::Status checkArgumentPackageName(const std::string& packageName) {
-    if (is_valid_package_name(packageName.c_str())) {
+    if (is_valid_package_name(packageName)) {
         return ok();
     } else {
         return exception(binder::Status::EX_ILLEGAL_ARGUMENT,
diff --git a/cmds/installd/dexopt.cpp b/cmds/installd/dexopt.cpp
index 20142aa..a5cc0df 100644
--- a/cmds/installd/dexopt.cpp
+++ b/cmds/installd/dexopt.cpp
@@ -1564,7 +1564,7 @@
         if (vdex_fd >= 0) {
             AddArg(vdex_fd_arg);
         }
-        AddArg(zip_fd_arg.c_str());
+        AddArg(zip_fd_arg);
         if (profile_was_updated) {
             AddArg(assume_profile_changed);
         }
@@ -1572,9 +1572,9 @@
             AddArg(downgrade_flag);
         }
         if (class_loader_context != nullptr) {
-            AddArg(class_loader_context_arg.c_str());
+            AddArg(class_loader_context_arg);
             if (!class_loader_context_fds.empty()) {
-                AddArg(class_loader_context_fds_arg.c_str());
+                AddArg(class_loader_context_fds_arg);
             }
         }
 
@@ -2259,7 +2259,7 @@
         drop_capabilities(uid);
 
         const char* volume_uuid_cstr = volume_uuid == nullptr ? nullptr : volume_uuid->c_str();
-        if (!validate_secondary_dex_path(pkgname.c_str(), dex_path.c_str(), volume_uuid_cstr,
+        if (!validate_secondary_dex_path(pkgname, dex_path, volume_uuid_cstr,
                 uid, storage_flag)) {
             LOG(ERROR) << "Could not validate secondary dex path " << dex_path;
             _exit(kReconcileSecondaryDexValidationError);
diff --git a/include/input/InputApplication.h b/include/input/InputApplication.h
index 71a8f20..7f04611 100644
--- a/include/input/InputApplication.h
+++ b/include/input/InputApplication.h
@@ -50,19 +50,19 @@
 class InputApplicationHandle : public RefBase {
 public:
     inline const InputApplicationInfo* getInfo() const {
-        return mInfo;
+        return &mInfo;
     }
 
     inline std::string getName() const {
-        return mInfo ? mInfo->name : "<invalid>";
+        return !mInfo.name.empty() ? mInfo.name : "<invalid>";
     }
 
     inline nsecs_t getDispatchingTimeout(nsecs_t defaultValue) const {
-        return mInfo ? mInfo->dispatchingTimeout : defaultValue;
+        return mInfo.token ? mInfo.dispatchingTimeout : defaultValue;
     }
 
     inline sp<IBinder> getApplicationToken() const {
-        return mInfo ? mInfo->token : nullptr;
+        return mInfo.token;
     }
 
     /**
@@ -75,18 +75,11 @@
      * Returns true on success, or false if the handle is no longer valid.
      */
     virtual bool updateInfo() = 0;
-
-    /**
-     * Releases the storage used by the associated information when it is
-     * no longer needed.
-     */
-    void releaseInfo();
-
 protected:
     InputApplicationHandle();
     virtual ~InputApplicationHandle();
 
-    InputApplicationInfo* mInfo;
+    InputApplicationInfo mInfo;
 };
 
 } // namespace android
diff --git a/libs/input/InputApplication.cpp b/libs/input/InputApplication.cpp
index 7936f50..1d9f8a7 100644
--- a/libs/input/InputApplication.cpp
+++ b/libs/input/InputApplication.cpp
@@ -24,19 +24,10 @@
 
 // --- InputApplicationHandle ---
 
-InputApplicationHandle::InputApplicationHandle() :
-    mInfo(nullptr) {
+InputApplicationHandle::InputApplicationHandle() {
 }
 
 InputApplicationHandle::~InputApplicationHandle() {
-    delete mInfo;
-}
-
-void InputApplicationHandle::releaseInfo() {
-    if (mInfo) {
-        delete mInfo;
-        mInfo = nullptr;
-    }
 }
 
 InputApplicationInfo InputApplicationInfo::read(const Parcel& from) {
diff --git a/libs/nativewindow/AHardwareBuffer.cpp b/libs/nativewindow/AHardwareBuffer.cpp
index bf80481..9bd3095 100644
--- a/libs/nativewindow/AHardwareBuffer.cpp
+++ b/libs/nativewindow/AHardwareBuffer.cpp
@@ -96,7 +96,12 @@
 int AHardwareBuffer_lockAndGetInfo(AHardwareBuffer* buffer, uint64_t usage,
         int32_t fence, const ARect* rect, void** outVirtualAddress,
         int32_t* outBytesPerPixel, int32_t* outBytesPerStride) {
-    if (!buffer) return BAD_VALUE;
+    if (outBytesPerPixel) *outBytesPerPixel = -1;
+    if (outBytesPerStride) *outBytesPerStride = -1;
+
+    if (!buffer) {
+        return BAD_VALUE;
+    }
 
     if (usage & ~(AHARDWAREBUFFER_USAGE_CPU_READ_MASK |
                   AHARDWAREBUFFER_USAGE_CPU_WRITE_MASK)) {
@@ -127,15 +132,19 @@
     } else {
         bounds.set(Rect(rect->left, rect->top, rect->right, rect->bottom));
     }
-    int result = gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, outBytesPerPixel, outBytesPerStride);
+    int32_t bytesPerPixel;
+    int32_t bytesPerStride;
+    int result = gbuffer->lockAsync(usage, usage, bounds, outVirtualAddress, fence, &bytesPerPixel, &bytesPerStride);
 
     // if hardware returns -1 for bytes per pixel or bytes per stride, we fail
     // and unlock the buffer
-    if (*outBytesPerPixel == -1 || *outBytesPerStride == -1) {
+    if (bytesPerPixel == -1 || bytesPerStride == -1) {
         gbuffer->unlock();
         return INVALID_OPERATION;
     }
 
+    if (outBytesPerPixel) *outBytesPerPixel = bytesPerPixel;
+    if (outBytesPerStride) *outBytesPerStride = bytesPerStride;
     return result;
 }
 
diff --git a/libs/renderengine/gl/GLESRenderEngine.cpp b/libs/renderengine/gl/GLESRenderEngine.cpp
index f651309..1980f50 100644
--- a/libs/renderengine/gl/GLESRenderEngine.cpp
+++ b/libs/renderengine/gl/GLESRenderEngine.cpp
@@ -595,11 +595,7 @@
 }
 
 void GLESRenderEngine::setScissor(const Rect& region) {
-    // Invert y-coordinate to map to GL-space.
-    int32_t canvasHeight = mFboHeight;
-    int32_t glBottom = canvasHeight - region.bottom;
-
-    glScissor(region.left, glBottom, region.getWidth(), region.getHeight());
+    glScissor(region.left, region.top, region.getWidth(), region.getHeight());
     glEnable(GL_SCISSOR_TEST);
 }
 
@@ -719,6 +715,36 @@
     return cropWin;
 }
 
+void GLESRenderEngine::handleRoundedCorners(const DisplaySettings& display,
+                                            const LayerSettings& layer, const Mesh& mesh) {
+    // We separate the layer into 3 parts essentially, such that we only turn on blending for the
+    // top rectangle and the bottom rectangle, and turn off blending for the middle rectangle.
+    FloatRect bounds = layer.geometry.roundedCornersCrop;
+    const auto transformMatrix = display.globalTransform * layer.geometry.positionTransform;
+    const vec4 leftTopCoordinate(bounds.left, bounds.top, 1.0, 1.0);
+    const vec4 rightBottomCoordinate(bounds.right, bounds.bottom, 1.0, 1.0);
+    const vec4 leftTopCoordinateInBuffer = transformMatrix * leftTopCoordinate;
+    const vec4 rightBottomCoordinateInBuffer = transformMatrix * rightBottomCoordinate;
+    bounds = FloatRect(leftTopCoordinateInBuffer[0], leftTopCoordinateInBuffer[1],
+                       rightBottomCoordinateInBuffer[0], rightBottomCoordinateInBuffer[1]);
+    const int32_t radius = ceil(layer.geometry.roundedCornersRadius);
+
+    const Rect topRect(bounds.left, bounds.top, bounds.right, bounds.top + radius);
+    setScissor(topRect);
+    drawMesh(mesh);
+    const Rect bottomRect(bounds.left, bounds.bottom - radius, bounds.right, bounds.bottom);
+    setScissor(bottomRect);
+    drawMesh(mesh);
+
+    // The middle part of the layer can turn off blending.
+    const Rect middleRect(bounds.left, bounds.top + radius, bounds.right, bounds.bottom - radius);
+    setScissor(middleRect);
+    mState.cornerRadius = 0.0;
+    disableBlending();
+    drawMesh(mesh);
+    disableScissor();
+}
+
 status_t GLESRenderEngine::bindFrameBuffer(Framebuffer* framebuffer) {
     ATRACE_CALL();
     GLFramebuffer* glFramebuffer = static_cast<GLFramebuffer*>(framebuffer);
@@ -738,8 +764,6 @@
     glBindFramebuffer(GL_FRAMEBUFFER, framebufferName);
     glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, textureName, 0);
 
-    mFboHeight = glFramebuffer->getBufferHeight();
-
     uint32_t glStatus = glCheckFramebufferStatus(GL_FRAMEBUFFER);
 
     ALOGE_IF(glStatus != GL_FRAMEBUFFER_COMPLETE_OES, "glCheckFramebufferStatusOES error %d",
@@ -750,7 +774,6 @@
 
 void GLESRenderEngine::unbindFrameBuffer(Framebuffer* /* framebuffer */) {
     ATRACE_CALL();
-    mFboHeight = 0;
 
     // back to main framebuffer
     glBindFramebuffer(GL_FRAMEBUFFER, 0);
@@ -917,7 +940,14 @@
             }
             setSourceDataSpace(layer.sourceDataspace);
 
-            drawMesh(mesh);
+            // We only want to do a special handling for rounded corners when having rounded corners
+            // is the only reason it needs to turn on blending, otherwise, we handle it like the
+            // usual way since it needs to turn on blending anyway.
+            if (layer.geometry.roundedCornersRadius > 0.0 && color.a >= 1.0f && isOpaque) {
+                handleRoundedCorners(display, layer, mesh);
+            } else {
+                drawMesh(mesh);
+            }
 
             // Cleanup if there's a buffer source
             if (layer.source.buffer.buffer != nullptr) {
diff --git a/libs/renderengine/gl/GLESRenderEngine.h b/libs/renderengine/gl/GLESRenderEngine.h
index efb6ef0..8c8f308 100644
--- a/libs/renderengine/gl/GLESRenderEngine.h
+++ b/libs/renderengine/gl/GLESRenderEngine.h
@@ -69,8 +69,6 @@
     void clearWithColor(float red, float green, float blue, float alpha) override;
     void fillRegionWithColor(const Region& region, float red, float green, float blue,
                              float alpha) override;
-    void setScissor(const Rect& region) override;
-    void disableScissor() override;
     void genTextures(size_t count, uint32_t* names) override;
     void deleteTextures(size_t count, uint32_t const* names) override;
     void bindExternalTextureImage(uint32_t texName, const Image& image) override;
@@ -141,6 +139,8 @@
                                        Protection protection);
     static EGLSurface createDummyEglPbufferSurface(EGLDisplay display, EGLConfig config,
                                                    int hwcFormat, Protection protection);
+    void setScissor(const Rect& region);
+    void disableScissor();
     bool waitSync(EGLSyncKHR sync, EGLint flags);
 
     // A data space is considered HDR data space if it has BT2020 color space
@@ -156,6 +156,13 @@
     // coordinates for the mesh.
     FloatRect setupLayerCropping(const LayerSettings& layer, Mesh& mesh);
 
+    // We do a special handling for rounded corners when it's possible to turn off blending
+    // for the majority of the layer. The rounded corners needs to turn on blending such that
+    // we can set the alpha value correctly, however, only the corners need this, and since
+    // blending is an expensive operation, we want to turn off blending when it's not necessary.
+    void handleRoundedCorners(const DisplaySettings& display, const LayerSettings& layer,
+                              const Mesh& mesh);
+
     EGLDisplay mEGLDisplay;
     EGLConfig mEGLConfig;
     EGLContext mEGLContext;
@@ -185,7 +192,6 @@
     bool mInProtectedContext = false;
     // If set to true, then enables tracing flush() and finish() to systrace.
     bool mTraceGpuCompletion = false;
-    int32_t mFboHeight = 0;
     // Maximum size of mFramebufferImageCache. If more images would be cached, then (approximately)
     // the last recently used buffer should be kicked out.
     uint32_t mFramebufferImageCacheSize = 0;
diff --git a/libs/renderengine/include/renderengine/RenderEngine.h b/libs/renderengine/include/renderengine/RenderEngine.h
index ab34274..b211551 100644
--- a/libs/renderengine/include/renderengine/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/RenderEngine.h
@@ -103,9 +103,6 @@
     virtual void clearWithColor(float red, float green, float blue, float alpha) = 0;
     virtual void fillRegionWithColor(const Region& region, float red, float green, float blue,
                                      float alpha) = 0;
-
-    virtual void setScissor(const Rect& region) = 0;
-    virtual void disableScissor() = 0;
     virtual void genTextures(size_t count, uint32_t* names) = 0;
     virtual void deleteTextures(size_t count, uint32_t const* names) = 0;
     virtual void bindExternalTextureImage(uint32_t texName, const Image& image) = 0;
diff --git a/libs/renderengine/include/renderengine/mock/RenderEngine.h b/libs/renderengine/include/renderengine/mock/RenderEngine.h
index ddf7420..479c7ac 100644
--- a/libs/renderengine/include/renderengine/mock/RenderEngine.h
+++ b/libs/renderengine/include/renderengine/mock/RenderEngine.h
@@ -48,8 +48,6 @@
     bool waitFence(base::unique_fd fd) override { return waitFence(&fd); };
     MOCK_METHOD4(clearWithColor, void(float, float, float, float));
     MOCK_METHOD5(fillRegionWithColor, void(const Region&, float, float, float, float));
-    MOCK_METHOD1(setScissor, void(const Rect&));
-    MOCK_METHOD0(disableScissor, void());
     MOCK_METHOD2(genTextures, void(size_t, uint32_t*));
     MOCK_METHOD2(deleteTextures, void(size_t, uint32_t const*));
     MOCK_METHOD2(bindExternalTextureImage, void(uint32_t, const renderengine::Image&));
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 45340a1..3fc6a2d 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -395,7 +395,7 @@
 status_t GraphicBuffer::flatten(void*& buffer, size_t& size, int*& fds, size_t& count) const {
 #ifndef LIBUI_IN_VNDK
     if (mBufferHubBuffer != nullptr) {
-        return flattenBufferHubBuffer(buffer, size, fds, count);
+        return flattenBufferHubBuffer(buffer, size);
     }
 #endif
     size_t sizeNeeded = GraphicBuffer::getFlattenedSize();
@@ -438,6 +438,11 @@
 
 status_t GraphicBuffer::unflatten(void const*& buffer, size_t& size, int const*& fds,
                                   size_t& count) {
+    // Check if size is not smaller than buf[0] is supposed to take.
+    if (size < sizeof(int)) {
+        return NO_MEMORY;
+    }
+
     int const* buf = static_cast<int const*>(buffer);
 
     // NOTE: it turns out that some media code generates a flattened GraphicBuffer manually!!!!!
@@ -451,7 +456,7 @@
         flattenWordCount = 12;
     } else if (buf[0] == 'BHBB') { // BufferHub backed buffer.
 #ifndef LIBUI_IN_VNDK
-        return unflattenBufferHubBuffer(buffer, size, fds, count);
+        return unflattenBufferHubBuffer(buffer, size);
 #else
         return BAD_TYPE;
 #endif
@@ -562,8 +567,7 @@
 }
 
 #ifndef LIBUI_IN_VNDK
-status_t GraphicBuffer::flattenBufferHubBuffer(void*& buffer, size_t& size, int*& fds,
-                                               size_t& count) const {
+status_t GraphicBuffer::flattenBufferHubBuffer(void*& buffer, size_t& size) const {
     sp<NativeHandle> tokenHandle = mBufferHubBuffer->duplicate();
     if (tokenHandle == nullptr || tokenHandle->handle() == nullptr ||
         tokenHandle->handle()->numFds != 0) {
@@ -587,14 +591,10 @@
     memcpy(buf + 2, tokenHandle->handle()->data, static_cast<size_t>(numIntsInToken) * sizeof(int));
     buf[2 + numIntsInToken] = static_cast<int32_t>(mGenerationNumber);
 
-    // Do not pass fds if it is BufferHubBuffer backed GraphicBuffer. Not modifying fds or count.
-    fds += 0;
-    count -= 0;
     return NO_ERROR;
 }
 
-status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& size, int const*& fds,
-                                                 size_t& count) {
+status_t GraphicBuffer::unflattenBufferHubBuffer(void const*& buffer, size_t& size) {
     const int* buf = static_cast<const int*>(buffer);
     int numIntsInToken = buf[1];
     // Size needed for one label, one number of ints inside the token, one generation number and
@@ -628,10 +628,6 @@
     mBufferId = bufferHubBuffer->id();
     mBufferHubBuffer.reset(std::move(bufferHubBuffer.get()));
 
-    // BufferHubBuffer backed GraphicBuffer does not have flattened handle. Not modifying fds or
-    // count.
-    fds += 0;
-    count -= 0;
     return NO_ERROR;
 }
 
diff --git a/libs/ui/include/ui/GraphicBuffer.h b/libs/ui/include/ui/GraphicBuffer.h
index c137860..c195342 100644
--- a/libs/ui/include/ui/GraphicBuffer.h
+++ b/libs/ui/include/ui/GraphicBuffer.h
@@ -302,7 +302,7 @@
 
 #ifndef LIBUI_IN_VNDK
     // Flatten this GraphicBuffer object if backed by BufferHubBuffer.
-    status_t flattenBufferHubBuffer(void*& buffer, size_t& size, int*& fds, size_t& count) const;
+    status_t flattenBufferHubBuffer(void*& buffer, size_t& size) const;
 
     // Unflatten into BufferHubBuffer backed GraphicBuffer.
     // Unflatten will fail if the original GraphicBuffer object is destructed. For instance, a
@@ -310,8 +310,7 @@
     // to process/thread B through a socket, BufferHubBuffer_1 dies and bufferhub invalidated the
     // token. Race condition occurs between the invalidation of the token in bufferhub process and
     // process/thread B trying to unflatten and import the buffer with that token.
-    status_t unflattenBufferHubBuffer(void const*& buffer, size_t& size, int const*& fds,
-                                      size_t& count);
+    status_t unflattenBufferHubBuffer(void const*& buffer, size_t& size);
 
     // Stores a BufferHubBuffer that handles buffer signaling, identification.
     std::unique_ptr<BufferHubBuffer> mBufferHubBuffer;
diff --git a/services/inputflinger/InputDispatcher.cpp b/services/inputflinger/InputDispatcher.cpp
index 1317620..0d5bc15 100644
--- a/services/inputflinger/InputDispatcher.cpp
+++ b/services/inputflinger/InputDispatcher.cpp
@@ -1958,17 +1958,17 @@
     bool wasEmpty = connection->outboundQueue.isEmpty();
 
     // Enqueue dispatch entries for the requested modes.
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_HOVER_EXIT);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_OUTSIDE);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_HOVER_ENTER);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_IS);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_SLIPPERY_EXIT);
-    enqueueDispatchEntry(connection, eventEntry, inputTarget,
+    enqueueDispatchEntryLocked(connection, eventEntry, inputTarget,
             InputTarget::FLAG_DISPATCH_AS_SLIPPERY_ENTER);
 
     // If the outbound queue was previously empty, start the dispatch cycle going.
@@ -1977,7 +1977,7 @@
     }
 }
 
-void InputDispatcher::enqueueDispatchEntry(
+void InputDispatcher::enqueueDispatchEntryLocked(
         const sp<Connection>& connection, EventEntry* eventEntry, const InputTarget* inputTarget,
         int32_t dispatchMode) {
     int32_t inputTargetFlags = inputTarget->flags;
@@ -2054,6 +2054,10 @@
             delete dispatchEntry;
             return; // skip the inconsistent event
         }
+
+        dispatchPointerDownOutsideFocusIfNecessary(motionEntry->source,
+                dispatchEntry->resolvedAction, inputTarget->inputChannel->getToken());
+
         break;
     }
     }
@@ -2066,6 +2070,32 @@
     // Enqueue the dispatch entry.
     connection->outboundQueue.enqueueAtTail(dispatchEntry);
     traceOutboundQueueLength(connection);
+
+}
+
+void InputDispatcher::dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
+        const sp<IBinder>& newToken) {
+    int32_t maskedAction = action & AMOTION_EVENT_ACTION_MASK;
+    if (source != AINPUT_SOURCE_CLASS_POINTER || maskedAction != AMOTION_EVENT_ACTION_DOWN) {
+        return;
+    }
+
+    sp<InputWindowHandle> inputWindowHandle = getWindowHandleLocked(newToken);
+    if (inputWindowHandle == nullptr) {
+        return;
+    }
+
+    int32_t displayId = inputWindowHandle->getInfo()->displayId;
+    sp<InputWindowHandle> focusedWindowHandle =
+            getValueByKey(mFocusedWindowHandlesByDisplay, displayId);
+
+    bool hasFocusChanged = !focusedWindowHandle || focusedWindowHandle->getToken() != newToken;
+
+    if (!hasFocusChanged) {
+        return;
+    }
+
+    // Dispatch onPointerDownOutsideFocus to the policy.
 }
 
 void InputDispatcher::startDispatchCycleLocked(nsecs_t currentTime,
@@ -2385,7 +2415,7 @@
             target.inputChannel = connection->inputChannel;
             target.flags = InputTarget::FLAG_DISPATCH_AS_IS;
 
-            enqueueDispatchEntry(connection, cancelationEventEntry, // increments ref
+            enqueueDispatchEntryLocked(connection, cancelationEventEntry, // increments ref
                     &target, InputTarget::FLAG_DISPATCH_AS_IS);
 
             cancelationEventEntry->release();
@@ -3221,13 +3251,11 @@
             if (oldFocusedApplicationHandle != inputApplicationHandle) {
                 if (oldFocusedApplicationHandle != nullptr) {
                     resetANRTimeoutsLocked();
-                    oldFocusedApplicationHandle->releaseInfo();
                 }
                 mFocusedApplicationHandlesByDisplay[displayId] = inputApplicationHandle;
             }
         } else if (oldFocusedApplicationHandle != nullptr) {
             resetANRTimeoutsLocked();
-            oldFocusedApplicationHandle->releaseInfo();
             oldFocusedApplicationHandle.clear();
             mFocusedApplicationHandlesByDisplay.erase(displayId);
         }
diff --git a/services/inputflinger/InputDispatcher.h b/services/inputflinger/InputDispatcher.h
index 4d2c216..3735a0b 100644
--- a/services/inputflinger/InputDispatcher.h
+++ b/services/inputflinger/InputDispatcher.h
@@ -1136,8 +1136,9 @@
             EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
     void enqueueDispatchEntriesLocked(nsecs_t currentTime, const sp<Connection>& connection,
             EventEntry* eventEntry, const InputTarget* inputTarget) REQUIRES(mLock);
-    void enqueueDispatchEntry(const sp<Connection>& connection,
-            EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode);
+    void enqueueDispatchEntryLocked(const sp<Connection>& connection,
+            EventEntry* eventEntry, const InputTarget* inputTarget, int32_t dispatchMode)
+            REQUIRES(mLock);
     void startDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection)
             REQUIRES(mLock);
     void finishDispatchCycleLocked(nsecs_t currentTime, const sp<Connection>& connection,
@@ -1147,6 +1148,9 @@
     void drainDispatchQueue(Queue<DispatchEntry>* queue);
     void releaseDispatchEntry(DispatchEntry* dispatchEntry);
     static int handleReceiveCallback(int fd, int events, void* data);
+    // The action sent should only be of type AMOTION_EVENT_*
+    void dispatchPointerDownOutsideFocusIfNecessary(uint32_t source, int32_t action,
+            const sp<IBinder>& newToken) REQUIRES(mLock);
 
     void synthesizeCancelationEventsForAllConnectionsLocked(
             const CancelationOptions& options) REQUIRES(mLock);
diff --git a/services/inputflinger/tests/InputDispatcher_test.cpp b/services/inputflinger/tests/InputDispatcher_test.cpp
index d63ff8c..745fac0 100644
--- a/services/inputflinger/tests/InputDispatcher_test.cpp
+++ b/services/inputflinger/tests/InputDispatcher_test.cpp
@@ -340,10 +340,7 @@
     virtual ~FakeApplicationHandle() {}
 
     virtual bool updateInfo() {
-        if (!mInfo) {
-            mInfo = new InputApplicationInfo();
-        }
-        mInfo->dispatchingTimeout = DISPATCHING_TIMEOUT;
+        mInfo.dispatchingTimeout = DISPATCHING_TIMEOUT;
         return true;
     }
 };
diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp
index 189ae36..a6ed75f 100644
--- a/services/sensorservice/SensorDevice.cpp
+++ b/services/sensorservice/SensorDevice.cpp
@@ -359,7 +359,7 @@
     for (const auto & s : mSensorList) {
         int32_t handle = s.handle;
         const Info& info = mActivationCount.valueFor(handle);
-        if (info.batchParams.isEmpty()) continue;
+        if (info.numActiveClients() == 0) continue;
 
         result.appendFormat("0x%08x) active-count = %zu; ", handle, info.batchParams.size());
 
@@ -730,6 +730,15 @@
     return mDisabledClients.indexOf(ident) >= 0;
 }
 
+bool SensorDevice::isSensorActive(int handle) const {
+    Mutex::Autolock _l(mLock);
+    ssize_t activationIndex = mActivationCount.indexOfKey(handle);
+    if (activationIndex < 0) {
+        return false;
+    }
+    return mActivationCount.valueAt(activationIndex).numActiveClients() > 0;
+}
+
 void SensorDevice::enableAllSensors() {
     if (mSensors == nullptr) return;
     Mutex::Autolock _l(mLock);
diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h
index 2a69654..71b918f 100644
--- a/services/sensorservice/SensorDevice.h
+++ b/services/sensorservice/SensorDevice.h
@@ -120,6 +120,8 @@
         return mReconnecting;
     }
 
+    bool isSensorActive(int handle) const;
+
     // Dumpable
     virtual std::string dump() const;
 private:
diff --git a/services/sensorservice/SensorEventConnection.cpp b/services/sensorservice/SensorEventConnection.cpp
index b66cbcf..c4cfdc6 100644
--- a/services/sensorservice/SensorEventConnection.cpp
+++ b/services/sensorservice/SensorEventConnection.cpp
@@ -78,7 +78,14 @@
 
 void SensorService::SensorEventConnection::dump(String8& result) {
     Mutex::Autolock _l(mConnectionLock);
-    result.appendFormat("\tOperating Mode: %s\n",mDataInjectionMode ? "DATA_INJECTION" : "NORMAL");
+    result.appendFormat("\tOperating Mode: ");
+    if (!mService->isWhiteListedPackage(getPackageName())) {
+        result.append("RESTRICTED\n");
+    } else if (mDataInjectionMode) {
+        result.append("DATA_INJECTION\n");
+    } else {
+        result.append("NORMAL\n");
+    }
     result.appendFormat("\t %s | WakeLockRefCount %d | uid %d | cache size %d | "
             "max cache size %d\n", mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize,
             mMaxCacheSize);
diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp
index 3fbd61e..e3dfde4 100644
--- a/services/sensorservice/SensorService.cpp
+++ b/services/sensorservice/SensorService.cpp
@@ -441,12 +441,15 @@
             }
 
             result.append("Active sensors:\n");
+            SensorDevice& dev = SensorDevice::getInstance();
             for (size_t i=0 ; i<mActiveSensors.size() ; i++) {
                 int handle = mActiveSensors.keyAt(i);
-                result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
-                        getSensorName(handle).string(),
-                        handle,
-                        mActiveSensors.valueAt(i)->getNumConnections());
+                if (dev.isSensorActive(handle)) {
+                    result.appendFormat("%s (handle=0x%08x, connections=%zu)\n",
+                            getSensorName(handle).string(),
+                            handle,
+                            mActiveSensors.valueAt(i)->getNumConnections());
+                }
             }
 
             result.appendFormat("Socket Buffer size = %zd events\n",
diff --git a/services/surfaceflinger/BufferQueueLayer.cpp b/services/surfaceflinger/BufferQueueLayer.cpp
index e4179ee..d3b36fe 100644
--- a/services/surfaceflinger/BufferQueueLayer.cpp
+++ b/services/surfaceflinger/BufferQueueLayer.cpp
@@ -361,8 +361,12 @@
 
     uint32_t hwcSlot = 0;
     sp<GraphicBuffer> hwcBuffer;
+
+    // INVALID_BUFFER_SLOT is used to identify BufferStateLayers.  Default to 0
+    // for BufferQueueLayers
+    int slot = (mActiveBufferSlot == BufferQueue::INVALID_BUFFER_SLOT) ? 0 : mActiveBufferSlot;
     (*outputLayer->editState().hwc)
-            .hwcBufferCache.getHwcBuffer(mActiveBuffer, &hwcSlot, &hwcBuffer);
+            .hwcBufferCache.getHwcBuffer(slot, mActiveBuffer, &hwcSlot, &hwcBuffer);
 
     auto acquireFence = mConsumer->getCurrentFence();
     auto error = hwcLayer->setBuffer(hwcSlot, hwcBuffer, acquireFence);
diff --git a/services/surfaceflinger/BufferStateLayer.cpp b/services/surfaceflinger/BufferStateLayer.cpp
index 5efa4e0..64dfdc3 100644
--- a/services/surfaceflinger/BufferStateLayer.cpp
+++ b/services/surfaceflinger/BufferStateLayer.cpp
@@ -585,10 +585,10 @@
 
     const State& s(getDrawingState());
 
-    // obtain slot
-    uint32_t hwcSlot = 0;
+    uint32_t hwcSlot;
     sp<GraphicBuffer> buffer;
-    hwcInfo.hwcBufferCache.getHwcBuffer(s.buffer, &hwcSlot, &buffer);
+    hwcInfo.hwcBufferCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, s.buffer, &hwcSlot,
+                                        &buffer);
 
     auto error = hwcLayer->setBuffer(hwcSlot, buffer, s.acquireFence);
     if (error != HWC2::Error::None) {
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
index 02d7890..97bdc8f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/HwcBufferCache.h
@@ -45,7 +45,7 @@
     //
     // outBuffer is set to buffer when buffer is not in the HWC cache;
     // otherwise, outBuffer is set to nullptr.
-    void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+    void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                       sp<GraphicBuffer>* outBuffer);
 
 protected:
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index 8613210..a941e09 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -48,12 +48,20 @@
     return std::distance(std::begin(mBuffers), iter);
 }
 
-void HwcBufferCache::getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+void HwcBufferCache::getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                                   sp<GraphicBuffer>* outBuffer) {
-    bool cached = getSlot(buffer, outSlot);
+    // if this slot corresponds to a BufferStateLayer, generate the slot
+    if (slot == BufferQueue::INVALID_BUFFER_SLOT) {
+        getSlot(buffer, outSlot);
+    } else if (slot < 0 || slot >= BufferQueue::NUM_BUFFER_SLOTS) {
+        *outSlot = 0;
+    } else {
+        *outSlot = slot;
+    }
 
     auto& [currentCounter, currentBuffer] = mBuffers[*outSlot];
-    if (cached) {
+    wp<GraphicBuffer> weakCopy(buffer);
+    if (currentBuffer == weakCopy) {
         // already cached in HWC, skip sending the buffer
         *outBuffer = nullptr;
         currentCounter = getCounter();
diff --git a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
index ac04cb3..b261493 100644
--- a/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/HwcBufferCacheTest.cpp
@@ -24,9 +24,9 @@
 
 class TestableHwcBufferCache : public impl::HwcBufferCache {
 public:
-    void getHwcBuffer(const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
+    void getHwcBuffer(int slot, const sp<GraphicBuffer>& buffer, uint32_t* outSlot,
                       sp<GraphicBuffer>* outBuffer) {
-        HwcBufferCache::getHwcBuffer(buffer, outSlot, outBuffer);
+        HwcBufferCache::getHwcBuffer(slot, buffer, outSlot, outBuffer);
     }
     bool getSlot(const sp<GraphicBuffer>& buffer, uint32_t* outSlot) {
         return HwcBufferCache::getSlot(buffer, outSlot);
@@ -38,64 +38,88 @@
 public:
     ~HwcBufferCacheTest() override = default;
 
-    TestableHwcBufferCache mCache;
+    void testSlot(const int inSlot, const uint32_t expectedSlot) {
+        uint32_t outSlot;
+        sp<GraphicBuffer> outBuffer;
+
+        // The first time, the output  is the same as the input
+        mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(mBuffer1, outBuffer);
+
+        // The second time with the same buffer, the outBuffer is nullptr.
+        mCache.getHwcBuffer(inSlot, mBuffer1, &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(nullptr, outBuffer.get());
+
+        // With a new buffer, the outBuffer is the input.
+        mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(mBuffer2, outBuffer);
+
+        // Again, the second request with the same buffer sets outBuffer to nullptr.
+        mCache.getHwcBuffer(inSlot, mBuffer2, &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(nullptr, outBuffer.get());
+
+        // Setting a slot to use nullptr lookslike works, but note that
+        // the output values make it look like no new buffer is being set....
+        mCache.getHwcBuffer(inSlot, sp<GraphicBuffer>(), &outSlot, &outBuffer);
+        EXPECT_EQ(expectedSlot, outSlot);
+        EXPECT_EQ(nullptr, outBuffer.get());
+    }
+
+    impl::HwcBufferCache mCache;
     sp<GraphicBuffer> mBuffer1{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
     sp<GraphicBuffer> mBuffer2{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
 };
 
-TEST_F(HwcBufferCacheTest, testSlot) {
+TEST_F(HwcBufferCacheTest, cacheWorksForSlotZero) {
+    testSlot(0, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheWorksForMaxSlot) {
+    testSlot(BufferQueue::NUM_BUFFER_SLOTS - 1, BufferQueue::NUM_BUFFER_SLOTS - 1);
+}
+
+TEST_F(HwcBufferCacheTest, cacheMapsNegativeSlotToZero) {
+    testSlot(-123, 0);
+}
+
+TEST_F(HwcBufferCacheTest, cacheGeneratesSlotForInvalidBufferSlot) {
     uint32_t outSlot;
     sp<GraphicBuffer> outBuffer;
 
-    // The first time, the output  is the same as the input
-    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer);
     EXPECT_EQ(0, outSlot);
     EXPECT_EQ(mBuffer1, outBuffer);
 
-    // The second time with the same buffer, the outBuffer is nullptr.
-    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer1, &outSlot, &outBuffer);
     EXPECT_EQ(0, outSlot);
     EXPECT_EQ(nullptr, outBuffer.get());
 
-    // With a new buffer, the outBuffer is the input.
-    mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
     EXPECT_EQ(1, outSlot);
     EXPECT_EQ(mBuffer2, outBuffer);
 
-    // Again, the second request with the same buffer sets outBuffer to nullptr.
-    mCache.getHwcBuffer(mBuffer2, &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
     EXPECT_EQ(1, outSlot);
     EXPECT_EQ(nullptr, outBuffer.get());
 
-    // Setting a slot to use nullptr lookslike works, but note that
-    // the output values make it look like no new buffer is being set....
-    mCache.getHwcBuffer(sp<GraphicBuffer>(), &outSlot, &outBuffer);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, sp<GraphicBuffer>(), &outSlot,
+                        &outBuffer);
     EXPECT_EQ(2, outSlot);
     EXPECT_EQ(nullptr, outBuffer.get());
-}
 
-TEST_F(HwcBufferCacheTest, testGetLeastRecentlyUsedSlot) {
-    int slot;
-    uint32_t outSlot;
-    sp<GraphicBuffer> outBuffer;
-
-    // fill up cache
-    for (int i = 0; i < BufferQueue::NUM_BUFFER_SLOTS; i++) {
-        sp<GraphicBuffer> buf{new GraphicBuffer(1, 1, HAL_PIXEL_FORMAT_RGBA_8888, 1, 0)};
-        mCache.getHwcBuffer(buf, &outSlot, &outBuffer);
-        EXPECT_EQ(buf, outBuffer);
-        EXPECT_EQ(i, outSlot);
-    }
-
-    slot = mCache.getLeastRecentlyUsedSlot();
-    EXPECT_EQ(0, slot);
-
-    mCache.getHwcBuffer(mBuffer1, &outSlot, &outBuffer);
-    EXPECT_EQ(0, outSlot);
+    // note that sending mBuffer1 with explicit slot 1 will overwrite mBuffer2
+    // and also cause mBuffer1 to be stored in two places
+    mCache.getHwcBuffer(1, mBuffer1, &outSlot, &outBuffer);
+    EXPECT_EQ(1, outSlot);
     EXPECT_EQ(mBuffer1, outBuffer);
 
-    slot = mCache.getLeastRecentlyUsedSlot();
-    EXPECT_EQ(1, slot);
+    mCache.getHwcBuffer(BufferQueue::INVALID_BUFFER_SLOT, mBuffer2, &outSlot, &outBuffer);
+    EXPECT_EQ(3, outSlot);
+    EXPECT_EQ(mBuffer2, outBuffer);
 }
 
 } // namespace
diff --git a/services/surfaceflinger/ContainerLayer.cpp b/services/surfaceflinger/ContainerLayer.cpp
index 7927fa9..ad08a92 100644
--- a/services/surfaceflinger/ContainerLayer.cpp
+++ b/services/surfaceflinger/ContainerLayer.cpp
@@ -42,4 +42,32 @@
 void ContainerLayer::setPerFrameData(const sp<const DisplayDevice>&, const ui::Transform&,
                                      const Rect&, int32_t, const ui::Dataspace) {}
 
+Layer::RoundedCornerState ContainerLayer::getRoundedCornerStateInternal(
+        const FloatRect bounds) const {
+    const auto& p = mDrawingParent.promote();
+    if (p != nullptr) {
+        RoundedCornerState parentState = p->getRoundedCornerStateInternal(bounds);
+        if (parentState.radius > 0) {
+            ui::Transform t = getActiveTransform(getDrawingState());
+            t = t.inverse();
+            parentState.cropRect = t.transform(parentState.cropRect);
+            // The rounded corners shader only accepts 1 corner radius for performance reasons,
+            // but a transform matrix can define horizontal and vertical scales.
+            // Let's take the average between both of them and pass into the shader, practically we
+            // never do this type of transformation on windows anyway.
+            parentState.radius *= (t[0][0] + t[1][1]) / 2.0f;
+            return parentState;
+        }
+    }
+    const float radius = getDrawingState().cornerRadius;
+    if (radius > 0) {
+        const Rect crop = getCrop(getDrawingState());
+        if (!crop.isEmpty()) {
+            return RoundedCornerState(bounds.intersect(crop.toFloatRect()), radius);
+        }
+        return RoundedCornerState(bounds, radius);
+    }
+    return RoundedCornerState();
+}
+
 } // namespace android
diff --git a/services/surfaceflinger/ContainerLayer.h b/services/surfaceflinger/ContainerLayer.h
index 7222a3e..cd8e722 100644
--- a/services/surfaceflinger/ContainerLayer.h
+++ b/services/surfaceflinger/ContainerLayer.h
@@ -40,6 +40,7 @@
     bool isCreatedFromMainThread() const override { return true; }
 
     bool onPreComposition(nsecs_t /*refreshStartTime*/) override { return false; }
+    Layer::RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const override;
 
 protected:
     bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
diff --git a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
index 775fb80..7370b0c 100644
--- a/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/FramebufferSurface.cpp
@@ -111,7 +111,7 @@
     BufferItem item;
     status_t err = acquireBufferLocked(&item, 0);
     if (err == BufferQueue::NO_BUFFER_AVAILABLE) {
-        mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
+        mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer);
         return NO_ERROR;
     } else if (err != NO_ERROR) {
         ALOGE("error acquiring buffer: %s (%d)", strerror(-err), err);
@@ -137,7 +137,7 @@
     mCurrentFence = item.mFence;
 
     outFence = item.mFence;
-    mHwcBufferCache.getHwcBuffer(mCurrentBuffer, &outSlot, &outBuffer);
+    mHwcBufferCache.getHwcBuffer(mCurrentBufferSlot, mCurrentBuffer, &outSlot, &outBuffer);
     outDataspace = static_cast<Dataspace>(item.mDataSpace);
     status_t result = mHwc.setClientTarget(mDisplayId, outSlot, outFence, outBuffer, outDataspace);
     if (result != NO_ERROR) {
diff --git a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
index 613dc77..4e0e4df 100644
--- a/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
+++ b/services/surfaceflinger/DisplayHardware/VirtualDisplaySurface.cpp
@@ -224,7 +224,7 @@
     if (fbBuffer != nullptr) {
         uint32_t hwcSlot = 0;
         sp<GraphicBuffer> hwcBuffer;
-        mHwcBufferCache.getHwcBuffer(fbBuffer, &hwcSlot, &hwcBuffer);
+        mHwcBufferCache.getHwcBuffer(mFbProducerSlot, fbBuffer, &hwcSlot, &hwcBuffer);
 
         // TODO: Correctly propagate the dataspace from GL composition
         result = mHwc.setClientTarget(*mDisplayId, hwcSlot, mFbFence, hwcBuffer,
diff --git a/services/surfaceflinger/Layer.cpp b/services/surfaceflinger/Layer.cpp
index 898d37e..73f27e4 100644
--- a/services/surfaceflinger/Layer.cpp
+++ b/services/surfaceflinger/Layer.cpp
@@ -1791,10 +1791,10 @@
     return getRoundedCornerStateInternal(mSourceBounds);
 }
 
-Layer::RoundedCornerState Layer::getRoundedCornerStateInternal(const FloatRect bounds) const {
+Layer::RoundedCornerState Layer::getRoundedCornerStateInternal(const FloatRect) const {
     const auto& p = mDrawingParent.promote();
     if (p != nullptr) {
-        RoundedCornerState parentState = p->getRoundedCornerStateInternal(bounds);
+        RoundedCornerState parentState = p->getRoundedCornerStateInternal(mSourceBounds);
         if (parentState.radius > 0) {
             ui::Transform t = getActiveTransform(getDrawingState());
             t = t.inverse();
@@ -1809,7 +1809,8 @@
     }
     const float radius = getDrawingState().cornerRadius;
     return radius > 0
-            ? RoundedCornerState(bounds.intersect(getCrop(getDrawingState()).toFloatRect()), radius)
+            ? RoundedCornerState(mSourceBounds.intersect(getCrop(getDrawingState()).toFloatRect()),
+                                 radius)
             : RoundedCornerState();
 }
 
diff --git a/services/surfaceflinger/Layer.h b/services/surfaceflinger/Layer.h
index 83ff3b6..b9dc7ec 100644
--- a/services/surfaceflinger/Layer.h
+++ b/services/surfaceflinger/Layer.h
@@ -452,13 +452,13 @@
 
     virtual void setPostTime(nsecs_t /*postTime*/) {}
     virtual void setDesiredPresentTime(nsecs_t /*desiredPresentTime*/) {}
+    virtual RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const;
 
 protected:
     virtual bool prepareClientLayer(const RenderArea& renderArea, const Region& clip,
                                     bool useIdentityTransform, Region& clearRegion,
                                     const bool supportProtectedContent,
                                     renderengine::LayerSettings& layer);
-
 public:
     /*
      * compositionengine::LayerFE overrides
@@ -908,8 +908,6 @@
      */
     Rect getCroppedBufferSize(const Layer::State& s) const;
 
-    RoundedCornerState getRoundedCornerStateInternal(const FloatRect bounds) const;
-
     // Cached properties computed from drawing state
     // Effective transform taking into account parent transforms and any parent scaling.
     ui::Transform mEffectiveTransform;
diff --git a/services/surfaceflinger/Scheduler/DispSync.cpp b/services/surfaceflinger/Scheduler/DispSync.cpp
index 6599f9e..a2a6bd8 100644
--- a/services/surfaceflinger/Scheduler/DispSync.cpp
+++ b/services/surfaceflinger/Scheduler/DispSync.cpp
@@ -211,13 +211,14 @@
             const nsecs_t numPeriodsSinceReference = baseTime / mPeriod;
             const nsecs_t predictedReference = mReferenceTime + numPeriodsSinceReference * mPeriod;
             const nsecs_t phaseCorrection = mPhase + listener.mPhase;
-            const nsecs_t predictedLastEventTime = predictedReference + phaseCorrection;
-            if (predictedLastEventTime >= now) {
-                // Make sure that the last event time does not exceed the current time.
-                // If it would, then back the last event time by a period.
-                listener.mLastEventTime = predictedLastEventTime - mPeriod;
-            } else {
-                listener.mLastEventTime = predictedLastEventTime;
+            listener.mLastEventTime = predictedReference + phaseCorrection;
+            // If we're very close in time to the predicted last event time,
+            // then we need to back up the last event time so that we can
+            // attempt to fire an event immediately.
+            //
+            // Otherwise, keep the last event time that we predicted.
+            if (isShorterThanPeriod(now - listener.mLastEventTime)) {
+                listener.mLastEventTime -= mPeriod;
             }
         } else {
             listener.mLastEventTime = now + mPhase - mWakeupLatency;
@@ -314,7 +315,7 @@
 
     // Sanity check that the duration is close enough in length to a period without
     // falling into double-rate vsyncs.
-    bool isCloseToPeriod(nsecs_t duration) {
+    bool isShorterThanPeriod(nsecs_t duration) {
         // Ratio of 3/5 is arbitrary, but it must be greater than 1/2.
         return duration < (3 * mPeriod) / 5;
     }
@@ -330,7 +331,7 @@
             nsecs_t t = computeListenerNextEventTimeLocked(eventListener, onePeriodAgo);
 
             if (t < now) {
-                if (isCloseToPeriod(now - eventListener.mLastCallbackTime)) {
+                if (isShorterThanPeriod(now - eventListener.mLastCallbackTime)) {
                     eventListener.mLastEventTime = t;
                     eventListener.mLastCallbackTime = now;
                     ALOGV("[%s] [%s] Skipping event due to model error", mName,
@@ -391,7 +392,7 @@
 
         // Check that it's been slightly more than half a period since the last
         // event so that we don't accidentally fall into double-rate vsyncs
-        if (isCloseToPeriod(t - listener.mLastEventTime)) {
+        if (isShorterThanPeriod(t - listener.mLastEventTime)) {
             t += mPeriod;
             ALOGV("[%s] Modifying t -> %" PRId64, mName, ns2us(t));
         }
diff --git a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
index cbcc031..9e95f95 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateConfigs.h
@@ -57,16 +57,23 @@
     }
     ~RefreshRateConfigs() = default;
 
-    const std::unordered_map<RefreshRateType, RefreshRate>& getRefreshRates() {
+    const std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>>& getRefreshRates() {
         return mRefreshRates;
     }
-    const RefreshRate& getRefreshRate(RefreshRateType type) { return mRefreshRates[type]; }
+    std::shared_ptr<RefreshRate> getRefreshRate(RefreshRateType type) {
+        const auto& refreshRate = mRefreshRates.find(type);
+        if (refreshRate != mRefreshRates.end()) {
+            return refreshRate->second;
+        }
+        return nullptr;
+    }
 
 private:
     void init(const std::vector<std::shared_ptr<const HWC2::Display::Config>>& configs) {
         // This is the rate that HWC encapsulates right now when the device is in DOZE mode.
         mRefreshRates.emplace(RefreshRateType::POWER_SAVING,
-                              RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0});
+                              std::make_shared<RefreshRate>(
+                                      RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0}));
 
         if (configs.size() < 1) {
             ALOGE("Device does not have valid configs. Config size is 0.");
@@ -90,9 +97,10 @@
         if (vsyncPeriod != 0) {
             const float fps = 1e9 / vsyncPeriod;
             mRefreshRates.emplace(RefreshRateType::DEFAULT,
-                                  RefreshRate{configIdToVsyncPeriod[0].first,
-                                              base::StringPrintf("%2.ffps", fps),
-                                              static_cast<uint32_t>(fps)});
+                                  std::make_shared<RefreshRate>(
+                                          RefreshRate{configIdToVsyncPeriod[0].first,
+                                                      base::StringPrintf("%2.ffps", fps),
+                                                      static_cast<uint32_t>(fps)}));
         }
 
         if (configs.size() < 2) {
@@ -105,13 +113,14 @@
         if (vsyncPeriod != 0) {
             const float fps = 1e9 / vsyncPeriod;
             mRefreshRates.emplace(RefreshRateType::PERFORMANCE,
-                                  RefreshRate{configIdToVsyncPeriod[1].first,
-                                              base::StringPrintf("%2.ffps", fps),
-                                              static_cast<uint32_t>(fps)});
+                                  std::make_shared<RefreshRate>(
+                                          RefreshRate{configIdToVsyncPeriod[1].first,
+                                                      base::StringPrintf("%2.ffps", fps),
+                                                      static_cast<uint32_t>(fps)}));
         }
     }
 
-    std::unordered_map<RefreshRateType, RefreshRate> mRefreshRates;
+    std::unordered_map<RefreshRateType, std::shared_ptr<RefreshRate>> mRefreshRates;
 };
 
 } // namespace scheduler
diff --git a/services/surfaceflinger/Scheduler/RefreshRateStats.h b/services/surfaceflinger/Scheduler/RefreshRateStats.h
index d4ae330..ff63faf 100644
--- a/services/surfaceflinger/Scheduler/RefreshRateStats.h
+++ b/services/surfaceflinger/Scheduler/RefreshRateStats.h
@@ -85,10 +85,13 @@
         std::unordered_map<std::string, int64_t> totalTime;
         for (auto [type, config] : mRefreshRateConfigs->getRefreshRates()) {
             int64_t totalTimeForConfig = 0;
-            if (mConfigModesTotalTime.find(config.configId) != mConfigModesTotalTime.end()) {
-                totalTimeForConfig = mConfigModesTotalTime.at(config.configId);
+            if (!config) {
+                continue;
             }
-            totalTime[config.name] = totalTimeForConfig;
+            if (mConfigModesTotalTime.find(config->configId) != mConfigModesTotalTime.end()) {
+                totalTimeForConfig = mConfigModesTotalTime.at(config->configId);
+            }
+            totalTime[config->name] = totalTimeForConfig;
         }
         return totalTime;
     }
@@ -124,8 +127,11 @@
 
         mConfigModesTotalTime[mode] += timeElapsedMs;
         for (const auto& [type, config] : mRefreshRateConfigs->getRefreshRates()) {
-            if (config.configId == mode) {
-                mTimeStats->recordRefreshRate(config.fps, timeElapsed);
+            if (!config) {
+                continue;
+            }
+            if (config->configId == mode) {
+                mTimeStats->recordRefreshRate(config->fps, timeElapsed);
             }
         }
     }
diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp
index 63a1e4f..945f6fa 100644
--- a/services/surfaceflinger/SurfaceFlinger.cpp
+++ b/services/surfaceflinger/SurfaceFlinger.cpp
@@ -592,10 +592,11 @@
         const auto displayId = getInternalDisplayIdLocked();
         LOG_ALWAYS_FATAL_IF(!displayId);
 
-        const auto performanceRefreshRate =
+        const auto& performanceRefreshRate =
                 mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
 
-        if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+        if (performanceRefreshRate &&
+            isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
             setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::None);
         } else {
             setRefreshRateTo(RefreshRateType::DEFAULT, Scheduler::ConfigEvent::None);
@@ -1471,17 +1472,24 @@
     LOG_ALWAYS_FATAL_IF(!displayId);
     const auto displayToken = getInternalDisplayTokenLocked();
 
-    auto desiredConfigId = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate).configId;
-    const auto display = getDisplayDeviceLocked(displayToken);
-    if (desiredConfigId == display->getActiveConfig()) {
+    const auto& refreshRateConfig = mRefreshRateConfigs[*displayId]->getRefreshRate(refreshRate);
+    if (!refreshRateConfig) {
+        ALOGV("Skipping refresh rate change request for unsupported rate.");
         return;
     }
 
+    const int desiredConfigId = refreshRateConfig->configId;
+
     if (!isConfigAllowed(*displayId, desiredConfigId)) {
         ALOGV("Skipping config %d as it is not part of allowed configs", desiredConfigId);
         return;
     }
 
+    const auto display = getDisplayDeviceLocked(displayToken);
+    if (desiredConfigId == display->getActiveConfig()) {
+        return;
+    }
+
     mPhaseOffsets->setRefreshRateType(refreshRate);
     setDesiredActiveConfig(getInternalDisplayTokenLocked(), desiredConfigId, event);
 }
@@ -5797,12 +5805,12 @@
     int currentConfigIndex = getHwComposer().getActiveConfigIndex(*displayId);
     if (!isConfigAllowed(*displayId, currentConfigIndex)) {
         for (const auto& [type, config] : mRefreshRateConfigs[*displayId]->getRefreshRates()) {
-            if (isConfigAllowed(*displayId, config.configId)) {
+            if (config && isConfigAllowed(*displayId, config->configId)) {
                 // TODO: we switch to the first allowed config. In the future
                 // we may want to enhance this logic to pick a similar config
                 // to the current one
-                ALOGV("Old config is not allowed - switching to config %d", config.configId);
-                setDesiredActiveConfig(displayToken, config.configId,
+                ALOGV("Old config is not allowed - switching to config %d", config->configId);
+                setDesiredActiveConfig(displayToken, config->configId,
                                        Scheduler::ConfigEvent::Changed);
                 break;
             }
@@ -5812,9 +5820,10 @@
     // If idle timer and fps detection are disabled and we are in RefreshRateType::DEFAULT,
     // there is no trigger to move to RefreshRateType::PERFORMANCE, even if it is an allowed.
     if (!mScheduler->isIdleTimerEnabled() && !mUseSmart90ForVideo) {
-        const auto performanceRefreshRate =
+        const auto& performanceRefreshRate =
                 mRefreshRateConfigs[*displayId]->getRefreshRate(RefreshRateType::PERFORMANCE);
-        if (isConfigAllowed(*displayId, performanceRefreshRate.configId)) {
+        if (performanceRefreshRate &&
+            isConfigAllowed(*displayId, performanceRefreshRate->configId)) {
             setRefreshRateTo(RefreshRateType::PERFORMANCE, Scheduler::ConfigEvent::Changed);
         }
     }
diff --git a/services/surfaceflinger/tests/unittests/Android.bp b/services/surfaceflinger/tests/unittests/Android.bp
index 25ce4ac..12b41fd 100644
--- a/services/surfaceflinger/tests/unittests/Android.bp
+++ b/services/surfaceflinger/tests/unittests/Android.bp
@@ -47,6 +47,7 @@
         "LayerMetadataTest.cpp",
         "SchedulerTest.cpp",
         "SchedulerUtilsTest.cpp",
+        "RefreshRateConfigsTest.cpp",
         "RefreshRateStatsTest.cpp",
         "TimeStatsTest.cpp",
         "mock/DisplayHardware/MockComposer.cpp",
diff --git a/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
new file mode 100644
index 0000000..b218ad6
--- /dev/null
+++ b/services/surfaceflinger/tests/unittests/RefreshRateConfigsTest.cpp
@@ -0,0 +1,164 @@
+/*
+ * 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.
+ */
+
+#undef LOG_TAG
+#define LOG_TAG "SchedulerUnittests"
+
+#include <gmock/gmock.h>
+#include <log/log.h>
+#include <thread>
+
+#include "DisplayHardware/HWC2.h"
+#include "Scheduler/RefreshRateConfigs.h"
+#include "mock/DisplayHardware/MockDisplay.h"
+
+using namespace std::chrono_literals;
+using testing::_;
+
+namespace android {
+namespace scheduler {
+
+using RefreshRateType = RefreshRateConfigs::RefreshRateType;
+using RefreshRate = RefreshRateConfigs::RefreshRate;
+
+class RefreshRateConfigsTest : public testing::Test {
+protected:
+    static constexpr int CONFIG_ID_60 = 0;
+    static constexpr int CONFIG_ID_90 = 1;
+    static constexpr int64_t VSYNC_60 = 16666667;
+    static constexpr int64_t VSYNC_90 = 11111111;
+
+    RefreshRateConfigsTest();
+    ~RefreshRateConfigsTest();
+
+    void assertRatesEqual(const RefreshRate& left, const RefreshRate& right) {
+        ASSERT_EQ(left.configId, right.configId);
+        ASSERT_EQ(left.name, right.name);
+        ASSERT_EQ(left.fps, right.fps);
+    }
+};
+
+RefreshRateConfigsTest::RefreshRateConfigsTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Setting up for %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+RefreshRateConfigsTest::~RefreshRateConfigsTest() {
+    const ::testing::TestInfo* const test_info =
+            ::testing::UnitTest::GetInstance()->current_test_info();
+    ALOGD("**** Tearing down after %s.%s\n", test_info->test_case_name(), test_info->name());
+}
+
+namespace {
+/* ------------------------------------------------------------------------
+ * Test cases
+ */
+TEST_F(RefreshRateConfigsTest, zeroDeviceConfigs_storesPowerSavingConfig) {
+    std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+    RefreshRateConfigs configs(displayConfigs);
+
+    // We always store a configuration for screen off.
+    const auto& rates = configs.getRefreshRates();
+    ASSERT_EQ(1, rates.size());
+    const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+    ASSERT_NE(rates.end(), powerSavingRate);
+    ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
+    ASSERT_EQ(rates.end(), rates.find(RefreshRateType::DEFAULT));
+
+    RefreshRate expectedConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+    assertRatesEqual(expectedConfig, *powerSavingRate->second);
+
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    assertRatesEqual(expectedConfig, *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+
+    // Sanity check that getRefreshRate() does not modify the underlying configs.
+    ASSERT_EQ(1, configs.getRefreshRates().size());
+}
+
+TEST_F(RefreshRateConfigsTest, oneDeviceConfig_storesDefaultConfig) {
+    auto display = new Hwc2::mock::Display();
+    std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+    auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
+    config60.setVsyncPeriod(VSYNC_60);
+    displayConfigs.push_back(config60.build());
+    RefreshRateConfigs configs(displayConfigs);
+
+    const auto& rates = configs.getRefreshRates();
+    ASSERT_EQ(2, rates.size());
+    const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+    const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
+    ASSERT_NE(rates.end(), powerSavingRate);
+    ASSERT_NE(rates.end(), defaultRate);
+    ASSERT_EQ(rates.end(), rates.find(RefreshRateType::PERFORMANCE));
+
+    RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+    assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
+    RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
+    assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
+
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    assertRatesEqual(expectedPowerSavingConfig,
+                     *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+    assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT));
+    ASSERT_FALSE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+
+    // Sanity check that getRefreshRate() does not modify the underlying configs.
+    ASSERT_EQ(2, configs.getRefreshRates().size());
+}
+
+TEST_F(RefreshRateConfigsTest, twoDeviceConfigs_storesPerformanceConfig) {
+    auto display = new Hwc2::mock::Display();
+    std::vector<std::shared_ptr<const HWC2::Display::Config>> displayConfigs;
+    auto config60 = HWC2::Display::Config::Builder(*display, CONFIG_ID_60);
+    config60.setVsyncPeriod(VSYNC_60);
+    displayConfigs.push_back(config60.build());
+    auto config90 = HWC2::Display::Config::Builder(*display, CONFIG_ID_90);
+    config90.setVsyncPeriod(VSYNC_90);
+    displayConfigs.push_back(config90.build());
+    RefreshRateConfigs configs(displayConfigs);
+
+    const auto& rates = configs.getRefreshRates();
+    ASSERT_EQ(3, rates.size());
+    const auto& powerSavingRate = rates.find(RefreshRateType::POWER_SAVING);
+    const auto& defaultRate = rates.find(RefreshRateType::DEFAULT);
+    const auto& performanceRate = rates.find(RefreshRateType::PERFORMANCE);
+    ASSERT_NE(rates.end(), powerSavingRate);
+    ASSERT_NE(rates.end(), defaultRate);
+    ASSERT_NE(rates.end(), performanceRate);
+
+    RefreshRate expectedPowerSavingConfig = RefreshRate{SCREEN_OFF_CONFIG_ID, "ScreenOff", 0};
+    assertRatesEqual(expectedPowerSavingConfig, *powerSavingRate->second);
+    RefreshRate expectedDefaultConfig = RefreshRate{CONFIG_ID_60, "60fps", 60};
+    assertRatesEqual(expectedDefaultConfig, *defaultRate->second);
+    RefreshRate expectedPerformanceConfig = RefreshRate{CONFIG_ID_90, "90fps", 90};
+    assertRatesEqual(expectedPerformanceConfig, *performanceRate->second);
+
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    assertRatesEqual(expectedPowerSavingConfig,
+                     *configs.getRefreshRate(RefreshRateType::POWER_SAVING));
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::DEFAULT));
+    assertRatesEqual(expectedDefaultConfig, *configs.getRefreshRate(RefreshRateType::DEFAULT));
+    ASSERT_TRUE(configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+    assertRatesEqual(expectedPerformanceConfig,
+                     *configs.getRefreshRate(RefreshRateType::PERFORMANCE));
+}
+} // namespace
+} // namespace scheduler
+} // namespace android