Delete ParcelableString, add StringParceledListSlice

Both inherit from package private BaseParceledListSlice.

This is still bad, but it's not as bad. The existing code that uses
this can just do Foo.bar().getList() now instead of having to marshal
to and from an oddball type at either end as well.

In the longer term ParceledListSlice<> should be eliminated, but it's
not clear how far into the future that is going to happen.

Test: runtest -x services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
Test: runtest -x core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
Change-Id: Ie69b96b5215d6e04990f6d31345772cdfee21d78
diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java
new file mode 100644
index 0000000..c4e4e06
--- /dev/null
+++ b/core/java/android/content/pm/BaseParceledListSlice.java
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.os.RemoteException;
+import android.util.Log;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * Transfer a large list of Parcelable objects across an IPC.  Splits into
+ * multiple transactions if needed.
+ *
+ * Caveat: for efficiency and security, all elements must be the same concrete type.
+ * In order to avoid writing the class name of each object, we must ensure that
+ * each object is the same type, or else unparceling then reparceling the data may yield
+ * a different result if the class name encoded in the Parcelable is a Base type.
+ * See b/17671747.
+ *
+ * @hide
+ */
+abstract class BaseParceledListSlice<T> implements Parcelable {
+    private static String TAG = "ParceledListSlice";
+    private static boolean DEBUG = false;
+
+    /*
+     * TODO get this number from somewhere else. For now set it to a quarter of
+     * the 1MB limit.
+     */
+    private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
+
+    private final List<T> mList;
+
+    public BaseParceledListSlice(List<T> list) {
+        mList = list;
+    }
+
+    @SuppressWarnings("unchecked")
+    BaseParceledListSlice(Parcel p, ClassLoader loader) {
+        final int N = p.readInt();
+        mList = new ArrayList<T>(N);
+        if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
+        if (N <= 0) {
+            return;
+        }
+
+        Parcelable.Creator<?> creator = readParcelableCreator(p, loader);
+        Class<?> listElementClass = null;
+
+        int i = 0;
+        while (i < N) {
+            if (p.readInt() == 0) {
+                break;
+            }
+
+            final T parcelable = readCreator(creator, p, loader);
+            if (listElementClass == null) {
+                listElementClass = parcelable.getClass();
+            } else {
+                verifySameType(listElementClass, parcelable.getClass());
+            }
+
+            mList.add(parcelable);
+
+            if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
+            i++;
+        }
+        if (i >= N) {
+            return;
+        }
+        final IBinder retriever = p.readStrongBinder();
+        while (i < N) {
+            if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
+            Parcel data = Parcel.obtain();
+            Parcel reply = Parcel.obtain();
+            data.writeInt(i);
+            try {
+                retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
+            } catch (RemoteException e) {
+                Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
+                return;
+            }
+            while (i < N && reply.readInt() != 0) {
+                final T parcelable = reply.readCreator(creator, loader);
+                verifySameType(listElementClass, parcelable.getClass());
+
+                mList.add(parcelable);
+
+                if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
+                i++;
+            }
+            reply.recycle();
+            data.recycle();
+        }
+    }
+
+    private T readCreator(Parcelable.Creator<?> creator, Parcel p, ClassLoader loader) {
+        if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
+            Parcelable.ClassLoaderCreator<?> classLoaderCreator =
+                    (Parcelable.ClassLoaderCreator<?>) creator;
+            return (T) classLoaderCreator.createFromParcel(p, loader);
+        }
+        return (T) creator.createFromParcel(p);
+    }
+
+    private static void verifySameType(final Class<?> expected, final Class<?> actual) {
+        if (!actual.equals(expected)) {
+            throw new IllegalArgumentException("Can't unparcel type "
+                    + actual.getName() + " in list of type "
+                    + expected.getName());
+        }
+    }
+
+    public List<T> getList() {
+        return mList;
+    }
+
+    /**
+     * Write this to another Parcel. Note that this discards the internal Parcel
+     * and should not be used anymore. This is so we can pass this to a Binder
+     * where we won't have a chance to call recycle on this.
+     */
+    @Override
+    public void writeToParcel(Parcel dest, int flags) {
+        final int N = mList.size();
+        final int callFlags = flags;
+        dest.writeInt(N);
+        if (DEBUG) Log.d(TAG, "Writing " + N + " items");
+        if (N > 0) {
+            final Class<?> listElementClass = mList.get(0).getClass();
+            writeParcelableCreator(mList.get(0), dest);
+            int i = 0;
+            while (i < N && dest.dataSize() < MAX_IPC_SIZE) {
+                dest.writeInt(1);
+
+                final T parcelable = mList.get(i);
+                verifySameType(listElementClass, parcelable.getClass());
+                writeElement(parcelable, dest, callFlags);
+
+                if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
+                i++;
+            }
+            if (i < N) {
+                dest.writeInt(0);
+                Binder retriever = new Binder() {
+                    @Override
+                    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
+                            throws RemoteException {
+                        if (code != FIRST_CALL_TRANSACTION) {
+                            return super.onTransact(code, data, reply, flags);
+                        }
+                        int i = data.readInt();
+                        if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
+                        while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
+                            reply.writeInt(1);
+
+                            final T parcelable = mList.get(i);
+                            verifySameType(listElementClass, parcelable.getClass());
+                            writeElement(parcelable, reply, callFlags);
+
+                            if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
+                            i++;
+                        }
+                        if (i < N) {
+                            if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
+                            reply.writeInt(0);
+                        }
+                        return true;
+                    }
+                };
+                if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
+                dest.writeStrongBinder(retriever);
+            }
+        }
+    }
+
+    protected abstract void writeElement(T parcelable, Parcel reply, int callFlags);
+
+    protected abstract void writeParcelableCreator(T parcelable, Parcel dest);
+
+    protected abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader);
+}
diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java
index 945858e6..d12e884 100644
--- a/core/java/android/content/pm/ParceledListSlice.java
+++ b/core/java/android/content/pm/ParceledListSlice.java
@@ -16,14 +16,9 @@
 
 package android.content.pm;
 
-import android.os.Binder;
-import android.os.IBinder;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.os.RemoteException;
-import android.util.Log;
 
-import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 
@@ -31,171 +26,46 @@
  * Transfer a large list of Parcelable objects across an IPC.  Splits into
  * multiple transactions if needed.
  *
- * Caveat: for efficiency and security, all elements must be the same concrete type.
- * In order to avoid writing the class name of each object, we must ensure that
- * each object is the same type, or else unparceling then reparceling the data may yield
- * a different result if the class name encoded in the Parcelable is a Base type.
- * See b/17671747.
+ * @see BaseParceledListSlice
  *
  * @hide
  */
-public class ParceledListSlice<T extends Parcelable> implements Parcelable {
-    private static String TAG = "ParceledListSlice";
-    private static boolean DEBUG = false;
+public class ParceledListSlice<T extends Parcelable> extends BaseParceledListSlice<T> {
+    public ParceledListSlice(List<T> list) {
+        super(list);
+    }
 
-    /*
-     * TODO get this number from somewhere else. For now set it to a quarter of
-     * the 1MB limit.
-     */
-    private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE;
-
-    private final List<T> mList;
+    private ParceledListSlice(Parcel in, ClassLoader loader) {
+        super(in, loader);
+    }
 
     public static <T extends Parcelable> ParceledListSlice<T> emptyList() {
         return new ParceledListSlice<T>(Collections.<T> emptyList());
     }
 
-    public ParceledListSlice(List<T> list) {
-        mList = list;
-    }
-
-    @SuppressWarnings("unchecked")
-    private ParceledListSlice(Parcel p, ClassLoader loader) {
-        final int N = p.readInt();
-        mList = new ArrayList<T>(N);
-        if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
-        if (N <= 0) {
-            return;
-        }
-
-        Parcelable.Creator<?> creator = p.readParcelableCreator(loader);
-        Class<?> listElementClass = null;
-
-        int i = 0;
-        while (i < N) {
-            if (p.readInt() == 0) {
-                break;
-            }
-
-            final T parcelable = p.readCreator(creator, loader);
-            if (listElementClass == null) {
-                listElementClass = parcelable.getClass();
-            } else {
-                verifySameType(listElementClass, parcelable.getClass());
-            }
-
-            mList.add(parcelable);
-
-            if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
-            i++;
-        }
-        if (i >= N) {
-            return;
-        }
-        final IBinder retriever = p.readStrongBinder();
-        while (i < N) {
-            if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
-            Parcel data = Parcel.obtain();
-            Parcel reply = Parcel.obtain();
-            data.writeInt(i);
-            try {
-                retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
-            } catch (RemoteException e) {
-                Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
-                return;
-            }
-            while (i < N && reply.readInt() != 0) {
-                final T parcelable = reply.readCreator(creator, loader);
-                verifySameType(listElementClass, parcelable.getClass());
-
-                mList.add(parcelable);
-
-                if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
-                i++;
-            }
-            reply.recycle();
-            data.recycle();
-        }
-    }
-
-    private static void verifySameType(final Class<?> expected, final Class<?> actual) {
-        if (!actual.equals(expected)) {
-            throw new IllegalArgumentException("Can't unparcel type "
-                    + actual.getName() + " in list of type "
-                    + expected.getName());
-        }
-    }
-
-    public List<T> getList() {
-        return mList;
-    }
-
     @Override
     public int describeContents() {
         int contents = 0;
-        for (int i=0; i<mList.size(); i++) {
-            contents |= mList.get(i).describeContents();
+        final List<T> list = getList();
+        for (int i=0; i<list.size(); i++) {
+            contents |= list.get(i).describeContents();
         }
         return contents;
     }
 
-    /**
-     * Write this to another Parcel. Note that this discards the internal Parcel
-     * and should not be used anymore. This is so we can pass this to a Binder
-     * where we won't have a chance to call recycle on this.
-     */
     @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        final int N = mList.size();
-        final int callFlags = flags;
-        dest.writeInt(N);
-        if (DEBUG) Log.d(TAG, "Writing " + N + " items");
-        if (N > 0) {
-            final Class<?> listElementClass = mList.get(0).getClass();
-            dest.writeParcelableCreator(mList.get(0));
-            int i = 0;
-            while (i < N && dest.dataSize() < MAX_IPC_SIZE) {
-                dest.writeInt(1);
+    protected void writeElement(T parcelable, Parcel dest, int callFlags) {
+        parcelable.writeToParcel(dest, callFlags);
+    }
 
-                final T parcelable = mList.get(i);
-                verifySameType(listElementClass, parcelable.getClass());
-                parcelable.writeToParcel(dest, callFlags);
+    @Override
+    protected void writeParcelableCreator(T parcelable, Parcel dest) {
+        dest.writeParcelableCreator((Parcelable) parcelable);
+    }
 
-                if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
-                i++;
-            }
-            if (i < N) {
-                dest.writeInt(0);
-                Binder retriever = new Binder() {
-                    @Override
-                    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
-                            throws RemoteException {
-                        if (code != FIRST_CALL_TRANSACTION) {
-                            return super.onTransact(code, data, reply, flags);
-                        }
-                        int i = data.readInt();
-                        if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
-                        while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
-                            reply.writeInt(1);
-
-                            final T parcelable = mList.get(i);
-                            verifySameType(listElementClass, parcelable.getClass());
-                            parcelable.writeToParcel(reply, callFlags);
-
-                            if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
-                            i++;
-                        }
-                        if (i < N) {
-                            if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
-                            reply.writeInt(0);
-                        }
-                        return true;
-                    }
-                };
-                if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
-                dest.writeStrongBinder(retriever);
-            }
-        }
+    @Override
+    protected Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
+        return from.readParcelableCreator(loader);
     }
 
     @SuppressWarnings("unchecked")
@@ -210,6 +80,7 @@
             return new ParceledListSlice(in, loader);
         }
 
+        @Override
         public ParceledListSlice[] newArray(int size) {
             return new ParceledListSlice[size];
         }
diff --git a/core/java/android/content/pm/StringParceledListSlice.aidl b/core/java/android/content/pm/StringParceledListSlice.aidl
new file mode 100644
index 0000000..345f3a7
--- /dev/null
+++ b/core/java/android/content/pm/StringParceledListSlice.aidl
@@ -0,0 +1,19 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+parcelable StringParceledListSlice;
diff --git a/core/java/android/content/pm/StringParceledListSlice.java b/core/java/android/content/pm/StringParceledListSlice.java
new file mode 100644
index 0000000..9540744
--- /dev/null
+++ b/core/java/android/content/pm/StringParceledListSlice.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.content.pm;
+
+import android.os.Parcel;
+import android.os.Parcelable;
+
+import java.util.Collections;
+import java.util.List;
+
+/**
+ * Transfer a large list of Parcelable objects across an IPC.  Splits into
+ * multiple transactions if needed.
+ *
+ * @see BaseParceledListSlice
+ *
+ * @hide
+ */
+public class StringParceledListSlice extends BaseParceledListSlice<String> {
+    public StringParceledListSlice(List<String> list) {
+        super(list);
+    }
+
+    private StringParceledListSlice(Parcel in, ClassLoader loader) {
+        super(in, loader);
+    }
+
+    public static StringParceledListSlice emptyList() {
+        return new StringParceledListSlice(Collections.<String> emptyList());
+    }
+
+    @Override
+    public int describeContents() {
+        return 0;
+    }
+
+    @Override
+    protected void writeElement(String parcelable, Parcel reply, int callFlags) {
+        reply.writeString(parcelable);
+    }
+
+    @Override
+    protected void writeParcelableCreator(String parcelable, Parcel dest) {
+        return;
+    }
+
+    @Override
+    protected Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader) {
+        return Parcel.STRING_CREATOR;
+    }
+
+    @SuppressWarnings("unchecked")
+    public static final Parcelable.ClassLoaderCreator<StringParceledListSlice> CREATOR =
+            new Parcelable.ClassLoaderCreator<StringParceledListSlice>() {
+        public StringParceledListSlice createFromParcel(Parcel in) {
+            return new StringParceledListSlice(in, null);
+        }
+
+        @Override
+        public StringParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
+            return new StringParceledListSlice(in, loader);
+        }
+
+        @Override
+        public StringParceledListSlice[] newArray(int size) {
+            return new StringParceledListSlice[size];
+        }
+    };
+}
diff --git a/core/java/com/android/internal/util/ParcelableString.java b/core/java/com/android/internal/util/ParcelableString.java
deleted file mode 100644
index 6bd856f..0000000
--- a/core/java/com/android/internal/util/ParcelableString.java
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * Copyright 2014, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.internal.util;
-
-import android.os.Parcel;
-import android.os.Parcelable;
-
-/**
- * Helper class to adapt a simple String to cases where a Parcelable is expected.
- * @hide
- */
-public class ParcelableString implements Parcelable {
-    public String string;
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @Override
-    public void writeToParcel(Parcel out, int flags) {
-        out.writeString(string);
-    }
-
-    public static final Parcelable.Creator<ParcelableString> CREATOR =
-            new Parcelable.Creator<ParcelableString>() {
-                @Override
-                public ParcelableString createFromParcel(Parcel in) {
-                    ParcelableString ret = new ParcelableString();
-                    ret.string = in.readString();
-                    return ret;
-                }
-                @Override
-                public ParcelableString[] newArray(int size) {
-                    return new ParcelableString[size];
-                }
-    };
-}
\ No newline at end of file
diff --git a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
index e5a92bf..5dd3c2c 100644
--- a/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
+++ b/core/tests/coretests/src/android/content/pm/ParceledListSliceTest.java
@@ -91,6 +91,28 @@
         }
     }
 
+    public void testStringList() throws Exception {
+        final int objectCount = 400;
+        List<String> list = new ArrayList<String>();
+        for (long i = 0; i < objectCount; i++) {
+            list.add(Long.toString(i * (6 - i)));
+        }
+
+        StringParceledListSlice slice;
+        Parcel parcel = Parcel.obtain();
+        try {
+            parcel.writeParcelable(new StringParceledListSlice(list), 0);
+            parcel.setDataPosition(0);
+            slice = parcel.readParcelable(getClass().getClassLoader());
+        } finally {
+            parcel.recycle();
+        }
+
+        assertNotNull(slice);
+        assertNotNull(slice.getList());
+        assertEquals(list, slice.getList());
+    }
+
     /**
      * Test that only homogeneous elements may be unparceled.
      */
diff --git a/keystore/java/android/security/IKeyChainService.aidl b/keystore/java/android/security/IKeyChainService.aidl
index deea972..b685431 100644
--- a/keystore/java/android/security/IKeyChainService.aidl
+++ b/keystore/java/android/security/IKeyChainService.aidl
@@ -15,7 +15,7 @@
  */
 package android.security;
 
-import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
 
 /**
  * Caller is required to ensure that {@link KeyStore#unlock
@@ -39,8 +39,8 @@
     // APIs used by Settings
     boolean deleteCaCertificate(String alias);
     boolean reset();
-    ParceledListSlice getUserCaAliases();
-    ParceledListSlice getSystemCaAliases();
+    StringParceledListSlice getUserCaAliases();
+    StringParceledListSlice getSystemCaAliases();
     boolean containsCaAlias(String alias);
     byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem);
     List<String> getCaCertificateChainAliases(String rootAlias, boolean includeDeletedSystem);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 14b1741..d715ef1 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -167,7 +167,6 @@
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
-import com.android.internal.util.ParcelableString;
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java b/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
index 03c137a..fb95f8e 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/MonitoringCertNotificationTask.java
@@ -35,7 +35,6 @@
 import android.util.Log;
 
 import com.android.internal.R;
-import com.android.internal.util.ParcelableString;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -150,12 +149,7 @@
     private List<String> getInstalledCaCertificates(UserHandle userHandle)
             throws RemoteException, RuntimeException {
         try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) {
-            List<ParcelableString> aliases = conn.getService().getUserCaAliases().getList();
-            List<String> result = new ArrayList<>(aliases.size());
-            for (int i = 0; i < aliases.size(); i++) {
-                result.add(aliases.get(i).string);
-            }
-            return result;
+            return conn.getService().getUserCaAliases().getList();
         } catch (InterruptedException e) {
             Thread.currentThread().interrupt();
             return null;
diff --git a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
index d65a9bf..756514b 100644
--- a/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/devicepolicy/DevicePolicyManagerTest.java
@@ -34,7 +34,7 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.ParceledListSlice;
+import android.content.pm.StringParceledListSlice;
 import android.content.res.Resources;
 import android.graphics.Color;
 import android.net.IIpConnectivityMetrics;
@@ -56,7 +56,6 @@
 import android.util.Pair;
 
 import com.android.internal.R;
-import com.android.internal.util.ParcelableString;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
 import com.android.server.SystemService;
@@ -1220,8 +1219,8 @@
         mContext.userContexts.put(user, mContext);
         when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE);
 
-        ParceledListSlice<ParcelableString> oneCert = asSlice(new String[] {"1"});
-        ParceledListSlice<ParcelableString> fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
+        StringParceledListSlice oneCert = asSlice(new String[] {"1"});
+        StringParceledListSlice fourCerts = asSlice(new String[] {"1", "2", "3", "4"});
 
         final String TEST_STRING = "Test for exactly 2 certs out of 4";
         doReturn(TEST_STRING).when(mContext.resources).getQuantityText(anyInt(), eq(2));
@@ -1229,7 +1228,7 @@
         // Given that we have exactly one certificate installed,
         when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(oneCert);
         // when that certificate is approved,
-        dpms.approveCaCert(oneCert.getList().get(0).string, userId, true);
+        dpms.approveCaCert(oneCert.getList().get(0), userId, true);
         // a notification should not be shown.
         verify(mContext.notificationManager, timeout(1000))
                 .cancelAsUser(anyString(), anyInt(), eq(user));
@@ -1237,8 +1236,8 @@
         // Given that we have four certificates installed,
         when(mContext.keyChainConnection.getService().getUserCaAliases()).thenReturn(fourCerts);
         // when two of them are approved (one of them approved twice hence no action),
-        dpms.approveCaCert(fourCerts.getList().get(0).string, userId, true);
-        dpms.approveCaCert(fourCerts.getList().get(1).string, userId, true);
+        dpms.approveCaCert(fourCerts.getList().get(0), userId, true);
+        dpms.approveCaCert(fourCerts.getList().get(1), userId, true);
         // a notification should be shown saying that there are two certificates left to approve.
         verify(mContext.notificationManager, timeout(1000))
                 .notifyAsUser(anyString(), anyInt(), argThat(
@@ -3974,18 +3973,9 @@
     }
 
     /**
-     * Convert String[] to ParceledListSlice&lt;ParcelableString&gt;.
-     * <p>
-     * TODO: This shouldn't be necessary. If ParcelableString does need to exist, it also needs
-     * a real constructor.
+     * Convert String[] to StringParceledListSlice.
      */
-    private static ParceledListSlice<ParcelableString> asSlice(String[] s) {
-        List<ParcelableString> list = new ArrayList<>(s.length);
-        for (int i = 0; i < s.length; i++) {
-            ParcelableString item = new ParcelableString();
-            item.string = s[i];
-            list.add(i, item);
-        }
-        return new ParceledListSlice<ParcelableString>(list);
+    private static StringParceledListSlice asSlice(String[] s) {
+        return new StringParceledListSlice(Arrays.asList(s));
     }
 }