From 23093756464d53733e241f7d1da2dc9feb467a4a Mon Sep 17 00:00:00 2001 From: Kohsuke Yatoh Date: Thu, 19 Nov 2020 21:49:33 -0800 Subject: [PATCH] Add perf test for Typeface serialization. Bug: 172891184 Test: atest TypefaceSerializationPerfTest Change-Id: I3a0c8ba26350d6ca51a93a458e73362ac23c566f --- .../TypefaceSerializationPerfTest.java | 83 +++++++++++++++++++ graphics/java/android/graphics/Typeface.java | 33 +++++++- libs/hwui/jni/Typeface.cpp | 7 ++ 3 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java diff --git a/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java new file mode 100644 index 0000000000000..547369055e954 --- /dev/null +++ b/apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java @@ -0,0 +1,83 @@ +/* + * 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 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); + } + } +} diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 5743df5216bee..eba7306d03e7d 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -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) @@ -1123,7 +1125,7 @@ public class Typeface { } native_instance = ni; - sRegistry.registerNativeAllocation(this, native_instance); + mCleaner = sRegistry.registerNativeAllocation(this, native_instance); mStyle = nativeGetStyle(ni); mWeight = nativeGetWeight(ni); } @@ -1237,6 +1239,13 @@ public class Typeface { bos.write(value & 0xFF); } + /** @hide */ + public static Map 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. @@ -1297,13 +1306,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 systemFontMap = new HashMap<>(); initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(), SystemFonts.getAliases()); setSystemFontMap(systemFontMap); } + static { + loadPreinstalledSystemFontMap(); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp index b88ffa6e79b86..6d626ad727ee5 100644 --- a/libs/hwui/jni/Typeface.cpp +++ b/libs/hwui/jni/Typeface.cpp @@ -145,6 +145,13 @@ static std::function()> readMinikinFontSki return [fontPath, fontIndex, axesPtr, axesCount]() -> std::shared_ptr { std::string path(fontPath.data(), fontPath.size()); sk_sp 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 axes(axesPtr, axesPtr + axesCount);