diff options
author | Dmitri Plotnikov <dplotnikov@google.com> | 2020-10-23 15:47:19 -0700 |
---|---|---|
committer | Dmitri Plotnikov <dplotnikov@google.com> | 2020-10-28 17:27:27 -0700 |
commit | ec2bc8d99fe9fad5f6e829b259b78a2bd58c4a76 (patch) | |
tree | c62d2ca580f76a001e6340ac2c4fe10a09b5cccf | |
parent | b2f811d3c8b536452f191bf6aa4ad7c14b0af077 (diff) |
Add async version of "uncanonicalize"
This CL is basically identical to http://ag/10353234, which
did the same with the sister method, "canonicalize".
Fixes: b/147705670
Test: atest FrameworksCoreTests:android.content.ContentResolverTest
Change-Id: Ide93850f225cdd61779a62fc2c4666efe438b536
9 files changed, 124 insertions, 3 deletions
diff --git a/core/java/android/content/ContentProvider.java b/core/java/android/content/ContentProvider.java index 03adbc782eef..49248b51a5c7 100644 --- a/core/java/android/content/ContentProvider.java +++ b/core/java/android/content/ContentProvider.java @@ -624,6 +624,20 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall } @Override + public void uncanonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri, + RemoteCallback callback) { + final Bundle result = new Bundle(); + try { + result.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, + uncanonicalize(callingPkg, attributionTag, uri)); + } catch (Exception e) { + result.putParcelable(ContentResolver.REMOTE_CALLBACK_ERROR, + new ParcelableException(e)); + } + callback.sendResult(result); + } + + @Override public boolean refresh(String callingPkg, String attributionTag, Uri uri, Bundle extras, ICancellationSignal cancellationSignal) throws RemoteException { uri = validateIncomingUri(uri); diff --git a/core/java/android/content/ContentProviderNative.java b/core/java/android/content/ContentProviderNative.java index 7bc59013bcfe..7d121d56c86d 100644 --- a/core/java/android/content/ContentProviderNative.java +++ b/core/java/android/content/ContentProviderNative.java @@ -382,6 +382,16 @@ abstract public class ContentProviderNative extends Binder implements IContentPr return true; } + case UNCANONICALIZE_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); + uncanonicalizeAsync(callingPkg, featureId, uri, callback); + return true; + } + case REFRESH_TRANSACTION: { data.enforceInterface(IContentProvider.descriptor); String callingPkg = data.readString(); @@ -875,6 +885,25 @@ final class ContentProviderProxy implements IContentProvider } @Override + /* oneway */ public void uncanonicalizeAsync(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.UNCANONICALIZE_ASYNC_TRANSACTION, data, null, + Binder.FLAG_ONEWAY); + } finally { + data.recycle(); + } + } + + @Override public boolean refresh(String callingPkg, @Nullable String featureId, Uri url, Bundle extras, ICancellationSignal signal) throws RemoteException { Parcel data = Parcel.obtain(); diff --git a/core/java/android/content/ContentResolver.java b/core/java/android/content/ContentResolver.java index 50092d17c692..422d3f7c6784 100644 --- a/core/java/android/content/ContentResolver.java +++ b/core/java/android/content/ContentResolver.java @@ -1338,7 +1338,14 @@ public abstract class ContentResolver implements ContentInterface { } try { - return provider.uncanonicalize(mPackageName, mAttributionTag, url); + final UriResultListener resultListener = new UriResultListener(); + provider.uncanonicalizeAsync(mPackageName, mAttributionTag, url, + new RemoteCallback(resultListener)); + resultListener.waitForResult(CONTENT_PROVIDER_TIMEOUT_MILLIS); + if (resultListener.exception != null) { + throw resultListener.exception; + } + return resultListener.result; } catch (RemoteException e) { // Arbitrary and not worth documenting, as Activity // Manager will kill this process shortly anyway. diff --git a/core/java/android/content/IContentProvider.java b/core/java/android/content/IContentProvider.java index becba67a0198..9210b132c75a 100644 --- a/core/java/android/content/IContentProvider.java +++ b/core/java/android/content/IContentProvider.java @@ -137,6 +137,14 @@ public interface IContentProvider extends IInterface { public Uri uncanonicalize(String callingPkg, @Nullable String attributionTag, Uri uri) throws RemoteException; + /** + * A oneway version of uncanonicalize. 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 uncanonicalizeAsync(String callingPkg, @Nullable String attributionTag, Uri uri, + RemoteCallback callback) throws RemoteException; + public boolean refresh(String callingPkg, @Nullable String attributionTag, Uri url, @Nullable Bundle extras, ICancellationSignal cancellationSignal) throws RemoteException; @@ -172,4 +180,5 @@ public interface IContentProvider extends IInterface { 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; + int UNCANONICALIZE_ASYNC_TRANSACTION = IBinder.FIRST_CALL_TRANSACTION + 30; } diff --git a/core/tests/coretests/src/android/content/ContentResolverTest.java b/core/tests/coretests/src/android/content/ContentResolverTest.java index f48e66681cc7..b517428f5b59 100644 --- a/core/tests/coretests/src/android/content/ContentResolverTest.java +++ b/core/tests/coretests/src/android/content/ContentResolverTest.java @@ -261,4 +261,12 @@ public class ContentResolverTest { // Expected } } + + @Test + public void testUncanonicalize() { + Uri uncanonical = mResolver.uncanonicalize( + Uri.parse("content://android.content.FakeProviderRemote/something")); + assertThat(uncanonical).isEqualTo( + Uri.parse("content://android.content.FakeProviderRemote/uncanonical")); + } } diff --git a/core/tests/coretests/src/android/content/FakeProviderRemote.java b/core/tests/coretests/src/android/content/FakeProviderRemote.java index 2c92da34d9a4..d0bb78101ee4 100644 --- a/core/tests/coretests/src/android/content/FakeProviderRemote.java +++ b/core/tests/coretests/src/android/content/FakeProviderRemote.java @@ -66,4 +66,13 @@ public class FakeProviderRemote extends ContentProvider { return new Uri.Builder().scheme(uri.getScheme()).authority(uri.getAuthority()) .appendPath("canonical").build(); } + + @Override + public Uri uncanonicalize(Uri uri) { + if (uri.getPath() != null && uri.getPath().contains("error")) { + throw new IllegalArgumentException("Expected exception"); + } + return new Uri.Builder().scheme(uri.getScheme()).authority(uri.getAuthority()) + .appendPath("uncanonical").build(); + } } diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java index 3e779a9b2435..bf742b7f96dc 100644 --- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java +++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java @@ -218,6 +218,22 @@ public class PreferencesHelperTest extends UiServiceTestCase { return null; }).when(mTestIContentProvider).canonicalizeAsync(any(), any(), any(), any()); doAnswer(invocation -> { + String callingPkg = invocation.getArgument(0); + String featureId = invocation.getArgument(1); + Uri uri = invocation.getArgument(2); + RemoteCallback cb = invocation.getArgument(3); + IContentProvider mock = (IContentProvider) (invocation.getMock()); + AsyncTask.SERIAL_EXECUTOR.execute(() -> { + final Bundle bundle = new Bundle(); + try { + bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, + mock.uncanonicalize(callingPkg, featureId, uri)); + } catch (RemoteException e) { /* consume */ } + cb.sendResult(bundle); + }); + return null; + }).when(mTestIContentProvider).uncanonicalizeAsync(any(), any(), any(), any()); + doAnswer(invocation -> { Uri uri = invocation.getArgument(0); RemoteCallback cb = invocation.getArgument(1); IContentProvider mock = (IContentProvider) (invocation.getMock()); diff --git a/test-mock/src/android/test/mock/MockContentProvider.java b/test-mock/src/android/test/mock/MockContentProvider.java index a5c254f1aca2..5b9f67efd95d 100644 --- a/test-mock/src/android/test/mock/MockContentProvider.java +++ b/test-mock/src/android/test/mock/MockContentProvider.java @@ -169,6 +169,12 @@ public class MockContentProvider extends ContentProvider { } @Override + public void uncanonicalizeAsync(String callingPkg, String featureId, Uri uri, + RemoteCallback callback) { + MockContentProvider.this.uncanonicalizeAsync(uri, callback); + } + + @Override public boolean refresh(String callingPkg, @Nullable String featureId, Uri url, Bundle args, ICancellationSignal cancellationSignal) throws RemoteException { return MockContentProvider.this.refresh(url, args); @@ -311,6 +317,18 @@ public class MockContentProvider extends ContentProvider { /** * @hide */ + @SuppressWarnings("deprecation") + public void uncanonicalizeAsync(Uri uri, RemoteCallback callback) { + AsyncTask.SERIAL_EXECUTOR.execute(() -> { + final Bundle bundle = new Bundle(); + bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, uncanonicalize(uri)); + callback.sendResult(bundle); + }); + } + + /** + * @hide + */ public boolean refresh(Uri url, Bundle args) { throw new UnsupportedOperationException("unimplemented mock method call"); } diff --git a/test-mock/src/android/test/mock/MockIContentProvider.java b/test-mock/src/android/test/mock/MockIContentProvider.java index 223bcc59039d..82a1cf7d1796 100644 --- a/test-mock/src/android/test/mock/MockIContentProvider.java +++ b/test-mock/src/android/test/mock/MockIContentProvider.java @@ -162,12 +162,23 @@ public class MockIContentProvider implements IContentProvider { } @Override - public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri) - throws RemoteException { + public Uri uncanonicalize(String callingPkg, @Nullable String featureId, Uri uri) { throw new UnsupportedOperationException("unimplemented mock method"); } @Override + @SuppressWarnings("deprecation") + public void uncanonicalizeAsync(String callingPkg, String featureId, Uri uri, + RemoteCallback remoteCallback) { + AsyncTask.SERIAL_EXECUTOR.execute(() -> { + final Bundle bundle = new Bundle(); + bundle.putParcelable(ContentResolver.REMOTE_CALLBACK_RESULT, + uncanonicalize(callingPkg, featureId, uri)); + remoteCallback.sendResult(bundle); + }); + } + + @Override public boolean refresh(String callingPkg, @Nullable String featureId, Uri url, Bundle args, ICancellationSignal cancellationSignal) throws RemoteException { throw new UnsupportedOperationException("unimplemented mock method"); |