From 735d447d4807bb9440b2037bc67e35da95edb209 Mon Sep 17 00:00:00 2001 From: Mohammad Samiul Islam Date: Thu, 12 Nov 2020 11:46:46 +0000 Subject: [PATCH] Revert "Support loading system font map from SharedMemory." This reverts commit c7a5b3a90db2f97c1d95332e9bb5b5c0f34084d7. Reason for revert: DroidMonitor: Potential culprit for Bug 173096532 - verifying through Forrest before revert submission. This is part of the standard investigation process, and does not mean your CL will be reverted. Change-Id: If71083df98155ae9e7f55ed1ca49b15456d12a82 --- .../src/android/graphics/TypefaceTest.java | 104 ++-------- graphics/java/android/graphics/Typeface.java | 188 +++++------------- 2 files changed, 68 insertions(+), 224 deletions(-) diff --git a/core/tests/coretests/src/android/graphics/TypefaceTest.java b/core/tests/coretests/src/android/graphics/TypefaceTest.java index 4393e9e713369..cfed2cef9ce6f 100644 --- a/core/tests/coretests/src/android/graphics/TypefaceTest.java +++ b/core/tests/coretests/src/android/graphics/TypefaceTest.java @@ -17,14 +17,12 @@ package android.graphics; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import android.content.Context; import android.content.res.AssetManager; import android.content.res.Resources; -import android.graphics.fonts.SystemFonts; -import android.os.SharedMemory; import androidx.test.InstrumentationRegistry; import androidx.test.filters.LargeTest; @@ -37,8 +35,9 @@ import com.android.frameworks.coretests.R; import org.junit.Test; import org.junit.runner.RunWith; -import java.util.HashMap; -import java.util.Map; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.util.List; import java.util.Random; @RunWith(AndroidJUnit4.class) @@ -55,33 +54,14 @@ public class TypefaceTest { Typeface.create(Typeface.MONOSPACE, 0) }; - private static final int[] STYLES = { - Typeface.NORMAL, Typeface.BOLD, Typeface.ITALIC, Typeface.BOLD_ITALIC, - }; - @SmallTest @Test - public void testBasic() { - assertNotEquals("basic", 0, Typeface.DEFAULT.native_instance); - assertNotEquals("basic", 0, Typeface.DEFAULT_BOLD.native_instance); - assertNotEquals("basic", 0, Typeface.SANS_SERIF.native_instance); - assertNotEquals("basic", 0, Typeface.SERIF.native_instance); - assertNotEquals("basic", 0, Typeface.MONOSPACE.native_instance); - assertEquals("basic", Typeface.NORMAL, Typeface.DEFAULT.getStyle()); - assertEquals("basic", Typeface.BOLD, Typeface.DEFAULT_BOLD.getStyle()); - assertEquals("basic", Typeface.NORMAL, Typeface.SANS_SERIF.getStyle()); - assertEquals("basic", Typeface.NORMAL, Typeface.SERIF.getStyle()); - assertEquals("basic", Typeface.NORMAL, Typeface.MONOSPACE.getStyle()); - } - - @SmallTest - @Test - public void testDefaults() { - for (int style : STYLES) { - String msg = "style = " + style; - assertNotEquals(msg, 0, Typeface.defaultFromStyle(style).native_instance); - assertEquals(msg, style, Typeface.defaultFromStyle(style).getStyle()); - } + public void testBasic() throws Exception { + assertTrue("basic", Typeface.DEFAULT != null); + assertTrue("basic", Typeface.DEFAULT_BOLD != null); + assertTrue("basic", Typeface.SANS_SERIF != null); + assertTrue("basic", Typeface.SERIF != null); + assertTrue("basic", Typeface.MONOSPACE != null); } @SmallTest @@ -198,67 +178,21 @@ public class TypefaceTest { @SmallTest @Test public void testSerialize() throws Exception { - HashMap systemFontMap = new HashMap<>(); - Typeface.initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(), - SystemFonts.getAliases()); - SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap); - Map copiedFontMap = Typeface.deserializeFontMap(sharedMemory); - assertEquals(systemFontMap.size(), copiedFontMap.size()); - for (String key : systemFontMap.keySet()) { - assertTrue(copiedFontMap.containsKey(key)); - Typeface original = systemFontMap.get(key); - Typeface copied = copiedFontMap.get(key); + int size = Typeface.writeTypefaces(null, Arrays.asList(mFaces)); + ByteBuffer buffer = ByteBuffer.allocateDirect(size); + Typeface.writeTypefaces(buffer, Arrays.asList(mFaces)); + List copiedTypefaces = Typeface.readTypefaces(buffer); + assertNotNull(copiedTypefaces); + assertEquals(mFaces.length, copiedTypefaces.size()); + for (int i = 0; i < mFaces.length; i++) { + Typeface original = mFaces[i]; + Typeface copied = copiedTypefaces.get(i); assertEquals(original.getStyle(), copied.getStyle()); assertEquals(original.getWeight(), copied.getWeight()); assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6); } } - @SmallTest - @Test - public void testSetSystemFontMap() throws Exception { - Context context = InstrumentationRegistry.getInstrumentation().getTargetContext(); - Resources res = context.getResources(); - Map fontMap = Map.of( - "sans-serif", Typeface.create(res.getFont(R.font.samplefont), Typeface.NORMAL), - "serif", Typeface.create(res.getFont(R.font.samplefont2), Typeface.NORMAL), - "monospace", Typeface.create(res.getFont(R.font.samplefont3), Typeface.NORMAL), - "sample", Typeface.create(res.getFont(R.font.samplefont4), Typeface.NORMAL), - "sample-italic", Typeface.create(res.getFont(R.font.samplefont4), Typeface.ITALIC)); - Typeface.setSystemFontMap(fontMap); - - // Test public static final fields - assertEquals(fontMap.get("sans-serif").native_instance, Typeface.DEFAULT.native_instance); - assertNotEquals(0, Typeface.DEFAULT_BOLD.native_instance); - assertEquals( - fontMap.get("sans-serif").native_instance, Typeface.SANS_SERIF.native_instance); - assertEquals(fontMap.get("serif").native_instance, Typeface.SERIF.native_instance); - assertEquals(fontMap.get("monospace").native_instance, Typeface.MONOSPACE.native_instance); - assertEquals(Typeface.NORMAL, Typeface.DEFAULT.getStyle()); - assertEquals(Typeface.BOLD, Typeface.DEFAULT_BOLD.getStyle()); - assertEquals(Typeface.NORMAL, Typeface.SANS_SERIF.getStyle()); - assertEquals(Typeface.NORMAL, Typeface.SERIF.getStyle()); - assertEquals(Typeface.NORMAL, Typeface.MONOSPACE.getStyle()); - - // Test defaults - assertEquals( - fontMap.get("sans-serif").native_instance, - Typeface.defaultFromStyle(Typeface.NORMAL).native_instance); - for (int style : STYLES) { - String msg = "style = " + style; - assertNotEquals(msg, 0, Typeface.defaultFromStyle(style).native_instance); - assertEquals(msg, style, Typeface.defaultFromStyle(style).getStyle()); - } - - // Test create() - assertEquals( - fontMap.get("sample").native_instance, - Typeface.create("sample", Typeface.NORMAL).native_instance); - assertEquals( - fontMap.get("sample-italic").native_instance, - Typeface.create("sample-italic", Typeface.ITALIC).native_instance); - } - private static float measureText(Typeface typeface, String text) { Paint paint = new Paint(); paint.setTypeface(typeface); diff --git a/graphics/java/android/graphics/Typeface.java b/graphics/java/android/graphics/Typeface.java index d44cb9c6032c9..c58e5f36cde39 100644 --- a/graphics/java/android/graphics/Typeface.java +++ b/graphics/java/android/graphics/Typeface.java @@ -34,12 +34,8 @@ import android.graphics.fonts.FontVariationAxis; import android.graphics.fonts.SystemFonts; import android.os.Build; import android.os.ParcelFileDescriptor; -import android.os.SharedMemory; -import android.os.Trace; import android.provider.FontRequest; import android.provider.FontsContract; -import android.system.ErrnoException; -import android.system.OsConstants; import android.text.FontConfig; import android.util.Base64; import android.util.LongSparseArray; @@ -54,7 +50,6 @@ import dalvik.annotation.optimization.CriticalNative; import libcore.util.NativeAllocationRegistry; -import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileDescriptor; import java.io.IOException; @@ -62,7 +57,6 @@ import java.io.InputStream; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.nio.ByteBuffer; -import java.nio.ByteOrder; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -85,19 +79,19 @@ public class Typeface { Typeface.class.getClassLoader(), nativeGetReleaseFunc()); /** The default NORMAL typeface object */ - public static final Typeface DEFAULT = new Typeface(); + public static final Typeface DEFAULT; /** * The default BOLD typeface object. Note: this may be not actually be * bold, depending on what fonts are installed. Call getStyle() to know * for sure. */ - public static final Typeface DEFAULT_BOLD = new Typeface(); + public static final Typeface DEFAULT_BOLD; /** The NORMAL style of the default sans serif typeface. */ - public static final Typeface SANS_SERIF = new Typeface(); + public static final Typeface SANS_SERIF; /** The NORMAL style of the default serif typeface. */ - public static final Typeface SERIF = new Typeface(); + public static final Typeface SERIF; /** The NORMAL style of the default monospace typeface. */ - public static final Typeface MONOSPACE = new Typeface(); + public static final Typeface MONOSPACE; /** * The default {@link Typeface}s for different text styles. @@ -139,7 +133,7 @@ public class Typeface { * Use public API {@link #create(String, int)} to get the typeface for given familyName. */ @UnsupportedAppUsage(trackingBug = 123769347) - static final Map sSystemFontMap = new HashMap<>(); + static final Map sSystemFontMap; // We cannot support sSystemFallbackMap since we will migrate to public FontFamily API. /** @@ -156,9 +150,6 @@ public class Typeface { @UnsupportedAppUsage public long native_instance; - // This destructs native_instance. - private Runnable mCleaner; - /** @hide */ @IntDef(value = {NORMAL, BOLD, ITALIC, BOLD_ITALIC}) @Retention(RetentionPolicy.SOURCE) @@ -1095,41 +1086,19 @@ public class Typeface { return new Typeface(nativeCreateFromArray(ptrArray, weight, italic)); } - /** - * Creates a fake Typeface object that are later modified to point to another Typeface object - * using {@link #reset(Typeface, int)}. - * - *

This constructor is only for filling 'static final' Typeface instances in Zygote process. - */ - private Typeface() { - } - // don't allow clients to call this directly @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.P, trackingBug = 115609023) private Typeface(long ni) { - init(ni); - } - - private void init(long ni) { if (ni == 0) { throw new RuntimeException("native typeface cannot be made"); } - if (mCleaner != null) { - mCleaner.run(); - } + native_instance = ni; - mCleaner = sRegistry.registerNativeAllocation(this, native_instance); + sRegistry.registerNativeAllocation(this, native_instance); mStyle = nativeGetStyle(ni); mWeight = nativeGetWeight(ni); } - private void reset(Typeface typeface, int style) { - // Just create a new native instance without looking into the cache, because we are going to - // claim the ownership. - long ni = nativeCreateFromTypeface(typeface.native_instance, style); - init(ni); - } - private static Typeface getSystemDefaultTypeface(@NonNull String familyName) { Typeface tf = sSystemFontMap.get(familyName); return tf == null ? Typeface.DEFAULT : tf; @@ -1168,105 +1137,23 @@ public class Typeface { } } - /** @hide */ - public static SharedMemory serializeFontMap(Map fontMap) - throws IOException, ErrnoException { - long[] nativePtrs = new long[fontMap.size()]; - // The name table will not be large, so let's create a byte array in memory. - ByteArrayOutputStream namesBytes = new ByteArrayOutputStream(); - int i = 0; - for (Map.Entry entry : fontMap.entrySet()) { - nativePtrs[i++] = entry.getValue().native_instance; - writeString(namesBytes, entry.getKey()); - } - int typefacesBytesCount = nativeWriteTypefaces(null, nativePtrs); - // int (typefacesBytesCount), typefaces, namesBytes - SharedMemory sharedMemory = SharedMemory.create( - "fontMap", Integer.BYTES + typefacesBytesCount + namesBytes.size()); - ByteBuffer writableBuffer = sharedMemory.mapReadWrite().order(ByteOrder.BIG_ENDIAN); - try { - writableBuffer.putInt(typefacesBytesCount); - int writtenBytesCount = nativeWriteTypefaces(writableBuffer.slice(), nativePtrs); - if (writtenBytesCount != typefacesBytesCount) { - throw new IOException(String.format("Unexpected bytes written: %d, expected: %d", - writtenBytesCount, typefacesBytesCount)); - } - writableBuffer.position(writableBuffer.position() + writtenBytesCount); - writableBuffer.put(namesBytes.toByteArray()); - } finally { - SharedMemory.unmap(writableBuffer); - } - sharedMemory.setProtect(OsConstants.PROT_READ); - return sharedMemory; - } - - /** @hide */ - @VisibleForTesting - public static Map deserializeFontMap(SharedMemory sharedMemory) - throws IOException, ErrnoException { - Trace.traceBegin(Trace.TRACE_TAG_GRAPHICS, "deserializeFontMap"); - try { - // TODO: unmap buffer when all Typefaces are gone. - // Currently deserializeFontMap() should be called at most once per process, so we don't - // need to unmap this buffer. - ByteBuffer buffer = sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN); - Map fontMap = new HashMap<>(); - int typefacesBytesCount = buffer.getInt(); - long[] nativePtrs = nativeReadTypefaces(buffer.slice()); - if (nativePtrs == null) { - throw new IOException("Could not read typefaces"); - } - buffer.position(buffer.position() + typefacesBytesCount); - for (long nativePtr : nativePtrs) { - String name = readString(buffer); - fontMap.put(name, new Typeface(nativePtr)); - } - return fontMap; - } finally { - Trace.traceEnd(Trace.TRACE_TAG_GRAPHICS); - } - } - - private static String readString(ByteBuffer buffer) { - int length = buffer.getInt(); - byte[] bytes = new byte[length]; - buffer.get(bytes); - return new String(bytes); - } - - private static void writeString(ByteArrayOutputStream bos, String value) throws IOException { - byte[] bytes = value.getBytes(); - writeInt(bos, bytes.length); - bos.write(bytes); - } - - private static void writeInt(ByteArrayOutputStream bos, int value) { - // Write in the big endian order. - bos.write((value >> 24) & 0xFF); - bos.write((value >> 16) & 0xFF); - bos.write((value >> 8) & 0xFF); - bos.write(value & 0xFF); - } - - /** @hide */ - @VisibleForTesting - public static void setSystemFontMap(Map systemFontMap) { - sSystemFontMap.clear(); - sSystemFontMap.putAll(systemFontMap); + static { + final HashMap systemFontMap = new HashMap<>(); + initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(), + SystemFonts.getAliases()); + sSystemFontMap = Collections.unmodifiableMap(systemFontMap); // We can't assume DEFAULT_FAMILY available on Roboletric. if (sSystemFontMap.containsKey(DEFAULT_FAMILY)) { setDefault(sSystemFontMap.get(DEFAULT_FAMILY)); } - // Set up defaults and typefaces exposed in public API. - // We cannot use getSystemDefaultTypeface() here to initialize DEFAULT, because it returns - // DEFAULT. - DEFAULT.reset(sDefaultTypeface, Typeface.NORMAL); - DEFAULT_BOLD.reset(sDefaultTypeface, Typeface.BOLD); - SANS_SERIF.reset(getSystemDefaultTypeface("sans-serif"), Typeface.NORMAL); - SERIF.reset(getSystemDefaultTypeface("serif"), Typeface.NORMAL); - MONOSPACE.reset(getSystemDefaultTypeface("monospace"), Typeface.NORMAL); + // Set up defaults and typefaces exposed in public API + DEFAULT = create((String) null, 0); + DEFAULT_BOLD = create((String) null, Typeface.BOLD); + SANS_SERIF = create("sans-serif", 0); + SERIF = create("serif", 0); + MONOSPACE = create("monospace", 0); sDefaults = new Typeface[] { DEFAULT, @@ -1286,13 +1173,6 @@ public class Typeface { } } - static { - final HashMap systemFontMap = new HashMap<>(); - initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(), - SystemFonts.getAliases()); - setSystemFontMap(systemFontMap); - } - @Override public boolean equals(Object o) { if (this == o) return true; @@ -1330,6 +1210,36 @@ public class Typeface { return Arrays.binarySearch(mSupportedAxes, axis) >= 0; } + /** + * Writes Typeface instances to the ByteBuffer and returns the number of bytes written. + * + *

If {@code buffer} is null, this method returns the number of bytes required to serialize + * the typefaces, without writing anything. + * @hide + */ + public static int writeTypefaces( + @Nullable ByteBuffer buffer, @NonNull List typefaces) { + long[] nativePtrs = new long[typefaces.size()]; + for (int i = 0; i < nativePtrs.length; i++) { + nativePtrs[i] = typefaces.get(i).native_instance; + } + return nativeWriteTypefaces(buffer, nativePtrs); + } + + /** + * Reads serialized Typeface instances from the ByteBuffer. Returns null on errors. + * @hide + */ + public static @Nullable List readTypefaces(@NonNull ByteBuffer buffer) { + long[] nativePtrs = nativeReadTypefaces(buffer); + if (nativePtrs == null) return null; + List typefaces = new ArrayList<>(nativePtrs.length); + for (long nativePtr : nativePtrs) { + typefaces.add(new Typeface(nativePtr)); + } + return typefaces; + } + private static native long nativeCreateFromTypeface(long native_instance, int style); private static native long nativeCreateFromTypefaceWithExactStyle( long native_instance, int weight, boolean italic);