blob: 44def3321c341f0bf53362a458d29ebadc78cfca [file] [log] [blame]
Makoto Onuki4501c61d2017-07-27 15:56:40 -07001/*
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
17package android.content.pm;
18
19import android.os.Parcel;
20import android.util.Log;
21
22import java.util.ArrayList;
23import java.util.HashMap;
24
25/**
26 * Helper classes to read from and write to Parcel with pooled strings.
27 *
28 * @hide
29 */
30public class 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
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 */
55 public void startAndInstall() {
56 mStrings.clear();
57
58 final int poolPosition = mParcel.readInt();
59 final int startPosition = mParcel.dataPosition();
60
61 // The pool is at the end of the parcel.
62 mParcel.setDataPosition(poolPosition);
63 mParcel.readStringList(mStrings);
64
65 // Then move back.
66 mParcel.setDataPosition(startPosition);
67
68 if (DEBUG) {
69 Log.i(TAG, "Read " + mStrings.size() + " strings");
70 for (int i = 0; i < mStrings.size(); i++) {
71 Log.i(TAG, " " + i + ": \"" + mStrings.get(i) + "\"");
72 }
73 }
74
75 mParcel.setReadWriteHelper(this);
76 }
77
78 /**
79 * Read an string index from a parcel, and returns the corresponding string from the pool.
80 */
81 @Override
82 public String readString(Parcel p) {
83 return mStrings.get(p.readInt());
84 }
85 }
86
87 /**
88 * Parcel write helper with a string pool.
89 */
90 public static class WriteHelper extends Parcel.ReadWriteHelper {
91 private final ArrayList<String> mStrings = new ArrayList<>();
92
93 private final HashMap<String, Integer> mIndexes = new HashMap<>();
94
95 private final Parcel mParcel;
96 private final int mStartPos;
97
98 /**
99 * Constructor. Prepare a parcel, and install it self as a read-write helper.
100 */
101 public WriteHelper(Parcel p) {
102 mParcel = p;
103 mStartPos = p.dataPosition();
104 mParcel.writeInt(0); // We come back later here and write the pool position.
105
106 mParcel.setReadWriteHelper(this);
107 }
108
109 /**
110 * Instead of writing a string directly to a parcel, this method adds it to the pool,
111 * and write the index in the pool to the parcel.
112 */
113 @Override
114 public void writeString(Parcel p, String s) {
115 final Integer cur = mIndexes.get(s);
116 if (cur != null) {
117 // String already in the pool. Just write the index.
118 p.writeInt(cur); // Already in the pool.
119 if (DEBUG) {
120 Log.i(TAG, "Duplicate '" + s + "' at " + cur);
121 }
122 } else {
123 // Not in the pool. Add to the pool, and write the index.
124 final int index = mStrings.size();
125 mIndexes.put(s, index);
126 mStrings.add(s);
127
128 if (DEBUG) {
129 Log.i(TAG, "New '" + s + "' at " + index);
130 }
131
132 p.writeInt(index);
133 }
134 }
135
136 /**
137 * Closes a parcel by appending the string pool at the end and updating the pool offset,
138 * which it assumes is at the first byte. It also uninstalls itself as a read-write helper.
139 */
140 public void finishAndUninstall() {
141 // Uninstall first, so that writeStringList() uses the native writeString.
142 mParcel.setReadWriteHelper(null);
143
144 final int poolPosition = mParcel.dataPosition();
145 mParcel.writeStringList(mStrings);
146
147 mParcel.setDataPosition(mStartPos);
148 mParcel.writeInt(poolPosition);
149
150 // Move back to the end.
151 mParcel.setDataPosition(mParcel.dataSize());
152 if (DEBUG) {
153 Log.i(TAG, "Wrote " + mStrings.size() + " strings");
154 }
155 }
156 }
157}