Merge "Add FontManager#updateFont API" into sc-dev am: ad68508496 am: ca3b164d78

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/13422366

MUST ONLY BE SUBMITTED BY AUTOMERGER

Change-Id: Ide21f938f21b37119bba546f6198fbd4ab865404
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 3fc2386..b7a876a 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -2610,6 +2610,17 @@
 
   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
   }
 
 }
@@ -13664,7 +13675,9 @@
   public final class FontConfig implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.List<android.text.FontConfig.Alias> getAliases();
+    method @IntRange(from=0) public int getConfigVersion();
     method @NonNull public java.util.List<android.text.FontConfig.FontFamily> getFontFamilies();
+    method public long getLastModifiedTimeMillis();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
   }
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 16c52c2..a3d8254 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -826,6 +826,17 @@
 
   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 @@
   public final class FontConfig implements android.os.Parcelable {
     method public int describeContents();
     method @NonNull public java.util.List<android.text.FontConfig.Alias> getAliases();
+    method @IntRange(from=0) public int getConfigVersion();
     method @NonNull public java.util.List<android.text.FontConfig.FontFamily> getFontFamilies();
+    method public long getLastModifiedTimeMillis();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.text.FontConfig> CREATOR;
   }
diff --git a/core/java/android/graphics/fonts/FontManager.java b/core/java/android/graphics/fonts/FontManager.java
index eca56b3..f0b218c 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 @@
 
 /**
  * This class gives you control of system installed font files.
+ *
+ * <p>
+ * This class gives you the information of system font configuration and ability of changing them.
+ *
  * @hide
  */
 @SystemApi
@@ -45,68 +53,87 @@
     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 @@
      *
      * @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 @@
      *
      * @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 @@
      *
      * @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 @@
      *
      * @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 @@
      *
      * @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) {
@@ -178,6 +205,70 @@
     }
 
     /**
+     * Update system installed font file.
+     *
+     * <p>
+     * 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.
      *
      * Do not use this method directly. Use getSystemService(Context.FONT_SERVICE) instead.
diff --git a/core/java/android/text/FontConfig.java b/core/java/android/text/FontConfig.java
index 53fe1ba..2de7558 100644
--- a/core/java/android/text/FontConfig.java
+++ b/core/java/android/text/FontConfig.java
@@ -53,7 +53,7 @@
 public final class FontConfig implements Parcelable {
     private final @NonNull List<FontFamily> mFamilies;
     private final @NonNull List<Alias> mAliases;
-    private final long mLastModifiedDate;
+    private final long mLastModifiedTimeMillis;
     private final int mConfigVersion;
 
     /**
@@ -65,10 +65,10 @@
      * @hide Only system server can create this instance and passed via IPC.
      */
     public FontConfig(@NonNull List<FontFamily> families, @NonNull List<Alias> 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 @@
     }
 
     /**
-     * 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 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 a11c7ef..cafe0de 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 @@
  */
 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 5f7d938..7461405 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.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 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.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 @@
         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 @@
             mErrorCode = errorCode;
         }
 
-        @FontManager.ErrorCode int getErrorCode() {
+        @FontManager.ResultCode
+        int getErrorCode() {
             return mErrorCode;
         }
     }
@@ -197,14 +219,21 @@
         }
     }
 
-    /* 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 @@
     /* 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 5a01a97..d2111e7 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 @@
         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 @@
                 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 @@
         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 720105d..b0bc65b 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 @@
 
     UpdatableFontDir(File filesDir, List<File> 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 @@
                 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 @@
             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 @@
                 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 @@
                     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 @@
                             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 @@
                     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 @@
                     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 @@
                     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 @@
                 HashMap<String, FontFileInfo> 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 @@
                     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 @@
     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 @@
             );
         }
     }
+
+    /* 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 f437d1f..d067790 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 @@
         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 @@
         // 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 @@
             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 @@
             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 @@
             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 @@
                 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 @@
             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 @@
             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 @@
             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();
     }