Loading core/java/android/app/ResourcesManager.java +25 −3 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.content.res.ResourcesImpl; import android.content.res.ResourcesKey; import android.hardware.display.DisplayManagerGlobal; import android.os.IBinder; import android.os.LocaleList; import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; Loading @@ -38,13 +37,12 @@ import android.util.Pair; import android.util.Slog; import android.view.Display; import android.view.DisplayAdjustments; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Objects; import java.util.WeakHashMap; import java.util.function.Predicate; Loading Loading @@ -120,6 +118,30 @@ public class ResourcesManager { } } /** * Invalidate and destroy any resources that reference content under the * given filesystem path. Typically used when unmounting a storage device to * try as hard as possible to release any open FDs. */ public void invalidatePath(String path) { synchronized (this) { int count = 0; for (int i = 0; i < mResourceImpls.size();) { final ResourcesKey key = mResourceImpls.keyAt(i); if (key.isPathReferenced(path)) { final ResourcesImpl res = mResourceImpls.removeAt(i).get(); if (res != null) { res.flushLayoutCache(); } count++; } else { i++; } } Log.i(TAG, "Invalidated " + count + " asset managers that referenced " + path); } } public Configuration getConfiguration() { synchronized (this) { return mResConfiguration; Loading core/java/android/content/res/ResourcesKey.java +20 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,26 @@ public final class ResourcesKey { return !Configuration.EMPTY.equals(mOverrideConfiguration); } public boolean isPathReferenced(String path) { if (mResDir != null && mResDir.startsWith(path)) { return true; } else { return anyStartsWith(mSplitResDirs, path) || anyStartsWith(mOverlayDirs, path) || anyStartsWith(mLibDirs, path); } } private static boolean anyStartsWith(String[] list, String prefix) { if (list != null) { for (String s : list) { if (s != null && s.startsWith(prefix)) { return true; } } } return false; } @Override public int hashCode() { return mHash; Loading services/core/java/com/android/server/AttributeCache.java +40 −16 Original line number Diff line number Diff line Loading @@ -24,10 +24,12 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.UserHandle; import android.util.ArrayMap; import android.util.SparseArray; import java.util.HashMap; import java.util.WeakHashMap; import com.android.internal.annotations.GuardedBy; import java.lang.ref.WeakReference; /** * TODO: This should be better integrated into the system so it doesn't need Loading @@ -37,14 +39,15 @@ public final class AttributeCache { private static AttributeCache sInstance = null; private final Context mContext; private final WeakHashMap<String, Package> mPackages = new WeakHashMap<String, Package>(); @GuardedBy("this") private final ArrayMap<String, WeakReference<Package>> mPackages = new ArrayMap<>(); @GuardedBy("this") private final Configuration mConfiguration = new Configuration(); public final static class Package { public final Context context; private final SparseArray<HashMap<int[], Entry>> mMap = new SparseArray<HashMap<int[], Entry>>(); private final SparseArray<ArrayMap<int[], Entry>> mMap = new SparseArray<>(); public Package(Context c) { context = c; Loading @@ -59,6 +62,12 @@ public final class AttributeCache { context = c; array = ta; } void recycle() { if (array != null) { array.recycle(); } } } public static void init(Context context) { Loading @@ -77,7 +86,21 @@ public final class AttributeCache { public void removePackage(String packageName) { synchronized (this) { mPackages.remove(packageName); final WeakReference<Package> ref = mPackages.remove(packageName); final Package pkg = (ref != null) ? ref.get() : null; if (pkg != null) { if (pkg.mMap != null) { for (int i = 0; i < pkg.mMap.size(); i++) { final ArrayMap<int[], Entry> map = pkg.mMap.valueAt(i); for (int j = 0; j < map.size(); j++) { map.valueAt(j).recycle(); } } } final Resources res = pkg.context.getResources(); res.flushLayoutCache(); } } } Loading @@ -97,8 +120,9 @@ public final class AttributeCache { public Entry get(String packageName, int resId, int[] styleable, int userId) { synchronized (this) { Package pkg = mPackages.get(packageName); HashMap<int[], Entry> map = null; WeakReference<Package> ref = mPackages.get(packageName); Package pkg = (ref != null) ? ref.get() : null; ArrayMap<int[], Entry> map = null; Entry ent = null; if (pkg != null) { map = pkg.mMap.get(resId); Loading @@ -120,11 +144,11 @@ public final class AttributeCache { return null; } pkg = new Package(context); mPackages.put(packageName, pkg); mPackages.put(packageName, new WeakReference<>(pkg)); } if (map == null) { map = new HashMap<int[], Entry>(); map = new ArrayMap<>(); pkg.mMap.put(resId, map); } Loading services/core/java/com/android/server/pm/PackageManagerService.java +16 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.ResourcesManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.IDevicePolicyManager; import android.app.admin.SecurityLog; Loading Loading @@ -238,6 +239,7 @@ import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.AttributeCache; import com.android.server.EventLogTags; import com.android.server.FgThread; import com.android.server.IntentResolver; Loading Loading @@ -19133,6 +19135,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); Slog.w(TAG, "Failed to unload " + ps.codePath); } } // Try very hard to release any references to this package // so we don't risk the system server being killed due to // open FDs AttributeCache.instance().removePackage(ps.name); } mSettings.writeLPr(); Loading @@ -19141,6 +19148,15 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); sendResourcesChangedBroadcast(false, false, unloaded, null); // Try very hard to release any references to this path so we don't risk // the system server being killed due to open FDs ResourcesManager.getInstance().invalidatePath(vol.getPath().getAbsolutePath()); for (int i = 0; i < 3; i++) { System.gc(); System.runFinalization(); } } /** Loading
core/java/android/app/ResourcesManager.java +25 −3 Original line number Diff line number Diff line Loading @@ -29,7 +29,6 @@ import android.content.res.ResourcesImpl; import android.content.res.ResourcesKey; import android.hardware.display.DisplayManagerGlobal; import android.os.IBinder; import android.os.LocaleList; import android.os.Trace; import android.util.ArrayMap; import android.util.DisplayMetrics; Loading @@ -38,13 +37,12 @@ import android.util.Pair; import android.util.Slog; import android.view.Display; import android.view.DisplayAdjustments; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.util.ArrayUtils; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.Objects; import java.util.WeakHashMap; import java.util.function.Predicate; Loading Loading @@ -120,6 +118,30 @@ public class ResourcesManager { } } /** * Invalidate and destroy any resources that reference content under the * given filesystem path. Typically used when unmounting a storage device to * try as hard as possible to release any open FDs. */ public void invalidatePath(String path) { synchronized (this) { int count = 0; for (int i = 0; i < mResourceImpls.size();) { final ResourcesKey key = mResourceImpls.keyAt(i); if (key.isPathReferenced(path)) { final ResourcesImpl res = mResourceImpls.removeAt(i).get(); if (res != null) { res.flushLayoutCache(); } count++; } else { i++; } } Log.i(TAG, "Invalidated " + count + " asset managers that referenced " + path); } } public Configuration getConfiguration() { synchronized (this) { return mResConfiguration; Loading
core/java/android/content/res/ResourcesKey.java +20 −0 Original line number Diff line number Diff line Loading @@ -77,6 +77,26 @@ public final class ResourcesKey { return !Configuration.EMPTY.equals(mOverrideConfiguration); } public boolean isPathReferenced(String path) { if (mResDir != null && mResDir.startsWith(path)) { return true; } else { return anyStartsWith(mSplitResDirs, path) || anyStartsWith(mOverlayDirs, path) || anyStartsWith(mLibDirs, path); } } private static boolean anyStartsWith(String[] list, String prefix) { if (list != null) { for (String s : list) { if (s != null && s.startsWith(prefix)) { return true; } } } return false; } @Override public int hashCode() { return mHash; Loading
services/core/java/com/android/server/AttributeCache.java +40 −16 Original line number Diff line number Diff line Loading @@ -24,10 +24,12 @@ import android.content.res.Configuration; import android.content.res.Resources; import android.content.res.TypedArray; import android.os.UserHandle; import android.util.ArrayMap; import android.util.SparseArray; import java.util.HashMap; import java.util.WeakHashMap; import com.android.internal.annotations.GuardedBy; import java.lang.ref.WeakReference; /** * TODO: This should be better integrated into the system so it doesn't need Loading @@ -37,14 +39,15 @@ public final class AttributeCache { private static AttributeCache sInstance = null; private final Context mContext; private final WeakHashMap<String, Package> mPackages = new WeakHashMap<String, Package>(); @GuardedBy("this") private final ArrayMap<String, WeakReference<Package>> mPackages = new ArrayMap<>(); @GuardedBy("this") private final Configuration mConfiguration = new Configuration(); public final static class Package { public final Context context; private final SparseArray<HashMap<int[], Entry>> mMap = new SparseArray<HashMap<int[], Entry>>(); private final SparseArray<ArrayMap<int[], Entry>> mMap = new SparseArray<>(); public Package(Context c) { context = c; Loading @@ -59,6 +62,12 @@ public final class AttributeCache { context = c; array = ta; } void recycle() { if (array != null) { array.recycle(); } } } public static void init(Context context) { Loading @@ -77,7 +86,21 @@ public final class AttributeCache { public void removePackage(String packageName) { synchronized (this) { mPackages.remove(packageName); final WeakReference<Package> ref = mPackages.remove(packageName); final Package pkg = (ref != null) ? ref.get() : null; if (pkg != null) { if (pkg.mMap != null) { for (int i = 0; i < pkg.mMap.size(); i++) { final ArrayMap<int[], Entry> map = pkg.mMap.valueAt(i); for (int j = 0; j < map.size(); j++) { map.valueAt(j).recycle(); } } } final Resources res = pkg.context.getResources(); res.flushLayoutCache(); } } } Loading @@ -97,8 +120,9 @@ public final class AttributeCache { public Entry get(String packageName, int resId, int[] styleable, int userId) { synchronized (this) { Package pkg = mPackages.get(packageName); HashMap<int[], Entry> map = null; WeakReference<Package> ref = mPackages.get(packageName); Package pkg = (ref != null) ? ref.get() : null; ArrayMap<int[], Entry> map = null; Entry ent = null; if (pkg != null) { map = pkg.mMap.get(resId); Loading @@ -120,11 +144,11 @@ public final class AttributeCache { return null; } pkg = new Package(context); mPackages.put(packageName, pkg); mPackages.put(packageName, new WeakReference<>(pkg)); } if (map == null) { map = new HashMap<int[], Entry>(); map = new ArrayMap<>(); pkg.mMap.put(resId, map); } Loading
services/core/java/com/android/server/pm/PackageManagerService.java +16 −0 Original line number Diff line number Diff line Loading @@ -105,6 +105,7 @@ import android.annotation.Nullable; import android.app.ActivityManager; import android.app.ActivityManagerNative; import android.app.IActivityManager; import android.app.ResourcesManager; import android.app.admin.DevicePolicyManagerInternal; import android.app.admin.IDevicePolicyManager; import android.app.admin.SecurityLog; Loading Loading @@ -238,6 +239,7 @@ import com.android.internal.util.FastXmlSerializer; import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.Preconditions; import com.android.internal.util.XmlUtils; import com.android.server.AttributeCache; import com.android.server.EventLogTags; import com.android.server.FgThread; import com.android.server.IntentResolver; Loading Loading @@ -19133,6 +19135,11 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); Slog.w(TAG, "Failed to unload " + ps.codePath); } } // Try very hard to release any references to this package // so we don't risk the system server being killed due to // open FDs AttributeCache.instance().removePackage(ps.name); } mSettings.writeLPr(); Loading @@ -19141,6 +19148,15 @@ Slog.v(TAG, ":: stepped forward, applying functor at tag " + parser.getName()); if (DEBUG_INSTALL) Slog.d(TAG, "Unloaded packages " + unloaded); sendResourcesChangedBroadcast(false, false, unloaded, null); // Try very hard to release any references to this path so we don't risk // the system server being killed due to open FDs ResourcesManager.getInstance().invalidatePath(vol.getPath().getAbsolutePath()); for (int i = 0; i < 3; i++) { System.gc(); System.runFinalization(); } } /**