From ff85b932d7fd0203038a732f5e98916cf0883959 Mon Sep 17 00:00:00 2001 From: Seigo Nonaka Date: Wed, 27 Jan 2021 18:20:56 -0800 Subject: [PATCH] Add FontManager#updateFont API Bug: 173619554 Test: atest FontManagerTest Change-Id: I261e55783978d9840b06c586389e2126bc6eb2ca --- core/api/system-current.txt | 13 ++ core/api/test-current.txt | 13 ++ .../android/graphics/fonts/FontManager.java | 173 +++++++++++++----- core/java/android/text/FontConfig.java | 19 +- .../internal/graphics/fonts/IFontManager.aidl | 3 + .../graphics/fonts/FontManagerService.java | 39 +++- .../fonts/FontManagerShellCommand.java | 20 +- .../graphics/fonts/UpdatableFontDir.java | 44 ++--- .../graphics/fonts/UpdatableFontDirTest.java | 20 +- 9 files changed, 247 insertions(+), 97 deletions(-) diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 0a0f77e33ed49..0242911c98263 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2608,6 +2608,17 @@ package android.graphics.fonts { public class FontManager { method @Nullable public android.text.FontConfig getFontConfig(); + method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int); + field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb + field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff + field public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6; // 0xfffffffa + field public static final int RESULT_ERROR_FONT_UPDATER_DISABLED = -7; // 0xfffffff9 + field public static final int RESULT_ERROR_INVALID_FONT_FILE = -3; // 0xfffffffd + field public static final int RESULT_ERROR_INVALID_FONT_NAME = -4; // 0xfffffffc + field public static final int RESULT_ERROR_REMOTE_EXCEPTION = -9; // 0xfffffff7 + field public static final int RESULT_ERROR_VERIFICATION_FAILURE = -2; // 0xfffffffe + field public static final int RESULT_ERROR_VERSION_MISMATCH = -8; // 0xfffffff8 + field public static final int RESULT_SUCCESS = 0; // 0x0 } } @@ -13660,7 +13671,9 @@ package android.text { public final class FontConfig implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List getAliases(); + method @IntRange(from=0) public int getConfigVersion(); method @NonNull public java.util.List getFontFamilies(); + method public long getLastModifiedTimeMillis(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } diff --git a/core/api/test-current.txt b/core/api/test-current.txt index ea7dc03c40077..276113bbde090 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -825,6 +825,17 @@ package android.graphics.fonts { public class FontManager { method @Nullable public android.text.FontConfig getFontConfig(); + method @RequiresPermission(android.Manifest.permission.UPDATE_FONTS) public int updateFontFile(@NonNull android.os.ParcelFileDescriptor, @NonNull byte[], @IntRange(from=0) int); + field public static final int RESULT_ERROR_DOWNGRADING = -5; // 0xfffffffb + field public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; // 0xffffffff + field public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6; // 0xfffffffa + field public static final int RESULT_ERROR_FONT_UPDATER_DISABLED = -7; // 0xfffffff9 + field public static final int RESULT_ERROR_INVALID_FONT_FILE = -3; // 0xfffffffd + field public static final int RESULT_ERROR_INVALID_FONT_NAME = -4; // 0xfffffffc + field public static final int RESULT_ERROR_REMOTE_EXCEPTION = -9; // 0xfffffff7 + field public static final int RESULT_ERROR_VERIFICATION_FAILURE = -2; // 0xfffffffe + field public static final int RESULT_ERROR_VERSION_MISMATCH = -8; // 0xfffffff8 + field public static final int RESULT_SUCCESS = 0; // 0x0 } } @@ -2032,7 +2043,9 @@ package android.text { public final class FontConfig implements android.os.Parcelable { method public int describeContents(); method @NonNull public java.util.List getAliases(); + method @IntRange(from=0) public int getConfigVersion(); method @NonNull public java.util.List getFontFamilies(); + method public long getLastModifiedTimeMillis(); method public void writeToParcel(@NonNull android.os.Parcel, int); field @NonNull public static final android.os.Parcelable.Creator CREATOR; } diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java index eca56b375dd48..f0b218ce5343f 100644 --- a/core/java/android/graphics/fonts/FontManager.java +++ b/core/java/android/graphics/fonts/FontManager.java @@ -16,13 +16,17 @@ package android.graphics.fonts; +import android.Manifest; import android.annotation.IntDef; +import android.annotation.IntRange; import android.annotation.NonNull; import android.annotation.Nullable; +import android.annotation.RequiresPermission; import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.content.Context; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.text.FontConfig; import android.util.Log; @@ -35,6 +39,10 @@ import java.util.Objects; /** * This class gives you control of system installed font files. + * + *

+ * This class gives you the information of system font configuration and ability of changing them. + * * @hide */ @SystemApi @@ -45,68 +53,87 @@ public class FontManager { private final @NonNull IFontManager mIFontManager; /** @hide */ - @IntDef(prefix = "ERROR_CODE_", - value = { ERROR_CODE_OK, ERROR_CODE_FAILED_TO_WRITE_FONT_FILE, - ERROR_CODE_VERIFICATION_FAILURE, ERROR_CODE_FONT_NAME_MISMATCH, - ERROR_CODE_INVALID_FONT_FILE, ERROR_CODE_MISSING_POST_SCRIPT_NAME, - ERROR_CODE_DOWNGRADING, ERROR_CODE_FAILED_TO_CREATE_CONFIG_FILE, - ERROR_CODE_FONT_UPDATER_DISABLED }) + @IntDef(prefix = "RESULT_", + value = { RESULT_SUCCESS, RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, + RESULT_ERROR_VERIFICATION_FAILURE, RESULT_ERROR_VERSION_MISMATCH, + RESULT_ERROR_INVALID_FONT_FILE, RESULT_ERROR_INVALID_FONT_NAME, + RESULT_ERROR_DOWNGRADING, RESULT_ERROR_FAILED_UPDATE_CONFIG, + RESULT_ERROR_FONT_UPDATER_DISABLED, RESULT_ERROR_REMOTE_EXCEPTION }) @Retention(RetentionPolicy.SOURCE) - public @interface ErrorCode {} + public @interface ResultCode {} /** - * Indicates an operation has processed successfully. - * @hide + * Indicates that the request has been processed successfully. */ - public static final int ERROR_CODE_OK = 0; + public static final int RESULT_SUCCESS = 0; /** - * Indicates a failure of writing font files. - * @hide + * Indicates that a failure occurred while writing the font file to disk. + * + * This is an internal error that the system cannot place the font file for being used by + * application. */ - public static final int ERROR_CODE_FAILED_TO_WRITE_FONT_FILE = -1; + public static final int RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE = -1; /** - * Indicates a failure of fs-verity setup. - * @hide + * Indicates that a failure occurred during the verification of the font file. + * + * The system failed to verify given font file contents and signature with system installed + * certificate. */ - public static final int ERROR_CODE_VERIFICATION_FAILURE = -2; + public static final int RESULT_ERROR_VERIFICATION_FAILURE = -2; /** - * Indicates a failure of verifying the font name with PostScript name. - * @hide + * Indicates that a failure occurred as a result of invalid font format or content. + * + * Android only accepts OpenType compliant font files. */ - public static final int ERROR_CODE_FONT_NAME_MISMATCH = -3; + public static final int RESULT_ERROR_INVALID_FONT_FILE = -3; /** - * Indicates a failure of placing fonts due to unexpected font contents. - * @hide + * Indicates a failure due to missing PostScript name in font's name table. + * + * Indicates that a failure occurred since PostScript name in the name table(ID=6) was missing. + * The font is expected to have a PostScript name. */ - public static final int ERROR_CODE_INVALID_FONT_FILE = -4; + public static final int RESULT_ERROR_INVALID_FONT_NAME = -4; /** - * Indicates a failure due to missing PostScript name in name table. - * @hide + * Indicates that a failure occurred due to downgrading the font version. + * + * The font must have equal or newer revision in its head table. */ - public static final int ERROR_CODE_MISSING_POST_SCRIPT_NAME = -5; + public static final int RESULT_ERROR_DOWNGRADING = -5; /** - * Indicates a failure of placing fonts due to downgrading. - * @hide + * Indicates that a failure occurred while updating system font configuration. + * + * This is an internal error that the system couldn't update the {@link FontConfig}. */ - public static final int ERROR_CODE_DOWNGRADING = -6; - - /** - * Indicates a failure of writing system font configuration XML file. - * @hide - */ - public static final int ERROR_CODE_FAILED_TO_CREATE_CONFIG_FILE = -7; + public static final int RESULT_ERROR_FAILED_UPDATE_CONFIG = -6; /** * Indicates a failure due to disabled font updater. - * @hide + * + * This is typically returned due to missing Linux kernel feature. + * The font updater only works with the Linux kernel that has fs-verity feature. The fs-verity + * is required after the device shipped with Android 11. Thus the updated device may not have + * fs-verity feature and font updater is disabled. */ - public static final int ERROR_CODE_FONT_UPDATER_DISABLED = -8; + public static final int RESULT_ERROR_FONT_UPDATER_DISABLED = -7; + + /** + * Indicates that a failure occurred because provided {@code baseVersion} did not match. + * + * The {@code baseVersion} provided does not match to the current {@link FontConfig} version. + * Please get the latest configuration and update {@code baseVersion} accordingly. + */ + public static final int RESULT_ERROR_VERSION_MISMATCH = -8; + + /** + * Indicates a failure due to IPC communication. + */ + public static final int RESULT_ERROR_REMOTE_EXCEPTION = -9; /** * Indicates a failure of opening font file. @@ -115,7 +142,7 @@ public class FontManager { * * @hide */ - public static final int ERROR_CODE_FAILED_TO_OPEN_FONT_FILE = -10001; + public static final int RESULT_ERROR_FAILED_TO_OPEN_FONT_FILE = -10001; /** * Indicates a failure of opening signature file. @@ -124,7 +151,7 @@ public class FontManager { * * @hide */ - public static final int ERROR_CODE_FAILED_TO_OPEN_SIGNATURE_FILE = -10002; + public static final int RESULT_ERROR_FAILED_TO_OPEN_SIGNATURE_FILE = -10002; /** * Indicates a failure of invalid shell command arguments. @@ -133,7 +160,7 @@ public class FontManager { * * @hide */ - public static final int ERROR_CODE_INVALID_SHELL_ARGUMENT = -10003; + public static final int RESULT_ERROR_INVALID_SHELL_ARGUMENT = -10003; /** * Indicates a failure of reading signature file. @@ -142,7 +169,7 @@ public class FontManager { * * @hide */ - public static final int ERROR_CODE_INVALID_SIGNATURE_FILE = -10004; + public static final int RESULT_ERROR_INVALID_SIGNATURE_FILE = -10004; /** * Indicates a failure due to exceeding allowed signature file size (8kb). @@ -151,7 +178,7 @@ public class FontManager { * * @hide */ - public static final int ERROR_CODE_SIGNATURE_TOO_LARGE = -10005; + public static final int RESULT_ERROR_SIGNATURE_TOO_LARGE = -10005; private FontManager(@NonNull IFontManager iFontManager) { @@ -177,6 +204,70 @@ public class FontManager { } } + /** + * Update system installed font file. + * + *

+ * To protect devices, system font updater relies on the Linux Kernel feature called fs-verity. + * If the device is not ready for fs-verity, {@link #RESULT_ERROR_FONT_UPDATER_DISABLED} will be + * returned. + * + * Android only accepts OpenType compliant font files. If other font files are provided, + * {@link #RESULT_ERROR_INVALID_FONT_FILE} will be returned. + * + * The font file to be updated is identified by PostScript name stored in name table. If the + * font file doesn't have PostScript name entry, {@link #RESULT_ERROR_INVALID_FONT_NAME} will be + * returned. + * + * The entire font file is verified with the given signature for the system installed + * certificate. If the system cannot verify the font contents, + * {@link #RESULT_ERROR_VERIFICATION_FAILURE} will be returned. + * + * The font file must have newer or equal revision number in the head table. In other words, the + * downgrading font file is not allowed. If the older font file is provided, + * {@link #RESULT_ERROR_DOWNGRADING} will be returned. + * + * The caller must specify the base config version for keeping consist system configuration. If + * the system configuration is updated for some reason between you get config with + * {@link #getFontConfig()} and calling this method, {@link #RESULT_ERROR_VERSION_MISMATCH} will + * be returned. Get the latest font configuration by calling {@link #getFontConfig()} again and + * try with the latest config version again. + * + * @param pfd A file descriptor of the font file. + * @param signature A PKCS#7 detached signature for verifying entire font files. + * @param baseVersion A base config version to be updated. You can get latest config version by + * {@link FontConfig#getConfigVersion()} via {@link #getFontConfig()}. If the + * system has newer config version, the update will fail with + * {@link #RESULT_ERROR_VERSION_MISMATCH}. Try to get the latest config and + * try update again. + * @return result code. + * + * @see FontConfig#getConfigVersion() + * @see #getFontConfig() + * @see #RESULT_SUCCESS + * @see #RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE + * @see #RESULT_ERROR_VERIFICATION_FAILURE + * @see #RESULT_ERROR_VERSION_MISMATCH + * @see #RESULT_ERROR_INVALID_FONT_FILE + * @see #RESULT_ERROR_INVALID_FONT_NAME + * @see #RESULT_ERROR_DOWNGRADING + * @see #RESULT_ERROR_FAILED_UPDATE_CONFIG + * @see #RESULT_ERROR_FONT_UPDATER_DISABLED + * @see #RESULT_ERROR_REMOTE_EXCEPTION + */ + @RequiresPermission(Manifest.permission.UPDATE_FONTS) public @ResultCode int updateFontFile( + @NonNull ParcelFileDescriptor pfd, + @NonNull byte[] signature, + @IntRange(from = 0) int baseVersion + ) { + try { + return mIFontManager.updateFont(pfd, signature, baseVersion); + } catch (RemoteException e) { + Log.e(TAG, "Failed to call updateFont API", e); + return RESULT_ERROR_REMOTE_EXCEPTION; + } + } + /** * Factory method of the FontManager. * diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java index 53fe1ba9c4b46..2de755857b70e 100644 --- a/core/java/android/text/FontConfig.java +++ b/core/java/android/text/FontConfig.java @@ -53,7 +53,7 @@ import java.util.List; public final class FontConfig implements Parcelable { private final @NonNull List mFamilies; private final @NonNull List mAliases; - private final long mLastModifiedDate; + private final long mLastModifiedTimeMillis; private final int mConfigVersion; /** @@ -65,10 +65,10 @@ public final class FontConfig implements Parcelable { * @hide Only system server can create this instance and passed via IPC. */ public FontConfig(@NonNull List families, @NonNull List aliases, - long lastModifiedDate, @IntRange(from = 0) int configVersion) { + long lastModifiedTimeMillis, @IntRange(from = 0) int configVersion) { mFamilies = families; mAliases = aliases; - mLastModifiedDate = lastModifiedDate; + mLastModifiedTimeMillis = lastModifiedTimeMillis; mConfigVersion = configVersion; } @@ -93,20 +93,21 @@ public final class FontConfig implements Parcelable { } /** - * Returns the last modified date as Java epoch seconds. + * Returns the last modified time in milliseconds. + * + * This is a value of {@link System#currentTimeMillis()} when the system font configuration was + * modified last time. * * If there is no update, this return 0. - * @hide */ - public long getLastModifiedDate() { - return mLastModifiedDate; + public long getLastModifiedTimeMillis() { + return mLastModifiedTimeMillis; } /** * Returns the monotonically increasing config version value. * * The config version is reset to 0 when the system is restarted. - * @hide */ public @IntRange(from = 0) int getConfigVersion() { return mConfigVersion; @@ -132,7 +133,7 @@ public final class FontConfig implements Parcelable { public void writeToParcel(@NonNull Parcel dest, int flags) { dest.writeParcelableList(mFamilies, flags); dest.writeParcelableList(mAliases, flags); - dest.writeLong(mLastModifiedDate); + dest.writeLong(mLastModifiedTimeMillis); dest.writeInt(mConfigVersion); } diff --git a/core/java/com/android/internal/graphics/fonts/IFontManager.aidl b/core/java/com/android/internal/graphics/fonts/IFontManager.aidl index a11c7effc688a..cafe0de58b78e 100644 --- a/core/java/com/android/internal/graphics/fonts/IFontManager.aidl +++ b/core/java/com/android/internal/graphics/fonts/IFontManager.aidl @@ -16,6 +16,7 @@ package com.android.internal.graphics.fonts; +import android.os.ParcelFileDescriptor; import android.text.FontConfig; import android.graphics.fonts.SystemFontState; @@ -26,4 +27,6 @@ import android.graphics.fonts.SystemFontState; */ interface IFontManager { FontConfig getFontConfig(); + + int updateFont(in ParcelFileDescriptor fd, in byte[] signature, int baseVersion); } 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 5f7d938673314..7461405c9a5ff 100644 --- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java @@ -16,6 +16,7 @@ package com.android.server.graphics.fonts; +import android.Manifest; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Context; @@ -24,6 +25,7 @@ import android.graphics.fonts.FontFamily; import android.graphics.fonts.FontFileUtil; import android.graphics.fonts.FontManager; import android.graphics.fonts.SystemFonts; +import android.os.ParcelFileDescriptor; import android.os.RemoteException; import android.os.ResultReceiver; import android.os.SharedMemory; @@ -37,6 +39,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.graphics.fonts.IFontManager; import com.android.internal.util.DumpUtils; +import com.android.internal.util.Preconditions; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.security.FileIntegrityService; @@ -53,6 +56,7 @@ import java.nio.channels.FileChannel; import java.util.Arrays; import java.util.Collections; import java.util.Map; +import java.util.Objects; /** A service for managing system fonts. */ // TODO(b/173619554): Add API to update fonts. @@ -66,10 +70,27 @@ public final class FontManagerService extends IFontManager.Stub { return getSystemFontConfig(); } + @Override + public int updateFont(ParcelFileDescriptor fd, byte[] signature, int baseVersion) + throws RemoteException { + Objects.requireNonNull(fd); + Objects.requireNonNull(signature); + Preconditions.checkArgumentNonnegative(baseVersion); + getContext().enforceCallingPermission(Manifest.permission.UPDATE_FONTS, + "UPDATE_FONTS permission required."); + try { + installFontFile(fd.getFileDescriptor(), signature, baseVersion); + return FontManager.RESULT_SUCCESS; + } catch (SystemFontException e) { + Slog.e(TAG, "Failed to update font file", e); + return e.getErrorCode(); + } + } + /* package */ static class SystemFontException extends AndroidException { private final int mErrorCode; - SystemFontException(@FontManager.ErrorCode int errorCode, String msg, Throwable cause) { + SystemFontException(@FontManager.ResultCode int errorCode, String msg, Throwable cause) { super(msg, cause); mErrorCode = errorCode; } @@ -79,7 +100,8 @@ public final class FontManagerService extends IFontManager.Stub { mErrorCode = errorCode; } - @FontManager.ErrorCode int getErrorCode() { + @FontManager.ResultCode + int getErrorCode() { return mErrorCode; } } @@ -197,14 +219,21 @@ public final class FontManagerService extends IFontManager.Stub { } } - /* package */ void installFontFile(FileDescriptor fd, byte[] pkcs7Signature) + /* package */ void installFontFile(FileDescriptor fd, byte[] pkcs7Signature, int baseVersion) throws SystemFontException { if (mUpdatableFontDir == null) { throw new SystemFontException( - FontManager.ERROR_CODE_FONT_UPDATER_DISABLED, + FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED, "The font updater is disabled."); } synchronized (FontManagerService.this) { + // baseVersion == -1 only happens from shell command. This is filtered and treated as + // error from SystemApi call. + if (baseVersion != -1 && mUpdatableFontDir.getConfigVersion() != baseVersion) { + throw new SystemFontException( + FontManager.RESULT_ERROR_VERSION_MISMATCH, + "The base config version is older than current."); + } mUpdatableFontDir.installFontFile(fd, pkcs7Signature); // Create updated font map in the next getSerializedSystemFontMap() call. mSerializedFontMap = null; @@ -214,7 +243,7 @@ public final class FontManagerService extends IFontManager.Stub { /* package */ void clearUpdates() throws SystemFontException { if (mUpdatableFontDir == null) { throw new SystemFontException( - FontManager.ERROR_CODE_FONT_UPDATER_DISABLED, + FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED, "The font updater is disabled."); } mUpdatableFontDir.clearUpdates(); diff --git a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java index 5a01a97dff1ad..d2111e72f383f 100644 --- a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java +++ b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java @@ -304,27 +304,27 @@ public class FontManagerShellCommand extends ShellCommand { String fontPath = shell.getNextArg(); if (fontPath == null) { throw new SystemFontException( - FontManager.ERROR_CODE_INVALID_SHELL_ARGUMENT, + FontManager.RESULT_ERROR_INVALID_SHELL_ARGUMENT, "Font file path argument is required."); } String signaturePath = shell.getNextArg(); if (signaturePath == null) { throw new SystemFontException( - FontManager.ERROR_CODE_INVALID_SHELL_ARGUMENT, + FontManager.RESULT_ERROR_INVALID_SHELL_ARGUMENT, "Signature file argument is required."); } ParcelFileDescriptor fontFd = shell.openFileForSystem(fontPath, "r"); if (fontFd == null) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_OPEN_FONT_FILE, + FontManager.RESULT_ERROR_FAILED_TO_OPEN_FONT_FILE, "Failed to open font file"); } ParcelFileDescriptor sigFd = shell.openFileForSystem(signaturePath, "r"); if (sigFd == null) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_OPEN_SIGNATURE_FILE, + FontManager.RESULT_ERROR_FAILED_TO_OPEN_SIGNATURE_FILE, "Failed to open signature file"); } @@ -333,24 +333,24 @@ public class FontManagerShellCommand extends ShellCommand { int len = sigFis.available(); if (len > MAX_SIGNATURE_FILE_SIZE_BYTES) { throw new SystemFontException( - FontManager.ERROR_CODE_SIGNATURE_TOO_LARGE, + FontManager.RESULT_ERROR_SIGNATURE_TOO_LARGE, "Signature file is too large"); } byte[] signature = new byte[len]; if (sigFis.read(signature, 0, len) != len) { throw new SystemFontException( - FontManager.ERROR_CODE_INVALID_SIGNATURE_FILE, + FontManager.RESULT_ERROR_INVALID_SIGNATURE_FILE, "Invalid read length"); } - mService.installFontFile(fontFis.getFD(), signature); + mService.installFontFile(fontFis.getFD(), signature, -1); } catch (IOException e) { throw new SystemFontException( - FontManager.ERROR_CODE_INVALID_SIGNATURE_FILE, + FontManager.RESULT_ERROR_INVALID_SIGNATURE_FILE, "Failed to read signature file.", e); } } catch (IOException e) { throw new SystemFontException( - FontManager.ERROR_CODE_INVALID_FONT_FILE, + FontManager.RESULT_ERROR_INVALID_FONT_FILE, "Failed to read font files.", e); } @@ -370,7 +370,7 @@ public class FontManagerShellCommand extends ShellCommand { FontConfig config = mService.getSystemFontConfig(); writer.println("Current Version: " + config.getConfigVersion()); - LocalDateTime dt = LocalDateTime.ofEpochSecond(config.getLastModifiedDate(), 0, + LocalDateTime dt = LocalDateTime.ofEpochSecond(config.getLastModifiedTimeMillis(), 0, ZoneOffset.UTC); writer.println("Last Modified Date: " + dt.format(DateTimeFormatter.ISO_DATE_TIME)); diff --git a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java index 720105d29836a..b0bc65bc77870 100644 --- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java +++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java @@ -130,13 +130,7 @@ final class UpdatableFontDir { UpdatableFontDir(File filesDir, List preinstalledFontDirs, FontFileParser parser, FsverityUtil fsverityUtil) { - mFilesDir = filesDir; - mPreinstalledFontDirs = preinstalledFontDirs; - mParser = parser; - mFsverityUtil = fsverityUtil; - mConfigFile = new File(CONFIG_XML_FILE); - mTmpConfigFile = new File(CONFIG_XML_FILE + ".tmp"); - loadFontFileMap(); + this(filesDir, preinstalledFontDirs, parser, fsverityUtil, new File(CONFIG_XML_FILE)); } // For unit testing @@ -199,7 +193,7 @@ final class UpdatableFontDir { PersistentSystemFontConfig.writeToXml(fos, mConfig); } catch (Exception e) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_CREATE_CONFIG_FILE, + FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG, "Failed to write config XML.", e); } mConfigVersion++; @@ -222,7 +216,7 @@ final class UpdatableFontDir { File newDir = getRandomDir(mFilesDir); if (!newDir.mkdir()) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_WRITE_FONT_FILE, + FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, "Failed to create font directory."); } try { @@ -230,7 +224,7 @@ final class UpdatableFontDir { Os.chmod(newDir.getAbsolutePath(), 0711); } catch (ErrnoException e) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_WRITE_FONT_FILE, + FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, "Failed to change mode to 711", e); } boolean success = false; @@ -240,7 +234,7 @@ final class UpdatableFontDir { FileUtils.copy(fd, out.getFD()); } catch (IOException e) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_WRITE_FONT_FILE, + FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, "Failed to write font file to storage.", e); } try { @@ -250,7 +244,7 @@ final class UpdatableFontDir { pkcs7Signature); } catch (IOException e) { throw new SystemFontException( - FontManager.ERROR_CODE_VERIFICATION_FAILURE, + FontManager.RESULT_ERROR_VERIFICATION_FAILURE, "Failed to setup fs-verity.", e); } String postScriptName; @@ -258,18 +252,18 @@ final class UpdatableFontDir { postScriptName = mParser.getPostScriptName(tempNewFontFile); } catch (IOException e) { throw new SystemFontException( - FontManager.ERROR_CODE_INVALID_FONT_FILE, + FontManager.RESULT_ERROR_INVALID_FONT_FILE, "Failed to read PostScript name from font file", e); } if (postScriptName == null) { throw new SystemFontException( - FontManager.ERROR_CODE_MISSING_POST_SCRIPT_NAME, + FontManager.RESULT_ERROR_INVALID_FONT_NAME, "Failed to read PostScript name from font file"); } File newFontFile = new File(newDir, postScriptName + ALLOWED_EXTENSION); if (!mFsverityUtil.rename(tempNewFontFile, newFontFile)) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_WRITE_FONT_FILE, + FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, "Failed to move verified font file."); } try { @@ -277,7 +271,7 @@ final class UpdatableFontDir { Os.chmod(newFontFile.getAbsolutePath(), 0644); } catch (ErrnoException e) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_WRITE_FONT_FILE, + FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE, "Failed to change mode to 711", e); } FontFileInfo fontFileInfo = validateFontFile(newFontFile); @@ -291,7 +285,7 @@ final class UpdatableFontDir { PersistentSystemFontConfig.writeToXml(fos, copied); } catch (Exception e) { throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_CREATE_CONFIG_FILE, + FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG, "Failed to write config XML.", e); } @@ -299,7 +293,7 @@ final class UpdatableFontDir { HashMap backup = new HashMap<>(mFontFileInfoMap); if (!addFileToMapIfNewerLocked(fontFileInfo, false)) { throw new SystemFontException( - FontManager.ERROR_CODE_DOWNGRADING, + FontManager.RESULT_ERROR_DOWNGRADING, "Downgrading font file is forbidden."); } @@ -308,7 +302,7 @@ final class UpdatableFontDir { mFontFileInfoMap.clear(); mFontFileInfoMap.putAll(backup); throw new SystemFontException( - FontManager.ERROR_CODE_FAILED_TO_CREATE_CONFIG_FILE, + FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG, "Failed to stage the config file."); } @@ -400,18 +394,18 @@ final class UpdatableFontDir { private FontFileInfo validateFontFile(File file) throws SystemFontException { if (!mFsverityUtil.hasFsverity(file.getAbsolutePath())) { throw new SystemFontException( - FontManager.ERROR_CODE_VERIFICATION_FAILURE, + FontManager.RESULT_ERROR_VERIFICATION_FAILURE, "Font validation failed. Fs-verity is not enabled: " + file); } if (!validateFontFileName(file)) { throw new SystemFontException( - FontManager.ERROR_CODE_FONT_NAME_MISMATCH, + FontManager.RESULT_ERROR_INVALID_FONT_NAME, "Font validation failed. Could not validate font file name: " + file); } long revision = getFontRevision(file); if (revision == -1) { throw new SystemFontException( - FontManager.ERROR_CODE_INVALID_FONT_FILE, + FontManager.RESULT_ERROR_INVALID_FONT_FILE, "Font validation failed. Could not read font revision: " + file); } return new FontFileInfo(file, revision); @@ -472,4 +466,10 @@ final class UpdatableFontDir { ); } } + + /* package */ int getConfigVersion() { + synchronized (UpdatableFontDir.this) { + return mConfigVersion; + } + } } 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 f437d1f214ea0..d067790488373 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 @@ -147,7 +147,7 @@ public final class UpdatableFontDirTest { UpdatableFontDir dirForPreparation = new UpdatableFontDir( mUpdatableFontFilesDir, mPreinstalledFontDirs, parser, fakeFsverityUtil, mConfigFile); - assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedDate()) + assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis()) .isEqualTo(expectedModifiedDate); installFontFile(dirForPreparation, "foo,1", GOOD_SIGNATURE); installFontFile(dirForPreparation, "bar,2", GOOD_SIGNATURE); @@ -156,7 +156,7 @@ public final class UpdatableFontDirTest { // Four font dirs are created. assertThat(mUpdatableFontFilesDir.list()).hasLength(4); // - assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedDate()) + assertThat(dirForPreparation.getSystemFontConfig().getLastModifiedTimeMillis()) .isNotEqualTo(expectedModifiedDate); UpdatableFontDir dir = new UpdatableFontDir( @@ -319,7 +319,7 @@ public final class UpdatableFontDirTest { installFontFile(dir, "test,1", GOOD_SIGNATURE); fail("Expect IllegalArgumentException"); } catch (FontManagerService.SystemFontException e) { - assertThat(e.getErrorCode()).isEqualTo(FontManager.ERROR_CODE_DOWNGRADING); + assertThat(e.getErrorCode()).isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING); } assertThat(dir.getFontFileMap()).containsKey("test.ttf"); assertWithMessage("Font should not be downgraded to an older revision") @@ -355,7 +355,7 @@ public final class UpdatableFontDirTest { fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) - .isEqualTo(FontManager.ERROR_CODE_VERIFICATION_FAILURE); + .isEqualTo(FontManager.RESULT_ERROR_VERIFICATION_FAILURE); } assertThat(dir.getFontFileMap()).isEmpty(); } @@ -373,7 +373,7 @@ public final class UpdatableFontDirTest { installFontFile(dir, "test,1", GOOD_SIGNATURE); fail("Expect IllegalArgumentException"); } catch (FontManagerService.SystemFontException e) { - assertThat(e.getErrorCode()).isEqualTo(FontManager.ERROR_CODE_DOWNGRADING); + assertThat(e.getErrorCode()).isEqualTo(FontManager.RESULT_ERROR_DOWNGRADING); } assertThat(dir.getFontFileMap()).isEmpty(); } @@ -403,9 +403,9 @@ public final class UpdatableFontDirTest { installFontFile(dir, "test,2", GOOD_SIGNATURE); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) - .isEqualTo(FontManager.ERROR_CODE_FAILED_TO_CREATE_CONFIG_FILE); + .isEqualTo(FontManager.RESULT_ERROR_FAILED_UPDATE_CONFIG); } - assertThat(dir.getSystemFontConfig().getLastModifiedDate()) + assertThat(dir.getSystemFontConfig().getLastModifiedTimeMillis()) .isEqualTo(expectedModifiedDate); assertThat(dir.getFontFileMap()).isEmpty(); } finally { @@ -435,7 +435,7 @@ public final class UpdatableFontDirTest { fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) - .isEqualTo(FontManager.ERROR_CODE_MISSING_POST_SCRIPT_NAME); + .isEqualTo(FontManager.RESULT_ERROR_INVALID_FONT_NAME); } assertThat(dir.getFontFileMap()).isEmpty(); } @@ -462,7 +462,7 @@ public final class UpdatableFontDirTest { fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) - .isEqualTo(FontManager.ERROR_CODE_INVALID_FONT_FILE); + .isEqualTo(FontManager.RESULT_ERROR_INVALID_FONT_FILE); } assertThat(dir.getFontFileMap()).isEmpty(); } @@ -497,7 +497,7 @@ public final class UpdatableFontDirTest { fail("Expect SystemFontException"); } catch (FontManagerService.SystemFontException e) { assertThat(e.getErrorCode()) - .isEqualTo(FontManager.ERROR_CODE_FAILED_TO_WRITE_FONT_FILE); + .isEqualTo(FontManager.RESULT_ERROR_FAILED_TO_WRITE_FONT_FILE); } assertThat(dir.getFontFileMap()).isEmpty(); }