Merge "Fix RootsCache invalidation bugs." into nyc-dev
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
|
||||
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
|
||||
@@ -52,7 +52,7 @@ public class Pair<F, S> {
|
||||
return false;
|
||||
}
|
||||
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());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Pair{" + String.valueOf(first) + " " + String.valueOf(second) + "}";
|
||||
}
|
||||
|
||||
/**
|
||||
* Convenience method for creating an appropriately typed pair.
|
||||
* @param a the first object in the Pair
|
||||
|
||||
@@ -65,8 +65,6 @@ public class RootsCache {
|
||||
|
||||
private static final String TAG = "RootsCache";
|
||||
|
||||
private static final boolean ENABLE_SYSTEM_CACHE = true;
|
||||
|
||||
private final Context mContext;
|
||||
private final ContentObserver mObserver;
|
||||
private OnCacheUpdateListener mCacheUpdateListener;
|
||||
@@ -200,7 +198,7 @@ public class RootsCache {
|
||||
synchronized (mLock) {
|
||||
for (String authority : mStoppedAuthorities) {
|
||||
if (DEBUG) Log.d(TAG, "Loading stopped authority " + authority);
|
||||
mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
|
||||
mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
|
||||
}
|
||||
mStoppedAuthorities.clear();
|
||||
}
|
||||
@@ -219,13 +217,13 @@ public class RootsCache {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Loading stopped authority " + authority);
|
||||
}
|
||||
mRoots.putAll(authority, loadRootsForAuthority(resolver, authority));
|
||||
mRoots.putAll(authority, loadRootsForAuthority(resolver, authority, true));
|
||||
mStoppedAuthorities.remove(authority);
|
||||
}
|
||||
}
|
||||
|
||||
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 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.
|
||||
*/
|
||||
public UpdateTask(String filterPackage) {
|
||||
mFilterPackage = filterPackage;
|
||||
public UpdateTask(String forceRefreshPackage) {
|
||||
mForceRefreshPackage = forceRefreshPackage;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Void doInBackground(Void... params) {
|
||||
final long start = SystemClock.elapsedRealtime();
|
||||
|
||||
if (mFilterPackage != null) {
|
||||
if (mForceRefreshPackage != null) {
|
||||
// We must have previously cached values to fill in non-matching
|
||||
// packages, so wait around for successful first load.
|
||||
if (!waitForFirstLoad()) {
|
||||
@@ -302,29 +300,17 @@ public class RootsCache {
|
||||
return;
|
||||
}
|
||||
|
||||
// Try using cached roots if filtering
|
||||
boolean cacheHit = false;
|
||||
if (mFilterPackage != null && !mFilterPackage.equals(info.packageName)) {
|
||||
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));
|
||||
}
|
||||
final boolean forceRefresh = Objects.equals(mForceRefreshPackage, info.packageName);
|
||||
mTaskRoots.putAll(info.authority, loadRootsForAuthority(mContext.getContentResolver(),
|
||||
info.authority, forceRefresh));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
synchronized (mObservedAuthorities) {
|
||||
@@ -336,7 +322,7 @@ public class RootsCache {
|
||||
}
|
||||
|
||||
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
|
||||
// long-lived system process.
|
||||
final Bundle systemCache = resolver.getCache(rootsUri);
|
||||
@@ -363,14 +349,12 @@ public class RootsCache {
|
||||
ContentProviderClient.releaseQuietly(client);
|
||||
}
|
||||
|
||||
if (ENABLE_SYSTEM_CACHE) {
|
||||
// Cache these freshly parsed roots over in the long-lived system
|
||||
// process, in case our process goes away. The system takes care of
|
||||
// invalidating the cache if the package or Uri changes.
|
||||
final Bundle systemCache = new Bundle();
|
||||
systemCache.putParcelableArrayList(TAG, roots);
|
||||
resolver.putCache(rootsUri, systemCache);
|
||||
}
|
||||
// Cache these freshly parsed roots over in the long-lived system
|
||||
// process, in case our process goes away. The system takes care of
|
||||
// invalidating the cache if the package or Uri changes.
|
||||
final Bundle systemCache = new Bundle();
|
||||
systemCache.putParcelableArrayList(TAG, roots);
|
||||
resolver.putCache(rootsUri, systemCache);
|
||||
|
||||
return roots;
|
||||
}
|
||||
@@ -384,8 +368,8 @@ public class RootsCache {
|
||||
synchronized (mLock) {
|
||||
RootInfo root = getRootLocked(authority, rootId);
|
||||
if (root == null) {
|
||||
mRoots.putAll(
|
||||
authority, loadRootsForAuthority(mContext.getContentResolver(), authority));
|
||||
mRoots.putAll(authority,
|
||||
loadRootsForAuthority(mContext.getContentResolver(), authority, false));
|
||||
root = getRootLocked(authority, rootId);
|
||||
}
|
||||
return root;
|
||||
|
||||
@@ -1231,7 +1231,8 @@ class MountService extends IMountService.Stub
|
||||
}
|
||||
|
||||
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_VOLUME_COUNT, volumeCount);
|
||||
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_STATE, newState);
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
@@ -26,9 +26,9 @@ import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.IContentService;
|
||||
import android.content.ISyncStatusObserver;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.ISyncStatusObserver;
|
||||
import android.content.PeriodicSync;
|
||||
import android.content.SyncAdapterType;
|
||||
import android.content.SyncInfo;
|
||||
@@ -58,18 +58,15 @@ import android.util.SparseIntArray;
|
||||
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.util.IndentingPrintWriter;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.server.LocalServices;
|
||||
|
||||
import java.io.FileDescriptor;
|
||||
import java.io.PrintWriter;
|
||||
import java.security.InvalidParameterException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* {@hide}
|
||||
@@ -1030,14 +1027,16 @@ public final class ContentService extends IContentService.Stub {
|
||||
|
||||
if (uri != null) {
|
||||
for (int i = 0; i < packageCache.size();) {
|
||||
final Uri key = packageCache.keyAt(i).second;
|
||||
if (Objects.equals(key, uri)) {
|
||||
final Pair<String, Uri> key = packageCache.keyAt(i);
|
||||
if (key.second != null && key.second.toString().startsWith(uri.toString())) {
|
||||
Slog.d(TAG, "Invalidating cache for key " + key);
|
||||
packageCache.removeAt(i);
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Slog.d(TAG, "Invalidating cache for package " + providerPackageName);
|
||||
packageCache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user