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

Commit 6c89096f authored by Kohsuke Yatoh's avatar Kohsuke Yatoh
Browse files

Make Typeface#releaseNativeObjectForTest @TestApi.

The test module would crash with SEGV_MAPERR if the following events
happen in order:
(1) Typeface#deserializeFontMap(ByteBuffer, Map<String, Typeface>)
    (also a @TestApi) is called.
(2) The ByteBuffer passed to deserializeFontMap is GC-ed.
(3) The Typeface objects generated by deserializeFontMap are GC-ed.

This is because Typeface reads the buffer in its native object
destructor after
commit 88e387449b3f477a4cde31127cee5c63f332999c

This crash won't happen in production, because the buffer will never be
released.
To prevent the crash in tests, we must release Typeface objects
manually before (2) happens.

Bug: 255798098
Test: atest CtsGraphicsTestCases
Change-Id: If4426beb9a0dcefde317e6a01b4de9bf3fa4c951
parent 8b9146f0
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -1037,6 +1037,7 @@ package android.graphics {
    method @NonNull public static android.util.Pair<java.util.List<android.graphics.Typeface>,java.util.List<android.graphics.Typeface>> changeDefaultFontForTest(@NonNull java.util.List<android.graphics.Typeface>, @NonNull java.util.List<android.graphics.Typeface>);
    method @NonNull public static long[] deserializeFontMap(@NonNull java.nio.ByteBuffer, @NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws java.io.IOException;
    method @Nullable public static android.os.SharedMemory getSystemFontMapSharedMemory();
    method public void releaseNativeObjectForTest();
    method @NonNull public static android.os.SharedMemory serializeFontMap(@NonNull java.util.Map<java.lang.String,android.graphics.Typeface>) throws android.system.ErrnoException, java.io.IOException;
  }

+16 −10
Original line number Diff line number Diff line
@@ -203,6 +203,7 @@ public class TypefaceTest {
                fallbackMap);
        SharedMemory sharedMemory = Typeface.serializeFontMap(systemFontMap);
        Map<String, Typeface> copiedFontMap = new ArrayMap<>();
        try {
            Typeface.deserializeFontMap(sharedMemory.mapReadOnly().order(ByteOrder.BIG_ENDIAN),
                    copiedFontMap);
            assertEquals(systemFontMap.size(), copiedFontMap.size());
@@ -214,6 +215,11 @@ public class TypefaceTest {
                assertEquals(original.getWeight(), copied.getWeight());
                assertEquals(measureText(original, "hello"), measureText(copied, "hello"), 1e-6);
            }
        } finally {
            for (Typeface typeface : copiedFontMap.values()) {
                typeface.releaseNativeObjectForTest();
            }
        }
    }

    @SmallTest
+8 −0
Original line number Diff line number Diff line
@@ -1207,6 +1207,7 @@ public class Typeface {
     * It is safe to call this method twice or more on the same instance.
     * @hide
     */
    @TestApi
    public void releaseNativeObjectForTest() {
        mCleaner.run();
    }
@@ -1294,6 +1295,13 @@ public class Typeface {
    /**
     * Deserialize the font mapping from the serialized byte buffer.
     *
     * <p>Warning: the given {@code buffer} must outlive generated Typeface
     * objects in {@code out}. In production code, this is guaranteed by
     * storing the buffer in {@link #sSystemFontMapBuffer}.
     * If you call this method in a test, please make sure to destroy the
     * generated Typeface objects by calling
     * {@link #releaseNativeObjectForTest()}.
     *
     * @hide
     */
    @TestApi