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

Commit 531245a7 authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add perf test for Typeface serialization."

parents 97a624b3 23093756
Loading
Loading
Loading
Loading
+83 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2020 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.
 */

package android.graphics.perftests;

import android.graphics.Typeface;
import android.os.SharedMemory;
import android.perftests.utils.BenchmarkState;
import android.perftests.utils.PerfStatusReporter;

import androidx.test.filters.LargeTest;
import androidx.test.runner.AndroidJUnit4;

import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Map;

@LargeTest
@RunWith(AndroidJUnit4.class)
public class TypefaceSerializationPerfTest {

    @Rule
    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();

    @Test
    public void testSerializeFontMap() throws Exception {
        Map<String, Typeface> systemFontMap = Typeface.getSystemFontMap();
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();

        while (state.keepRunning()) {
            Typeface.serializeFontMap(systemFontMap);
        }
    }

    @Test
    public void testDeserializeFontMap() throws Exception {
        SharedMemory memory = Typeface.serializeFontMap(Typeface.getSystemFontMap());
        ByteBuffer buffer = memory.mapReadOnly().order(ByteOrder.BIG_ENDIAN);
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();

        while (state.keepRunning()) {
            buffer.position(0);
            Typeface.deserializeFontMap(buffer);
        }
    }

    @Test
    public void testSetSystemFontMap() throws Exception {
        SharedMemory memory = null;
        BenchmarkState state = mPerfStatusReporter.getBenchmarkState();

        while (state.keepRunning()) {
            state.pauseTiming();
            // Explicitly destroy lazy-loaded typefaces, so that we don't hit the mmap limit
            // (max_map_count).
            Typeface.destroySystemFontMap();
            Typeface.loadPreinstalledSystemFontMap();
            if (memory != null) {
                memory.close();
            }
            memory = Typeface.serializeFontMap(Typeface.getSystemFontMap());
            state.resumeTiming();
            Typeface.setSystemFontMap(memory);
        }
    }
}
+31 −2
Original line number Diff line number Diff line
@@ -169,6 +169,8 @@ public class Typeface {
    @UnsupportedAppUsage
    public long native_instance;

    private Runnable mCleaner;

    /** @hide */
    @IntDef(value = {NORMAL, BOLD, ITALIC, BOLD_ITALIC})
    @Retention(RetentionPolicy.SOURCE)
@@ -1120,7 +1122,7 @@ public class Typeface {
        }

        native_instance = ni;
        sRegistry.registerNativeAllocation(this, native_instance);
        mCleaner = sRegistry.registerNativeAllocation(this, native_instance);
        mStyle = nativeGetStyle(ni);
        mWeight = nativeGetWeight(ni);
    }
@@ -1234,6 +1236,13 @@ public class Typeface {
        bos.write(value & 0xFF);
    }

    /** @hide */
    public static Map<String, Typeface> getSystemFontMap() {
        synchronized (SYSTEM_FONT_MAP_LOCK) {
            return sSystemFontMap;
        }
    }

    /**
     * Deserialize font map and set it as system font map. This method should be called at most once
     * per process.
@@ -1294,13 +1303,33 @@ public class Typeface {
        }
    }

    static {
    /** @hide */
    @VisibleForTesting
    public static void destroySystemFontMap() {
        synchronized (SYSTEM_FONT_MAP_LOCK) {
            for (Typeface typeface : sSystemFontMap.values()) {
                typeface.mCleaner.run();
            }
            sSystemFontMap.clear();
            if (sSystemFontMapBuffer != null) {
                SharedMemory.unmap(sSystemFontMapBuffer);
            }
            sSystemFontMapBuffer = null;
        }
    }

    /** @hide */
    public static void loadPreinstalledSystemFontMap() {
        final HashMap<String, Typeface> systemFontMap = new HashMap<>();
        initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(),
                SystemFonts.getAliases());
        setSystemFontMap(systemFontMap);
    }

    static {
        loadPreinstalledSystemFontMap();
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
+7 −0
Original line number Diff line number Diff line
@@ -159,6 +159,13 @@ static std::function<std::shared_ptr<minikin::MinikinFont>()> readMinikinFontSki
    return [fontPath, fontIndex, axesPtr, axesCount]() -> std::shared_ptr<minikin::MinikinFont> {
        std::string path(fontPath.data(), fontPath.size());
        sk_sp<SkData> data = SkData::MakeFromFileName(path.c_str());
        if (data == nullptr) {
            // This may happen if:
            // 1. When the process failed to open the file (e.g. invalid path or permission).
            // 2. When the process failed to map the file (e.g. hitting max_map_count limit).
            ALOGE("Failed to make SkData from file name: %s", path.c_str());
            return nullptr;
        }
        const void* fontPtr = data->data();
        size_t fontSize = data->size();
        std::vector<minikin::FontVariation> axes(axesPtr, axesPtr + axesCount);