diff options
Diffstat (limited to 'tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java')
-rw-r--r-- | tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java | 98 |
1 files changed, 92 insertions, 6 deletions
diff --git a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java index 898b8d4cbdc1..80b0dfeb8804 100644 --- a/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java +++ b/tests/UpdatableSystemFontTest/src/com/android/updatablesystemfont/UpdatableSystemFontTest.java @@ -20,6 +20,7 @@ import static android.os.ParcelFileDescriptor.MODE_READ_ONLY; import static com.google.common.truth.Truth.assertThat; +import static org.junit.Assert.assertThrows; import static org.junit.Assume.assumeTrue; import static java.util.concurrent.TimeUnit.SECONDS; @@ -56,6 +57,11 @@ import java.io.InputStream; import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.List; +import java.util.regex.Pattern; /** * Tests if fonts can be updated by {@link FontManager} API. @@ -95,6 +101,12 @@ public class UpdatableSystemFontTest { EMOJI_RENDERING_TEST_APP_ID + "/.EmojiRenderingTestActivity"; private static final long ACTIVITY_TIMEOUT_MILLIS = SECONDS.toMillis(10); + private static final Pattern PATTERN_FONT_FILES = Pattern.compile("\\.(ttf|otf|ttc|otc)$"); + private static final Pattern PATTERN_TMP_FILES = Pattern.compile("^/data/local/tmp/"); + private static final Pattern PATTERN_DATA_FONT_FILES = Pattern.compile("^/data/fonts/files/"); + private static final Pattern PATTERN_SYSTEM_FONT_FILES = + Pattern.compile("^/(system|product)/fonts/"); + private String mKeyId; private FontManager mFontManager; @@ -236,6 +248,45 @@ public class UpdatableSystemFontTest { assertThat(fontPathAfterReboot).isEqualTo(fontPath); } + @Test + public void fdLeakTest() throws Exception { + long originalOpenFontCount = + countMatch(getOpenFiles("system_server"), PATTERN_FONT_FILES); + Pattern patternEmojiVPlus1 = + Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF)); + for (int i = 0; i < 10; i++) { + assertThat(updateFontFile( + TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF, TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)) + .isEqualTo(FontManager.RESULT_SUCCESS); + List<String> openFiles = getOpenFiles("system_server"); + for (Pattern p : Arrays.asList(PATTERN_FONT_FILES, PATTERN_SYSTEM_FONT_FILES, + PATTERN_DATA_FONT_FILES, PATTERN_TMP_FILES)) { + Log.i(TAG, String.format("num of %s: %d", p, countMatch(openFiles, p))); + } + // system_server should not keep /data/fonts files open. + assertThat(countMatch(openFiles, PATTERN_DATA_FONT_FILES)).isEqualTo(0); + // system_server should not keep passed FD open. + assertThat(countMatch(openFiles, patternEmojiVPlus1)).isEqualTo(0); + // The number of open font FD should not increase. + assertThat(countMatch(openFiles, PATTERN_FONT_FILES)) + .isAtMost(originalOpenFontCount); + } + } + + @Test + public void fdLeakTest_withoutPermission() throws Exception { + Pattern patternEmojiVPlus1 = + Pattern.compile(Pattern.quote(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF)); + byte[] signature = Files.readAllBytes(Paths.get(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF_FSV_SIG)); + try (ParcelFileDescriptor fd = ParcelFileDescriptor.open( + new File(TEST_NOTO_COLOR_EMOJI_VPLUS1_TTF), MODE_READ_ONLY)) { + assertThrows(SecurityException.class, + () -> updateFontFileWithoutPermission(fd, signature, 0)); + } + List<String> openFiles = getOpenFiles("system_server"); + assertThat(countMatch(openFiles, patternEmojiVPlus1)).isEqualTo(0); + } + private static String insertCert(String certPath) throws Exception { Pair<String, String> result; try (InputStream is = new FileInputStream(certPath)) { @@ -253,16 +304,21 @@ public class UpdatableSystemFontTest { try (ParcelFileDescriptor fd = ParcelFileDescriptor.open(new File(fontPath), MODE_READ_ONLY)) { return SystemUtil.runWithShellPermissionIdentity(() -> { - FontConfig fontConfig = mFontManager.getFontConfig(); - return mFontManager.updateFontFamily( - new FontFamilyUpdateRequest.Builder() - .addFontFileUpdateRequest(new FontFileUpdateRequest(fd, signature)) - .build(), - fontConfig.getConfigVersion()); + int configVersion = mFontManager.getFontConfig().getConfigVersion(); + return updateFontFileWithoutPermission(fd, signature, configVersion); }); } } + private int updateFontFileWithoutPermission(ParcelFileDescriptor fd, byte[] signature, + int configVersion) { + return mFontManager.updateFontFamily( + new FontFamilyUpdateRequest.Builder() + .addFontFileUpdateRequest(new FontFileUpdateRequest(fd, signature)) + .build(), + configVersion); + } + private String getFontPath(String psName) { return SystemUtil.runWithShellPermissionIdentity(() -> { FontConfig fontConfig = mFontManager.getFontConfig(); @@ -338,7 +394,37 @@ public class UpdatableSystemFontTest { return !expectCommandToSucceed(cmd).trim().isEmpty(); } + private static List<String> getOpenFiles(String appId) throws Exception { + String pid = pidOf(appId); + if (pid.isEmpty()) { + return Collections.emptyList(); + } + String cmd = String.format("lsof -p %s", pid); + String out = expectCommandToSucceed(cmd); + List<String> paths = new ArrayList<>(); + boolean first = true; + for (String line : out.split("\n")) { + // Skip the header. + if (first) { + first = false; + continue; + } + String[] records = line.split(" "); + if (records.length > 0) { + paths.add(records[records.length - 1]); + } + } + return paths; + } + private static String pidOf(String appId) throws Exception { return expectCommandToSucceed("pidof " + appId).trim(); } + + private static long countMatch(List<String> paths, Pattern pattern) { + // Note: asPredicate() returns true for partial matching. + return paths.stream() + .filter(pattern.asPredicate()) + .count(); + } } |