Loading core/java/android/content/ContentProvider.java +9 −0 Original line number Diff line number Diff line Loading @@ -579,6 +579,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall } } @Override public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri, RemoteCallback callback) { final Bundle result = new Bundle(); result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, canonicalize(callingPkg, featureId, uri)); callback.sendResult(result); } @Override public Uri uncanonicalize(String callingPkg, String featureId, Uri uri) { uri = validateIncomingUri(uri); Loading core/java/android/content/ContentProviderNative.java +29 −0 Original line number Diff line number Diff line Loading @@ -359,6 +359,16 @@ abstract public class ContentProviderNative extends Binder implements IContentPr return true; } case CANONICALIZE_ASYNC_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); String callingPkg = data.readString(); String featureId = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data); canonicalizeAsync(callingPkg, featureId, uri, callback); return true; } case UNCANONICALIZE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); Loading Loading @@ -822,6 +832,25 @@ final class ContentProviderProxy implements IContentProvider } } @Override /* oneway */ public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri, RemoteCallback callback) throws RemoteException { Parcel data = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); data.writeString(callingPkg); data.writeString(featureId); uri.writeToParcel(data, 0); callback.writeToParcel(data, 0); mRemote.transact(IContentProvider.CANONICALIZE_ASYNC_TRANSACTION, data, null, Binder.FLAG_ONEWAY); } finally { data.recycle(); } } @Override public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri url) throws RemoteException { Loading core/java/android/content/ContentResolver.java +38 −15 Original line number Diff line number Diff line Loading @@ -712,14 +712,17 @@ public abstract class ContentResolver implements ContentInterface { * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}. * @hide */ public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS = public static final int CONTENT_PROVIDER_READY_TIMEOUT_MILLIS = CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000; // Timeout given a ContentProvider that has already been started and connected to. private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = 3 * 1000; // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how // long ActivityManagerService is giving a content provider to get published if a new process // needs to be started for that. private static final int GET_TYPE_TIMEOUT_MILLIS = CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000; private static final int REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS = CONTENT_PROVIDER_READY_TIMEOUT_MILLIS + CONTENT_PROVIDER_TIMEOUT_MILLIS; public ContentResolver(@Nullable Context context) { this(context, null); Loading Loading @@ -833,10 +836,10 @@ public abstract class ContentResolver implements ContentInterface { IContentProvider provider = acquireExistingProvider(url); if (provider != null) { try { final GetTypeResultListener resultListener = new GetTypeResultListener(); final StringResultListener resultListener = new StringResultListener(); provider.getTypeAsync(url, new RemoteCallback(resultListener)); resultListener.waitForResult(); return resultListener.type; resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS); return resultListener.result; } catch (RemoteException e) { // Arbitrary and not worth documenting, as Activity // Manager will kill this process shortly anyway. Loading @@ -854,13 +857,13 @@ public abstract class ContentResolver implements ContentInterface { } try { GetTypeResultListener resultListener = new GetTypeResultListener(); final StringResultListener resultListener = new StringResultListener(); ActivityManager.getService().getProviderMimeTypeAsync( ContentProvider.getUriWithoutUserId(url), resolveUserId(url), new RemoteCallback(resultListener)); resultListener.waitForResult(); return resultListener.type; resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS); return resultListener.result; } catch (RemoteException e) { // We just failed to send a oneway request to the System Server. Nothing to do. return null; Loading @@ -870,27 +873,29 @@ public abstract class ContentResolver implements ContentInterface { } } private static class GetTypeResultListener implements RemoteCallback.OnResultListener { private abstract static class ResultListener<T> implements RemoteCallback.OnResultListener { @GuardedBy("this") public boolean done; @GuardedBy("this") public String type; public T result; @Override public void onResult(Bundle result) { synchronized (this) { type = result.getString(REMOTE_CALLBACK_RESULT); this.result = getResultFromBundle(result); done = true; notifyAll(); } } public void waitForResult() { protected abstract T getResultFromBundle(Bundle result); public void waitForResult(long timeout) { synchronized (this) { if (!done) { try { wait(GET_TYPE_TIMEOUT_MILLIS); wait(timeout); } catch (InterruptedException e) { // Ignore } Loading @@ -899,6 +904,20 @@ public abstract class ContentResolver implements ContentInterface { } } private static class StringResultListener extends ResultListener<String> { @Override protected String getResultFromBundle(Bundle result) { return result.getString(REMOTE_CALLBACK_RESULT); } } private static class UriResultListener extends ResultListener<Uri> { @Override protected Uri getResultFromBundle(Bundle result) { return result.getParcelable(REMOTE_CALLBACK_RESULT); } } /** * Query for the possible MIME types for the representations the given * content URL can be returned when opened as as stream with Loading Loading @@ -1192,7 +1211,11 @@ public abstract class ContentResolver implements ContentInterface { } try { return provider.canonicalize(mPackageName, mFeatureId, url); final UriResultListener resultListener = new UriResultListener(); provider.canonicalizeAsync(mPackageName, mFeatureId, url, new RemoteCallback(resultListener)); resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS); return resultListener.result; } catch (RemoteException e) { // Arbitrary and not worth documenting, as Activity // Manager will kill this process shortly anyway. Loading core/java/android/content/IContentProvider.java +10 −1 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ public interface IContentProvider extends IInterface { public String getType(Uri url) throws RemoteException; /** * An oneway version of getType. The functionality is exactly the same, except that the * A oneway version of getType. The functionality is exactly the same, except that the * call returns immediately, and the resulting type is returned when available via * a binder callback. */ Loading Loading @@ -126,6 +126,14 @@ public interface IContentProvider extends IInterface { public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) throws RemoteException; /** * A oneway version of canonicalize. The functionality is exactly the same, except that the * call returns immediately, and the resulting type is returned when available via * a binder callback. */ void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri, RemoteCallback callback) throws RemoteException; public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri) throws RemoteException; Loading Loading @@ -162,4 +170,5 @@ public interface IContentProvider extends IInterface { static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26; static final int CHECK_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 27; int GET_TYPE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 28; int CANONICALIZE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 29; } core/tests/coretests/src/android/content/ContentResolverTest.java +8 −0 Original line number Diff line number Diff line Loading @@ -234,4 +234,12 @@ public class ContentResolverTest { assertThat(type).isNull(); assertThat(end).isLessThan(start + 5000); } @Test public void testCanonicalize() { Uri canonical = mResolver.canonicalize( Uri.parse("content://android.content.FakeProviderRemote/something")); assertThat(canonical).isEqualTo( Uri.parse("content://android.content.FakeProviderRemote/canonical")); } } Loading
core/java/android/content/ContentProvider.java +9 −0 Original line number Diff line number Diff line Loading @@ -579,6 +579,15 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall } } @Override public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri, RemoteCallback callback) { final Bundle result = new Bundle(); result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, canonicalize(callingPkg, featureId, uri)); callback.sendResult(result); } @Override public Uri uncanonicalize(String callingPkg, String featureId, Uri uri) { uri = validateIncomingUri(uri); Loading
core/java/android/content/ContentProviderNative.java +29 −0 Original line number Diff line number Diff line Loading @@ -359,6 +359,16 @@ abstract public class ContentProviderNative extends Binder implements IContentPr return true; } case CANONICALIZE_ASYNC_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); String callingPkg = data.readString(); String featureId = data.readString(); Uri uri = Uri.CREATOR.createFromParcel(data); RemoteCallback callback = RemoteCallback.CREATOR.createFromParcel(data); canonicalizeAsync(callingPkg, featureId, uri, callback); return true; } case UNCANONICALIZE_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); Loading Loading @@ -822,6 +832,25 @@ final class ContentProviderProxy implements IContentProvider } } @Override /* oneway */ public void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri, RemoteCallback callback) throws RemoteException { Parcel data = Parcel.obtain(); try { data.writeInterfaceToken(IContentProvider.descriptor); data.writeString(callingPkg); data.writeString(featureId); uri.writeToParcel(data, 0); callback.writeToParcel(data, 0); mRemote.transact(IContentProvider.CANONICALIZE_ASYNC_TRANSACTION, data, null, Binder.FLAG_ONEWAY); } finally { data.recycle(); } } @Override public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri url) throws RemoteException { Loading
core/java/android/content/ContentResolver.java +38 −15 Original line number Diff line number Diff line Loading @@ -712,14 +712,17 @@ public abstract class ContentResolver implements ContentInterface { * {@link #CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS}. * @hide */ public static final int CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS = public static final int CONTENT_PROVIDER_READY_TIMEOUT_MILLIS = CONTENT_PROVIDER_PUBLISH_TIMEOUT_MILLIS + 10 * 1000; // Timeout given a ContentProvider that has already been started and connected to. private static final int CONTENT_PROVIDER_TIMEOUT_MILLIS = 3 * 1000; // Should be >= {@link #CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS}, because that's how // long ActivityManagerService is giving a content provider to get published if a new process // needs to be started for that. private static final int GET_TYPE_TIMEOUT_MILLIS = CONTENT_PROVIDER_WAIT_TIMEOUT_MILLIS + 5 * 1000; private static final int REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS = CONTENT_PROVIDER_READY_TIMEOUT_MILLIS + CONTENT_PROVIDER_TIMEOUT_MILLIS; public ContentResolver(@Nullable Context context) { this(context, null); Loading Loading @@ -833,10 +836,10 @@ public abstract class ContentResolver implements ContentInterface { IContentProvider provider = acquireExistingProvider(url); if (provider != null) { try { final GetTypeResultListener resultListener = new GetTypeResultListener(); final StringResultListener resultListener = new StringResultListener(); provider.getTypeAsync(url, new RemoteCallback(resultListener)); resultListener.waitForResult(); return resultListener.type; resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS); return resultListener.result; } catch (RemoteException e) { // Arbitrary and not worth documenting, as Activity // Manager will kill this process shortly anyway. Loading @@ -854,13 +857,13 @@ public abstract class ContentResolver implements ContentInterface { } try { GetTypeResultListener resultListener = new GetTypeResultListener(); final StringResultListener resultListener = new StringResultListener(); ActivityManager.getService().getProviderMimeTypeAsync( ContentProvider.getUriWithoutUserId(url), resolveUserId(url), new RemoteCallback(resultListener)); resultListener.waitForResult(); return resultListener.type; resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS); return resultListener.result; } catch (RemoteException e) { // We just failed to send a oneway request to the System Server. Nothing to do. return null; Loading @@ -870,27 +873,29 @@ public abstract class ContentResolver implements ContentInterface { } } private static class GetTypeResultListener implements RemoteCallback.OnResultListener { private abstract static class ResultListener<T> implements RemoteCallback.OnResultListener { @GuardedBy("this") public boolean done; @GuardedBy("this") public String type; public T result; @Override public void onResult(Bundle result) { synchronized (this) { type = result.getString(REMOTE_CALLBACK_RESULT); this.result = getResultFromBundle(result); done = true; notifyAll(); } } public void waitForResult() { protected abstract T getResultFromBundle(Bundle result); public void waitForResult(long timeout) { synchronized (this) { if (!done) { try { wait(GET_TYPE_TIMEOUT_MILLIS); wait(timeout); } catch (InterruptedException e) { // Ignore } Loading @@ -899,6 +904,20 @@ public abstract class ContentResolver implements ContentInterface { } } private static class StringResultListener extends ResultListener<String> { @Override protected String getResultFromBundle(Bundle result) { return result.getString(REMOTE_CALLBACK_RESULT); } } private static class UriResultListener extends ResultListener<Uri> { @Override protected Uri getResultFromBundle(Bundle result) { return result.getParcelable(REMOTE_CALLBACK_RESULT); } } /** * Query for the possible MIME types for the representations the given * content URL can be returned when opened as as stream with Loading Loading @@ -1192,7 +1211,11 @@ public abstract class ContentResolver implements ContentInterface { } try { return provider.canonicalize(mPackageName, mFeatureId, url); final UriResultListener resultListener = new UriResultListener(); provider.canonicalizeAsync(mPackageName, mFeatureId, url, new RemoteCallback(resultListener)); resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS); return resultListener.result; } catch (RemoteException e) { // Arbitrary and not worth documenting, as Activity // Manager will kill this process shortly anyway. Loading
core/java/android/content/IContentProvider.java +10 −1 Original line number Diff line number Diff line Loading @@ -45,7 +45,7 @@ public interface IContentProvider extends IInterface { public String getType(Uri url) throws RemoteException; /** * An oneway version of getType. The functionality is exactly the same, except that the * A oneway version of getType. The functionality is exactly the same, except that the * call returns immediately, and the resulting type is returned when available via * a binder callback. */ Loading Loading @@ -126,6 +126,14 @@ public interface IContentProvider extends IInterface { public Uri canonicalize(String callingPkg, @Nullable String featureId, Uri uri) throws RemoteException; /** * A oneway version of canonicalize. The functionality is exactly the same, except that the * call returns immediately, and the resulting type is returned when available via * a binder callback. */ void canonicalizeAsync(String callingPkg, @Nullable String featureId, Uri uri, RemoteCallback callback) throws RemoteException; public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri) throws RemoteException; Loading Loading @@ -162,4 +170,5 @@ public interface IContentProvider extends IInterface { static final int REFRESH_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 26; static final int CHECK_URI_PERMISSION_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 27; int GET_TYPE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 28; int CANONICALIZE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 29; }
core/tests/coretests/src/android/content/ContentResolverTest.java +8 −0 Original line number Diff line number Diff line Loading @@ -234,4 +234,12 @@ public class ContentResolverTest { assertThat(type).isNull(); assertThat(end).isLessThan(start + 5000); } @Test public void testCanonicalize() { Uri canonical = mResolver.canonicalize( Uri.parse("content://android.content.FakeProviderRemote/something")); assertThat(canonical).isEqualTo( Uri.parse("content://android.content.FakeProviderRemote/canonical")); } }