diff options
-rw-r--r-- | apct-tests/perftests/core/src/android/graphics/perftests/TypefaceSerializationPerfTest.java | 83 | ||||
-rw-r--r-- | graphics/java/android/graphics/Typeface.java | 33 | ||||
-rw-r--r-- | libs/hwui/jni/Typeface.cpp | 7 |
3 files changed, 121 insertions, 2 deletions
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 000000000000..547369055e95 --- /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<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); + } + } +} diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index 9fb4ed59e81f..712349aaee57 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) @@ -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; diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp index 9e5b1fb17c01..a2964d6627a1 100644 --- a/libs/hwui/jni/Typeface.cpp +++ b/libs/hwui/jni/Typeface.cpp @@ -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); |