Merge changes I09ac3f34,Id3e36922 into sc-dev
* changes: Close FDs / mmap handles promptly. Remove unused IFontManager#updateFontFile().
This commit is contained in:
committed by
Android (Google) Code Review
commit
c27e46f595
@@ -30,7 +30,5 @@ import java.util.List;
|
||||
interface IFontManager {
|
||||
FontConfig getFontConfig();
|
||||
|
||||
int updateFontFile(in FontUpdateRequest request, int baseVersion);
|
||||
|
||||
int updateFontFamily(in List<FontUpdateRequest> request, int baseVersion);
|
||||
}
|
||||
|
||||
@@ -262,8 +262,14 @@ public final class SystemFonts {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static Map<String, FontFamily[]> buildSystemFallback(FontConfig fontConfig) {
|
||||
return buildSystemFallback(fontConfig, new ArrayMap<>());
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public static Map<String, FontFamily[]> buildSystemFallback(FontConfig fontConfig,
|
||||
ArrayMap<String, ByteBuffer> outBufferCache) {
|
||||
final Map<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
final ArrayMap<String, ByteBuffer> bufferCache = new ArrayMap<>();
|
||||
final List<FontConfig.FontFamily> xmlFamilies = fontConfig.getFontFamilies();
|
||||
|
||||
final ArrayMap<String, ArrayList<FontFamily>> 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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<FontUpdateRequest> 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<String, ByteBuffer> bufferCache = new ArrayMap<>();
|
||||
try {
|
||||
final FontConfig fontConfig = getSystemFontConfig();
|
||||
final Map<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
|
||||
final Map<String, FontFamily[]> fallback =
|
||||
SystemFonts.buildSystemFallback(fontConfig, bufferCache);
|
||||
final Map<String, Typeface> 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<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
|
||||
final Map<String, Typeface> 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -139,9 +139,11 @@ public final class UpdatableFontDirTest {
|
||||
private File mUpdatableFontFilesDir;
|
||||
private File mConfigFile;
|
||||
private List<File> mPreinstalledFontDirs;
|
||||
private Supplier<Long> mCurrentTimeSupplier = () -> CURRENT_TIME;
|
||||
private Function<Map<String, File>, FontConfig> mConfigSupplier =
|
||||
private final Supplier<Long> mCurrentTimeSupplier = () -> CURRENT_TIME;
|
||||
private final Function<Map<String, File>, 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<Map<String, File>, 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<FontUpdateRequest.Font> fonts = new ArrayList<>();
|
||||
for (FontConfig.Font font : fontFamily.getFontList()) {
|
||||
String name = font.getFile().getName();
|
||||
|
||||
@@ -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<String> 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<String, String> result;
|
||||
try (InputStream is = new FileInputStream(certPath)) {
|
||||
@@ -338,7 +375,37 @@ public class UpdatableSystemFontTest {
|
||||
return !expectCommandToSucceed(cmd).trim().isEmpty();
|
||||
}
|
||||
|
||||
private static List<String> 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<String> 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<String> paths, Pattern pattern) {
|
||||
// Note: asPredicate() returns true for partial matching.
|
||||
return paths.stream()
|
||||
.filter(pattern.asPredicate())
|
||||
.count();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user