Merge "Fix RootsCache invalidation bugs." into nyc-dev

This commit is contained in:
Jeff Sharkey
2016-03-31 00:27:20 +00:00
committed by Android (Google) Code Review
4 changed files with 37 additions and 47 deletions

View File

@@ -16,7 +16,7 @@
package android.util; package android.util;
import libcore.util.Objects; import java.util.Objects;
/** /**
* Container to ease passing around a tuple of two objects. This object provides a sensible * Container to ease passing around a tuple of two objects. This object provides a sensible
@@ -52,7 +52,7 @@ public class Pair<F, S> {
return false; return false;
} }
Pair<?, ?> p = (Pair<?, ?>) o; Pair<?, ?> p = (Pair<?, ?>) o;
return Objects.equal(p.first, first) && Objects.equal(p.second, second); return Objects.equals(p.first, first) && Objects.equals(p.second, second);
} }
/** /**
@@ -65,6 +65,11 @@ public class Pair<F, S> {
return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode()); return (first == null ? 0 : first.hashCode()) ^ (second == null ? 0 : second.hashCode());
} }
@Override
public String toString() {
return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
}
/** /**
* Convenience method for creating an appropriately typed pair. * Convenience method for creating an appropriately typed pair.
* @param a the first object in the Pair * @param a the first object in the Pair

View File

@@ -65,8 +65,6 @@ public class RootsCache {
private static final String TAG = "RootsCache"; private static final String TAG = "RootsCache";
private static final boolean ENABLE_SYSTEM_CACHE = true;
private final Context mContext; private final Context mContext;
private final ContentObserver mObserver; private final ContentObserver mObserver;
private OnCacheUpdateListener mCacheUpdateListener; private OnCacheUpdateListener mCacheUpdateListener;
@@ -200,7 +198,7 @@ public class RootsCache {
synchronized (mLock) { synchronized (mLock) {
for (String authority : mStoppedAuthorities) { for (String authority : mStoppedAuthorities) {
if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority); if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority);
mRoots.putAll(authority, loadRootsForAuthority(resolver, authority)); mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
} }
mStoppedAuthorities.clear(); mStoppedAuthorities.clear();
} }
@@ -219,13 +217,13 @@ public class RootsCache {
if (DEBUG) { if (DEBUG) {
Log.d(TAG, "Loading stopped authority " + authority); Log.d(TAG, "Loading stopped authority " + authority);
} }
mRoots.putAll(authority, loadRootsForAuthority(resolver, authority)); mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
mStoppedAuthorities.remove(authority); mStoppedAuthorities.remove(authority);
} }
} }
private class UpdateTask extends AsyncTask<Void, Void, Void> { private class UpdateTask extends AsyncTask<Void, Void, Void> {
private final String mFilterPackage; private final String mForceRefreshPackage;
private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create(); private final Multimap<String, RootInfo> mTaskRoots = ArrayListMultimap.create();
private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>(); private final HashSet<String> mTaskStoppedAuthorities = new HashSet<>();
@@ -238,18 +236,18 @@ public class RootsCache {
} }
/** /**
* Only update roots belonging to given package name. Other roots will * Force update roots belonging to given package name. Other roots will
* be copied from cached {@link #mRoots} values. * be copied from cached {@link #mRoots} values.
*/ */
public UpdateTask(String filterPackage) { public UpdateTask(String forceRefreshPackage) {
mFilterPackage = filterPackage; mForceRefreshPackage = forceRefreshPackage;
} }
@Override @Override
protected Void doInBackground(Void... params) { protected Void doInBackground(Void... params) {
final long start = SystemClock.elapsedRealtime(); final long start = SystemClock.elapsedRealtime();
if (mFilterPackage != null) { if (mForceRefreshPackage != null) {
// We must have previously cached values to fill in non-matching // We must have previously cached values to fill in non-matching
// packages, so wait around for successful first load. // packages, so wait around for successful first load.
if (!waitForFirstLoad()) { if (!waitForFirstLoad()) {
@@ -302,29 +300,17 @@ public class RootsCache {
return; return;
} }
// Try using cached roots if filtering final boolean forceRefresh = Objects.equals(mForceRefreshPackage, info.packageName);
boolean cacheHit = false; mTaskRoots.putAll(info.authority, loadRootsForAuthority(mContext.getContentResolver(),
if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) { info.authority, forceRefresh));
synchronized (mLock) {
if (mTaskRoots.putAll(info.authority, mRoots.get(info.authority))) {
if (DEBUG) Log.d(TAG, "Used cached roots for " + info.authority);
cacheHit = true;
}
}
}
// Cache miss, or loading everything
if (!cacheHit) {
mTaskRoots.putAll(info.authority,
loadRootsForAuthority(mContext.getContentResolver(), info.authority));
}
} }
} }
/** /**
* Bring up requested provider and query for all active roots. * Bring up requested provider and query for all active roots.
*/ */
private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority) { private Collection<RootInfo> loadRootsForAuthority(ContentResolver resolver, String authority,
boolean forceRefresh) {
if (DEBUG) Log.d(TAG, "Loading roots for " + authority); if (DEBUG) Log.d(TAG, "Loading roots for " + authority);
synchronized (mObservedAuthorities) { synchronized (mObservedAuthorities) {
@@ -336,7 +322,7 @@ public class RootsCache {
} }
final Uri rootsUri = DocumentsContract.buildRootsUri(authority); final Uri rootsUri = DocumentsContract.buildRootsUri(authority);
if (ENABLE_SYSTEM_CACHE) { if (!forceRefresh) {
// Look for roots data that we might have cached for ourselves in the // Look for roots data that we might have cached for ourselves in the
// long-lived system process. // long-lived system process.
final Bundle systemCache = resolver.getCache(rootsUri); final Bundle systemCache = resolver.getCache(rootsUri);
@@ -363,14 +349,12 @@ public class RootsCache {
ContentProviderClient.releaseQuietly(client); ContentProviderClient.releaseQuietly(client);
} }
if (ENABLE_SYSTEM_CACHE) { // Cache these freshly parsed roots over in the long-lived system
// Cache these freshly parsed roots over in the long-lived system // process, in case our process goes away. The system takes care of
// process, in case our process goes away. The system takes care of // invalidating the cache if the package or Uri changes.
// invalidating the cache if the package or Uri changes. final Bundle systemCache = new Bundle();
final Bundle systemCache = new Bundle(); systemCache.putParcelableArrayList(TAG, roots);
systemCache.putParcelableArrayList(TAG, roots); resolver.putCache(rootsUri, systemCache);
resolver.putCache(rootsUri, systemCache);
}
return roots; return roots;
} }
@@ -384,8 +368,8 @@ public class RootsCache {
synchronized (mLock) { synchronized (mLock) {
RootInfo root = getRootLocked(authority, rootId); RootInfo root = getRootLocked(authority, rootId);
if (root == null) { if (root == null) {
mRoots.putAll( mRoots.putAll(authority,
authority, loadRootsForAuthority(mContext.getContentResolver(), authority)); loadRootsForAuthority(mContext.getContentResolver(), authority, false));
root = getRootLocked(authority, rootId); root = getRootLocked(authority, rootId);
} }
return root; return root;

View File

@@ -1231,7 +1231,8 @@ class MountService extends IMountService.Stub
} }
final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED); final Intent intent = new Intent(DiskInfo.ACTION_DISK_SCANNED);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id); intent.putExtra(DiskInfo.EXTRA_DISK_ID, disk.id);
intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount); intent.putExtra(DiskInfo.EXTRA_VOLUME_COUNT, volumeCount);
mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget(); mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
@@ -1347,7 +1348,8 @@ class MountService extends IMountService.Stub
intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id); intent.putExtra(VolumeInfo.EXTRA_VOLUME_ID, vol.id);
intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState); intent.putExtra(VolumeInfo.EXTRA_VOLUME_STATE, newState);
intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid); intent.putExtra(VolumeRecord.EXTRA_FS_UUID, vol.fsUuid);
intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT); intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT
| Intent.FLAG_RECEIVER_INCLUDE_BACKGROUND);
mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget(); mHandler.obtainMessage(H_INTERNAL_BROADCAST, intent).sendToTarget();
} }

View File

@@ -26,9 +26,9 @@ import android.content.ComponentName;
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.content.IContentService; import android.content.IContentService;
import android.content.ISyncStatusObserver;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.ISyncStatusObserver;
import android.content.PeriodicSync; import android.content.PeriodicSync;
import android.content.SyncAdapterType; import android.content.SyncAdapterType;
import android.content.SyncInfo; import android.content.SyncInfo;
@@ -58,18 +58,15 @@ import android.util.SparseIntArray;
import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.IndentingPrintWriter; import com.android.internal.util.IndentingPrintWriter;
import com.android.internal.util.Preconditions;
import com.android.server.LocalServices; import com.android.server.LocalServices;
import java.io.FileDescriptor; import java.io.FileDescriptor;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.security.InvalidParameterException; import java.security.InvalidParameterException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Objects;
/** /**
* {@hide} * {@hide}
@@ -1030,14 +1027,16 @@ public final class ContentService extends IContentService.Stub {
if (uri != null) { if (uri != null) {
for (int i = 0; i < packageCache.size();) { for (int i = 0; i < packageCache.size();) {
final Uri key = packageCache.keyAt(i).second; final Pair<String, Uri> key = packageCache.keyAt(i);
if (Objects.equals(key, uri)) { if (key.second != null && key.second.toString().startsWith(uri.toString())) {
Slog.d(TAG, "Invalidating cache for key " + key);
packageCache.removeAt(i); packageCache.removeAt(i);
} else { } else {
i++; i++;
} }
} }
} else { } else {
Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
packageCache.clear(); packageCache.clear();
} }
} }