1abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee/* 2abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * Copyright (C) 2011 The Android Open Source Project 3abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * 4abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * Licensed under the Apache License, Version 2.0 (the "License"); 5abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * you may not use this file except in compliance with the License. 6abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * You may obtain a copy of the License at 7abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * 8abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * http://www.apache.org/licenses/LICENSE-2.0 9abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * 10abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * Unless required by applicable law or agreed to in writing, software 11abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * distributed under the License is distributed on an "AS IS" BASIS, 12abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * See the License for the specific language governing permissions and 14abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * limitations under the License. 15abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee */ 16abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 17abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leepackage android.content.pm; 18abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 19abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeimport android.os.Binder; 20abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeimport android.os.IBinder; 21abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeimport android.os.Parcel; 22abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeimport android.os.Parcelable; 23abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeimport android.os.RemoteException; 24abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeimport android.util.Log; 25abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 26abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeimport java.util.ArrayList; 27abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeimport java.util.List; 28abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 29abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee/** 30abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * Transfer a large list of Parcelable objects across an IPC. Splits into 31abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * multiple transactions if needed. 32abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * 33abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * Caveat: for efficiency and security, all elements must be the same concrete type. 34abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * In order to avoid writing the class name of each object, we must ensure that 35abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * each object is the same type, or else unparceling then reparceling the data may yield 36abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * a different result if the class name encoded in the Parcelable is a Base type. 37abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * See b/17671747. 38abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * 39abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * @hide 40abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee */ 41abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Leeabstract class BaseParceledListSlice<T> implements Parcelable { 42abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee private static String TAG = "ParceledListSlice"; 43abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee private static boolean DEBUG = false; 44abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 45abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee /* 46abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * TODO get this number from somewhere else. For now set it to a quarter of 47abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * the 1MB limit. 48abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee */ 49abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee private static final int MAX_IPC_SIZE = IBinder.MAX_IPC_SIZE; 50abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 51abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee private final List<T> mList; 52abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 533f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn private int mInlineCountLimit = Integer.MAX_VALUE; 543f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn 55abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee public BaseParceledListSlice(List<T> list) { 56abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee mList = list; 57abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 58abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 59abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee @SuppressWarnings("unchecked") 60abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee BaseParceledListSlice(Parcel p, ClassLoader loader) { 61abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final int N = p.readInt(); 62abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee mList = new ArrayList<T>(N); 63abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Retrieving " + N + " items"); 64abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (N <= 0) { 65abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee return; 66abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 67abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 68abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee Parcelable.Creator<?> creator = readParcelableCreator(p, loader); 69abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee Class<?> listElementClass = null; 70abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 71abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee int i = 0; 72abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee while (i < N) { 73abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (p.readInt() == 0) { 74abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee break; 75abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 76abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 77abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final T parcelable = readCreator(creator, p, loader); 78abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (listElementClass == null) { 79abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee listElementClass = parcelable.getClass(); 80abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } else { 81abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee verifySameType(listElementClass, parcelable.getClass()); 82abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 83abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 84abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee mList.add(parcelable); 85abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 86abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1)); 87abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee i++; 88abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 89abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (i >= N) { 90abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee return; 91abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 92abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final IBinder retriever = p.readStrongBinder(); 93abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee while (i < N) { 94abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever); 95abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee Parcel data = Parcel.obtain(); 96abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee Parcel reply = Parcel.obtain(); 97abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee data.writeInt(i); 98abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee try { 99abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0); 100abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } catch (RemoteException e) { 101abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e); 102abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee return; 103abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 104abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee while (i < N && reply.readInt() != 0) { 105abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final T parcelable = reply.readCreator(creator, loader); 106abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee verifySameType(listElementClass, parcelable.getClass()); 107abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 108abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee mList.add(parcelable); 109abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 110abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1)); 111abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee i++; 112abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 113abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee reply.recycle(); 114abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee data.recycle(); 115abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 116abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 117abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 118abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee private T readCreator(Parcelable.Creator<?> creator, Parcel p, ClassLoader loader) { 119abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (creator instanceof Parcelable.ClassLoaderCreator<?>) { 120abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee Parcelable.ClassLoaderCreator<?> classLoaderCreator = 121abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee (Parcelable.ClassLoaderCreator<?>) creator; 122abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee return (T) classLoaderCreator.createFromParcel(p, loader); 123abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 124abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee return (T) creator.createFromParcel(p); 125abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 126abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 127abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee private static void verifySameType(final Class<?> expected, final Class<?> actual) { 128abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (!actual.equals(expected)) { 129abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee throw new IllegalArgumentException("Can't unparcel type " 130abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee + actual.getName() + " in list of type " 131abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee + expected.getName()); 132abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 133abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 134abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 135abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee public List<T> getList() { 136abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee return mList; 137abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 138abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 139abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee /** 1403f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn * Set a limit on the maximum number of entries in the array that will be included 1413f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn * inline in the initial parcelling of this object. 1423f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn */ 1433f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn public void setInlineCountLimit(int maxCount) { 1443f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn mInlineCountLimit = maxCount; 1453f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn } 1463f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn 1473f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn /** 148abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * Write this to another Parcel. Note that this discards the internal Parcel 149abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * and should not be used anymore. This is so we can pass this to a Binder 150abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee * where we won't have a chance to call recycle on this. 151abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee */ 152abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee @Override 153abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee public void writeToParcel(Parcel dest, int flags) { 154abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final int N = mList.size(); 155abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final int callFlags = flags; 156abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee dest.writeInt(N); 157abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Writing " + N + " items"); 158abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (N > 0) { 159abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final Class<?> listElementClass = mList.get(0).getClass(); 160abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee writeParcelableCreator(mList.get(0), dest); 161abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee int i = 0; 1623f7c9f2d0164f2b5826c194e9309791637f35c2cDianne Hackborn while (i < N && i < mInlineCountLimit && dest.dataSize() < MAX_IPC_SIZE) { 163abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee dest.writeInt(1); 164abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 165abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final T parcelable = mList.get(i); 166abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee verifySameType(listElementClass, parcelable.getClass()); 167abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee writeElement(parcelable, dest, callFlags); 168abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 169abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i)); 170abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee i++; 171abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 172abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (i < N) { 173abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee dest.writeInt(0); 174abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee Binder retriever = new Binder() { 175abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee @Override 176abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee protected boolean onTransact(int code, Parcel data, Parcel reply, int flags) 177abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee throws RemoteException { 178abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (code != FIRST_CALL_TRANSACTION) { 179abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee return super.onTransact(code, data, reply, flags); 180abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 181abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee int i = data.readInt(); 182abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N); 183abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee while (i < N && reply.dataSize() < MAX_IPC_SIZE) { 184abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee reply.writeInt(1); 185abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 186abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee final T parcelable = mList.get(i); 187abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee verifySameType(listElementClass, parcelable.getClass()); 188abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee writeElement(parcelable, reply, callFlags); 189abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 190abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i)); 191abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee i++; 192abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 193abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (i < N) { 194abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N); 195abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee reply.writeInt(0); 196abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 197abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee return true; 198abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 199abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee }; 200abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever); 201abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee dest.writeStrongBinder(retriever); 202abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 203abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 204abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee } 205abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 206abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee protected abstract void writeElement(T parcelable, Parcel reply, int callFlags); 207abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 208abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee protected abstract void writeParcelableCreator(T parcelable, Parcel dest); 209abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee 210abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee protected abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, ClassLoader loader); 211abaa0695c5361b36a7a2cdbe87c77bf60be20af7Robin Lee} 212