Merge "Release AssetManagers when ejecting storage." into nyc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
380f3b12a4
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -35,17 +37,18 @@ import java.util.WeakHashMap;
|
||||
*/
|
||||
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;
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -74,13 +83,27 @@ public final class AttributeCache {
|
||||
public AttributeCache(Context context) {
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void updateConfiguration(Configuration config) {
|
||||
synchronized (this) {
|
||||
int changes = mConfiguration.updateFrom(config);
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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();
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user