Loading services/core/java/com/android/server/graphics/fonts/FontManagerService.java +12 −1 Original line number Diff line number Diff line Loading @@ -151,7 +151,17 @@ public final class FontManagerService extends IFontManager.Stub { /* package */ static class OtfFontFileParser implements UpdatableFontDir.FontFileParser { @Override public String getCanonicalFileName(File file) throws IOException { 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); Loading @@ -172,6 +182,7 @@ public final class FontManagerService extends IFontManager.Stub { } finally { NioUtils.freeDirectBuffer(buffer); } } @Override Loading services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java +27 −54 Original line number Diff line number Diff line Loading @@ -59,7 +59,9 @@ final class UpdatableFontDir { /** Interface to mock font file access in tests. */ interface FontFileParser { String getCanonicalFileName(File file) throws IOException; String getPostScriptName(File file) throws IOException; String buildFontFileName(File file) throws IOException; long getRevision(File file) throws IOException; } Loading @@ -76,10 +78,12 @@ final class UpdatableFontDir { /** Data class to hold font file path and revision. */ private static final class FontFileInfo { private final File mFile; private final String mPsName; private final long mRevision; FontFileInfo(File file, long revision) { FontFileInfo(File file, String psName, long revision) { mFile = file; mPsName = psName; mRevision = revision; } Loading @@ -87,6 +91,10 @@ final class UpdatableFontDir { return mFile; } public String getPostScriptName() { return mPsName; } /** Returns the unique randomized font dir containing this font file. */ public File getRandomizedFontDir() { return mFile.getParentFile(); Loading @@ -98,7 +106,9 @@ final class UpdatableFontDir { @Override public String toString() { return "FontFileInfo{mFile=" + mFile + ", mRevision=" + mRevision + '}'; return "FontFileInfo{mFile=" + mFile + ", psName=" + mPsName + ", mRevision=" + mRevision + '}'; } } Loading Loading @@ -329,20 +339,20 @@ final class UpdatableFontDir { FontManager.RESULT_ERROR_VERIFICATION_FAILURE, "Failed to setup fs-verity.", e); } String canonicalFileName; String fontFileName; try { canonicalFileName = mParser.getCanonicalFileName(tempNewFontFile); fontFileName = mParser.buildFontFileName(tempNewFontFile); } catch (IOException e) { throw new SystemFontException( FontManager.RESULT_ERROR_INVALID_FONT_FILE, "Failed to read PostScript name from font file", e); } if (canonicalFileName == null) { if (fontFileName == null) { throw new SystemFontException( FontManager.RESULT_ERROR_INVALID_FONT_NAME, "Failed to read PostScript name from font file"); } File newFontFile = new File(newDir, canonicalFileName); File newFontFile = new File(newDir, fontFileName); if (!mFsverityUtil.rename(tempNewFontFile, newFontFile)) { throw new SystemFontException( FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, Loading Loading @@ -388,22 +398,12 @@ final class UpdatableFontDir { return dir; } private FontFileInfo lookupFontFileInfo(File file) { String name = file.getName(); if (!name.endsWith(".ttf") && !name.endsWith(".otf") && !name.endsWith(".ttc") && !name.endsWith(".otc")) { return null; } String key = name.substring(0, name.length() - 4); return mFontFileInfoMap.get(key); private FontFileInfo lookupFontFileInfo(String psName) { return mFontFileInfoMap.get(psName); } private void putFontFileInfo(FontFileInfo info) { String name = info.getFile().getName(); // The file name in FontFileInfo is already validated. Thus, just strip last 4 chars. String key = name.substring(0, name.length() - 4); mFontFileInfoMap.put(key, info); mFontFileInfoMap.put(info.getPostScriptName(), info); } /** Loading @@ -412,7 +412,7 @@ final class UpdatableFontDir { * #mPreinstalledFontDirs}). */ private boolean addFileToMapIfNewer(FontFileInfo fontFileInfo, boolean deleteOldFile) { FontFileInfo existingInfo = lookupFontFileInfo(fontFileInfo.getFile()); FontFileInfo existingInfo = lookupFontFileInfo(fontFileInfo.getPostScriptName()); final boolean shouldAddToMap; if (existingInfo == null) { // We got a new updatable font. We need to check if it's newer than preinstalled fonts. Loading Loading @@ -465,10 +465,13 @@ final class UpdatableFontDir { FontManager.RESULT_ERROR_VERIFICATION_FAILURE, "Font validation failed. Fs-verity is not enabled: " + file); } if (!validateFontFileName(file)) { final String psName; try { psName = mParser.getPostScriptName(file); } catch (IOException e) { throw new SystemFontException( FontManager.RESULT_ERROR_INVALID_FONT_NAME, "Font validation failed. Could not validate font file name: " + file); "Font validation failed. Could not read PostScript name name: " + file); } long revision = getFontRevision(file); if (revision == -1) { Loading @@ -476,38 +479,8 @@ final class UpdatableFontDir { FontManager.RESULT_ERROR_INVALID_FONT_FILE, "Font validation failed. Could not read font revision: " + file); } return new FontFileInfo(file, revision); return new FontFileInfo(file, psName, revision); } /** * Returns true if the font file's file name matches with the PostScript name metadata in the * font file. * * <p>We check the font file names because apps use file name to look up fonts. * <p>Because PostScript name does not include extension, the extension is appended for * comparison. For example, if the file name is "NotoColorEmoji.ttf", the PostScript name should * be "NotoColorEmoji". */ private boolean validateFontFileName(File file) { String fileName = file.getName(); String canonicalFileName = getCanonicalFileName(file); if (canonicalFileName == null) { return false; } return canonicalFileName.equals(fileName); } /** Returns the PostScript name of the given font file, or null. */ @Nullable private String getCanonicalFileName(File file) { try { return mParser.getCanonicalFileName(file); } catch (IOException e) { Slog.e(TAG, "Failed to read font file", e); return null; } } /** Returns the non-negative font revision of the given font file, or -1. */ private long getFontRevision(File file) { try { Loading services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java +22 −3 Original line number Diff line number Diff line Loading @@ -69,7 +69,14 @@ public final class UpdatableFontDirTest { */ private static class FakeFontFileParser implements UpdatableFontDir.FontFileParser { @Override public String getCanonicalFileName(File file) throws IOException { public String getPostScriptName(File file) throws IOException { String content = FileUtils.readTextFile(file, 100, ""); String filename = content.split(",")[0]; return filename.substring(0, filename.length() - 4); } @Override public String buildFontFileName(File file) throws IOException { String content = FileUtils.readTextFile(file, 100, ""); return content.split(",")[0]; } Loading @@ -77,6 +84,7 @@ public final class UpdatableFontDirTest { @Override public long getRevision(File file) throws IOException { String content = FileUtils.readTextFile(file, 100, ""); android.util.Log.e("Debug", "content: " + content); return Long.parseLong(content.split(",")[1]); } } Loading Loading @@ -549,8 +557,14 @@ public final class UpdatableFontDirTest { UpdatableFontDir dir = new UpdatableFontDir( mUpdatableFontFilesDir, mPreinstalledFontDirs, new UpdatableFontDir.FontFileParser() { @Override public String getCanonicalFileName(File file) throws IOException { public String getPostScriptName(File file) throws IOException { return null; } @Override public String buildFontFileName(File file) throws IOException { return null; } Loading Loading @@ -579,7 +593,12 @@ public final class UpdatableFontDirTest { mUpdatableFontFilesDir, mPreinstalledFontDirs, new UpdatableFontDir.FontFileParser() { @Override public String getCanonicalFileName(File file) throws IOException { public String getPostScriptName(File file) throws IOException { throw new IOException(); } @Override public String buildFontFileName(File file) throws IOException { throw new IOException(); } Loading Loading
services/core/java/com/android/server/graphics/fonts/FontManagerService.java +12 −1 Original line number Diff line number Diff line Loading @@ -151,7 +151,17 @@ public final class FontManagerService extends IFontManager.Stub { /* package */ static class OtfFontFileParser implements UpdatableFontDir.FontFileParser { @Override public String getCanonicalFileName(File file) throws IOException { 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); Loading @@ -172,6 +182,7 @@ public final class FontManagerService extends IFontManager.Stub { } finally { NioUtils.freeDirectBuffer(buffer); } } @Override Loading
services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java +27 −54 Original line number Diff line number Diff line Loading @@ -59,7 +59,9 @@ final class UpdatableFontDir { /** Interface to mock font file access in tests. */ interface FontFileParser { String getCanonicalFileName(File file) throws IOException; String getPostScriptName(File file) throws IOException; String buildFontFileName(File file) throws IOException; long getRevision(File file) throws IOException; } Loading @@ -76,10 +78,12 @@ final class UpdatableFontDir { /** Data class to hold font file path and revision. */ private static final class FontFileInfo { private final File mFile; private final String mPsName; private final long mRevision; FontFileInfo(File file, long revision) { FontFileInfo(File file, String psName, long revision) { mFile = file; mPsName = psName; mRevision = revision; } Loading @@ -87,6 +91,10 @@ final class UpdatableFontDir { return mFile; } public String getPostScriptName() { return mPsName; } /** Returns the unique randomized font dir containing this font file. */ public File getRandomizedFontDir() { return mFile.getParentFile(); Loading @@ -98,7 +106,9 @@ final class UpdatableFontDir { @Override public String toString() { return "FontFileInfo{mFile=" + mFile + ", mRevision=" + mRevision + '}'; return "FontFileInfo{mFile=" + mFile + ", psName=" + mPsName + ", mRevision=" + mRevision + '}'; } } Loading Loading @@ -329,20 +339,20 @@ final class UpdatableFontDir { FontManager.RESULT_ERROR_VERIFICATION_FAILURE, "Failed to setup fs-verity.", e); } String canonicalFileName; String fontFileName; try { canonicalFileName = mParser.getCanonicalFileName(tempNewFontFile); fontFileName = mParser.buildFontFileName(tempNewFontFile); } catch (IOException e) { throw new SystemFontException( FontManager.RESULT_ERROR_INVALID_FONT_FILE, "Failed to read PostScript name from font file", e); } if (canonicalFileName == null) { if (fontFileName == null) { throw new SystemFontException( FontManager.RESULT_ERROR_INVALID_FONT_NAME, "Failed to read PostScript name from font file"); } File newFontFile = new File(newDir, canonicalFileName); File newFontFile = new File(newDir, fontFileName); if (!mFsverityUtil.rename(tempNewFontFile, newFontFile)) { throw new SystemFontException( FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, Loading Loading @@ -388,22 +398,12 @@ final class UpdatableFontDir { return dir; } private FontFileInfo lookupFontFileInfo(File file) { String name = file.getName(); if (!name.endsWith(".ttf") && !name.endsWith(".otf") && !name.endsWith(".ttc") && !name.endsWith(".otc")) { return null; } String key = name.substring(0, name.length() - 4); return mFontFileInfoMap.get(key); private FontFileInfo lookupFontFileInfo(String psName) { return mFontFileInfoMap.get(psName); } private void putFontFileInfo(FontFileInfo info) { String name = info.getFile().getName(); // The file name in FontFileInfo is already validated. Thus, just strip last 4 chars. String key = name.substring(0, name.length() - 4); mFontFileInfoMap.put(key, info); mFontFileInfoMap.put(info.getPostScriptName(), info); } /** Loading @@ -412,7 +412,7 @@ final class UpdatableFontDir { * #mPreinstalledFontDirs}). */ private boolean addFileToMapIfNewer(FontFileInfo fontFileInfo, boolean deleteOldFile) { FontFileInfo existingInfo = lookupFontFileInfo(fontFileInfo.getFile()); FontFileInfo existingInfo = lookupFontFileInfo(fontFileInfo.getPostScriptName()); final boolean shouldAddToMap; if (existingInfo == null) { // We got a new updatable font. We need to check if it's newer than preinstalled fonts. Loading Loading @@ -465,10 +465,13 @@ final class UpdatableFontDir { FontManager.RESULT_ERROR_VERIFICATION_FAILURE, "Font validation failed. Fs-verity is not enabled: " + file); } if (!validateFontFileName(file)) { final String psName; try { psName = mParser.getPostScriptName(file); } catch (IOException e) { throw new SystemFontException( FontManager.RESULT_ERROR_INVALID_FONT_NAME, "Font validation failed. Could not validate font file name: " + file); "Font validation failed. Could not read PostScript name name: " + file); } long revision = getFontRevision(file); if (revision == -1) { Loading @@ -476,38 +479,8 @@ final class UpdatableFontDir { FontManager.RESULT_ERROR_INVALID_FONT_FILE, "Font validation failed. Could not read font revision: " + file); } return new FontFileInfo(file, revision); return new FontFileInfo(file, psName, revision); } /** * Returns true if the font file's file name matches with the PostScript name metadata in the * font file. * * <p>We check the font file names because apps use file name to look up fonts. * <p>Because PostScript name does not include extension, the extension is appended for * comparison. For example, if the file name is "NotoColorEmoji.ttf", the PostScript name should * be "NotoColorEmoji". */ private boolean validateFontFileName(File file) { String fileName = file.getName(); String canonicalFileName = getCanonicalFileName(file); if (canonicalFileName == null) { return false; } return canonicalFileName.equals(fileName); } /** Returns the PostScript name of the given font file, or null. */ @Nullable private String getCanonicalFileName(File file) { try { return mParser.getCanonicalFileName(file); } catch (IOException e) { Slog.e(TAG, "Failed to read font file", e); return null; } } /** Returns the non-negative font revision of the given font file, or -1. */ private long getFontRevision(File file) { try { Loading
services/tests/servicestests/src/com/android/server/graphics/fonts/UpdatableFontDirTest.java +22 −3 Original line number Diff line number Diff line Loading @@ -69,7 +69,14 @@ public final class UpdatableFontDirTest { */ private static class FakeFontFileParser implements UpdatableFontDir.FontFileParser { @Override public String getCanonicalFileName(File file) throws IOException { public String getPostScriptName(File file) throws IOException { String content = FileUtils.readTextFile(file, 100, ""); String filename = content.split(",")[0]; return filename.substring(0, filename.length() - 4); } @Override public String buildFontFileName(File file) throws IOException { String content = FileUtils.readTextFile(file, 100, ""); return content.split(",")[0]; } Loading @@ -77,6 +84,7 @@ public final class UpdatableFontDirTest { @Override public long getRevision(File file) throws IOException { String content = FileUtils.readTextFile(file, 100, ""); android.util.Log.e("Debug", "content: " + content); return Long.parseLong(content.split(",")[1]); } } Loading Loading @@ -549,8 +557,14 @@ public final class UpdatableFontDirTest { UpdatableFontDir dir = new UpdatableFontDir( mUpdatableFontFilesDir, mPreinstalledFontDirs, new UpdatableFontDir.FontFileParser() { @Override public String getCanonicalFileName(File file) throws IOException { public String getPostScriptName(File file) throws IOException { return null; } @Override public String buildFontFileName(File file) throws IOException { return null; } Loading Loading @@ -579,7 +593,12 @@ public final class UpdatableFontDirTest { mUpdatableFontFilesDir, mPreinstalledFontDirs, new UpdatableFontDir.FontFileParser() { @Override public String getCanonicalFileName(File file) throws IOException { public String getPostScriptName(File file) throws IOException { throw new IOException(); } @Override public String buildFontFileName(File file) throws IOException { throw new IOException(); } Loading