Merge "Update parcling logic for Uris." into rvc-dev am: cdb758450b am: adc6fe9aa4 am: e6f4326547

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23835332

Change-Id: I5f62e8c99e62c3e2fb3a8ffee77a22513e9ab5e9
Signed-off-by: Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
This commit is contained in:
Varun Shah
2023-07-12 20:20:06 +00:00
committed by Automerger Merge Worker
2 changed files with 77 additions and 75 deletions

View File

@@ -885,10 +885,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
} }
static Uri readFrom(Parcel parcel) { static Uri readFrom(Parcel parcel) {
final StringUri stringUri = new StringUri(parcel.readString8());
return new OpaqueUri( return new OpaqueUri(
parcel.readString8(), stringUri.parseScheme(),
Part.readFrom(parcel), stringUri.getSsp(),
Part.readFrom(parcel) stringUri.getFragmentPart()
); );
} }
@@ -898,9 +899,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
public void writeToParcel(Parcel parcel, int flags) { public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID); parcel.writeInt(TYPE_ID);
parcel.writeString8(scheme); parcel.writeString8(toString());
ssp.writeTo(parcel);
fragment.writeTo(parcel);
} }
public boolean isHierarchical() { public boolean isHierarchical() {
@@ -1199,22 +1198,25 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
Part query, Part fragment) { Part query, Part fragment) {
this.scheme = scheme; this.scheme = scheme;
this.authority = Part.nonNull(authority); this.authority = Part.nonNull(authority);
this.path = path == null ? PathPart.NULL : path; this.path = generatePath(path);
this.query = Part.nonNull(query); this.query = Part.nonNull(query);
this.fragment = Part.nonNull(fragment); this.fragment = Part.nonNull(fragment);
} }
static Uri readFrom(Parcel parcel) { private PathPart generatePath(PathPart originalPath) {
final String scheme = parcel.readString8();
final Part authority = Part.readFrom(parcel);
// In RFC3986 the path should be determined based on whether there is a scheme or // In RFC3986 the path should be determined based on whether there is a scheme or
// authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3). // authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3).
final boolean hasSchemeOrAuthority = final boolean hasSchemeOrAuthority =
(scheme != null && scheme.length() > 0) || !authority.isEmpty(); (scheme != null && scheme.length() > 0) || !authority.isEmpty();
final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel); final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath)
final Part query = Part.readFrom(parcel); : originalPath;
final Part fragment = Part.readFrom(parcel); return newPath == null ? PathPart.NULL : newPath;
return new HierarchicalUri(scheme, authority, path, query, fragment); }
static Uri readFrom(Parcel parcel) {
final StringUri stringUri = new StringUri(parcel.readString8());
return new HierarchicalUri(stringUri.getScheme(), stringUri.getAuthorityPart(),
stringUri.getPathPart(), stringUri.getQueryPart(), stringUri.getFragmentPart());
} }
public int describeContents() { public int describeContents() {
@@ -1223,11 +1225,7 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
public void writeToParcel(Parcel parcel, int flags) { public void writeToParcel(Parcel parcel, int flags) {
parcel.writeInt(TYPE_ID); parcel.writeInt(TYPE_ID);
parcel.writeString8(scheme); parcel.writeString8(toString());
authority.writeTo(parcel);
path.writeTo(parcel);
query.writeTo(parcel);
fragment.writeTo(parcel);
} }
public boolean isHierarchical() { public boolean isHierarchical() {

View File

@@ -25,8 +25,6 @@ import junit.framework.TestCase;
import java.io.File; import java.io.File;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays; import java.util.Arrays;
import java.util.Iterator; import java.util.Iterator;
import java.util.List; import java.util.List;
@@ -869,84 +867,90 @@ public class UriTest extends TestCase {
return (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null); return (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null);
} }
/** Attempting to unparcel a legacy parcel format of Uri.{,Path}Part should fail. */ private Uri buildUriFromParts(boolean argumentsEncoded,
public void testUnparcelLegacyPart_fails() throws Exception {
assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$Part"));
assertUnparcelLegacyPart_fails(Class.forName("android.net.Uri$PathPart"));
}
private static void assertUnparcelLegacyPart_fails(Class partClass) throws Exception {
Parcel parcel = Parcel.obtain();
parcel.writeInt(0 /* BOTH */);
parcel.writeString("encoded");
parcel.writeString("decoded");
parcel.setDataPosition(0);
Method readFromMethod = partClass.getDeclaredMethod("readFrom", Parcel.class);
readFromMethod.setAccessible(true);
try {
readFromMethod.invoke(null, parcel);
fail();
} catch (InvocationTargetException expected) {
Throwable targetException = expected.getTargetException();
// Check that the exception was thrown for the correct reason.
assertEquals("Unknown representation: 0", targetException.getMessage());
} finally {
parcel.recycle();
}
}
private Uri buildUriFromRawParcel(boolean argumentsEncoded,
String scheme, String scheme,
String authority, String authority,
String path, String path,
String query, String query,
String fragment) { String fragment) {
// Representation value (from AbstractPart.REPRESENTATION_{ENCODED,DECODED}). final Uri.Builder builder = new Uri.Builder();
final int representation = argumentsEncoded ? 1 : 2; builder.scheme(scheme);
Parcel parcel = Parcel.obtain(); if (argumentsEncoded) {
try { builder.encodedAuthority(authority);
parcel.writeInt(3); // hierarchical builder.encodedPath(path);
parcel.writeString8(scheme); builder.encodedQuery(query);
parcel.writeInt(representation); builder.encodedFragment(fragment);
parcel.writeString8(authority); } else {
parcel.writeInt(representation); builder.authority(authority);
parcel.writeString8(path); builder.path(path);
parcel.writeInt(representation); builder.query(query);
parcel.writeString8(query); builder.fragment(fragment);
parcel.writeInt(representation);
parcel.writeString8(fragment);
parcel.setDataPosition(0);
return Uri.CREATOR.createFromParcel(parcel);
} finally {
parcel.recycle();
} }
return builder.build();
} }
public void testUnparcelMalformedPath() { public void testUnparcelMalformedPath() {
// Regression tests for b/171966843. // Regression tests for b/171966843.
// Test cases with arguments encoded (covering testing `scheme` * `authority` options). // Test cases with arguments encoded (covering testing `scheme` * `authority` options).
Uri uri0 = buildUriFromRawParcel(true, "https", "google.com", "@evil.com", null, null); Uri uri0 = buildUriFromParts(true, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/@evil.com", uri0.toString()); assertEquals("https://google.com/@evil.com", uri0.toString());
Uri uri1 = buildUriFromRawParcel(true, null, "google.com", "@evil.com", "name=spark", "x"); Uri uri1 = buildUriFromParts(true, null, "google.com", "@evil.com", "name=spark", "x");
assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString()); assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString());
Uri uri2 = buildUriFromRawParcel(true, "http:", null, "@evil.com", null, null); Uri uri2 = buildUriFromParts(true, "http:", null, "@evil.com", null, null);
assertEquals("http::/@evil.com", uri2.toString()); assertEquals("http::/@evil.com", uri2.toString());
Uri uri3 = buildUriFromRawParcel(true, null, null, "@evil.com", null, null); Uri uri3 = buildUriFromParts(true, null, null, "@evil.com", null, null);
assertEquals("@evil.com", uri3.toString()); assertEquals("@evil.com", uri3.toString());
// Test cases with arguments not encoded (covering testing `scheme` * `authority` options). // Test cases with arguments not encoded (covering testing `scheme` * `authority` options).
Uri uriA = buildUriFromRawParcel(false, "https", "google.com", "@evil.com", null, null); Uri uriA = buildUriFromParts(false, "https", "google.com", "@evil.com", null, null);
assertEquals("https://google.com/%40evil.com", uriA.toString()); assertEquals("https://google.com/%40evil.com", uriA.toString());
Uri uriB = buildUriFromRawParcel(false, null, "google.com", "@evil.com", null, null); Uri uriB = buildUriFromParts(false, null, "google.com", "@evil.com", null, null);
assertEquals("//google.com/%40evil.com", uriB.toString()); assertEquals("//google.com/%40evil.com", uriB.toString());
Uri uriC = buildUriFromRawParcel(false, "http:", null, "@evil.com", null, null); Uri uriC = buildUriFromParts(false, "http:", null, "@evil.com", null, null);
assertEquals("http::/%40evil.com", uriC.toString()); assertEquals("http::/%40evil.com", uriC.toString());
Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y"); Uri uriD = buildUriFromParts(false, null, null, "@evil.com", "name=spark", "y");
assertEquals("%40evil.com?name%3Dspark#y", uriD.toString()); assertEquals("%40evil.com?name%3Dspark#y", uriD.toString());
} }
public void testParsedUriFromStringEquality() {
Uri uri = buildUriFromParts(
true, "https", "google.com", "@evil.com", null, null);
assertEquals(uri, Uri.parse(uri.toString()));
Uri uri2 = buildUriFromParts(
true, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
assertEquals(uri2, Uri.parse(uri2.toString()));
Uri uri3 = buildUriFromParts(
false, "content://evil.authority?foo=", "safe.authority", "@evil.com", null, null);
assertEquals(uri3, Uri.parse(uri3.toString()));
}
public void testParceledUrisAreEqual() {
Uri opaqueUri = Uri.fromParts("fake://uri#", "ssp", "fragment");
Parcel parcel = Parcel.obtain();
try {
opaqueUri.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
Uri parsedUri = Uri.parse(postParcelUri.toString());
assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
} finally {
parcel.recycle();
}
Uri hierarchicalUri = new Uri.Builder().scheme("fake://uri#").authority("auth").build();
parcel = Parcel.obtain();
try {
hierarchicalUri.writeToParcel(parcel, 0);
parcel.setDataPosition(0);
Uri postParcelUri = Uri.CREATOR.createFromParcel(parcel);
Uri parsedUri = Uri.parse(postParcelUri.toString());
assertEquals(parsedUri.getScheme(), postParcelUri.getScheme());
} finally {
parcel.recycle();
}
}
public void testToSafeString() { public void testToSafeString() {
checkToSafeString("tel:xxxxxx", "tel:Google"); checkToSafeString("tel:xxxxxx", "tel:Google");
checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890"); checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");