Merge "Add infrastructure for accessing "unstable" content providers." into jb-dev

This commit is contained in:
Dianne Hackborn
2012-05-09 18:30:23 -07:00
committed by Android (Google) Code Review
7 changed files with 204 additions and 53 deletions

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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.
*/