14501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki/*
24501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * Copyright (C) 2017 The Android Open Source Project
34501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki *
44501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * Licensed under the Apache License, Version 2.0 (the "License");
54501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * you may not use this file except in compliance with the License.
64501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * You may obtain a copy of the License at
74501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki *
84501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki *      http://www.apache.org/licenses/LICENSE-2.0
94501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki *
104501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * Unless required by applicable law or agreed to in writing, software
114501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * distributed under the License is distributed on an "AS IS" BASIS,
124501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
134501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * See the License for the specific language governing permissions and
144501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * limitations under the License.
154501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki */
164501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
174501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onukipackage android.content.pm;
184501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
194501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onukiimport android.os.Parcel;
204501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onukiimport android.util.Log;
214501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
224501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onukiimport java.util.ArrayList;
234501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onukiimport java.util.HashMap;
244501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
254501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki/**
264501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * Helper classes to read from and write to Parcel with pooled strings.
274501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki *
284501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki * @hide
294501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki */
304501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onukipublic class PackageParserCacheHelper {
314501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    private PackageParserCacheHelper() {
324501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    }
334501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
344501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    private static final String TAG = "PackageParserCacheHelper";
354501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    private static final boolean DEBUG = false;
364501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
374501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    /**
384501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki     * Parcel read helper with a string pool.
394501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki     */
404501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    public static class ReadHelper extends Parcel.ReadWriteHelper {
414501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        private final ArrayList<String> mStrings = new ArrayList<>();
424501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
434501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        private final Parcel mParcel;
444501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
454501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        public ReadHelper(Parcel p) {
464501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel = p;
474501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        }
484501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
494501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        /**
504501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * Prepare to read from a parcel, and install itself as a read-write helper.
514501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         *
524501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * (We don't do it in the constructor to avoid calling methods before the constructor
534501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * finishes.)
544501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         */
554501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        public void startAndInstall() {
564501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mStrings.clear();
574501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
584501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            final int poolPosition = mParcel.readInt();
594501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            final int startPosition = mParcel.dataPosition();
604501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
614501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            // The pool is at the end of the parcel.
624501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.setDataPosition(poolPosition);
634501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.readStringList(mStrings);
644501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
654501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            // Then move back.
664501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.setDataPosition(startPosition);
674501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
684501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            if (DEBUG) {
694501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                Log.i(TAG, "Read " + mStrings.size() + " strings");
704501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                for (int i = 0; i < mStrings.size(); i++) {
714501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                    Log.i(TAG, "  " + i + ": \"" + mStrings.get(i) + "\"");
724501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                }
734501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            }
744501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
754501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.setReadWriteHelper(this);
764501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        }
774501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
784501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        /**
794501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * Read an string index from a parcel, and returns the corresponding string from the pool.
804501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         */
814501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        @Override
824501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        public String readString(Parcel p) {
834501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            return mStrings.get(p.readInt());
844501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        }
854501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    }
864501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
874501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    /**
884501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki     * Parcel write helper with a string pool.
894501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki     */
904501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    public static class WriteHelper extends Parcel.ReadWriteHelper {
914501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        private final ArrayList<String> mStrings = new ArrayList<>();
924501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
934501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        private final HashMap<String, Integer> mIndexes = new HashMap<>();
944501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
954501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        private final Parcel mParcel;
964501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        private final int mStartPos;
974501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
984501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        /**
994501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * Constructor.  Prepare a parcel, and install it self as a read-write helper.
1004501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         */
1014501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        public WriteHelper(Parcel p) {
1024501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel = p;
1034501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mStartPos = p.dataPosition();
1044501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.writeInt(0); // We come back later here and write the pool position.
1054501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
1064501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.setReadWriteHelper(this);
1074501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        }
1084501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
1094501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        /**
1104501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * Instead of writing a string directly to a parcel, this method adds it to the pool,
1114501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * and write the index in the pool to the parcel.
1124501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         */
1134501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        @Override
1144501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        public void writeString(Parcel p, String s) {
1154501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            final Integer cur = mIndexes.get(s);
1164501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            if (cur != null) {
1174501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                // String already in the pool. Just write the index.
1184501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                p.writeInt(cur); // Already in the pool.
1194501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                if (DEBUG) {
1204501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                    Log.i(TAG, "Duplicate '" + s + "' at " + cur);
1214501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                }
1224501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            } else {
1234501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                // Not in the pool. Add to the pool, and write the index.
1244501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                final int index = mStrings.size();
1254501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                mIndexes.put(s, index);
1264501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                mStrings.add(s);
1274501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
1284501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                if (DEBUG) {
1294501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                    Log.i(TAG, "New '" + s + "' at " + index);
1304501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                }
1314501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
1324501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                p.writeInt(index);
1334501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            }
1344501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        }
1354501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
1364501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        /**
1374501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * Closes a parcel by appending the string pool at the end and updating the pool offset,
1384501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         * which it assumes is at the first byte.  It also uninstalls itself as a read-write helper.
1394501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki         */
1404501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        public void finishAndUninstall() {
1414501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            // Uninstall first, so that writeStringList() uses the native writeString.
1424501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.setReadWriteHelper(null);
1434501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
1444501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            final int poolPosition = mParcel.dataPosition();
1454501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.writeStringList(mStrings);
1464501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
1474501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.setDataPosition(mStartPos);
1484501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.writeInt(poolPosition);
1494501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki
1504501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            // Move back to the end.
1514501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            mParcel.setDataPosition(mParcel.dataSize());
1524501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            if (DEBUG) {
1534501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki                Log.i(TAG, "Wrote " + mStrings.size() + " strings");
1544501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki            }
1554501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki        }
1564501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki    }
1574501c61d65f0590bdc4e6a8a6f3a1b0cf2165b9fMakoto Onuki}
158