diff --git a/core/java/com/android/internal/graphics/fonts/IFontManager.aidl b/core/java/com/android/internal/graphics/fonts/IFontManager.aidl index 1c7eca8b6c8e9..87df5eb9e75a6 100644 --- a/core/java/com/android/internal/graphics/fonts/IFontManager.aidl +++ b/core/java/com/android/internal/graphics/fonts/IFontManager.aidl @@ -30,7 +30,5 @@ import java.util.List; interface IFontManager { FontConfig getFontConfig(); - int updateFontFile(in FontUpdateRequest request, int baseVersion); - int updateFontFamily(in List request, int baseVersion); } diff --git a/graphics/java/android/graphics/fonts/SystemFonts.java b/graphics/java/android/graphics/fonts/SystemFonts.java index 255f9e659c367..1d392d2c27b57 100644 --- a/graphics/java/android/graphics/fonts/SystemFonts.java +++ b/graphics/java/android/graphics/fonts/SystemFonts.java @@ -262,8 +262,14 @@ public final class SystemFonts { */ @VisibleForTesting public static Map buildSystemFallback(FontConfig fontConfig) { + return buildSystemFallback(fontConfig, new ArrayMap<>()); + } + + /** @hide */ + @VisibleForTesting + public static Map buildSystemFallback(FontConfig fontConfig, + ArrayMap outBufferCache) { final Map fallbackMap = new ArrayMap<>(); - final ArrayMap bufferCache = new ArrayMap<>(); final List xmlFamilies = fontConfig.getFontFamilies(); final ArrayMap> fallbackListMap = new ArrayMap<>(); @@ -273,7 +279,7 @@ public final class SystemFonts { if (familyName == null) { continue; } - appendNamedFamily(xmlFamily, bufferCache, fallbackListMap); + appendNamedFamily(xmlFamily, outBufferCache, fallbackListMap); } // Then, add fallback fonts to the each fallback map. @@ -282,7 +288,7 @@ public final class SystemFonts { // The first family (usually the sans-serif family) is always placed immediately // after the primary family in the fallback. if (i == 0 || xmlFamily.getName() == null) { - pushFamilyToFallback(xmlFamily, fallbackListMap, bufferCache); + pushFamilyToFallback(xmlFamily, fallbackListMap, outBufferCache); } } diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java index 0949dddd1209d..dc3dc468f7633 100644 --- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java @@ -20,25 +20,19 @@ import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; -import android.graphics.Bitmap; -import android.graphics.Canvas; import android.graphics.Typeface; -import android.graphics.fonts.Font; import android.graphics.fonts.FontFamily; -import android.graphics.fonts.FontFileUtil; import android.graphics.fonts.FontManager; import android.graphics.fonts.FontUpdateRequest; import android.graphics.fonts.SystemFonts; +import android.os.ParcelFileDescriptor; import android.os.ResultReceiver; import android.os.SharedMemory; import android.os.ShellCallback; import android.system.ErrnoException; import android.text.FontConfig; -import android.text.Layout; -import android.text.StaticLayout; -import android.text.TextPaint; -import android.text.TextUtils; import android.util.AndroidException; +import android.util.ArrayMap; import android.util.IndentingPrintWriter; import android.util.Slog; @@ -52,19 +46,17 @@ import com.android.server.SystemService; import java.io.File; import java.io.FileDescriptor; -import java.io.FileInputStream; import java.io.IOException; import java.io.PrintWriter; import java.nio.ByteBuffer; +import java.nio.DirectByteBuffer; import java.nio.NioUtils; -import java.nio.channels.FileChannel; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; /** A service for managing system fonts. */ -// TODO(b/173619554): Add API to update fonts. public final class FontManagerService extends IFontManager.Stub { private static final String TAG = "FontManagerService"; @@ -77,23 +69,6 @@ public final class FontManagerService extends IFontManager.Stub { return getSystemFontConfig(); } - @Override - public int updateFontFile(@NonNull FontUpdateRequest request, int baseVersion) { - Preconditions.checkArgumentNonnegative(baseVersion); - Objects.requireNonNull(request); - Objects.requireNonNull(request.getFd()); - Objects.requireNonNull(request.getSignature()); - getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS, - "UPDATE_FONTS permission required."); - try { - update(baseVersion, Collections.singletonList(request)); - return FontManager.RESULT_SUCCESS; - } catch (SystemFontException e) { - Slog.e(TAG, "Failed to update font file", e); - return e.getErrorCode(); - } - } - @Override public int updateFontFamily(@NonNull List requests, int baseVersion) { Preconditions.checkArgumentNonnegative(baseVersion); @@ -106,6 +81,17 @@ public final class FontManagerService extends IFontManager.Stub { } catch (SystemFontException e) { Slog.e(TAG, "Failed to update font family", e); return e.getErrorCode(); + } finally { + for (FontUpdateRequest request : requests) { + ParcelFileDescriptor fd = request.getFd(); + if (fd != null) { + try { + fd.close(); + } catch (IOException e) { + Slog.w(TAG, "Failed to close fd", e); + } + } + } } } @@ -154,89 +140,6 @@ public final class FontManagerService extends IFontManager.Stub { } } - /* package */ static class OtfFontFileParser implements UpdatableFontDir.FontFileParser { - @Override - public String getPostScriptName(File file) throws IOException { - ByteBuffer buffer = mmap(file); - try { - return FontFileUtil.getPostScriptName(buffer, 0); - } finally { - NioUtils.freeDirectBuffer(buffer); - } - } - - @Override - public String buildFontFileName(File file) throws IOException { - ByteBuffer buffer = mmap(file); - try { - String psName = FontFileUtil.getPostScriptName(buffer, 0); - int isType1Font = FontFileUtil.isPostScriptType1Font(buffer, 0); - int isCollection = FontFileUtil.isCollectionFont(buffer); - - if (TextUtils.isEmpty(psName) || isType1Font == -1 || isCollection == -1) { - return null; - } - - String extension; - if (isCollection == 1) { - extension = isType1Font == 1 ? ".otc" : ".ttc"; - } else { - extension = isType1Font == 1 ? ".otf" : ".ttf"; - } - return psName + extension; - } finally { - NioUtils.freeDirectBuffer(buffer); - } - - } - - @Override - public long getRevision(File file) throws IOException { - ByteBuffer buffer = mmap(file); - try { - return FontFileUtil.getRevision(buffer, 0); - } finally { - NioUtils.freeDirectBuffer(buffer); - } - } - - @Override - public void tryToCreateTypeface(File file) throws Throwable { - Font font = new Font.Builder(file).build(); - FontFamily family = new FontFamily.Builder(font).build(); - Typeface typeface = new Typeface.CustomFallbackBuilder(family).build(); - - TextPaint p = new TextPaint(); - p.setTextSize(24f); - p.setTypeface(typeface); - - // Test string to try with the passed font. - // TODO: Good to extract from font file. - String testTextToDraw = "abcXYZ@- " - + "\uD83E\uDED6" // Emoji E13.0 - + "\uD83C\uDDFA\uD83C\uDDF8" // Emoji Flags - + "\uD83D\uDC8F\uD83C\uDFFB" // Emoji Skin tone Sequence - // ZWJ Sequence - + "\uD83D\uDC68\uD83C\uDFFC\u200D\u2764\uFE0F\u200D\uD83D\uDC8B\u200D" - + "\uD83D\uDC68\uD83C\uDFFF"; - - int width = (int) Math.ceil(Layout.getDesiredWidth(testTextToDraw, p)); - StaticLayout layout = StaticLayout.Builder.obtain( - testTextToDraw, 0, testTextToDraw.length(), p, width).build(); - Bitmap bmp = Bitmap.createBitmap( - layout.getWidth(), layout.getHeight(), Bitmap.Config.ALPHA_8); - Canvas canvas = new Canvas(bmp); - layout.draw(canvas); - } - - private static ByteBuffer mmap(File file) throws IOException { - try (FileInputStream in = new FileInputStream(file)) { - FileChannel fileChannel = in.getChannel(); - return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()); - } - } - } - private static class FsverityUtilImpl implements UpdatableFontDir.FsverityUtil { @Override public boolean hasFsverity(String filePath) { @@ -289,13 +192,7 @@ public final class FontManagerService extends IFontManager.Stub { private void initialize() { synchronized (mUpdatableFontDirLock) { if (mUpdatableFontDir == null) { - synchronized (mSerializedFontMapLock) { - try { - mSerializedFontMap = Typeface.serializeFontMap(Typeface.getSystemFontMap()); - } catch (IOException | ErrnoException e) { - mSerializedFontMap = null; - } - } + setSerializedFontMap(serializeSystemServerFontMap()); return; } mUpdatableFontDir.loadFontFileMap(); @@ -391,36 +288,57 @@ public final class FontManagerService extends IFontManager.Stub { /** * Makes new serialized font map data and updates mSerializedFontMap. */ - public void updateSerializedFontMap() { + private void updateSerializedFontMap() { + SharedMemory serializedFontMap = serializeFontMap(getSystemFontConfig()); + if (serializedFontMap == null) { + // Fallback to the preloaded config. + serializedFontMap = serializeSystemServerFontMap(); + } + setSerializedFontMap(serializedFontMap); + } + + @Nullable + private static SharedMemory serializeFontMap(FontConfig fontConfig) { + final ArrayMap bufferCache = new ArrayMap<>(); try { - final FontConfig fontConfig = getSystemFontConfig(); - final Map fallback = SystemFonts.buildSystemFallback(fontConfig); + final Map fallback = + SystemFonts.buildSystemFallback(fontConfig, bufferCache); final Map typefaceMap = SystemFonts.buildSystemTypefaces(fontConfig, fallback); - - SharedMemory serializeFontMap = Typeface.serializeFontMap(typefaceMap); - synchronized (mSerializedFontMapLock) { - mSerializedFontMap = serializeFontMap; - } - return; + return Typeface.serializeFontMap(typefaceMap); } catch (IOException | ErrnoException e) { Slog.w(TAG, "Failed to serialize updatable font map. " + "Retrying with system image fonts.", e); - } - - try { - final FontConfig fontConfig = SystemFonts.getSystemPreinstalledFontConfig(); - final Map fallback = SystemFonts.buildSystemFallback(fontConfig); - final Map typefaceMap = - SystemFonts.buildSystemTypefaces(fontConfig, fallback); - - SharedMemory serializeFontMap = Typeface.serializeFontMap(typefaceMap); - synchronized (mSerializedFontMapLock) { - mSerializedFontMap = serializeFontMap; + return null; + } finally { + // Unmap buffers promptly, as we map a lot of files and may hit mmap limit before + // GC collects ByteBuffers and unmaps them. + for (ByteBuffer buffer : bufferCache.values()) { + if (buffer instanceof DirectByteBuffer) { + NioUtils.freeDirectBuffer(buffer); + } } - } catch (IOException | ErrnoException e) { - Slog.e(TAG, "Failed to serialize SystemServer system font map", e); } } + @Nullable + private static SharedMemory serializeSystemServerFontMap() { + try { + return Typeface.serializeFontMap(Typeface.getSystemFontMap()); + } catch (IOException | ErrnoException e) { + Slog.e(TAG, "Failed to serialize SystemServer system font map", e); + return null; + } + } + + private void setSerializedFontMap(SharedMemory serializedFontMap) { + SharedMemory oldFontMap = null; + synchronized (mSerializedFontMapLock) { + oldFontMap = mSerializedFontMap; + mSerializedFontMap = serializedFontMap; + } + if (oldFontMap != null) { + oldFontMap.close(); + } + } } diff --git a/services/core/java/com/android/server/graphics/fonts/OtfFontFileParser.java b/services/core/java/com/android/server/graphics/fonts/OtfFontFileParser.java new file mode 100644 index 0000000000000..1ed3972ed309e --- /dev/null +++ b/services/core/java/com/android/server/graphics/fonts/OtfFontFileParser.java @@ -0,0 +1,130 @@ +/* + * Copyright (C) 2021 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 com.android.server.graphics.fonts; + +import android.graphics.Bitmap; +import android.graphics.Canvas; +import android.graphics.Typeface; +import android.graphics.fonts.Font; +import android.graphics.fonts.FontFamily; +import android.graphics.fonts.FontFileUtil; +import android.text.Layout; +import android.text.StaticLayout; +import android.text.TextPaint; +import android.text.TextUtils; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.DirectByteBuffer; +import java.nio.NioUtils; +import java.nio.channels.FileChannel; + +/* package */ class OtfFontFileParser implements UpdatableFontDir.FontFileParser { + @Override + public String getPostScriptName(File file) throws IOException { + ByteBuffer buffer = mmap(file); + try { + return FontFileUtil.getPostScriptName(buffer, 0); + } finally { + unmap(buffer); + } + } + + @Override + public String buildFontFileName(File file) throws IOException { + ByteBuffer buffer = mmap(file); + try { + String psName = FontFileUtil.getPostScriptName(buffer, 0); + int isType1Font = FontFileUtil.isPostScriptType1Font(buffer, 0); + int isCollection = FontFileUtil.isCollectionFont(buffer); + + if (TextUtils.isEmpty(psName) || isType1Font == -1 || isCollection == -1) { + return null; + } + + String extension; + if (isCollection == 1) { + extension = isType1Font == 1 ? ".otc" : ".ttc"; + } else { + extension = isType1Font == 1 ? ".otf" : ".ttf"; + } + return psName + extension; + } finally { + unmap(buffer); + } + + } + + @Override + public long getRevision(File file) throws IOException { + ByteBuffer buffer = mmap(file); + try { + return FontFileUtil.getRevision(buffer, 0); + } finally { + unmap(buffer); + } + } + + @Override + public void tryToCreateTypeface(File file) throws Throwable { + ByteBuffer buffer = mmap(file); + try { + Font font = new Font.Builder(buffer).build(); + FontFamily family = new FontFamily.Builder(font).build(); + Typeface typeface = new Typeface.CustomFallbackBuilder(family).build(); + + TextPaint p = new TextPaint(); + p.setTextSize(24f); + p.setTypeface(typeface); + + // Test string to try with the passed font. + // TODO: Good to extract from font file. + String testTextToDraw = "abcXYZ@- " + + "\uD83E\uDED6" // Emoji E13.0 + + "\uD83C\uDDFA\uD83C\uDDF8" // Emoji Flags + + "\uD83D\uDC8F\uD83C\uDFFB" // Emoji Skin tone Sequence + // ZWJ Sequence + + "\uD83D\uDC68\uD83C\uDFFC\u200D\u2764\uFE0F\u200D\uD83D\uDC8B\u200D" + + "\uD83D\uDC68\uD83C\uDFFF"; + + int width = (int) Math.ceil(Layout.getDesiredWidth(testTextToDraw, p)); + StaticLayout layout = StaticLayout.Builder.obtain( + testTextToDraw, 0, testTextToDraw.length(), p, width).build(); + Bitmap bmp = Bitmap.createBitmap( + layout.getWidth(), layout.getHeight(), Bitmap.Config.ALPHA_8); + Canvas canvas = new Canvas(bmp); + layout.draw(canvas); + } finally { + unmap(buffer); + } + } + + private static ByteBuffer mmap(File file) throws IOException { + try (FileInputStream in = new FileInputStream(file)) { + FileChannel fileChannel = in.getChannel(); + return fileChannel.map(FileChannel.MapMode.READ_ONLY, 0, fileChannel.size()); + } + } + + private static void unmap(ByteBuffer buffer) { + if (buffer instanceof DirectByteBuffer) { + NioUtils.freeDirectBuffer(buffer); + } + } +} diff --git a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java index 7003ef7601968..c862febbd62b2 100644 --- a/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java +++ b/services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java @@ -139,9 +139,11 @@ public final class UpdatableFontDirTest { private File mUpdatableFontFilesDir; private File mConfigFile; private List mPreinstalledFontDirs; - private Supplier mCurrentTimeSupplier = () -> CURRENT_TIME; - private Function, FontConfig> mConfigSupplier = + private final Supplier mCurrentTimeSupplier = () -> CURRENT_TIME; + private final Function, FontConfig> mConfigSupplier = (map) -> SystemFonts.getSystemFontConfig(map, 0, 0); + private FakeFontFileParser mParser; + private FakeFsverityUtil mFakeFsverityUtil; @SuppressWarnings("ResultOfMethodCallIgnored") @Before @@ -159,6 +161,8 @@ public final class UpdatableFontDirTest { dir.mkdir(); } mConfigFile = new File(mCacheDir, "config.xml"); + mParser = new FakeFontFileParser(); + mFakeFsverityUtil = new FakeFsverityUtil(); } @After @@ -169,13 +173,11 @@ public final class UpdatableFontDirTest { @Test public void construct() throws Exception { long expectedModifiedDate = CURRENT_TIME / 2; - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config(); config.lastModifiedMillis = expectedModifiedDate; writeConfig(config, mConfigFile); UpdatableFontDir dirForPreparation = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dirForPreparation.loadFontFileMap(); assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis()) @@ -198,13 +200,13 @@ public final class UpdatableFontDirTest { .isNotEqualTo(expectedModifiedDate); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); assertThat(dir.getPostScriptMap()).containsKey("foo"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(3); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(3); assertThat(dir.getPostScriptMap()).containsKey("bar"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(4); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(4); // Outdated font dir should be deleted. assertThat(mUpdatableFontFilesDir.list()).hasLength(2); assertNamedFamilyExists(dir.getSystemFontConfig(), "foobar"); @@ -219,10 +221,8 @@ public final class UpdatableFontDirTest { @Test public void construct_empty() { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); assertThat(dir.getPostScriptMap()).isEmpty(); @@ -231,10 +231,8 @@ public final class UpdatableFontDirTest { @Test public void construct_missingFsverity() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dirForPreparation = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dirForPreparation.loadFontFileMap(); dirForPreparation.update(Arrays.asList( @@ -249,10 +247,10 @@ public final class UpdatableFontDirTest { // Four font dirs are created. assertThat(mUpdatableFontFilesDir.list()).hasLength(4); - fakeFsverityUtil.remove( + mFakeFsverityUtil.remove( dirForPreparation.getPostScriptMap().get("foo").getAbsolutePath()); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); assertThat(dir.getPostScriptMap()).isEmpty(); @@ -263,10 +261,8 @@ public final class UpdatableFontDirTest { @Test public void construct_fontNameMismatch() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dirForPreparation = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dirForPreparation.loadFontFileMap(); dirForPreparation.update(Arrays.asList( @@ -285,7 +281,7 @@ public final class UpdatableFontDirTest { FileUtils.stringToFile(dirForPreparation.getPostScriptMap().get("foo"), "bar,4"); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); assertThat(dir.getPostScriptMap()).isEmpty(); @@ -296,8 +292,6 @@ public final class UpdatableFontDirTest { @Test public void construct_olderThanPreinstalledFont() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); Function, FontConfig> configSupplier = (map) -> { FontConfig.Font fooFont = new FontConfig.Font( new File(mPreinstalledFontDirs.get(0), "foo.ttf"), null, "foo", @@ -314,7 +308,7 @@ public final class UpdatableFontDirTest { }; UpdatableFontDir dirForPreparation = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, configSupplier); dirForPreparation.loadFontFileMap(); dirForPreparation.update(Arrays.asList( @@ -334,14 +328,14 @@ public final class UpdatableFontDirTest { FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(1), "bar.ttf"), "bar,1,bar"); FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(1), "bar.ttf"), "bar,2,bar"); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, configSupplier); dir.loadFontFileMap(); // For foo.ttf, preinstalled font (revision 5) should be used. assertThat(dir.getPostScriptMap()).doesNotContainKey("foo"); // For bar.ttf, updated font (revision 4) should be used. assertThat(dir.getPostScriptMap()).containsKey("bar"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(4); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(4); // Outdated font dir should be deleted. // We don't delete bar.ttf in this case, because it's normal that OTA updates preinstalled // fonts. @@ -352,10 +346,8 @@ public final class UpdatableFontDirTest { @Test public void construct_failedToLoadConfig() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, new File("/dev/null"), mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); assertThat(dir.getPostScriptMap()).isEmpty(); @@ -364,10 +356,8 @@ public final class UpdatableFontDirTest { @Test public void construct_afterBatchFailure() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dirForPreparation = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dirForPreparation.loadFontFileMap(); dirForPreparation.update(Arrays.asList( @@ -389,12 +379,12 @@ public final class UpdatableFontDirTest { } UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); // The state should be rolled back as a whole if one of the update requests fail. assertThat(dir.getPostScriptMap()).containsKey("foo"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(1); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(1); assertThat(dir.getFontFamilyMap()).containsKey("foobar"); FontConfig.FontFamily foobar = dir.getFontFamilyMap().get("foobar"); assertThat(foobar.getFontList()).hasSize(1); @@ -404,10 +394,8 @@ public final class UpdatableFontDirTest { @Test public void loadFontFileMap_twice() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1,test", @@ -420,17 +408,15 @@ public final class UpdatableFontDirTest { @Test public void installFontFile() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1,test", GOOD_SIGNATURE))); assertThat(dir.getPostScriptMap()).containsKey("test"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(1); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(1); File fontFile = dir.getPostScriptMap().get("test"); assertThat(Os.stat(fontFile.getAbsolutePath()).st_mode & 0777).isEqualTo(0644); File fontDir = fontFile.getParentFile(); @@ -439,10 +425,8 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_upgrade() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -452,10 +436,10 @@ public final class UpdatableFontDirTest { dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2,test", GOOD_SIGNATURE))); assertThat(dir.getPostScriptMap()).containsKey("test"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(2); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(2); assertThat(mapBeforeUpgrade).containsKey("test"); assertWithMessage("Older fonts should not be deleted until next loadFontFileMap") - .that(parser.getRevision(mapBeforeUpgrade.get("test"))).isEqualTo(1); + .that(mParser.getRevision(mapBeforeUpgrade.get("test"))).isEqualTo(1); // Check that updatedFontDirs is pruned. assertWithMessage("config.updatedFontDirs should only list latest active dirs") .that(readConfig(mConfigFile).updatedFontDirs) @@ -464,15 +448,13 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_systemFontHasPSNameDifferentFromFileName() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); // Setup the environment that the system installed font file named "foo.ttf" has PostScript // name "bar". File file = new File(mPreinstalledFontDirs.get(0), "foo.ttf"); FileUtils.stringToFile(file, "foo.ttf,1,bar"); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, (map) -> { FontConfig.Font font = new FontConfig.Font( file, null, "bar", new FontStyle(400, FontStyle.FONT_SLANT_UPRIGHT), @@ -489,7 +471,7 @@ public final class UpdatableFontDirTest { GOOD_SIGNATURE))); assertThat(dir.getPostScriptMap()).containsKey("bar"); assertThat(dir.getPostScriptMap().size()).isEqualTo(1); - assertThat(parser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(2); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(2); File fontFile = dir.getPostScriptMap().get("bar"); assertThat(Os.stat(fontFile.getAbsolutePath()).st_mode & 0777).isEqualTo(0644); File fontDir = fontFile.getParentFile(); @@ -498,10 +480,8 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_sameVersion() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -510,15 +490,13 @@ public final class UpdatableFontDirTest { dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1,test", GOOD_SIGNATURE))); assertThat(dir.getPostScriptMap()).containsKey("test"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(1); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(1); } @Test public void installFontFile_downgrade() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -533,7 +511,7 @@ public final class UpdatableFontDirTest { } assertThat(dir.getPostScriptMap()).containsKey("test"); assertWithMessage("Font should not be downgraded to an older revision") - .that(parser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(2); + .that(mParser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(2); // Check that updatedFontDirs is not updated. assertWithMessage("config.updatedFontDirs should only list latest active dirs") .that(readConfig(mConfigFile).updatedFontDirs) @@ -542,10 +520,8 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_multiple() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -554,17 +530,15 @@ public final class UpdatableFontDirTest { dir.update(Collections.singletonList(newFontUpdateRequest("bar.ttf,2,bar", GOOD_SIGNATURE))); assertThat(dir.getPostScriptMap()).containsKey("foo"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(1); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(1); assertThat(dir.getPostScriptMap()).containsKey("bar"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(2); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(2); } @Test public void installFontFile_batch() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -572,17 +546,15 @@ public final class UpdatableFontDirTest { newFontUpdateRequest("foo.ttf,1,foo", GOOD_SIGNATURE), newFontUpdateRequest("bar.ttf,2,bar", GOOD_SIGNATURE))); assertThat(dir.getPostScriptMap()).containsKey("foo"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(1); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(1); assertThat(dir.getPostScriptMap()).containsKey("bar"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(2); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("bar"))).isEqualTo(2); } @Test public void installFontFile_invalidSignature() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -600,46 +572,40 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_preinstalled_upgrade() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1,test"); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,2,test", GOOD_SIGNATURE))); assertThat(dir.getPostScriptMap()).containsKey("test"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(2); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(2); } @Test public void installFontFile_preinstalled_sameVersion() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1,test"); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); dir.update(Collections.singletonList(newFontUpdateRequest("test.ttf,1,test", GOOD_SIGNATURE))); assertThat(dir.getPostScriptMap()).containsKey("test"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(1); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("test"))).isEqualTo(1); } @Test public void installFontFile_preinstalled_downgrade() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); File file = new File(mPreinstalledFontDirs.get(0), "test.ttf"); FileUtils.stringToFile(file, "test.ttf,2,test"); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, (map) -> { FontConfig.Font font = new FontConfig.Font( file, null, "test", new FontStyle(400, FontStyle.FONT_SLANT_UPRIGHT), 0, null, @@ -664,8 +630,6 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_failedToWriteConfigXml() throws Exception { long expectedModifiedDate = 1234567890; - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); FileUtils.stringToFile(new File(mPreinstalledFontDirs.get(0), "test.ttf"), "test.ttf,1,test"); @@ -680,7 +644,7 @@ public final class UpdatableFontDirTest { assertThat(readonlyDir.setWritable(false, false)).isTrue(); try { UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, readonlyFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -702,7 +666,6 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_failedToParsePostScript() throws Exception { - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( mUpdatableFontFilesDir, new UpdatableFontDir.FontFileParser() { @@ -725,7 +688,7 @@ public final class UpdatableFontDirTest { @Override public void tryToCreateTypeface(File file) throws IOException { } - }, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); + }, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); try { @@ -741,7 +704,6 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_failedToParsePostScriptName_invalidFont() throws Exception { - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( mUpdatableFontFilesDir, new UpdatableFontDir.FontFileParser() { @@ -763,7 +725,7 @@ public final class UpdatableFontDirTest { @Override public void tryToCreateTypeface(File file) throws IOException { } - }, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); + }, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); try { @@ -779,31 +741,29 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_failedToCreateTypeface() throws Exception { - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); - FakeFontFileParser parser = new FakeFontFileParser(); UpdatableFontDir dir = new UpdatableFontDir( mUpdatableFontFilesDir, new UpdatableFontDir.FontFileParser() { @Override public String getPostScriptName(File file) throws IOException { - return parser.getPostScriptName(file); + return mParser.getPostScriptName(file); } @Override public String buildFontFileName(File file) throws IOException { - return parser.buildFontFileName(file); + return mParser.buildFontFileName(file); } @Override public long getRevision(File file) throws IOException { - return parser.getRevision(file); + return mParser.getRevision(file); } @Override public void tryToCreateTypeface(File file) throws IOException { throw new IOException(); } - }, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); + }, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); try { @@ -820,16 +780,15 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_renameToPsNameFailure() throws Exception { UpdatableFontDir.FsverityUtil fakeFsverityUtil = new UpdatableFontDir.FsverityUtil() { - private final FakeFsverityUtil mFake = new FakeFsverityUtil(); @Override public boolean hasFsverity(String path) { - return mFake.hasFsverity(path); + return mFakeFsverityUtil.hasFsverity(path); } @Override public void setUpFsverity(String path, byte[] pkcs7Signature) throws IOException { - mFake.setUpFsverity(path, pkcs7Signature); + mFakeFsverityUtil.setUpFsverity(path, pkcs7Signature); } @Override @@ -837,9 +796,8 @@ public final class UpdatableFontDirTest { return false; } }; - FakeFontFileParser parser = new FakeFontFileParser(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, fakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -856,10 +814,8 @@ public final class UpdatableFontDirTest { @Test public void installFontFile_batchFailure() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -875,15 +831,13 @@ public final class UpdatableFontDirTest { } // The state should be rolled back as a whole if one of the update requests fail. assertThat(dir.getPostScriptMap()).containsKey("foo"); - assertThat(parser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(1); + assertThat(mParser.getRevision(dir.getPostScriptMap().get("foo"))).isEqualTo(1); } @Test public void addFontFamily() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -902,10 +856,8 @@ public final class UpdatableFontDirTest { @Test public void addFontFamily_noName() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -924,10 +876,8 @@ public final class UpdatableFontDirTest { @Test public void addFontFamily_fontNotAvailable() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); @@ -944,10 +894,8 @@ public final class UpdatableFontDirTest { @Test public void getSystemFontConfig() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); // We assume we have monospace. @@ -976,10 +924,8 @@ public final class UpdatableFontDirTest { @Test public void getSystemFontConfig_preserveFirstFontFamily() throws Exception { - FakeFontFileParser parser = new FakeFontFileParser(); - FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil(); UpdatableFontDir dir = new UpdatableFontDir( - mUpdatableFontFilesDir, parser, fakeFsverityUtil, + mUpdatableFontFilesDir, mParser, mFakeFsverityUtil, mConfigFile, mCurrentTimeSupplier, mConfigSupplier); dir.loadFontFileMap(); assertThat(dir.getSystemFontConfig().getFontFamilies()).isNotEmpty(); @@ -1011,12 +957,12 @@ public final class UpdatableFontDirTest { } private static FontUpdateRequest newAddFontFamilyRequest(String xml) throws Exception { - XmlPullParser parser = Xml.newPullParser(); + XmlPullParser mParser = Xml.newPullParser(); ByteArrayInputStream is = new ByteArrayInputStream(xml.getBytes(StandardCharsets.UTF_8)); - parser.setInput(is, "UTF-8"); - parser.nextTag(); + mParser.setInput(is, "UTF-8"); + mParser.nextTag(); - FontConfig.FontFamily fontFamily = FontListParser.readFamily(parser, "", null, true); + FontConfig.FontFamily fontFamily = FontListParser.readFamily(mParser, "", null, true); List fonts = new ArrayList<>(); for (FontConfig.Font font : fontFamily.getFontList()) { String name = font.getFile().getName(); diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java index 898b8d4cbdc13..44f96c5a987b3 100644 --- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java +++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java @@ -56,6 +56,11 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; /** * Tests if fonts can be updated by {@link FontManager} API. @@ -95,6 +100,12 @@ public class UpdatableSystemFontTest { EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity"; private static final long ACTIVITY_TIMEOUT_MILLIS = SECONDS.toMillis(10); + private static final Pattern PATTERN_FONT_FILES = Pattern.compile("\\.(ttf|otf|ttc|otc)$"); + private static final Pattern PATTERN_TMP_FILES = Pattern.compile("^/data/local/tmp/"); + private static final Pattern PATTERN_DATA_FONT_FILES = Pattern.compile("^/data/fonts/files/"); + private static final Pattern PATTERN_SYSTEM_FONT_FILES = + Pattern.compile("^/(system|product)/fonts/"); + private String mKeyId; private FontManager mFontManager; @@ -236,6 +247,32 @@ public class UpdatableSystemFontTest { assertThat(fontPathAfterReboot).isEqualTo(fontPath); } + + @Test + public void fdLeakTest() throws Exception { + long originalOpenFontCount = + countMatch(getOpenFiles("system_server"), PATTERN_FONT_FILES); + Pattern patternEmojiVPlus1 = + Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF)); + for (int i = 0; i < 10; i++) { + assertThat(updateFontFile( + TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)) + .isEqualTo(FontManager.RESULT_SUCCESS); + List openFiles = getOpenFiles("system_server"); + for (Pattern p : Arrays.asList(PATTERN_FONT_FILES, PATTERN_SYSTEM_FONT_FILES, + PATTERN_DATA_FONT_FILES, PATTERN_TMP_FILES)) { + Log.i(TAG, String.format("num of %s: %d", p, countMatch(openFiles, p))); + } + // system_server should not keep /data/fonts files open. + assertThat(countMatch(openFiles, PATTERN_DATA_FONT_FILES)).isEqualTo(0); + // system_server should not keep passed FD open. + assertThat(countMatch(openFiles, patternEmojiVPlus1)).isEqualTo(0); + // The number of open font FD should not increase. + assertThat(countMatch(openFiles, PATTERN_FONT_FILES)) + .isAtMost(originalOpenFontCount); + } + } + private static String insertCert(String certPath) throws Exception { Pair result; try (InputStream is = new FileInputStream(certPath)) { @@ -338,7 +375,37 @@ public class UpdatableSystemFontTest { return !expectCommandToSucceed(cmd).trim().isEmpty(); } + private static List getOpenFiles(String appId) throws Exception { + String pid = pidOf(appId); + if (pid.isEmpty()) { + return Collections.emptyList(); + } + String cmd = String.format("lsof -p %s", pid); + String out = expectCommandToSucceed(cmd); + List paths = new ArrayList<>(); + boolean first = true; + for (String line : out.split("\n")) { + // Skip the header. + if (first) { + first = false; + continue; + } + String[] records = line.split(" "); + if (records.length > 0) { + paths.add(records[records.length - 1]); + } + } + return paths; + } + private static String pidOf(String appId) throws Exception { return expectCommandToSucceed("pidof " + appId).trim(); } + + private static long countMatch(List paths, Pattern pattern) { + // Note: asPredicate() returns true for partial matching. + return paths.stream() + .filter(pattern.asPredicate()) + .count(); + } }