From 4ee8a655a0b41cec660578081fa1a21248e457cc Mon Sep 17 00:00:00 2001
From: Jeff Sharkey <jsharkey@google.com>
Date: Tue, 14 Nov 2023 08:45:56 -0700
Subject: [PATCH] PersistableBundle for Ravenwood, with CTS.

We have the XML interfaces from libcore, but the implementations
there are tied closely to things like StringPool.  We thankfully
have our own human-readable XML serializer that we could use, but
there's unfortunately not a good pull parser.

To get us unstuck for the moment, pivot the internals to
unconditionally use the binary XML format, which at least we
know is thoroughly tested, and any data written through this path
can then also be parsed.

This is enough to support PersistableBundle, and we'll circle back
to get ourselves a human-readable XML implementation in the future.

Bug: 292141694
Test: atest-dev CtsOsTestCasesRavenwood CtsOsTestCases
Change-Id: I875a3a2b0e95e52861afe187e2a5e9f1e740d8d5
---
 core/java/android/util/Xml.java               | 68 +++++++++++++++++++
 .../internal/util/ArtFastDataInput.java       | 15 +++-
 .../internal/util/ArtFastDataOutput.java      | 14 +++-
 ravenwood/Android.bp                          |  7 ++
 ...ramework-minus-apex-ravenwood-policies.txt | 14 ++++
 .../ravenwood-annotation-allowed-classes.txt  |  2 +
 tools/hoststubgen/hoststubgen/Android.bp      |  3 +
 7 files changed, 117 insertions(+), 6 deletions(-)

diff --git a/core/java/android/util/Xml.java b/core/java/android/util/Xml.java
index 33058d84b2e5..2a33caaf7e28 100644
--- a/core/java/android/util/Xml.java
+++ b/core/java/android/util/Xml.java
@@ -26,6 +26,7 @@ import com.android.internal.util.ArtBinaryXmlPullParser;
 import com.android.internal.util.ArtBinaryXmlSerializer;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.XmlUtils;
+import com.android.modules.utils.BinaryXmlPullParser;
 import com.android.modules.utils.BinaryXmlSerializer;
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
@@ -38,6 +39,7 @@ import org.xml.sax.SAXException;
 import org.xml.sax.XMLReader;
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
+import org.xmlpull.v1.XmlPullParserFactory;
 import org.xmlpull.v1.XmlSerializer;
 
 import java.io.BufferedInputStream;
@@ -115,6 +117,7 @@ public class Xml {
     /**
      * Returns a new pull parser with namespace support.
      */
+    @android.ravenwood.annotation.RavenwoodReplace
     public static XmlPullParser newPullParser() {
         try {
             XmlPullParser parser = XmlObjectFactory.newXmlPullParser();
@@ -126,6 +129,12 @@ public class Xml {
         }
     }
 
+    /** @hide */
+    public static XmlPullParser newPullParser$ravenwood() {
+        // TODO: remove once we're linking against libcore
+        return new BinaryXmlPullParser();
+    }
+
     /**
      * Creates a new {@link TypedXmlPullParser} which is optimized for use
      * inside the system, typically by supporting only a basic set of features.
@@ -136,10 +145,17 @@ public class Xml {
      * @hide
      */
     @SuppressWarnings("AndroidFrameworkEfficientXml")
+    @android.ravenwood.annotation.RavenwoodReplace
     public static @NonNull TypedXmlPullParser newFastPullParser() {
         return XmlUtils.makeTyped(newPullParser());
     }
 
+    /** @hide */
+    public static TypedXmlPullParser newFastPullParser$ravenwood() {
+        // TODO: remove once we're linking against libcore
+        return new BinaryXmlPullParser();
+    }
+
     /**
      * Creates a new {@link XmlPullParser} that reads XML documents using a
      * custom binary wire protocol which benchmarking has shown to be 8.5x
@@ -148,10 +164,17 @@ public class Xml {
      *
      * @hide
      */
+    @android.ravenwood.annotation.RavenwoodReplace
     public static @NonNull TypedXmlPullParser newBinaryPullParser() {
         return new ArtBinaryXmlPullParser();
     }
 
+    /** @hide */
+    public static TypedXmlPullParser newBinaryPullParser$ravenwood() {
+        // TODO: remove once we're linking against libcore
+        return new BinaryXmlPullParser();
+    }
+
     /**
      * Creates a new {@link XmlPullParser} which is optimized for use inside the
      * system, typically by supporting only a basic set of features.
@@ -166,6 +189,7 @@ public class Xml {
      *
      * @hide
      */
+    @android.ravenwood.annotation.RavenwoodReplace
     public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in)
             throws IOException {
         final byte[] magic = new byte[4];
@@ -198,13 +222,33 @@ public class Xml {
         return xml;
     }
 
+    /** @hide */
+    public static @NonNull TypedXmlPullParser resolvePullParser$ravenwood(@NonNull InputStream in)
+            throws IOException {
+        // TODO: remove once we're linking against libcore
+        final TypedXmlPullParser xml = new BinaryXmlPullParser();
+        try {
+            xml.setInput(in, StandardCharsets.UTF_8.name());
+        } catch (XmlPullParserException e) {
+            throw new IOException(e);
+        }
+        return xml;
+    }
+
     /**
      * Creates a new xml serializer.
      */
+    @android.ravenwood.annotation.RavenwoodReplace
     public static XmlSerializer newSerializer() {
         return XmlObjectFactory.newXmlSerializer();
     }
 
+    /** @hide */
+    public static XmlSerializer newSerializer$ravenwood() {
+        // TODO: remove once we're linking against libcore
+        return new BinaryXmlSerializer();
+    }
+
     /**
      * Creates a new {@link XmlSerializer} which is optimized for use inside the
      * system, typically by supporting only a basic set of features.
@@ -215,10 +259,17 @@ public class Xml {
      * @hide
      */
     @SuppressWarnings("AndroidFrameworkEfficientXml")
+    @android.ravenwood.annotation.RavenwoodReplace
     public static @NonNull TypedXmlSerializer newFastSerializer() {
         return XmlUtils.makeTyped(new FastXmlSerializer());
     }
 
+    /** @hide */
+    public static @NonNull TypedXmlSerializer newFastSerializer$ravenwood() {
+        // TODO: remove once we're linking against libcore
+        return new BinaryXmlSerializer();
+    }
+
     /**
      * Creates a new {@link XmlSerializer} that writes XML documents using a
      * custom binary wire protocol which benchmarking has shown to be 4.4x
@@ -227,10 +278,17 @@ public class Xml {
      *
      * @hide
      */
+    @android.ravenwood.annotation.RavenwoodReplace
     public static @NonNull TypedXmlSerializer newBinarySerializer() {
         return new ArtBinaryXmlSerializer();
     }
 
+    /** @hide */
+    public static @NonNull TypedXmlSerializer newBinarySerializer$ravenwood() {
+        // TODO: remove once we're linking against libcore
+        return new BinaryXmlSerializer();
+    }
+
     /**
      * Creates a new {@link XmlSerializer} which is optimized for use inside the
      * system, typically by supporting only a basic set of features.
@@ -245,6 +303,7 @@ public class Xml {
      *
      * @hide
      */
+    @android.ravenwood.annotation.RavenwoodReplace
     public static @NonNull TypedXmlSerializer resolveSerializer(@NonNull OutputStream out)
             throws IOException {
         final TypedXmlSerializer xml;
@@ -257,6 +316,15 @@ public class Xml {
         return xml;
     }
 
+    /** @hide */
+    public static @NonNull TypedXmlSerializer resolveSerializer$ravenwood(@NonNull OutputStream out)
+            throws IOException {
+        // TODO: remove once we're linking against libcore
+        final TypedXmlSerializer xml = new BinaryXmlSerializer();
+        xml.setOutput(out, StandardCharsets.UTF_8.name());
+        return xml;
+    }
+
     /**
      * Copy the first XML document into the second document.
      * <p>
diff --git a/core/java/com/android/internal/util/ArtFastDataInput.java b/core/java/com/android/internal/util/ArtFastDataInput.java
index 3e8916caead9..768ea82e0c71 100644
--- a/core/java/com/android/internal/util/ArtFastDataInput.java
+++ b/core/java/com/android/internal/util/ArtFastDataInput.java
@@ -21,6 +21,8 @@ import android.util.CharsetUtils;
 
 import com.android.modules.utils.FastDataInput;
 
+import dalvik.system.VMRuntime;
+
 import java.io.DataInput;
 import java.io.IOException;
 import java.io.InputStream;
@@ -35,13 +37,14 @@ import java.util.concurrent.atomic.AtomicReference;
  */
 public class ArtFastDataInput extends FastDataInput {
     private static AtomicReference<ArtFastDataInput> sInCache = new AtomicReference<>();
+    private static VMRuntime sRuntime = VMRuntime.getRuntime();
 
     private final long mBufferPtr;
 
     public ArtFastDataInput(@NonNull InputStream in, int bufferSize) {
         super(in, bufferSize);
 
-        mBufferPtr = mRuntime.addressOf(mBuffer);
+        mBufferPtr = sRuntime.addressOf(mBuffer);
     }
 
     /**
@@ -66,6 +69,7 @@ public class ArtFastDataInput extends FastDataInput {
      * Release a {@link ArtFastDataInput} to potentially be recycled. You must not
      * interact with the object after releasing it.
      */
+    @Override
     public void release() {
         super.release();
 
@@ -75,6 +79,11 @@ public class ArtFastDataInput extends FastDataInput {
         }
     }
 
+    @Override
+    public byte[] newByteArray(int bufferSize) {
+        return (byte[]) sRuntime.newNonMovableArray(byte.class, bufferSize);
+    }
+
     @Override
     public String readUTF() throws IOException {
         // Attempt to read directly from buffer space if there's enough room,
@@ -86,9 +95,9 @@ public class ArtFastDataInput extends FastDataInput {
             mBufferPos += len;
             return res;
         } else {
-            final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
+            final byte[] tmp = (byte[]) sRuntime.newNonMovableArray(byte.class, len + 1);
             readFully(tmp, 0, len);
-            return CharsetUtils.fromModifiedUtf8Bytes(mRuntime.addressOf(tmp), 0, len);
+            return CharsetUtils.fromModifiedUtf8Bytes(sRuntime.addressOf(tmp), 0, len);
         }
     }
 }
diff --git a/core/java/com/android/internal/util/ArtFastDataOutput.java b/core/java/com/android/internal/util/ArtFastDataOutput.java
index ac595b6fd151..360ddb814aa2 100644
--- a/core/java/com/android/internal/util/ArtFastDataOutput.java
+++ b/core/java/com/android/internal/util/ArtFastDataOutput.java
@@ -21,6 +21,8 @@ import android.util.CharsetUtils;
 
 import com.android.modules.utils.FastDataOutput;
 
+import dalvik.system.VMRuntime;
+
 import java.io.DataOutput;
 import java.io.IOException;
 import java.io.OutputStream;
@@ -35,13 +37,14 @@ import java.util.concurrent.atomic.AtomicReference;
  */
 public class ArtFastDataOutput extends FastDataOutput {
     private static AtomicReference<ArtFastDataOutput> sOutCache = new AtomicReference<>();
+    private static VMRuntime sRuntime = VMRuntime.getRuntime();
 
     private final long mBufferPtr;
 
     public ArtFastDataOutput(@NonNull OutputStream out, int bufferSize) {
         super(out, bufferSize);
 
-        mBufferPtr = mRuntime.addressOf(mBuffer);
+        mBufferPtr = sRuntime.addressOf(mBuffer);
     }
 
     /**
@@ -72,6 +75,11 @@ public class ArtFastDataOutput extends FastDataOutput {
         }
     }
 
+    @Override
+    public byte[] newByteArray(int bufferSize) {
+        return (byte[]) sRuntime.newNonMovableArray(byte.class, bufferSize);
+    }
+
     @Override
     public void writeUTF(String s) throws IOException {
         // Attempt to write directly to buffer space if there's enough room,
@@ -94,8 +102,8 @@ public class ArtFastDataOutput extends FastDataOutput {
             // Negative value indicates buffer was too small and we need to
             // allocate a temporary buffer for encoding
             len = -len;
-            final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);
-            CharsetUtils.toModifiedUtf8Bytes(s, mRuntime.addressOf(tmp), 0, tmp.length);
+            final byte[] tmp = (byte[]) sRuntime.newNonMovableArray(byte.class, len + 1);
+            CharsetUtils.toModifiedUtf8Bytes(s, sRuntime.addressOf(tmp), 0, tmp.length);
             writeShort(len);
             write(tmp, 0, len);
         }
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index fc4ed1d4d527..b9e34ee97f21 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -33,3 +33,10 @@ java_library {
     ],
     visibility: ["//visibility:public"],
 }
+
+java_host_for_device {
+    name: "core-xml-for-device",
+    libs: [
+        "core-xml-for-host",
+    ],
+}
diff --git a/ravenwood/framework-minus-apex-ravenwood-policies.txt b/ravenwood/framework-minus-apex-ravenwood-policies.txt
index 692d598ac2bb..3e54c7a06288 100644
--- a/ravenwood/framework-minus-apex-ravenwood-policies.txt
+++ b/ravenwood/framework-minus-apex-ravenwood-policies.txt
@@ -103,7 +103,21 @@ class android.os.TransactionTooLargeException stubclass
 # Containers
 class android.os.BaseBundle stubclass
 class android.os.Bundle stubclass
+class android.os.PersistableBundle stubclass
 
 # Misc
 class android.os.PatternMatcher stubclass
 class android.os.ParcelUuid stubclass
+
+# XML
+class com.android.internal.util.XmlPullParserWrapper stubclass
+class com.android.internal.util.XmlSerializerWrapper stubclass
+class com.android.internal.util.XmlUtils stubclass
+
+class com.android.modules.utils.BinaryXmlPullParser stubclass
+class com.android.modules.utils.BinaryXmlSerializer stubclass
+class com.android.modules.utils.FastDataInput stubclass
+class com.android.modules.utils.FastDataOutput stubclass
+class com.android.modules.utils.ModifiedUtf8 stubclass
+class com.android.modules.utils.TypedXmlPullParser stubclass
+class com.android.modules.utils.TypedXmlSerializer stubclass
diff --git a/ravenwood/ravenwood-annotation-allowed-classes.txt b/ravenwood/ravenwood-annotation-allowed-classes.txt
index 930dfc967cf3..1ac6bf0a7c4d 100644
--- a/ravenwood/ravenwood-annotation-allowed-classes.txt
+++ b/ravenwood/ravenwood-annotation-allowed-classes.txt
@@ -2,6 +2,8 @@
 
 com.android.internal.util.ArrayUtils
 
+android.util.Xml
+
 android.os.Binder
 android.os.Binder$IdentitySupplier
 android.os.IBinder
diff --git a/tools/hoststubgen/hoststubgen/Android.bp b/tools/hoststubgen/hoststubgen/Android.bp
index fd4ec8bd5931..5949bca2f9a3 100644
--- a/tools/hoststubgen/hoststubgen/Android.bp
+++ b/tools/hoststubgen/hoststubgen/Android.bp
@@ -284,6 +284,9 @@ java_library {
         "hoststubgen-helper-runtime.ravenwood",
         "framework-minus-apex.ravenwood",
     ],
+    static_libs: [
+        "core-xml-for-device",
+    ],
 }
 
 // Defaults for host side test modules.
-- 
GitLab