• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package android.content.pm;
18 
19 import android.os.Parcel;
20 import android.util.Log;
21 
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 
25 /**
26  * Helper classes to read from and write to Parcel with pooled strings.
27  *
28  * @hide
29  */
30 public class PackageParserCacheHelper {
PackageParserCacheHelper()31     private PackageParserCacheHelper() {
32     }
33 
34     private static final String TAG = "PackageParserCacheHelper";
35     private static final boolean DEBUG = false;
36 
37     /**
38      * Parcel read helper with a string pool.
39      */
40     public static class ReadHelper extends Parcel.ReadWriteHelper {
41         private final ArrayList<String> mStrings = new ArrayList<>();
42 
43         private final Parcel mParcel;
44 
ReadHelper(Parcel p)45         public ReadHelper(Parcel p) {
46             mParcel = p;
47         }
48 
49         /**
50          * Prepare to read from a parcel, and install itself as a read-write helper.
51          *
52          * (We don't do it in the constructor to avoid calling methods before the constructor
53          * finishes.)
54          */
startAndInstall()55         public void startAndInstall() {
56             mStrings.clear();
57 
58             final int poolPosition = mParcel.readInt();
59             if (poolPosition < 0) {
60                 throw new IllegalStateException("Invalid string pool position: " + poolPosition);
61             }
62             final int startPosition = mParcel.dataPosition();
63 
64             // The pool is at the end of the parcel.
65             mParcel.setDataPosition(poolPosition);
66             mParcel.readStringList(mStrings);
67 
68             // Then move back.
69             mParcel.setDataPosition(startPosition);
70 
71             if (DEBUG) {
72                 Log.i(TAG, "Read " + mStrings.size() + " strings");
73                 for (int i = 0; i < mStrings.size(); i++) {
74                     Log.i(TAG, "  " + i + ": \"" + mStrings.get(i) + "\"");
75                 }
76             }
77 
78             mParcel.setReadWriteHelper(this);
79         }
80 
81         /**
82          * Read an string index from a parcel, and returns the corresponding string from the pool.
83          */
readString(Parcel p)84         public String readString(Parcel p) {
85             return mStrings.get(p.readInt());
86         }
87 
88         @Override
readString8(Parcel p)89         public String readString8(Parcel p) {
90             return readString(p);
91         }
92 
93         @Override
readString16(Parcel p)94         public String readString16(Parcel p) {
95             return readString(p);
96         }
97     }
98 
99     /**
100      * Parcel write helper with a string pool.
101      */
102     public static class WriteHelper extends Parcel.ReadWriteHelper {
103         private final ArrayList<String> mStrings = new ArrayList<>();
104 
105         private final HashMap<String, Integer> mIndexes = new HashMap<>();
106 
107         private final Parcel mParcel;
108         private final int mStartPos;
109 
110         /**
111          * Constructor.  Prepare a parcel, and install it self as a read-write helper.
112          */
WriteHelper(Parcel p)113         public WriteHelper(Parcel p) {
114             mParcel = p;
115             mStartPos = p.dataPosition();
116             mParcel.writeInt(0); // We come back later here and write the pool position.
117 
118             mParcel.setReadWriteHelper(this);
119         }
120 
121         /**
122          * Instead of writing a string directly to a parcel, this method adds it to the pool,
123          * and write the index in the pool to the parcel.
124          */
writeString(Parcel p, String s)125         public void writeString(Parcel p, String s) {
126             final Integer cur = mIndexes.get(s);
127             if (cur != null) {
128                 // String already in the pool. Just write the index.
129                 p.writeInt(cur); // Already in the pool.
130                 if (DEBUG) {
131                     Log.i(TAG, "Duplicate '" + s + "' at " + cur);
132                 }
133             } else {
134                 // Not in the pool. Add to the pool, and write the index.
135                 final int index = mStrings.size();
136                 mIndexes.put(s, index);
137                 mStrings.add(s);
138 
139                 if (DEBUG) {
140                     Log.i(TAG, "New '" + s + "' at " + index);
141                 }
142 
143                 p.writeInt(index);
144             }
145         }
146 
147         @Override
writeString8(Parcel p, String s)148         public void writeString8(Parcel p, String s) {
149             writeString(p, s);
150         }
151 
152         @Override
writeString16(Parcel p, String s)153         public void writeString16(Parcel p, String s) {
154             writeString(p, s);
155         }
156 
157         /**
158          * Closes a parcel by appending the string pool at the end and updating the pool offset,
159          * which it assumes is at the first byte.  It also uninstalls itself as a read-write helper.
160          */
finishAndUninstall()161         public void finishAndUninstall() {
162             // Uninstall first, so that writeStringList() uses the native writeString.
163             mParcel.setReadWriteHelper(null);
164 
165             final int poolPosition = mParcel.dataPosition();
166             mParcel.writeStringList(mStrings);
167 
168             mParcel.setDataPosition(mStartPos);
169             mParcel.writeInt(poolPosition);
170 
171             // Move back to the end.
172             mParcel.setDataPosition(mParcel.dataSize());
173             if (DEBUG) {
174                 Log.i(TAG, "Wrote " + mStrings.size() + " strings");
175             }
176         }
177     }
178 }
179