Loading core/java/android/content/ContentProvider.java +18 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.os.Bundle; import android.os.CancellationSignal; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteCallback; Loading Loading @@ -303,7 +304,23 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall @Override public void getTypeAsync(Uri uri, RemoteCallback callback) { final Bundle result = new Bundle(); try { result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri)); } catch (Exception e) { Parcel parcel = Parcel.obtain(); try { try { parcel.writeException(e); } catch (Exception ex) { // getType threw an unparcelable exception. Wrap the message into // a parcelable exception type parcel.writeException(new IllegalStateException(e.getMessage())); } result.putByteArray(ContentResolver.REMOTE_CALLBACK_ERROR, parcel.marshall()); } finally { parcel.recycle(); } } callback.sendResult(result); } Loading core/java/android/content/ContentResolver.java +40 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import android.os.DeadObjectException; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.OperationCanceledException; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; import android.os.RemoteException; Loading Loading @@ -735,6 +736,9 @@ public abstract class ContentResolver implements ContentInterface { /** @hide */ public static final String REMOTE_CALLBACK_RESULT = "result"; /** @hide */ public static final String REMOTE_CALLBACK_ERROR = "error"; /** * How long we wait for an attached process to publish its content providers * before we decide it must be hung. Loading Loading @@ -874,6 +878,9 @@ public abstract class ContentResolver implements ContentInterface { final StringResultListener resultListener = new StringResultListener(); provider.getTypeAsync(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 Loading @@ -898,6 +905,9 @@ public abstract class ContentResolver implements ContentInterface { resolveUserId(url), new RemoteCallback(resultListener)); resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS); if (resultListener.exception != null) { throw resultListener.exception; } return resultListener.result; } catch (RemoteException e) { // We just failed to send a oneway request to the System Server. Nothing to do. Loading @@ -915,15 +925,41 @@ public abstract class ContentResolver implements ContentInterface { @GuardedBy("this") public T result; @GuardedBy("this") public RuntimeException exception; @Override public void onResult(Bundle result) { synchronized (this) { this.exception = getExceptionFromBundle(result); if (this.exception == null) { this.result = getResultFromBundle(result); } done = true; notifyAll(); } } private RuntimeException getExceptionFromBundle(Bundle result) { byte[] bytes = result.getByteArray(REMOTE_CALLBACK_ERROR); if (bytes == null) { return null; } Parcel parcel = Parcel.obtain(); try { parcel.unmarshall(bytes, 0, bytes.length); parcel.setDataPosition(0); parcel.readException(); } catch (RuntimeException ex) { return ex; } finally { parcel.recycle(); } return null; } protected abstract T getResultFromBundle(Bundle result); public void waitForResult(long timeout) { Loading Loading @@ -1250,6 +1286,9 @@ public abstract class ContentResolver implements ContentInterface { provider.canonicalizeAsync(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 Loading core/tests/coretests/src/android/content/ContentResolverTest.java +11 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; Loading Loading @@ -235,6 +236,16 @@ public class ContentResolverTest { assertThat(end).isLessThan(start + 5000); } @Test public void testGetType_providerException() { try { mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote/error")); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // Expected } } @Test public void testCanonicalize() { Uri canonical = mResolver.canonicalize( Loading core/tests/coretests/src/android/content/FakeProviderRemote.java +3 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,9 @@ public class FakeProviderRemote extends ContentProvider { @Override public String getType(Uri uri) { if (uri.getPath() != null && uri.getPath().contains("error")) { throw new IllegalArgumentException("Expected exception"); } return "fake/remote"; } Loading Loading
core/java/android/content/ContentProvider.java +18 −1 Original line number Diff line number Diff line Loading @@ -47,6 +47,7 @@ import android.os.Bundle; import android.os.CancellationSignal; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.Process; import android.os.RemoteCallback; Loading Loading @@ -303,7 +304,23 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall @Override public void getTypeAsync(Uri uri, RemoteCallback callback) { final Bundle result = new Bundle(); try { result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri)); } catch (Exception e) { Parcel parcel = Parcel.obtain(); try { try { parcel.writeException(e); } catch (Exception ex) { // getType threw an unparcelable exception. Wrap the message into // a parcelable exception type parcel.writeException(new IllegalStateException(e.getMessage())); } result.putByteArray(ContentResolver.REMOTE_CALLBACK_ERROR, parcel.marshall()); } finally { parcel.recycle(); } } callback.sendResult(result); } Loading
core/java/android/content/ContentResolver.java +40 −1 Original line number Diff line number Diff line Loading @@ -55,6 +55,7 @@ import android.os.DeadObjectException; import android.os.IBinder; import android.os.ICancellationSignal; import android.os.OperationCanceledException; import android.os.Parcel; import android.os.ParcelFileDescriptor; import android.os.RemoteCallback; import android.os.RemoteException; Loading Loading @@ -735,6 +736,9 @@ public abstract class ContentResolver implements ContentInterface { /** @hide */ public static final String REMOTE_CALLBACK_RESULT = "result"; /** @hide */ public static final String REMOTE_CALLBACK_ERROR = "error"; /** * How long we wait for an attached process to publish its content providers * before we decide it must be hung. Loading Loading @@ -874,6 +878,9 @@ public abstract class ContentResolver implements ContentInterface { final StringResultListener resultListener = new StringResultListener(); provider.getTypeAsync(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 Loading @@ -898,6 +905,9 @@ public abstract class ContentResolver implements ContentInterface { resolveUserId(url), new RemoteCallback(resultListener)); resultListener.waitForResult(REMOTE_CONTENT_PROVIDER_TIMEOUT_MILLIS); if (resultListener.exception != null) { throw resultListener.exception; } return resultListener.result; } catch (RemoteException e) { // We just failed to send a oneway request to the System Server. Nothing to do. Loading @@ -915,15 +925,41 @@ public abstract class ContentResolver implements ContentInterface { @GuardedBy("this") public T result; @GuardedBy("this") public RuntimeException exception; @Override public void onResult(Bundle result) { synchronized (this) { this.exception = getExceptionFromBundle(result); if (this.exception == null) { this.result = getResultFromBundle(result); } done = true; notifyAll(); } } private RuntimeException getExceptionFromBundle(Bundle result) { byte[] bytes = result.getByteArray(REMOTE_CALLBACK_ERROR); if (bytes == null) { return null; } Parcel parcel = Parcel.obtain(); try { parcel.unmarshall(bytes, 0, bytes.length); parcel.setDataPosition(0); parcel.readException(); } catch (RuntimeException ex) { return ex; } finally { parcel.recycle(); } return null; } protected abstract T getResultFromBundle(Bundle result); public void waitForResult(long timeout) { Loading Loading @@ -1250,6 +1286,9 @@ public abstract class ContentResolver implements ContentInterface { provider.canonicalizeAsync(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 Loading
core/tests/coretests/src/android/content/ContentResolverTest.java +11 −0 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; Loading Loading @@ -235,6 +236,16 @@ public class ContentResolverTest { assertThat(end).isLessThan(start + 5000); } @Test public void testGetType_providerException() { try { mResolver.getType(Uri.parse("content://android.content.FakeProviderRemote/error")); fail("Expected IllegalArgumentException"); } catch (IllegalArgumentException e) { // Expected } } @Test public void testCanonicalize() { Uri canonical = mResolver.canonicalize( Loading
core/tests/coretests/src/android/content/FakeProviderRemote.java +3 −0 Original line number Diff line number Diff line Loading @@ -37,6 +37,9 @@ public class FakeProviderRemote extends ContentProvider { @Override public String getType(Uri uri) { if (uri.getPath() != null && uri.getPath().contains("error")) { throw new IllegalArgumentException("Expected exception"); } return "fake/remote"; } Loading