Merge "Convert country code to Layoutinfo (Language tag + Layout type)"
diff --git a/libs/jpegrecoverymap/recoverymap.cpp b/libs/jpegrecoverymap/recoverymap.cpp
index bc69a83..1b69743 100644
--- a/libs/jpegrecoverymap/recoverymap.cpp
+++ b/libs/jpegrecoverymap/recoverymap.cpp
@@ -192,6 +192,31 @@
   return NO_ERROR;
 }
 
+/*
+ * Helper function copies the JPEG image from without EXIF.
+ *
+ * @param dest destination of the data to be written.
+ * @param source source of data being written.
+ * @param exif_pos position of the EXIF package, which is aligned with jpegdecoder.getEXIFPos().
+ *                 (4 bypes offset to FF sign, the byte after FF E1 XX XX <this byte>).
+ * @param exif_size exif size without the initial 4 bytes, aligned with jpegdecoder.getEXIFSize().
+ */
+void copyJpegWithoutExif(jr_compressed_ptr dest,
+                         jr_compressed_ptr source,
+                         size_t exif_pos,
+                         size_t exif_size) {
+  memcpy(dest, source, sizeof(jpegr_compressed_struct));
+
+  const size_t exif_offset = 4; //exif_pos has 4 bypes offset to the FF sign
+  dest->length = source->length - exif_size - exif_offset;
+  dest->data = malloc(dest->length);
+
+  memcpy(dest->data, source->data, exif_pos - exif_offset);
+  memcpy((uint8_t*)dest->data + exif_pos - exif_offset,
+         (uint8_t*)source->data + exif_pos + exif_size,
+         source->length - exif_pos - exif_size);
+}
+
 /* Encode API-0 */
 status_t RecoveryMap::encodeJPEGR(jr_uncompressed_ptr uncompressed_p010_image,
                                   jpegr_transfer_function hdr_tf,
@@ -367,17 +392,18 @@
     return ERROR_JPEGR_DECODE_ERROR;
   }
 
+  // Update exif.
   jpegr_exif_struct exif;
   exif.data = nullptr;
   exif.length = 0;
-  // Delete EXIF package if it appears, and update exif.
+  jpegr_compressed_struct new_jpeg_image;
+  new_jpeg_image.data = nullptr;
+  new_jpeg_image.length = 0;
   if (jpeg_decoder.getEXIFPos() != 0) {
-    int new_length = compressed_jpeg_image->length - jpeg_decoder.getEXIFSize() - 4;
-    memcpy((uint8_t*)compressed_jpeg_image->data + jpeg_decoder.getEXIFPos() - 4,
-           (uint8_t*)compressed_jpeg_image->data + jpeg_decoder.getEXIFPos()
-                  + jpeg_decoder.getEXIFSize(),
-           compressed_jpeg_image->length - jpeg_decoder.getEXIFPos() - jpeg_decoder.getEXIFSize());
-    compressed_jpeg_image->length = new_length;
+    copyJpegWithoutExif(&new_jpeg_image,
+                        compressed_jpeg_image,
+                        jpeg_decoder.getEXIFPos(),
+                        jpeg_decoder.getEXIFSize());
     exif.data = jpeg_decoder.getEXIFPtr();
     exif.length = jpeg_decoder.getEXIFSize();
   }
@@ -395,7 +421,12 @@
   JPEGR_CHECK(updateExif(&exif, &new_exif));
 
   JPEGR_CHECK(appendRecoveryMap(
-          compressed_jpeg_image, &compressed_map, &new_exif, &metadata, dest));
+          new_jpeg_image.data == nullptr ? compressed_jpeg_image : &new_jpeg_image,
+          &compressed_map, &new_exif, &metadata, dest));
+
+  if (new_jpeg_image.data != nullptr) {
+    free(new_jpeg_image.data);
+  }
 
   return NO_ERROR;
 }
@@ -421,17 +452,18 @@
   uncompressed_yuv_420_image.height = jpeg_decoder.getDecompressedImageHeight();
   uncompressed_yuv_420_image.colorGamut = compressed_jpeg_image->colorGamut;
 
+  // Update exif.
   jpegr_exif_struct exif;
   exif.data = nullptr;
   exif.length = 0;
-  // Delete EXIF package if it appears, and update exif.
+  jpegr_compressed_struct new_jpeg_image;
+  new_jpeg_image.data = nullptr;
+  new_jpeg_image.length = 0;
   if (jpeg_decoder.getEXIFPos() != 0) {
-    int new_length = compressed_jpeg_image->length - jpeg_decoder.getEXIFSize() - 4;
-    memcpy((uint8_t*)compressed_jpeg_image->data + jpeg_decoder.getEXIFPos() - 4,
-           (uint8_t*)compressed_jpeg_image->data + jpeg_decoder.getEXIFPos()
-                  + jpeg_decoder.getEXIFSize(),
-           compressed_jpeg_image->length - jpeg_decoder.getEXIFPos() - jpeg_decoder.getEXIFSize());
-    compressed_jpeg_image->length = new_length;
+    copyJpegWithoutExif(&new_jpeg_image,
+                        compressed_jpeg_image,
+                        jpeg_decoder.getEXIFPos(),
+                        jpeg_decoder.getEXIFSize());
     exif.data = jpeg_decoder.getEXIFPtr();
     exif.length = jpeg_decoder.getEXIFSize();
   }
@@ -472,7 +504,12 @@
   JPEGR_CHECK(compressRecoveryMap(&map, &compressed_map));
 
   JPEGR_CHECK(appendRecoveryMap(
-          compressed_jpeg_image, &compressed_map, &new_exif, &metadata, dest));
+          new_jpeg_image.data == nullptr ? compressed_jpeg_image : &new_jpeg_image,
+          &compressed_map, &new_exif, &metadata, dest));
+
+  if (new_jpeg_image.data != nullptr) {
+    free(new_jpeg_image.data);
+  }
 
   return NO_ERROR;
 }
diff --git a/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h b/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h
index 974e0fd..b95f011 100644
--- a/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h
+++ b/libs/renderengine/include/renderengine/mock/FakeExternalTexture.h
@@ -23,7 +23,9 @@
 namespace mock {
 
 class FakeExternalTexture : public renderengine::ExternalTexture {
-    const sp<GraphicBuffer> mNullBuffer = nullptr;
+    const sp<GraphicBuffer> mEmptyBuffer =
+            sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888,
+                                    GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
     uint32_t mWidth;
     uint32_t mHeight;
     uint64_t mId;
@@ -34,7 +36,7 @@
     FakeExternalTexture(uint32_t width, uint32_t height, uint64_t id, PixelFormat pixelFormat,
                         uint64_t usage)
           : mWidth(width), mHeight(height), mId(id), mPixelFormat(pixelFormat), mUsage(usage) {}
-    const sp<GraphicBuffer>& getBuffer() const { return mNullBuffer; }
+    const sp<GraphicBuffer>& getBuffer() const { return mEmptyBuffer; }
     bool hasSameBuffer(const renderengine::ExternalTexture& other) const override {
         return getId() == other.getId();
     }
diff --git a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
index 2a5bfae..b86782f 100644
--- a/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
+++ b/services/surfaceflinger/CompositionEngine/include/compositionengine/impl/OutputLayerCompositionState.h
@@ -137,6 +137,7 @@
         HwcBufferCache hwcBufferCache;
 
         // The previously-active buffer for this layer.
+        uint64_t activeBufferId;
         uint32_t activeBufferSlot;
 
         // Set to true when overridden info has been sent to HW composer
diff --git a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
index 34ed214..f0105b2 100644
--- a/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/HwcBufferCache.cpp
@@ -28,11 +28,6 @@
 }
 
 HwcSlotAndBuffer HwcBufferCache::getHwcSlotAndBuffer(const sp<GraphicBuffer>& buffer) {
-    // TODO(b/261930578): This is for unit tests which don't mock GraphicBuffers but instead send
-    // in nullptrs.
-    if (buffer == nullptr) {
-        return {0, nullptr};
-    }
     if (auto i = mCacheByBufferId.find(buffer->getId()); i != mCacheByBufferId.end()) {
         Cache& cache = i->second;
         // mark this cache slot as more recently used so it won't get evicted anytime soon
diff --git a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
index 766d7ea..60a2c83 100644
--- a/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
+++ b/services/surfaceflinger/CompositionEngine/src/OutputLayer.cpp
@@ -617,13 +617,24 @@
         return;
     }
 
+    // Uncache the active buffer last so that it's the first buffer to be purged from the cache
+    // next time a buffer is sent to this layer.
+    bool uncacheActiveBuffer = false;
+
     std::vector<uint32_t> slotsToClear;
     for (uint64_t bufferId : bufferIdsToUncache) {
-        uint32_t slot = state.hwc->hwcBufferCache.uncache(bufferId);
-        if (slot != UINT32_MAX) {
-            slotsToClear.push_back(slot);
+        if (bufferId == state.hwc->activeBufferId) {
+            uncacheActiveBuffer = true;
+        } else {
+            uint32_t slot = state.hwc->hwcBufferCache.uncache(bufferId);
+            if (slot != UINT32_MAX) {
+                slotsToClear.push_back(slot);
+            }
         }
     }
+    if (uncacheActiveBuffer) {
+        slotsToClear.push_back(state.hwc->hwcBufferCache.uncache(state.hwc->activeBufferId));
+    }
 
     hal::Error error =
             state.hwc->hwcLayer->setBufferSlotsToClear(slotsToClear, state.hwc->activeBufferSlot);
@@ -655,17 +666,20 @@
             hwcSlotAndBuffer = state.hwc->hwcBufferCache.getOverrideHwcSlotAndBuffer(
                     state.overrideInfo.buffer->getBuffer());
             hwcFence = state.overrideInfo.acquireFence;
+            // Keep track of the active buffer ID so when it's discarded we uncache it last so its
+            // slot will be used first, allowing the memory to be freed as soon as possible.
+            state.hwc->activeBufferId = state.overrideInfo.buffer->getBuffer()->getId();
         } else {
             hwcSlotAndBuffer =
                     state.hwc->hwcBufferCache.getHwcSlotAndBuffer(outputIndependentState.buffer);
             hwcFence = outputIndependentState.acquireFence;
+            // Keep track of the active buffer ID so when it's discarded we uncache it last so its
+            // slot will be used first, allowing the memory to be freed as soon as possible.
+            state.hwc->activeBufferId = outputIndependentState.buffer->getId();
         }
-
         // Keep track of the active buffer slot, so we can restore it after clearing other buffer
         // slots.
-        if (hwcSlotAndBuffer.buffer) {
-            state.hwc->activeBufferSlot = hwcSlotAndBuffer.slot;
-        }
+        state.hwc->activeBufferSlot = hwcSlotAndBuffer.slot;
     }
 
     if (auto error = hwcLayer->setBuffer(hwcSlotAndBuffer.slot, hwcSlotAndBuffer.buffer, hwcFence);
diff --git a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
index 0edc226..9ad2edb 100644
--- a/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
+++ b/services/surfaceflinger/CompositionEngine/tests/OutputLayerTest.cpp
@@ -1318,6 +1318,7 @@
 struct OutputLayerUncacheBufferTest : public OutputLayerTest {
     static const sp<GraphicBuffer> kBuffer1;
     static const sp<GraphicBuffer> kBuffer2;
+    static const sp<GraphicBuffer> kBuffer3;
     static const sp<Fence> kFence;
 
     OutputLayerUncacheBufferTest() {
@@ -1343,6 +1344,10 @@
         sp<GraphicBuffer>::make(2, 3, PIXEL_FORMAT_RGBA_8888,
                                 AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
                                         AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
+const sp<GraphicBuffer> OutputLayerUncacheBufferTest::kBuffer3 =
+        sp<GraphicBuffer>::make(4, 5, PIXEL_FORMAT_RGBA_8888,
+                                AHARDWAREBUFFER_USAGE_CPU_WRITE_OFTEN |
+                                        AHARDWAREBUFFER_USAGE_CPU_READ_OFTEN);
 const sp<Fence> OutputLayerUncacheBufferTest::kFence = sp<Fence>::make();
 
 TEST_F(OutputLayerUncacheBufferTest, canUncacheAndReuseSlot) {
@@ -1360,26 +1365,38 @@
                                  /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
     Mock::VerifyAndClearExpectations(&mHwcLayer);
 
-    // buffer slots are cleared in HWC
-    std::vector<uint32_t> slotsToClear = {0, 1};
-    EXPECT_CALL(mHwcLayer,
-                setBufferSlotsToClear(/*slotsToClear*/ slotsToClear, /*activeBufferSlot*/ 1));
-    mOutputLayer.uncacheBuffers({kBuffer1->getId(), kBuffer2->getId()});
+    // Buffer3 is stored in slot 2
+    mLayerFEState.buffer = kBuffer3;
+    EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 2, kBuffer3, kFence));
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
     Mock::VerifyAndClearExpectations(&mHwcLayer);
 
-    // rather than allocating a new slot, the active buffer slot (slot 1) is reused first to free
-    // the memory as soon as possible
+    // Buffer2 becomes the active buffer again (with a nullptr) and reuses slot 1
+    mLayerFEState.buffer = kBuffer2;
+    sp<GraphicBuffer> nullBuffer = nullptr;
+    EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 1, nullBuffer, kFence));
+    mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
+                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
+    Mock::VerifyAndClearExpectations(&mHwcLayer);
+
+    // Buffer slots are cleared
+    std::vector<uint32_t> slotsToClear = {0, 2, 1}; // order doesn't matter
+    EXPECT_CALL(mHwcLayer, setBufferSlotsToClear(slotsToClear, /*activeBufferSlot*/ 1));
+    // Uncache the active buffer in between other buffers to exercise correct algorithmic behavior.
+    mOutputLayer.uncacheBuffers({kBuffer1->getId(), kBuffer2->getId(), kBuffer3->getId()});
+    Mock::VerifyAndClearExpectations(&mHwcLayer);
+
+    // Buffer1 becomes active again, and rather than allocating a new slot, or re-using slot 0,
+    // the active buffer slot (slot 1 for Buffer2) is reused first, which allows HWC to free the
+    // memory for the active buffer. Note: slot 1 is different from the first and last buffer slot
+    // requested to be cleared in slotsToClear (slot 1), above, indicating that the algorithm
+    // correctly identifies the active buffer as the buffer in slot 1, despite ping-ponging.
     mLayerFEState.buffer = kBuffer1;
     EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 1, kBuffer1, kFence));
     mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
                                  /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
     Mock::VerifyAndClearExpectations(&mHwcLayer);
-
-    // rather than allocating a new slot, slot 0 is reused
-    mLayerFEState.buffer = kBuffer2;
-    EXPECT_CALL(mHwcLayer, setBuffer(/*slot*/ 0, kBuffer2, kFence));
-    mOutputLayer.writeStateToHWC(/*includeGeometry*/ false, /*skipLayer*/ false, 0,
-                                 /*zIsOverridden*/ false, /*isPeekingThrough*/ false);
 }
 
 /*
diff --git a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
index f1a6c0e..ab98dbf 100644
--- a/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
+++ b/services/surfaceflinger/Tracing/tools/LayerTraceGenerator.cpp
@@ -27,7 +27,6 @@
 #include <log/log.h>
 #include <mock/MockEventThread.h>
 #include <renderengine/ExternalTexture.h>
-#include <renderengine/mock/FakeExternalTexture.h>
 #include <renderengine/mock/RenderEngine.h>
 #include <utils/String16.h>
 #include <string>
@@ -95,6 +94,30 @@
     }
 };
 
+class FakeExternalTexture : public renderengine::ExternalTexture {
+    const sp<GraphicBuffer> mNullBuffer = nullptr;
+    uint32_t mWidth;
+    uint32_t mHeight;
+    uint64_t mId;
+    PixelFormat mPixelFormat;
+    uint64_t mUsage;
+
+public:
+    FakeExternalTexture(uint32_t width, uint32_t height, uint64_t id, PixelFormat pixelFormat,
+                        uint64_t usage)
+          : mWidth(width), mHeight(height), mId(id), mPixelFormat(pixelFormat), mUsage(usage) {}
+    const sp<GraphicBuffer>& getBuffer() const { return mNullBuffer; }
+    bool hasSameBuffer(const renderengine::ExternalTexture& other) const override {
+        return getId() == other.getId();
+    }
+    uint32_t getWidth() const override { return mWidth; }
+    uint32_t getHeight() const override { return mHeight; }
+    uint64_t getId() const override { return mId; }
+    PixelFormat getPixelFormat() const override { return mPixelFormat; }
+    uint64_t getUsage() const override { return mUsage; }
+    ~FakeExternalTexture() = default;
+};
+
 class MockSurfaceFlinger : public SurfaceFlinger {
 public:
     MockSurfaceFlinger(Factory& factory)
@@ -102,12 +125,10 @@
     std::shared_ptr<renderengine::ExternalTexture> getExternalTextureFromBufferData(
             BufferData& bufferData, const char* /* layerName */,
             uint64_t /* transactionId */) override {
-        return std::make_shared<renderengine::mock::FakeExternalTexture>(bufferData.getWidth(),
-                                                                         bufferData.getHeight(),
-                                                                         bufferData.getId(),
-                                                                         bufferData
-                                                                                 .getPixelFormat(),
-                                                                         bufferData.getUsage());
+        return std::make_shared<FakeExternalTexture>(bufferData.getWidth(), bufferData.getHeight(),
+                                                     bufferData.getId(),
+                                                     bufferData.getPixelFormat(),
+                                                     bufferData.getUsage());
     };
 
     // b/220017192 migrate from transact codes to ISurfaceComposer apis
diff --git a/services/surfaceflinger/tests/unittests/CompositionTest.cpp b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
index 06b9caa..ba77600 100644
--- a/services/surfaceflinger/tests/unittests/CompositionTest.cpp
+++ b/services/surfaceflinger/tests/unittests/CompositionTest.cpp
@@ -182,7 +182,9 @@
     sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
     std::vector<sp<Layer>> mAuxiliaryLayers;
 
-    sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make();
+    sp<GraphicBuffer> mBuffer =
+            sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888,
+                                    GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
     ANativeWindowBuffer* mNativeWindowBuffer = mBuffer->getNativeBuffer();
 
     Hwc2::mock::Composer* mComposer = nullptr;
diff --git a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
index d58e644..223f4db 100644
--- a/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
+++ b/services/surfaceflinger/tests/unittests/DisplayTransactionTestHelpers.h
@@ -115,7 +115,9 @@
 
     TestableSurfaceFlinger mFlinger;
     sp<mock::NativeWindow> mNativeWindow = sp<mock::NativeWindow>::make();
-    sp<GraphicBuffer> mBuffer = sp<GraphicBuffer>::make();
+    sp<GraphicBuffer> mBuffer =
+            sp<GraphicBuffer>::make(1u, 1u, PIXEL_FORMAT_RGBA_8888,
+                                    GRALLOC_USAGE_SW_WRITE_OFTEN | GRALLOC_USAGE_SW_READ_OFTEN);
     Hwc2::mock::PowerAdvisor mPowerAdvisor;
 
     FakeDisplayInjector mFakeDisplayInjector{mFlinger, mPowerAdvisor, mNativeWindow};