diff --git a/core/java/android/net/Uri.java b/core/java/android/net/Uri.java
index 7fbaf1027af60e4cda7cbbdc7fa83fc3fc680214..3da696ad0bc795bd33476676cb7fa83722e0a8c6 100644
--- a/core/java/android/net/Uri.java
+++ b/core/java/android/net/Uri.java
@@ -882,11 +882,10 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
         }
 
         static Uri readFrom(Parcel parcel) {
-            final StringUri stringUri = new StringUri(parcel.readString8());
             return new OpaqueUri(
-                stringUri.parseScheme(),
-                stringUri.getSsp(),
-                stringUri.getFragmentPart()
+                parcel.readString8(),
+                Part.readFrom(parcel),
+                Part.readFrom(parcel)
             );
         }
 
@@ -896,7 +895,9 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
 
         public void writeToParcel(Parcel parcel, int flags) {
             parcel.writeInt(TYPE_ID);
-            parcel.writeString8(toString());
+            parcel.writeString8(scheme);
+            ssp.writeTo(parcel);
+            fragment.writeTo(parcel);
         }
 
         public boolean isHierarchical() {
@@ -1195,25 +1196,22 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
                 Part query, Part fragment) {
             this.scheme = scheme;
             this.authority = Part.nonNull(authority);
-            this.path = generatePath(path);
+            this.path = path == null ? PathPart.NULL : path;
             this.query = Part.nonNull(query);
             this.fragment = Part.nonNull(fragment);
         }
 
-        private PathPart generatePath(PathPart originalPath) {
+        static Uri readFrom(Parcel parcel) {
+            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
             // authority present (https://www.rfc-editor.org/rfc/rfc3986.html#section-3.3).
             final boolean hasSchemeOrAuthority =
                     (scheme != null && scheme.length() > 0) || !authority.isEmpty();
-            final PathPart newPath = hasSchemeOrAuthority ? PathPart.makeAbsolute(originalPath)
-                                                          : originalPath;
-            return newPath == null ? PathPart.NULL : newPath;
-        }
-
-        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());
+            final PathPart path = PathPart.readFrom(hasSchemeOrAuthority, parcel);
+            final Part query = Part.readFrom(parcel);
+            final Part fragment = Part.readFrom(parcel);
+            return new HierarchicalUri(scheme, authority, path, query, fragment);
         }
 
         public int describeContents() {
@@ -1222,7 +1220,11 @@ public abstract class Uri implements Parcelable, Comparable<Uri> {
 
         public void writeToParcel(Parcel parcel, int flags) {
             parcel.writeInt(TYPE_ID);
-            parcel.writeString8(toString());
+            parcel.writeString8(scheme);
+            authority.writeTo(parcel);
+            path.writeTo(parcel);
+            query.writeTo(parcel);
+            fragment.writeTo(parcel);
         }
 
         public boolean isHierarchical() {
diff --git a/core/tests/coretests/src/android/net/UriTest.java b/core/tests/coretests/src/android/net/UriTest.java
index 2a4ca79d997e835b2922e7f6c9551e42efdad9c9..89632a46267e6306f2e53dcce825e749242b0683 100644
--- a/core/tests/coretests/src/android/net/UriTest.java
+++ b/core/tests/coretests/src/android/net/UriTest.java
@@ -25,6 +25,8 @@ import junit.framework.TestCase;
 
 import java.io.File;
 import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.Arrays;
 import java.util.Iterator;
 import java.util.List;
@@ -867,90 +869,84 @@ public class UriTest extends TestCase {
         return (Uri) hierarchicalUriConstructor.newInstance("https", authority, path, null, null);
     }
 
-    private Uri buildUriFromParts(boolean argumentsEncoded,
+    /** Attempting to unparcel a legacy parcel format of Uri.{,Path}Part should fail. */
+    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 authority,
                                       String path,
                                       String query,
                                       String fragment) {
-        final Uri.Builder builder = new Uri.Builder();
-        builder.scheme(scheme);
-        if (argumentsEncoded) {
-            builder.encodedAuthority(authority);
-            builder.encodedPath(path);
-            builder.encodedQuery(query);
-            builder.encodedFragment(fragment);
-        } else {
-            builder.authority(authority);
-            builder.path(path);
-            builder.query(query);
-            builder.fragment(fragment);
+        // Representation value (from AbstractPart.REPRESENTATION_{ENCODED,DECODED}).
+        final int representation = argumentsEncoded ? 1 : 2;
+        Parcel parcel = Parcel.obtain();
+        try {
+            parcel.writeInt(3);  // hierarchical
+            parcel.writeString8(scheme);
+            parcel.writeInt(representation);
+            parcel.writeString8(authority);
+            parcel.writeInt(representation);
+            parcel.writeString8(path);
+            parcel.writeInt(representation);
+            parcel.writeString8(query);
+            parcel.writeInt(representation);
+            parcel.writeString8(fragment);
+            parcel.setDataPosition(0);
+            return Uri.CREATOR.createFromParcel(parcel);
+        } finally {
+            parcel.recycle();
         }
-        return builder.build();
     }
 
     public void testUnparcelMalformedPath() {
         // Regression tests for b/171966843.
 
         // Test cases with arguments encoded (covering testing `scheme` * `authority` options).
-        Uri uri0 = buildUriFromParts(true, "https", "google.com", "@evil.com", null, null);
+        Uri uri0 = buildUriFromRawParcel(true, "https", "google.com", "@evil.com", null, null);
         assertEquals("https://google.com/@evil.com", uri0.toString());
-        Uri uri1 = buildUriFromParts(true, null, "google.com", "@evil.com", "name=spark", "x");
+        Uri uri1 = buildUriFromRawParcel(true, null, "google.com", "@evil.com", "name=spark", "x");
         assertEquals("//google.com/@evil.com?name=spark#x", uri1.toString());
-        Uri uri2 = buildUriFromParts(true, "http:", null, "@evil.com", null, null);
+        Uri uri2 = buildUriFromRawParcel(true, "http:", null, "@evil.com", null, null);
         assertEquals("http::/@evil.com", uri2.toString());
-        Uri uri3 = buildUriFromParts(true, null, null, "@evil.com", null, null);
+        Uri uri3 = buildUriFromRawParcel(true, null, null, "@evil.com", null, null);
         assertEquals("@evil.com", uri3.toString());
 
         // Test cases with arguments not encoded (covering testing `scheme` * `authority` options).
-        Uri uriA = buildUriFromParts(false, "https", "google.com", "@evil.com", null, null);
+        Uri uriA = buildUriFromRawParcel(false, "https", "google.com", "@evil.com", null, null);
         assertEquals("https://google.com/%40evil.com", uriA.toString());
-        Uri uriB = buildUriFromParts(false, null, "google.com", "@evil.com", null, null);
+        Uri uriB = buildUriFromRawParcel(false, null, "google.com", "@evil.com", null, null);
         assertEquals("//google.com/%40evil.com", uriB.toString());
-        Uri uriC = buildUriFromParts(false, "http:", null, "@evil.com", null, null);
+        Uri uriC = buildUriFromRawParcel(false, "http:", null, "@evil.com", null, null);
         assertEquals("http::/%40evil.com", uriC.toString());
-        Uri uriD = buildUriFromParts(false, null, null, "@evil.com", "name=spark", "y");
+        Uri uriD = buildUriFromRawParcel(false, null, null, "@evil.com", "name=spark", "y");
         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() {
         checkToSafeString("tel:xxxxxx", "tel:Google");
         checkToSafeString("tel:xxxxxxxxxx", "tel:1234567890");