Reduce the memory usage in system_server
SystemFonts and related classes are now aggressively used in system server. To reduce the memory impact, use ArrayMap/Set instead of HashMap/Set. Also, the language tags are duplicated in two places, one in Java and one in Native object. Remove Java reference. Bug: 178472803 Test: N/A Change-Id: Id94b68bd34a1958fda67512dcdc683b20b12003f
This commit is contained in:
@@ -42,6 +42,7 @@ import android.provider.FontsContract;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.OsConstants;
|
||||
import android.text.FontConfig;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Base64;
|
||||
import android.util.LongSparseArray;
|
||||
import android.util.LruCache;
|
||||
@@ -67,7 +68,6 @@ import java.nio.ByteOrder;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
@@ -147,7 +147,7 @@ public class Typeface {
|
||||
*/
|
||||
@GuardedBy("SYSTEM_FONT_MAP_LOCK")
|
||||
@UnsupportedAppUsage(trackingBug = 123769347)
|
||||
static final Map<String, Typeface> sSystemFontMap = new HashMap<>();
|
||||
static final Map<String, Typeface> sSystemFontMap = new ArrayMap<>();
|
||||
|
||||
// DirectByteBuffer object to hold sSystemFontMap's backing memory mapping.
|
||||
static ByteBuffer sSystemFontMapBuffer = null;
|
||||
@@ -1231,7 +1231,7 @@ public class Typeface {
|
||||
/** @hide */
|
||||
@VisibleForTesting
|
||||
public static Map<String, Typeface> deserializeFontMap(ByteBuffer buffer) throws IOException {
|
||||
Map<String, Typeface> fontMap = new HashMap<>();
|
||||
Map<String, Typeface> fontMap = new ArrayMap<>();
|
||||
int typefacesBytesCount = buffer.getInt();
|
||||
long[] nativePtrs = nativeReadTypefaces(buffer.slice());
|
||||
if (nativePtrs == null) {
|
||||
|
||||
@@ -20,15 +20,16 @@ import android.annotation.IntRange;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.text.FontConfig;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.util.Preconditions;
|
||||
|
||||
import dalvik.annotation.optimization.CriticalNative;
|
||||
import dalvik.annotation.optimization.FastNative;
|
||||
|
||||
import libcore.util.NativeAllocationRegistry;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
|
||||
/**
|
||||
* A font family class can be used for creating Typeface.
|
||||
@@ -68,7 +69,9 @@ public final class FontFamily {
|
||||
nGetReleaseNativeFamily());
|
||||
|
||||
private final ArrayList<Font> mFonts = new ArrayList<>();
|
||||
private final HashSet<Integer> mStyleHashSet = new HashSet<>();
|
||||
// Most FontFamily only has regular, bold, italic, bold-italic. Thus 4 should be good for
|
||||
// initial capacity.
|
||||
private final SparseIntArray mStyles = new SparseIntArray(4);
|
||||
|
||||
/**
|
||||
* Constructs a builder.
|
||||
@@ -77,7 +80,7 @@ public final class FontFamily {
|
||||
*/
|
||||
public Builder(@NonNull Font font) {
|
||||
Preconditions.checkNotNull(font, "font can not be null");
|
||||
mStyleHashSet.add(makeStyleIdentifier(font));
|
||||
mStyles.append(makeStyleIdentifier(font), 0);
|
||||
mFonts.add(font);
|
||||
}
|
||||
|
||||
@@ -97,9 +100,11 @@ public final class FontFamily {
|
||||
*/
|
||||
public @NonNull Builder addFont(@NonNull Font font) {
|
||||
Preconditions.checkNotNull(font, "font can not be null");
|
||||
if (!mStyleHashSet.add(makeStyleIdentifier(font))) {
|
||||
int key = makeStyleIdentifier(font);
|
||||
if (mStyles.indexOfKey(key) >= 0) {
|
||||
throw new IllegalArgumentException(font + " has already been added");
|
||||
}
|
||||
mStyles.append(key, 0);
|
||||
mFonts.add(font);
|
||||
return this;
|
||||
}
|
||||
@@ -120,7 +125,7 @@ public final class FontFamily {
|
||||
nAddFont(builderPtr, mFonts.get(i).getNativePtr());
|
||||
}
|
||||
final long ptr = nBuild(builderPtr, langTags, variant, isCustomFallback);
|
||||
final FontFamily family = new FontFamily(mFonts, langTags, variant, ptr);
|
||||
final FontFamily family = new FontFamily(mFonts, ptr);
|
||||
sFamilyRegistory.registerNativeAllocation(family, ptr);
|
||||
return family;
|
||||
}
|
||||
@@ -139,15 +144,11 @@ public final class FontFamily {
|
||||
}
|
||||
|
||||
private final ArrayList<Font> mFonts;
|
||||
private final String mLangTags;
|
||||
private final int mVariant;
|
||||
private final long mNativePtr;
|
||||
|
||||
// Use Builder instead.
|
||||
private FontFamily(@NonNull ArrayList<Font> fonts, String langTags, int variant, long ptr) {
|
||||
private FontFamily(@NonNull ArrayList<Font> fonts, long ptr) {
|
||||
mFonts = fonts;
|
||||
mLangTags = langTags;
|
||||
mVariant = variant;
|
||||
mNativePtr = ptr;
|
||||
}
|
||||
|
||||
@@ -157,7 +158,7 @@ public final class FontFamily {
|
||||
* @return a BCP-47 compliant language tag.
|
||||
*/
|
||||
public @Nullable String getLangTags() {
|
||||
return mLangTags;
|
||||
return nGetLangTags(mNativePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -165,7 +166,7 @@ public final class FontFamily {
|
||||
* @return a family variant
|
||||
*/
|
||||
public int getVariant() {
|
||||
return mVariant;
|
||||
return nGetVariant(mNativePtr);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -191,4 +192,10 @@ public final class FontFamily {
|
||||
public long getNativePtr() {
|
||||
return mNativePtr;
|
||||
}
|
||||
|
||||
@FastNative
|
||||
private static native String nGetLangTags(long family);
|
||||
|
||||
@CriticalNative
|
||||
private static native int nGetVariant(long family);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import android.graphics.FontListParser;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.FontConfig;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
@@ -36,8 +37,6 @@ import java.nio.ByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
@@ -76,7 +75,7 @@ public final class SystemFonts {
|
||||
if (Typeface.ENABLE_LAZY_TYPEFACE_INITIALIZATION) {
|
||||
sAvailableFonts = collectAllFonts();
|
||||
} else {
|
||||
Set<Font> set = new HashSet<>();
|
||||
Set<Font> set = new ArraySet<>();
|
||||
for (FontFamily[] items : sFamilyMap.values()) {
|
||||
for (FontFamily family : items) {
|
||||
for (int i = 0; i < family.getSize(); ++i) {
|
||||
@@ -96,7 +95,7 @@ public final class SystemFonts {
|
||||
FontConfig fontConfig = getSystemPreinstalledFontConfig();
|
||||
Map<String, FontFamily[]> map = buildSystemFallback(fontConfig);
|
||||
|
||||
Set<Font> res = new HashSet<>();
|
||||
Set<Font> res = new ArraySet<>();
|
||||
for (FontFamily[] families : map.values()) {
|
||||
for (FontFamily family : families) {
|
||||
for (int i = 0; i < family.getSize(); ++i) {
|
||||
@@ -218,7 +217,7 @@ public final class SystemFonts {
|
||||
}
|
||||
|
||||
private static void appendNamedFamily(@NonNull FontConfig.FontFamily xmlFamily,
|
||||
@NonNull HashMap<String, ByteBuffer> bufferCache,
|
||||
@NonNull ArrayMap<String, ByteBuffer> bufferCache,
|
||||
@NonNull ArrayMap<String, ArrayList<FontFamily>> fallbackListMap) {
|
||||
final String familyName = xmlFamily.getName();
|
||||
final FontFamily family = createFontFamily(
|
||||
@@ -284,8 +283,8 @@ public final class SystemFonts {
|
||||
*/
|
||||
@VisibleForTesting
|
||||
public static Map<String, FontFamily[]> buildSystemFallback(FontConfig fontConfig) {
|
||||
final Map<String, FontFamily[]> fallbackMap = new HashMap<>();
|
||||
final HashMap<String, ByteBuffer> bufferCache = new HashMap<>();
|
||||
final Map<String, FontFamily[]> fallbackMap = new ArrayMap<>();
|
||||
final ArrayMap<String, ByteBuffer> bufferCache = new ArrayMap<>();
|
||||
final List<FontConfig.FontFamily> xmlFamilies = fontConfig.getFontFamilies();
|
||||
|
||||
final ArrayMap<String, ArrayList<FontFamily>> fallbackListMap = new ArrayMap<>();
|
||||
@@ -326,7 +325,7 @@ public final class SystemFonts {
|
||||
public static Map<String, Typeface> buildSystemTypefaces(
|
||||
FontConfig fontConfig,
|
||||
Map<String, FontFamily[]> fallbackMap) {
|
||||
final HashMap<String, Typeface> result = new HashMap<>();
|
||||
final ArrayMap<String, Typeface> result = new ArrayMap<>();
|
||||
Typeface.initSystemDefaultTypefaces(fallbackMap, fontConfig.getAliases(), result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -83,6 +83,23 @@ static jlong FontFamily_Builder_GetReleaseFunc(CRITICAL_JNI_PARAMS) {
|
||||
return reinterpret_cast<jlong>(releaseFontFamily);
|
||||
}
|
||||
|
||||
// FastNative
|
||||
static jstring FontFamily_getLangTags(JNIEnv* env, jobject, jlong familyPtr) {
|
||||
FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
|
||||
uint32_t localeListId = family->family->localeListId();
|
||||
if (localeListId == 0) {
|
||||
return nullptr;
|
||||
}
|
||||
std::string langTags = minikin::getLocaleString(localeListId);
|
||||
return env->NewStringUTF(langTags.c_str());
|
||||
}
|
||||
|
||||
// CriticalNative
|
||||
static jint FontFamily_getVariant(jlong familyPtr) {
|
||||
FontFamilyWrapper* family = reinterpret_cast<FontFamilyWrapper*>(familyPtr);
|
||||
return static_cast<jint>(family->family->variant());
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static const JNINativeMethod gFontFamilyBuilderMethods[] = {
|
||||
@@ -93,9 +110,16 @@ static const JNINativeMethod gFontFamilyBuilderMethods[] = {
|
||||
{ "nGetReleaseNativeFamily", "()J", (void*) FontFamily_Builder_GetReleaseFunc },
|
||||
};
|
||||
|
||||
static const JNINativeMethod gFontFamilyMethods[] = {
|
||||
{"nGetLangTags", "(J)Ljava/lang/String;", (void*)FontFamily_getLangTags},
|
||||
{"nGetVariant", "(J)I", (void*)FontFamily_getVariant},
|
||||
};
|
||||
|
||||
int register_android_graphics_fonts_FontFamily(JNIEnv* env) {
|
||||
return RegisterMethodsOrDie(env, "android/graphics/fonts/FontFamily$Builder",
|
||||
gFontFamilyBuilderMethods, NELEM(gFontFamilyBuilderMethods));
|
||||
gFontFamilyBuilderMethods, NELEM(gFontFamilyBuilderMethods)) +
|
||||
RegisterMethodsOrDie(env, "android/graphics/fonts/FontFamily", gFontFamilyMethods,
|
||||
NELEM(gFontFamilyMethods));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import android.os.FileUtils;
|
||||
import android.system.ErrnoException;
|
||||
import android.system.Os;
|
||||
import android.text.FontConfig;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.Base64;
|
||||
import android.util.Slog;
|
||||
|
||||
@@ -39,7 +40,6 @@ import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.SecureRandom;
|
||||
import java.time.Instant;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -116,7 +116,7 @@ final class UpdatableFontDir {
|
||||
* FontFileInfo}. All files in this map are validated, and have higher revision numbers than
|
||||
* corresponding font files in {@link #mPreinstalledFontDirs}.
|
||||
*/
|
||||
private final Map<String, FontFileInfo> mFontFileInfoMap = new HashMap<>();
|
||||
private final ArrayMap<String, FontFileInfo> mFontFileInfoMap = new ArrayMap<>();
|
||||
|
||||
UpdatableFontDir(File filesDir, List<File> preinstalledFontDirs, FontFileParser parser,
|
||||
FsverityUtil fsverityUtil) {
|
||||
@@ -205,7 +205,7 @@ final class UpdatableFontDir {
|
||||
*/
|
||||
public void update(List<FontUpdateRequest> requests) throws SystemFontException {
|
||||
// Backup the mapping for rollback.
|
||||
HashMap<String, FontFileInfo> backupMap = new HashMap<>(mFontFileInfoMap);
|
||||
ArrayMap<String, FontFileInfo> backupMap = new ArrayMap<>(mFontFileInfoMap);
|
||||
long backupLastModifiedDate = mLastModifiedDate;
|
||||
boolean success = false;
|
||||
try {
|
||||
@@ -464,7 +464,7 @@ final class UpdatableFontDir {
|
||||
}
|
||||
|
||||
Map<String, File> getFontFileMap() {
|
||||
Map<String, File> map = new HashMap<>();
|
||||
Map<String, File> map = new ArrayMap<>();
|
||||
for (Map.Entry<String, FontFileInfo> entry : mFontFileInfoMap.entrySet()) {
|
||||
map.put(entry.getKey(), entry.getValue().getFile());
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user