Clear updated font files in safe mode.
Bug: 176939176
Bug: 181536798
Bug: 187190639
Test: atest FrameworksServicesTests:UpdatableFontDirTest
Test: atest UpdatableSystemFontTest
Test: manually triggered safe mode and confirmed updated fonts are
removed.
Change-Id: I946a7df383a27bbfda2931a916ca28d8ee14feb6
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 7c013e0..1bfb6a9 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerService.java
@@ -63,6 +63,7 @@
private static final String TAG = "FontManagerService";
private static final String FONT_FILES_DIR = "/data/fonts/files";
+ private static final String CONFIG_XML_FILE = "/data/fonts/config/config.xml";
@Override
public FontConfig getFontConfig() {
@@ -126,9 +127,9 @@
public static final class Lifecycle extends SystemService {
private final FontManagerService mService;
- public Lifecycle(@NonNull Context context) {
+ public Lifecycle(@NonNull Context context, boolean safeMode) {
super(context);
- mService = new FontManagerService(context);
+ mService = new FontManagerService(context, safeMode);
}
@Override
@@ -237,18 +238,24 @@
@Nullable
private SharedMemory mSerializedFontMap = null;
- private FontManagerService(Context context) {
+ private FontManagerService(Context context, boolean safeMode) {
+ if (safeMode) {
+ Slog.i(TAG, "Entering safe mode. Deleting all font updates.");
+ UpdatableFontDir.deleteAllFiles(new File(FONT_FILES_DIR), new File(CONFIG_XML_FILE));
+ }
mContext = context;
- mUpdatableFontDir = createUpdatableFontDir();
+ mUpdatableFontDir = createUpdatableFontDir(safeMode);
initialize();
}
@Nullable
- private static UpdatableFontDir createUpdatableFontDir() {
+ private static UpdatableFontDir createUpdatableFontDir(boolean safeMode) {
+ // Never read updatable font files in safe mode.
+ if (safeMode) return null;
// If apk verity is supported, fs-verity should be available.
if (!VerityUtils.isFsVeritySupported()) return null;
- return new UpdatableFontDir(new File(FONT_FILES_DIR),
- new OtfFontFileParser(), new FsverityUtilImpl());
+ return new UpdatableFontDir(new File(FONT_FILES_DIR), new OtfFontFileParser(),
+ new FsverityUtilImpl(), new File(CONFIG_XML_FILE));
}
private void initialize() {
@@ -299,18 +306,23 @@
}
}
- /* package */ void clearUpdates() throws SystemFontException {
- if (mUpdatableFontDir == null) {
- throw new SystemFontException(
- FontManager.RESULT_ERROR_FONT_UPDATER_DISABLED,
- "The font updater is disabled.");
- }
- synchronized (mUpdatableFontDirLock) {
- mUpdatableFontDir.clearUpdates();
- updateSerializedFontMap();
- }
+ /**
+ * Clears all updates and restarts FontManagerService.
+ *
+ * <p>CAUTION: this method is not safe. Existing processes may crash due to missing font files.
+ * This method is only for {@link FontManagerShellCommand}.
+ */
+ /* package */ void clearUpdates() {
+ UpdatableFontDir.deleteAllFiles(new File(FONT_FILES_DIR), new File(CONFIG_XML_FILE));
+ initialize();
}
+ /**
+ * Restarts FontManagerService, removing not-the-latest font files.
+ *
+ * <p>CAUTION: this method is not safe. Existing processes may crash due to missing font files.
+ * This method is only for {@link FontManagerShellCommand}.
+ */
/* package */ void restart() {
initialize();
}
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 e4928ce..3fecef7 100644
--- a/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
+++ b/services/core/java/com/android/server/graphics/fonts/FontManagerShellCommand.java
@@ -448,7 +448,7 @@
}
}
- private int clear(ShellCommand shell) throws SystemFontException {
+ private int clear(ShellCommand shell) {
mService.clearUpdates();
shell.getOutPrintWriter().println("Success");
return 0;
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 d532605..4fa08eb 100644
--- a/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
+++ b/services/core/java/com/android/server/graphics/fonts/UpdatableFontDir.java
@@ -59,8 +59,6 @@
private static final String TAG = "UpdatableFontDir";
private static final String RANDOM_DIR_PREFIX = "~~";
- private static final String CONFIG_XML_FILE = "/data/fonts/config/config.xml";
-
/** Interface to mock font file access in tests. */
interface FontFileParser {
String getPostScriptName(File file) throws IOException;
@@ -137,8 +135,9 @@
*/
private final ArrayMap<String, FontFileInfo> mFontFileInfoMap = new ArrayMap<>();
- UpdatableFontDir(File filesDir, FontFileParser parser, FsverityUtil fsverityUtil) {
- this(filesDir, parser, fsverityUtil, new File(CONFIG_XML_FILE),
+ UpdatableFontDir(File filesDir, FontFileParser parser, FsverityUtil fsverityUtil,
+ File configFile) {
+ this(filesDir, parser, fsverityUtil, configFile,
System::currentTimeMillis,
(map) -> SystemFonts.getSystemFontConfig(map, 0, 0)
);
@@ -213,17 +212,6 @@
}
}
- /* package */ void clearUpdates() throws SystemFontException {
- mFontFileInfoMap.clear();
- FileUtils.deleteContents(mFilesDir);
-
- mLastModifiedMillis = mCurrentTimeSupplier.get();
- PersistentSystemFontConfig.Config config = new PersistentSystemFontConfig.Config();
- config.lastModifiedMillis = mLastModifiedMillis;
- writePersistentConfig(config);
- mConfigVersion++;
- }
-
/**
* Applies multiple {@link FontUpdateRequest}s in transaction.
* If one of the request fails, the fonts and config are rolled back to the previous state
@@ -604,4 +592,19 @@
}
return familyMap;
}
+
+ /* package */ static void deleteAllFiles(File filesDir, File configFile) {
+ // As this method is called in safe mode, try to delete all files even though an exception
+ // is thrown.
+ try {
+ new AtomicFile(configFile).delete();
+ } catch (Throwable t) {
+ Slog.w(TAG, "Failed to delete " + configFile);
+ }
+ try {
+ FileUtils.deleteContents(filesDir);
+ } catch (Throwable t) {
+ Slog.w(TAG, "Failed to delete " + filesDir);
+ }
+ }
}
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index 8dc5011..fd76e4aa 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -1804,7 +1804,7 @@
t.traceEnd();
t.traceBegin("StartFontManagerService");
- mSystemServiceManager.startService(FontManagerService.Lifecycle.class);
+ mSystemServiceManager.startService(new FontManagerService.Lifecycle(context, safeMode));
t.traceEnd();
t.traceBegin("StartTextServicesManager");
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 7b48037..6b7e1dd 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
@@ -949,6 +949,24 @@
assertThat(updated).isNotEqualTo(firstFontFamily);
}
+ @Test
+ public void deleteAllFiles() throws Exception {
+ FakeFontFileParser parser = new FakeFontFileParser();
+ FakeFsverityUtil fakeFsverityUtil = new FakeFsverityUtil();
+ UpdatableFontDir dirForPreparation = new UpdatableFontDir(
+ mUpdatableFontFilesDir, parser, fakeFsverityUtil,
+ mConfigFile, mCurrentTimeSupplier, mConfigSupplier);
+ dirForPreparation.loadFontFileMap();
+ dirForPreparation.update(Collections.singletonList(
+ newFontUpdateRequest("foo.ttf,1,foo", GOOD_SIGNATURE)));
+ assertThat(mConfigFile.exists()).isTrue();
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(1);
+
+ UpdatableFontDir.deleteAllFiles(mUpdatableFontFilesDir, mConfigFile);
+ assertThat(mConfigFile.exists()).isFalse();
+ assertThat(mUpdatableFontFilesDir.list()).hasLength(0);
+ }
+
private FontUpdateRequest newFontUpdateRequest(String content, String signature)
throws Exception {
File file = File.createTempFile("font", "ttf", mCacheDir);