Merge "Propagate exception thrown by ContentProvider.getType" into rvc-dev am: f903ef10e5 am: 84a2bbf8b9

Change-Id: Iabc1ea0e689a99609a9f364c0cc06601914d6cb9
This commit is contained in:
Dmitri Plotnikov
2020-03-25 17:39:45 +00:00
committed by Automerger Merge Worker
4 changed files with 72 additions and 2 deletions

View File

@@ -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;
@@ -303,7 +304,23 @@ public abstract class ContentProvider implements ContentInterface, ComponentCall
@Override
public void getTypeAsync(Uri uri, RemoteCallback callback) {
final Bundle result = new Bundle();
result.putString(ContentResolver.REMOTE_CALLBACK_RESULT, getType(uri));
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);
}

View File

@@ -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;
@@ -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.
@@ -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
@@ -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.
@@ -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.result = getResultFromBundle(result);
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) {
@@ -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

View File

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

View File

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