Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c3127a78 authored by John Reck's avatar John Reck
Browse files

Fix TextDropShadowCache infinite loop

Bug: 26862239

Switch TextDropCacheShadow to use the tracked objectSize()
instead of the optional bitmapSize. A mismatch here
results in ::get() infinite looping trying to free space in
the cache since the LRU removal callback would always
decrement mSize by 0 since bitmapSize was not being set.

Also prevent the infinite loop in the future by crashing if
this scenario happens again.

Change-Id: Ib4e9fbe1c8327af2335ad650fd694a1627d9824f
parent f3e5d1d4
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -248,7 +248,8 @@ LOCAL_SRC_FILES += \
    tests/unit/VectorDrawableTests.cpp \
    tests/unit/OffscreenBufferPoolTests.cpp \
    tests/unit/StringUtilsTests.cpp \
    tests/unit/BufferPoolTests.cpp
    tests/unit/BufferPoolTests.cpp \
    tests/unit/TextDropShadowCacheTests.cpp

ifeq (true, $(HWUI_NEW_OPS))
    LOCAL_SRC_FILES += \
+5 −3
Original line number Diff line number Diff line
@@ -148,7 +148,7 @@ void TextDropShadowCache::setMaxSize(uint32_t maxSize) {

void TextDropShadowCache::operator()(ShadowText&, ShadowTexture*& texture) {
    if (texture) {
        mSize -= texture->bitmapSize;
        mSize -= texture->objectSize();

        if (mDebugEnabled) {
            ALOGD("Shadow texture deleted, size = %d", texture->bitmapSize);
@@ -195,7 +195,9 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* glyphs
        // Don't even try to cache a bitmap that's bigger than the cache
        if (size < mMaxSize) {
            while (mSize + size > mMaxSize) {
                mCache.removeOldest();
                LOG_ALWAYS_FATAL_IF(!mCache.removeOldest(),
                        "Failed to remove oldest from cache. mSize = %"
                        PRIu32 ", mCache.size() = %zu", mSize, mCache.size());
            }
        }

@@ -212,7 +214,7 @@ ShadowTexture* TextDropShadowCache::get(const SkPaint* paint, const char* glyphs

            entry.copyTextLocally();

            mSize += size;
            mSize += texture->objectSize();
            mCache.put(entry, texture);
        } else {
            texture->cleanup = true;
+53 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2016 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include <gtest/gtest.h>

#include "GammaFontRenderer.h"
#include "TextDropShadowCache.h"
#include "utils/Blur.h"
#include "tests/common/TestUtils.h"

#include <SkBlurDrawLooper.h>
#include <SkPaint.h>

using namespace android;
using namespace android::uirenderer;

RENDERTHREAD_TEST(TextDropShadowCache, addRemove) {
    GammaFontRenderer gammaFontRenderer;
    FontRenderer& fontRenderer = gammaFontRenderer.getFontRenderer();
    TextDropShadowCache cache(5000);
    cache.setFontRenderer(fontRenderer);

    SkPaint paint;
    paint.setLooper(SkBlurDrawLooper::Create((SkColor)0xFFFFFFFF,
            Blur::convertRadiusToSigma(10), 10, 10))->unref();
    std::string msg("This is a test");
    std::unique_ptr<float[]> positions(new float[msg.length()]);
    for (size_t i = 0; i < msg.length(); i++) {
        positions[i] = i * 10.0f;
    }
    fontRenderer.setFont(&paint, SkMatrix::I());
    ShadowTexture* texture = cache.get(&paint, msg.c_str(), msg.length(),
            10.0f, positions.get());
    ASSERT_TRUE(texture);
    ASSERT_FALSE(texture->cleanup);
    ASSERT_EQ((uint32_t) texture->objectSize(), cache.getSize());
    ASSERT_TRUE(cache.getSize());
    cache.clear();
    ASSERT_EQ(cache.getSize(), 0u);
}