10e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root/*
20e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * Copyright (C) 2011 The Android Open Source Project
30e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *
40e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * Licensed under the Apache License, Version 2.0 (the "License");
50e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * you may not use this file except in compliance with the License.
60e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * You may obtain a copy of the License at
70e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *
80e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *      http://www.apache.org/licenses/LICENSE-2.0
90e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *
100e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * Unless required by applicable law or agreed to in writing, software
110e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * distributed under the License is distributed on an "AS IS" BASIS,
120e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
130e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * See the License for the specific language governing permissions and
140e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * limitations under the License.
150e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root */
160e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
170e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootpackage android.content.pm;
180e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
19d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackbornimport android.os.Binder;
20d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackbornimport android.os.IBinder;
210e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootimport android.os.Parcel;
220e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootimport android.os.Parcelable;
23d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackbornimport android.os.RemoteException;
24d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackbornimport android.util.Log;
250e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
26d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackbornimport java.util.ArrayList;
270e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootimport java.util.List;
280e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
290e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root/**
30d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn * Transfer a large list of Parcelable objects across an IPC.  Splits into
31d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn * multiple transactions if needed.
320e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root *
330e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root * @hide
340e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root */
350e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Rootpublic class ParceledListSlice<T extends Parcelable> implements Parcelable {
36d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    private static String TAG = "ParceledListSlice";
37d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    private static boolean DEBUG = false;
38d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn
390e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    /*
400e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * TODO get this number from somewhere else. For now set it to a quarter of
410e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * the 1MB limit.
420e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     */
430e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    private static final int MAX_IPC_SIZE = 256 * 1024;
44d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    private static final int MAX_FIRST_IPC_SIZE = MAX_IPC_SIZE / 2;
450e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
46d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    private final List<T> mList;
470e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
48d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    public ParceledListSlice(List<T> list) {
49d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        mList = list;
50d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    }
510e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
52d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    private ParceledListSlice(Parcel p, ClassLoader loader) {
53d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        final int N = p.readInt();
54d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        mList = new ArrayList<T>(N);
55d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
56d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        if (N <= 0) {
57d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            return;
58d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        }
59d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        Parcelable.Creator<T> creator = p.readParcelableCreator(loader);
60d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        int i = 0;
61d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        while (i < N) {
62d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            if (p.readInt() == 0) {
63d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                break;
64d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            }
65d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            mList.add(p.readCreator(creator, loader));
66d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
67d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            i++;
68d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        }
69d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        if (i >= N) {
70d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            return;
71d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        }
72d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        final IBinder retriever = p.readStrongBinder();
73d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        while (i < N) {
74d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
75d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            Parcel data = Parcel.obtain();
76d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            Parcel reply = Parcel.obtain();
77d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            data.writeInt(i);
78d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            try {
79d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
80d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            } catch (RemoteException e) {
81d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
82d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                return;
83d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            }
84d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            while (i < N && reply.readInt() != 0) {
85d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                mList.add(reply.readCreator(creator, loader));
86d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
87d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                i++;
88d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            }
89d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            reply.recycle();
90d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            data.recycle();
91d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        }
920e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
930e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
94d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    public List<T> getList() {
95d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        return mList;
960e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
970e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
980e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    @Override
990e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public int describeContents() {
100d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        int contents = 0;
101d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        for (int i=0; i<mList.size(); i++) {
102d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            contents |= mList.get(i).describeContents();
103d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        }
104d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        return contents;
1050e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
1060e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1070e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    /**
1080e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * Write this to another Parcel. Note that this discards the internal Parcel
1090e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * and should not be used anymore. This is so we can pass this to a Binder
1100e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     * where we won't have a chance to call recycle on this.
1110e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root     */
1120e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    @Override
1130e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    public void writeToParcel(Parcel dest, int flags) {
114d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        final int N = mList.size();
115d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        final int callFlags = flags;
116d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        dest.writeInt(N);
117d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        if (DEBUG) Log.d(TAG, "Writing " + N + " items");
118d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        if (N > 0) {
119d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            dest.writeParcelableCreator(mList.get(0));
120d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            int i = 0;
121d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            while (i < N && dest.dataSize() < MAX_FIRST_IPC_SIZE) {
122d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                dest.writeInt(1);
123d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                mList.get(i).writeToParcel(dest, callFlags);
124d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
125d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                i++;
126d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            }
127d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            if (i < N) {
128d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                dest.writeInt(0);
129d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                Binder retriever = new Binder() {
130d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                    @Override
131d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                    protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
132d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                            throws RemoteException {
133d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        if (code != FIRST_CALL_TRANSACTION) {
134d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                            return super.onTransact(code, data, reply, flags);
135d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        }
136d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        int i = data.readInt();
137d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
138d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
139d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                            reply.writeInt(1);
140d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                            mList.get(i).writeToParcel(reply, callFlags);
141d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                            if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
142d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                            i++;
143d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        }
144d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        if (i < N) {
145d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                            if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
146d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                            reply.writeInt(0);
147d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        }
148d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                        return true;
149d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                    }
150d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                };
151d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
152d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn                dest.writeStrongBinder(retriever);
153d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            }
1540e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        }
1550e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    }
1560e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1570e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    @SuppressWarnings("unchecked")
158d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn    public static final Parcelable.ClassLoaderCreator<ParceledListSlice> CREATOR =
159d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            new Parcelable.ClassLoaderCreator<ParceledListSlice>() {
1600e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        public ParceledListSlice createFromParcel(Parcel in) {
161d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            return new ParceledListSlice(in, null);
162d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        }
1630e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
164d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        @Override
165d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn        public ParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
166d8e1dbb6bc1fbaf4f2e38c3ba92ced94270deaacDianne Hackborn            return new ParceledListSlice(in, loader);
1670e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        }
1680e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root
1690e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        public ParceledListSlice[] newArray(int size) {
1700e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root            return new ParceledListSlice[size];
1710e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root        }
1720e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root    };
1730e2c0f37d98bb5539b0fe41865aaf1add0ff1bb3Kenny Root}
174