Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit e2d2ccc9 authored by Kohsuke Yatoh's avatar Kohsuke Yatoh
Browse files

Split lock in FontManagerService.

Split the lock for mUpdatableFontDir from mSerializedFontMap, so that
mSerializedFontMap can be used even during performing font updates.

Bug: 179103383
Test: atest FrameworksServicesTests:UpdatableFontDirTest
Change-Id: Ic3d3ee6f3cccfcbe86996b67543fc5fdc64c85aa
parent bf01409e
Loading
Loading
Loading
Loading
+36 −24
Original line number Diff line number Diff line
@@ -26,7 +26,6 @@ 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;
import android.os.ShellCallback;
@@ -67,13 +66,12 @@ public final class FontManagerService extends IFontManager.Stub {
    private static final String CRASH_MARKER_FILE = "/data/fonts/config/crash.txt";

    @Override
    public FontConfig getFontConfig() throws RemoteException {
    public FontConfig getFontConfig() {
        return getSystemFontConfig();
    }

    @Override
    public int updateFont(ParcelFileDescriptor fd, byte[] signature, int baseVersion)
            throws RemoteException {
    public int updateFont(ParcelFileDescriptor fd, byte[] signature, int baseVersion) {
        Objects.requireNonNull(fd);
        Objects.requireNonNull(signature);
        Preconditions.checkArgumentNonnegative(baseVersion);
@@ -183,14 +181,21 @@ public final class FontManagerService extends IFontManager.Stub {
    @NonNull
    private final Context mContext;

    @GuardedBy("FontManagerService.this")
    private final Object mUpdatableFontDirLock = new Object();

    @GuardedBy("mUpdatableFontDirLock")
    @NonNull
    private final FontCrashDetector mFontCrashDetector;

    @GuardedBy("mUpdatableFontDirLock")
    @Nullable
    private final UpdatableFontDir mUpdatableFontDir;

    @GuardedBy("FontManagerService.this")
    // mSerializedFontMapLock can be acquired while holding mUpdatableFontDirLock.
    // mUpdatableFontDirLock should not be newly acquired while holding mSerializedFontMapLock.
    private final Object mSerializedFontMapLock = new Object();

    @GuardedBy("mSerializedFontMapLock")
    @Nullable
    private SharedMemory mSerializedFontMap = null;

@@ -212,9 +217,9 @@ public final class FontManagerService extends IFontManager.Stub {
    }

    private void initialize() {
        synchronized (FontManagerService.this) {
        synchronized (mUpdatableFontDirLock) {
            if (mUpdatableFontDir == null) {
                mSerializedFontMap = buildNewSerializedFontMap();
                updateSerializedFontMap();
                return;
            }
            if (mFontCrashDetector.hasCrashed()) {
@@ -228,7 +233,7 @@ public final class FontManagerService extends IFontManager.Stub {
            }
            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
                mUpdatableFontDir.loadFontFileMap();
                mSerializedFontMap = buildNewSerializedFontMap();
                updateSerializedFontMap();
            }
        }
    }
@@ -239,7 +244,7 @@ public final class FontManagerService extends IFontManager.Stub {
    }

    @Nullable /* package */ SharedMemory getCurrentFontMap() {
        synchronized (FontManagerService.this) {
        synchronized (mSerializedFontMapLock) {
            return mSerializedFontMap;
        }
    }
@@ -251,7 +256,7 @@ public final class FontManagerService extends IFontManager.Stub {
                    FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
                    "The font updater is disabled.");
        }
        synchronized (FontManagerService.this) {
        synchronized (mUpdatableFontDirLock) {
            // baseVersion == -1 only happens from shell command. This is filtered and treated as
            // error from SystemApi call.
            if (baseVersion != -1 && mUpdatableFontDir.getConfigVersion() != baseVersion) {
@@ -261,7 +266,7 @@ public final class FontManagerService extends IFontManager.Stub {
            }
            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
                mUpdatableFontDir.installFontFile(fd, pkcs7Signature);
                mSerializedFontMap = buildNewSerializedFontMap();
                updateSerializedFontMap();
            }
        }
    }
@@ -272,10 +277,10 @@ public final class FontManagerService extends IFontManager.Stub {
                    FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
                    "The font updater is disabled.");
        }
        synchronized (FontManagerService.this) {
        synchronized (mUpdatableFontDirLock) {
            try (FontCrashDetector.MonitoredBlock ignored = mFontCrashDetector.start()) {
                mUpdatableFontDir.clearUpdates();
                mSerializedFontMap = buildNewSerializedFontMap();
                updateSerializedFontMap();
            }
        }
    }
@@ -283,7 +288,8 @@ public final class FontManagerService extends IFontManager.Stub {
    /* package */ Map<String, File> getFontFileMap() {
        if (mUpdatableFontDir == null) {
            return Collections.emptyMap();
        } else {
        }
        synchronized (mUpdatableFontDirLock) {
            return mUpdatableFontDir.getFontFileMap();
        }
    }
@@ -301,7 +307,7 @@ public final class FontManagerService extends IFontManager.Stub {
            @Nullable FileDescriptor err,
            @NonNull String[] args,
            @Nullable ShellCallback callback,
            @NonNull ResultReceiver result) throws RemoteException {
            @NonNull ResultReceiver result) {
        new FontManagerShellCommand(this).exec(this, in, out, err, args, callback, result);
    }

@@ -309,24 +315,28 @@ public final class FontManagerService extends IFontManager.Stub {
     * Returns an active system font configuration.
     */
    public @NonNull FontConfig getSystemFontConfig() {
        if (mUpdatableFontDir != null) {
            return mUpdatableFontDir.getSystemFontConfig();
        } else {
        if (mUpdatableFontDir == null) {
            return SystemFonts.getSystemPreinstalledFontConfig();
        }
        synchronized (mUpdatableFontDirLock) {
            return mUpdatableFontDir.getSystemFontConfig();
        }
    }

    /**
     * Make new serialized font map data.
     * Makes new serialized font map data and updates mSerializedFontMap.
     */
    public @Nullable SharedMemory buildNewSerializedFontMap() {
    public void updateSerializedFontMap() {
        try {
            final FontConfig fontConfig = getSystemFontConfig();
            final Map<String, FontFamily[]> fallback = SystemFonts.buildSystemFallback(fontConfig);
            final Map<String, Typeface> typefaceMap =
                    SystemFonts.buildSystemTypefaces(fontConfig, fallback);

            return Typeface.serializeFontMap(typefaceMap);
            SharedMemory serializeFontMap = Typeface.serializeFontMap(typefaceMap);
            synchronized (mSerializedFontMapLock) {
                mSerializedFontMap = serializeFontMap;
            }
        } catch (IOException | ErrnoException e) {
            Slog.w(TAG, "Failed to serialize updatable font map. "
                    + "Retrying with system image fonts.", e);
@@ -338,11 +348,13 @@ public final class FontManagerService extends IFontManager.Stub {
            final Map<String, Typeface> typefaceMap =
                    SystemFonts.buildSystemTypefaces(fontConfig, fallback);

            return Typeface.serializeFontMap(typefaceMap);
            SharedMemory serializeFontMap = Typeface.serializeFontMap(typefaceMap);
            synchronized (mSerializedFontMapLock) {
                mSerializedFontMap = serializeFontMap;
            }
        } catch (IOException | ErrnoException e) {
            Slog.e(TAG, "Failed to serialize SystemServer system font map", e);
        }
        return null;
    }

}
+146 −158
Original line number Diff line number Diff line
@@ -29,8 +29,6 @@ import android.text.FontConfig;
import android.util.Base64;
import android.util.Slog;

import com.android.internal.annotations.GuardedBy;

import org.xmlpull.v1.XmlPullParserException;

import java.io.File;
@@ -44,6 +42,11 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Manages set of updatable font files.
 *
 * <p>This class is not thread safe.
 */
final class UpdatableFontDir {

    private static final String TAG = "UpdatableFontDir";
@@ -113,11 +116,9 @@ final class UpdatableFontDir {
    private final File mConfigFile;
    private final File mTmpConfigFile;

    @GuardedBy("UpdatableFontDir.this")
    private final PersistentSystemFontConfig.Config mConfig =
            new PersistentSystemFontConfig.Config();

    @GuardedBy("UpdatableFontDir.this")
    private int mConfigVersion = 1;

    /**
@@ -125,7 +126,6 @@ final class UpdatableFontDir {
     * FontFileInfo}. All files in this map are validated, and have higher revision numbers than
     * corresponding font files in {@link #mPreinstalledFontDirs}.
     */
    @GuardedBy("UpdatableFontDir.this")
    private final Map<String, FontFileInfo> mFontFileInfoMap = new HashMap<>();

    UpdatableFontDir(File filesDir, List<File> preinstalledFontDirs, FontFileParser parser,
@@ -145,7 +145,6 @@ final class UpdatableFontDir {
    }

    /* package */ void loadFontFileMap() {
        synchronized (UpdatableFontDir.this) {
        boolean success = false;

        try (FileInputStream fis = new FileInputStream(mConfigFile)) {
@@ -163,7 +162,7 @@ final class UpdatableFontDir {
                File[] files = dir.listFiles();
                if (files == null || files.length != 1) return;
                FontFileInfo fontFileInfo = validateFontFile(files[0]);
                    addFileToMapIfNewerLocked(fontFileInfo, true /* deleteOldFile */);
                addFileToMapIfNewer(fontFileInfo, true /* deleteOldFile */);
            }
            success = true;
        } catch (Throwable t) {
@@ -178,10 +177,8 @@ final class UpdatableFontDir {
            }
        }
    }
    }

    /* package */ void clearUpdates() throws SystemFontException {
        synchronized (UpdatableFontDir.this) {
        mFontFileInfoMap.clear();
        FileUtils.deleteContents(mFilesDir);

@@ -196,7 +193,6 @@ final class UpdatableFontDir {
        }
        mConfigVersion++;
    }
    }

    /**
     * Installs a new font file, or updates an existing font file.
@@ -210,7 +206,6 @@ final class UpdatableFontDir {
     * @throws SystemFontException if error occurs.
     */
    void installFontFile(FileDescriptor fd, byte[] pkcs7Signature) throws SystemFontException {
        synchronized (UpdatableFontDir.this) {
        File newDir = getRandomDir(mFilesDir);
        if (!newDir.mkdir()) {
            throw new SystemFontException(
@@ -289,7 +284,7 @@ final class UpdatableFontDir {

            // Backup the mapping for rollback.
            HashMap<String, FontFileInfo> backup = new HashMap<>(mFontFileInfoMap);
                if (!addFileToMapIfNewerLocked(fontFileInfo, false)) {
            if (!addFileToMapIfNewer(fontFileInfo, false)) {
                throw new SystemFontException(
                        FontManager.RESULT_ERROR_DOWNGRADING,
                        "Downgrading font file is forbidden.");
@@ -316,7 +311,6 @@ final class UpdatableFontDir {
            }
        }
    }
    }

    /**
     * Given {@code parent}, returns {@code parent/~~[randomStr]}.
@@ -341,7 +335,7 @@ final class UpdatableFontDir {
     * higher than the currently used font file (either in {@link #mFontFileInfoMap} or {@link
     * #mPreinstalledFontDirs}).
     */
    private boolean addFileToMapIfNewerLocked(FontFileInfo fontFileInfo, boolean deleteOldFile) {
    private boolean addFileToMapIfNewer(FontFileInfo fontFileInfo, boolean deleteOldFile) {
        String name = fontFileInfo.getFile().getName();
        FontFileInfo existingInfo = mFontFileInfoMap.get(name);
        final boolean shouldAddToMap;
@@ -447,27 +441,21 @@ final class UpdatableFontDir {

    Map<String, File> getFontFileMap() {
        Map<String, File> map = new HashMap<>();
        synchronized (UpdatableFontDir.this) {
        for (Map.Entry<String, FontFileInfo> entry : mFontFileInfoMap.entrySet()) {
            map.put(entry.getKey(), entry.getValue().getFile());
        }
        }
        return map;
    }

    /* package */ FontConfig getSystemFontConfig() {
        synchronized (UpdatableFontDir.this) {
        return SystemFonts.getSystemFontConfig(
                getFontFileMap(),
                mConfig.lastModifiedDate,
                mConfigVersion
        );
    }
    }

    /* package */ int getConfigVersion() {
        synchronized (UpdatableFontDir.this) {
        return mConfigVersion;
    }
}
}