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
This commit is contained in:
Dmitri Plotnikov
2020-10-23 15:47:19 -07:00
parent b2f811d3c8
commit ec2bc8d99f
9 changed files with 124 additions and 3 deletions

View File

@@ -623,6 +623,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 {

View File

@@ -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();
@@ -874,6 +884,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 {

View File

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

View File

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

View File

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

View File

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

View File

@@ -217,6 +217,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);

View File

@@ -168,6 +168,12 @@ public class MockContentProvider extends ContentProvider {
return MockContentProvider.this.uncanonicalize(uri);
}
@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 {
@@ -308,6 +314,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
*/

View File

@@ -162,11 +162,22 @@ 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 {