From abaa0695c5361b36a7a2cdbe87c77bf60be20af7 Mon Sep 17 00:00:00 2001 From: Robin Lee Date: Mon, 20 Feb 2017 20:54:22 +0000 Subject: [PATCH] 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 --- .../content/pm/BaseParceledListSlice.java | 201 ++++++++++++++++++ .../android/content/pm/ParceledListSlice.java | 173 ++------------- .../content/pm/StringParceledListSlice.aidl | 19 ++ .../content/pm/StringParceledListSlice.java | 83 ++++++++ .../internal/util/ParcelableString.java | 52 ----- .../content/pm/ParceledListSliceTest.java | 22 ++ .../android/security/IKeyChainService.aidl | 6 +- .../DevicePolicyManagerService.java | 1 - .../MonitoringCertNotificationTask.java | 8 +- .../devicepolicy/DevicePolicyManagerTest.java | 28 +-- 10 files changed, 360 insertions(+), 233 deletions(-) create mode 100644 core/java/android/content/pm/BaseParceledListSlice.java create mode 100644 core/java/android/content/pm/StringParceledListSlice.aidl create mode 100644 core/java/android/content/pm/StringParceledListSlice.java delete mode 100644 core/java/com/android/internal/util/ParcelableString.java diff --git a/core/java/android/content/pm/BaseParceledListSlice.java b/core/java/android/content/pm/BaseParceledListSlice.java new file mode 100644 index 0000000000000..c4e4e06be7497 --- /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 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 mList; + + public BaseParceledListSlice(List list) { + mList = list; + } + + @SuppressWarnings("unchecked") + BaseParceledListSlice(Parcel p, ClassLoader loader) { + final int N = p.readInt(); + mList = new ArrayList(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 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 945858e6d3c65..d12e8846aabbd 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 @@ 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. + * @see BaseParceledListSlice * * @hide */ -public class ParceledListSlice implements Parcelable { - private static String TAG = "ParceledListSlice"; - private static boolean DEBUG = false; +public class ParceledListSlice extends BaseParceledListSlice { + public ParceledListSlice(List 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 mList; + private ParceledListSlice(Parcel in, ClassLoader loader) { + super(in, loader); + } public static ParceledListSlice emptyList() { return new ParceledListSlice(Collections. emptyList()); } - public ParceledListSlice(List list) { - mList = list; - } - - @SuppressWarnings("unchecked") - private ParceledListSlice(Parcel p, ClassLoader loader) { - final int N = p.readInt(); - mList = new ArrayList(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 getList() { - return mList; - } - @Override public int describeContents() { int contents = 0; - for (int i=0; i list = getList(); + for (int i=0; i 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 @@ public class ParceledListSlice implements Parcelable { 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 0000000000000..345f3a7b5e3e2 --- /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 0000000000000..95407449a0183 --- /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 { + public StringParceledListSlice(List list) { + super(list); + } + + private StringParceledListSlice(Parcel in, ClassLoader loader) { + super(in, loader); + } + + public static StringParceledListSlice emptyList() { + return new StringParceledListSlice(Collections. 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 CREATOR = + new Parcelable.ClassLoaderCreator() { + 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 6bd856f5521de..0000000000000 --- 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 CREATOR = - new Parcelable.Creator() { - @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 e5a92bf23bdc7..5dd3c2ce6b5d1 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 class ParceledListSliceTest extends TestCase { } } + public void testStringList() throws Exception { + final int objectCount = 400; + List list = new ArrayList(); + 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 deea9726403ff..b68543146a511 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 @@ interface IKeyChainService { // 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 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 14b1741346b9b..d715ef1f275dd 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.logging.MetricsLogger; 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 03c137a95b85a..fb95f8e4d9199 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.security.KeyChain.KeyChainConnection; 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 @@ public class MonitoringCertNotificationTask extends AsyncTask getInstalledCaCertificates(UserHandle userHandle) throws RemoteException, RuntimeException { try (KeyChainConnection conn = mInjector.keyChainBindAsUser(userHandle)) { - List aliases = conn.getService().getUserCaAliases().getList(); - List 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 d65a9bfbf8973..756514bbecc40 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.ServiceConnection; 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.ArraySet; 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 @@ public class DevicePolicyManagerTest extends DpmTestBase { mContext.userContexts.put(user, mContext); when(mContext.resources.getColor(anyInt(), anyObject())).thenReturn(Color.WHITE); - ParceledListSlice oneCert = asSlice(new String[] {"1"}); - ParceledListSlice 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 @@ public class DevicePolicyManagerTest extends DpmTestBase { // 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 @@ public class DevicePolicyManagerTest extends DpmTestBase { // 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 @@ public class DevicePolicyManagerTest extends DpmTestBase { } /** - * Convert String[] to ParceledListSlice<ParcelableString>. - *

- * 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 asSlice(String[] s) { - List 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(list); + private static StringParceledListSlice asSlice(String[] s) { + return new StringParceledListSlice(Arrays.asList(s)); } }