Merge "Release AssetManagers when ejecting storage." into nyc-dev

This commit is contained in:
TreeHugger Robot
2016-06-01 22:14:56 +00:00
committed by Android (Google) Code Review
4 changed files with 101 additions and 19 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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);
}

View File

@@ -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();
}
}
/**