Merge "Add infrastructure for accessing "unstable" content providers." into jb-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
dd79ae6b72
@ -5118,6 +5118,8 @@ package android.content {
|
||||
ctor public ContentResolver(android.content.Context);
|
||||
method public final android.content.ContentProviderClient acquireContentProviderClient(android.net.Uri);
|
||||
method public final android.content.ContentProviderClient acquireContentProviderClient(java.lang.String);
|
||||
method public final android.content.ContentProviderClient acquireUnstableContentProviderClient(android.net.Uri);
|
||||
method public final android.content.ContentProviderClient acquireUnstableContentProviderClient(java.lang.String);
|
||||
method public static void addPeriodicSync(android.accounts.Account, java.lang.String, android.os.Bundle, long);
|
||||
method public static java.lang.Object addStatusChangeListener(int, android.content.SyncStatusObserver);
|
||||
method public android.content.ContentProviderResult[] applyBatch(java.lang.String, java.util.ArrayList<android.content.ContentProviderOperation>) throws android.content.OperationApplicationException, android.os.RemoteException;
|
||||
|
@ -4278,6 +4278,14 @@ public final class ActivityThread {
|
||||
}
|
||||
}
|
||||
|
||||
public final IContentProvider acquireUnstableProvider(Context c, String name) {
|
||||
return acquireProvider(c, name);
|
||||
}
|
||||
|
||||
public final boolean releaseUnstableProvider(IContentProvider provider) {
|
||||
return releaseProvider(provider);
|
||||
}
|
||||
|
||||
final void completeRemoveProvider(IContentProvider provider) {
|
||||
IBinder jBinder = provider.asBinder();
|
||||
String remoteProviderName = null;
|
||||
|
@ -1692,6 +1692,16 @@ class ContextImpl extends Context {
|
||||
return mMainThread.releaseProvider(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IContentProvider acquireUnstableProvider(Context c, String name) {
|
||||
return mMainThread.acquireUnstableProvider(c, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean releaseUnstableProvider(IContentProvider icp) {
|
||||
return mMainThread.releaseUnstableProvider(icp);
|
||||
}
|
||||
|
||||
private final ActivityThread mMainThread;
|
||||
}
|
||||
}
|
||||
|
@ -37,13 +37,16 @@ import java.util.ArrayList;
|
||||
public class ContentProviderClient {
|
||||
private final IContentProvider mContentProvider;
|
||||
private final ContentResolver mContentResolver;
|
||||
private final boolean mStable;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
ContentProviderClient(ContentResolver contentResolver, IContentProvider contentProvider) {
|
||||
ContentProviderClient(ContentResolver contentResolver,
|
||||
IContentProvider contentProvider, boolean stable) {
|
||||
mContentProvider = contentProvider;
|
||||
mContentResolver = contentResolver;
|
||||
mStable = stable;
|
||||
}
|
||||
|
||||
/** See {@link ContentProvider#query ContentProvider.query} */
|
||||
@ -141,7 +144,11 @@ public class ContentProviderClient {
|
||||
* @return true if this was release, false if it was already released
|
||||
*/
|
||||
public boolean release() {
|
||||
return mContentResolver.releaseProvider(mContentProvider);
|
||||
if (mStable) {
|
||||
return mContentResolver.releaseProvider(mContentProvider);
|
||||
} else {
|
||||
return mContentResolver.releaseUnstableProvider(mContentProvider);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -198,6 +198,10 @@ public abstract class ContentResolver {
|
||||
}
|
||||
/** @hide */
|
||||
public abstract boolean releaseProvider(IContentProvider icp);
|
||||
/** @hide */
|
||||
protected abstract IContentProvider acquireUnstableProvider(Context c, String name);
|
||||
/** @hide */
|
||||
public abstract boolean releaseUnstableProvider(IContentProvider icp);
|
||||
|
||||
/**
|
||||
* Return the MIME type of the given content URL.
|
||||
@ -588,34 +592,48 @@ public abstract class ContentResolver {
|
||||
if ("r".equals(mode)) {
|
||||
return openTypedAssetFileDescriptor(uri, "*/*", null);
|
||||
} else {
|
||||
IContentProvider provider = acquireProvider(uri);
|
||||
if (provider == null) {
|
||||
throw new FileNotFoundException("No content provider: " + uri);
|
||||
}
|
||||
try {
|
||||
AssetFileDescriptor fd = provider.openAssetFile(uri, mode);
|
||||
if(fd == null) {
|
||||
// The provider will be released by the finally{} clause
|
||||
return null;
|
||||
int n = 0;
|
||||
while (true) {
|
||||
n++;
|
||||
IContentProvider provider = acquireUnstableProvider(uri);
|
||||
if (provider == null) {
|
||||
throw new FileNotFoundException("No content provider: " + uri);
|
||||
}
|
||||
ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
|
||||
fd.getParcelFileDescriptor(), provider);
|
||||
try {
|
||||
AssetFileDescriptor fd = provider.openAssetFile(uri, mode);
|
||||
if (fd == null) {
|
||||
// The provider will be released by the finally{} clause
|
||||
return null;
|
||||
}
|
||||
ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
|
||||
fd.getParcelFileDescriptor(), provider);
|
||||
|
||||
// Success! Don't release the provider when exiting, let
|
||||
// ParcelFileDescriptorInner do that when it is closed.
|
||||
provider = null;
|
||||
// Success! Don't release the provider when exiting, let
|
||||
// ParcelFileDescriptorInner do that when it is closed.
|
||||
provider = null;
|
||||
|
||||
return new AssetFileDescriptor(pfd, fd.getStartOffset(),
|
||||
fd.getDeclaredLength());
|
||||
} catch (RemoteException e) {
|
||||
// Somewhat pointless, as Activity Manager will kill this
|
||||
// process shortly anyway if the depdendent ContentProvider dies.
|
||||
throw new FileNotFoundException("Dead content provider: " + uri);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
if (provider != null) {
|
||||
releaseProvider(provider);
|
||||
return new AssetFileDescriptor(pfd, fd.getStartOffset(),
|
||||
fd.getDeclaredLength());
|
||||
} catch (RemoteException e) {
|
||||
// The provider died for some reason. Since we are
|
||||
// acquiring it unstable, its process could have gotten
|
||||
// killed and need to be restarted. We'll retry a couple
|
||||
// times and if still can't succeed then fail.
|
||||
if (n <= 2) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e1) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Whatever, whatever, we'll go away.
|
||||
throw new FileNotFoundException("Dead content provider: " + uri);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
if (provider != null) {
|
||||
releaseUnstableProvider(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -652,32 +670,48 @@ public abstract class ContentResolver {
|
||||
*/
|
||||
public final AssetFileDescriptor openTypedAssetFileDescriptor(Uri uri,
|
||||
String mimeType, Bundle opts) throws FileNotFoundException {
|
||||
IContentProvider provider = acquireProvider(uri);
|
||||
if (provider == null) {
|
||||
throw new FileNotFoundException("No content provider: " + uri);
|
||||
}
|
||||
try {
|
||||
AssetFileDescriptor fd = provider.openTypedAssetFile(uri, mimeType, opts);
|
||||
if (fd == null) {
|
||||
// The provider will be released by the finally{} clause
|
||||
return null;
|
||||
int n = 0;
|
||||
while (true) {
|
||||
n++;
|
||||
IContentProvider provider = acquireUnstableProvider(uri);
|
||||
if (provider == null) {
|
||||
throw new FileNotFoundException("No content provider: " + uri);
|
||||
}
|
||||
ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
|
||||
fd.getParcelFileDescriptor(), provider);
|
||||
try {
|
||||
AssetFileDescriptor fd = provider.openTypedAssetFile(uri, mimeType, opts);
|
||||
if (fd == null) {
|
||||
// The provider will be released by the finally{} clause
|
||||
return null;
|
||||
}
|
||||
ParcelFileDescriptor pfd = new ParcelFileDescriptorInner(
|
||||
fd.getParcelFileDescriptor(), provider);
|
||||
|
||||
// Success! Don't release the provider when exiting, let
|
||||
// ParcelFileDescriptorInner do that when it is closed.
|
||||
provider = null;
|
||||
// Success! Don't release the provider when exiting, let
|
||||
// ParcelFileDescriptorInner do that when it is closed.
|
||||
provider = null;
|
||||
|
||||
return new AssetFileDescriptor(pfd, fd.getStartOffset(),
|
||||
fd.getDeclaredLength());
|
||||
} catch (RemoteException e) {
|
||||
throw new FileNotFoundException("Dead content provider: " + uri);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
if (provider != null) {
|
||||
releaseProvider(provider);
|
||||
return new AssetFileDescriptor(pfd, fd.getStartOffset(),
|
||||
fd.getDeclaredLength());
|
||||
} catch (RemoteException e) {
|
||||
// The provider died for some reason. Since we are
|
||||
// acquiring it unstable, its process could have gotten
|
||||
// killed and need to be restarted. We'll retry a couple
|
||||
// times and if still can't succeed then fail.
|
||||
if (n <= 2) {
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e1) {
|
||||
}
|
||||
continue;
|
||||
}
|
||||
// Whatever, whatever, we'll go away.
|
||||
throw new FileNotFoundException("Dead content provider: " + uri);
|
||||
} catch (FileNotFoundException e) {
|
||||
throw e;
|
||||
} finally {
|
||||
if (provider != null) {
|
||||
releaseUnstableProvider(provider);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1002,6 +1036,34 @@ public abstract class ContentResolver {
|
||||
return acquireProvider(mContext, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the content provider for the given content URI.
|
||||
*
|
||||
* @param uri The URI to a content provider
|
||||
* @return The ContentProvider for the given URI, or null if no content provider is found.
|
||||
* @hide
|
||||
*/
|
||||
public final IContentProvider acquireUnstableProvider(Uri uri) {
|
||||
if (!SCHEME_CONTENT.equals(uri.getScheme())) {
|
||||
return null;
|
||||
}
|
||||
String auth = uri.getAuthority();
|
||||
if (auth != null) {
|
||||
return acquireUnstableProvider(mContext, uri.getAuthority());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final IContentProvider acquireUnstableProvider(String name) {
|
||||
if (name == null) {
|
||||
return null;
|
||||
}
|
||||
return acquireProvider(mContext, name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a {@link ContentProviderClient} that is associated with the {@link ContentProvider}
|
||||
* that services the content at uri, starting the provider if necessary. Returns
|
||||
@ -1016,7 +1078,7 @@ public abstract class ContentResolver {
|
||||
public final ContentProviderClient acquireContentProviderClient(Uri uri) {
|
||||
IContentProvider provider = acquireProvider(uri);
|
||||
if (provider != null) {
|
||||
return new ContentProviderClient(this, provider);
|
||||
return new ContentProviderClient(this, provider, true);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -1036,7 +1098,47 @@ public abstract class ContentResolver {
|
||||
public final ContentProviderClient acquireContentProviderClient(String name) {
|
||||
IContentProvider provider = acquireProvider(name);
|
||||
if (provider != null) {
|
||||
return new ContentProviderClient(this, provider);
|
||||
return new ContentProviderClient(this, provider, true);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #acquireContentProviderClient(Uri)}, but for use when you do
|
||||
* not trust the stability of the target content provider. This turns off
|
||||
* the mechanism in the platform clean up processes that are dependent on
|
||||
* a content provider if that content provider's process goes away. Normally
|
||||
* you can safely assume that once you have acquired a provider, you can freely
|
||||
* use it as needed and it won't disappear, even if your process is in the
|
||||
* background. If using this method, you need to take care to deal with any
|
||||
* failures when communicating with the provider, and be sure to close it
|
||||
* so that it can be re-opened later.
|
||||
*/
|
||||
public final ContentProviderClient acquireUnstableContentProviderClient(Uri uri) {
|
||||
IContentProvider provider = acquireProvider(uri);
|
||||
if (provider != null) {
|
||||
return new ContentProviderClient(this, provider, false);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Like {@link #acquireContentProviderClient(String)}, but for use when you do
|
||||
* not trust the stability of the target content provider. This turns off
|
||||
* the mechanism in the platform clean up processes that are dependent on
|
||||
* a content provider if that content provider's process goes away. Normally
|
||||
* you can safely assume that once you have acquired a provider, you can freely
|
||||
* use it as needed and it won't disappear, even if your process is in the
|
||||
* background. If using this method, you need to take care to deal with any
|
||||
* failures when communicating with the provider, and be sure to close it
|
||||
* so that it can be re-opened later.
|
||||
*/
|
||||
public final ContentProviderClient acquireUnstableContentProviderClient(String name) {
|
||||
IContentProvider provider = acquireProvider(name);
|
||||
if (provider != null) {
|
||||
return new ContentProviderClient(this, provider, false);
|
||||
}
|
||||
|
||||
return null;
|
||||
@ -1690,7 +1792,7 @@ public abstract class ContentResolver {
|
||||
public void close() throws IOException {
|
||||
if(!mReleaseProviderFlag) {
|
||||
super.close();
|
||||
ContentResolver.this.releaseProvider(mContentProvider);
|
||||
ContentResolver.this.releaseUnstableProvider(mContentProvider);
|
||||
mReleaseProviderFlag = true;
|
||||
}
|
||||
}
|
||||
|
@ -106,6 +106,18 @@ public class MockContentResolver extends ContentResolver {
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
protected IContentProvider acquireUnstableProvider(Context c, String name) {
|
||||
return acquireProvider(c, name);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public boolean releaseUnstableProvider(IContentProvider icp) {
|
||||
return releaseProvider(icp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Overrides {@link android.content.ContentResolver#notifyChange(Uri, ContentObserver, boolean)
|
||||
* ContentResolver.notifChange(Uri, ContentObserver, boolean)}. All parameters are ignored.
|
||||
|
@ -62,6 +62,16 @@ public class BridgeContentResolver extends ContentResolver {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected IContentProvider acquireUnstableProvider(Context c, String name) {
|
||||
return acquireProvider(c, name);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean releaseUnstableProvider(IContentProvider icp) {
|
||||
return releaseProvider(icp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stub for the layoutlib bridge content resolver.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user