Revert "Support loading system font map from SharedMemory."

This reverts commit c7a5b3a90d.

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
This commit is contained in:
Mohammad Samiul Islam
2020-11-12 11:46:46 +00:00
parent c7a5b3a90d
commit 735d447d48
2 changed files with 68 additions and 224 deletions

View File

@@ -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<String, Typeface> systemFontMap = new HashMap<>();
Typeface.initSystemDefaultTypefaces(systemFontMap, SystemFonts.getRawSystemFallbackMap(),
SystemFonts.getAliases());
SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
Map<String, Typeface> 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<Typeface> 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<String, Typeface> 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);

View File

@@ -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<String, Typeface> sSystemFontMap = new HashMap<>();
static final Map<String, Typeface> 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)}.
*
* <p>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<String, Typeface> 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<String, Typeface> 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<String, Typeface> 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<String, Typeface> 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<String, Typeface> systemFontMap) {
sSystemFontMap.clear();
sSystemFontMap.putAll(systemFontMap);
static {
final HashMap<String, Typeface> 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<String, Typeface> 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.
*
* <p>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<Typeface> 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<Typeface> readTypefaces(@NonNull ByteBuffer buffer) {
long[] nativePtrs = nativeReadTypefaces(buffer);
if (nativePtrs == null) return null;
List<Typeface> 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);