Merge "Reduce duplicate strings due to the package cache." into oc-mr1-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
bb77e6c689
@@ -50,6 +50,8 @@ import android.app.ActivityManager;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.pm.PackageParserCacheHelper.ReadHelper;
|
||||
import android.content.pm.PackageParserCacheHelper.WriteHelper;
|
||||
import android.content.pm.split.DefaultSplitAssetLoader;
|
||||
import android.content.pm.split.SplitAssetDependencyLoader;
|
||||
import android.content.pm.split.SplitAssetLoader;
|
||||
@@ -1024,11 +1026,17 @@ public class PackageParser {
|
||||
|
||||
@VisibleForTesting
|
||||
protected Package fromCacheEntry(byte[] bytes) throws IOException {
|
||||
Parcel p = Parcel.obtain();
|
||||
final ReadHelper helper = new ReadHelper();
|
||||
|
||||
final Parcel p = Parcel.obtain();
|
||||
p.setReadWriteHelper(helper);
|
||||
|
||||
p.unmarshall(bytes, 0, bytes.length);
|
||||
p.setDataPosition(0);
|
||||
|
||||
helper.start(p);
|
||||
PackageParser.Package pkg = new PackageParser.Package(p);
|
||||
|
||||
p.recycle();
|
||||
|
||||
return pkg;
|
||||
@@ -1036,8 +1044,15 @@ public class PackageParser {
|
||||
|
||||
@VisibleForTesting
|
||||
protected byte[] toCacheEntry(Package pkg) throws IOException {
|
||||
Parcel p = Parcel.obtain();
|
||||
final WriteHelper helper = new WriteHelper();
|
||||
|
||||
final Parcel p = Parcel.obtain();
|
||||
p.setReadWriteHelper(helper);
|
||||
|
||||
pkg.writeToParcel(p, 0 /* flags */);
|
||||
|
||||
helper.finish(p);
|
||||
|
||||
byte[] serialized = p.marshall();
|
||||
p.recycle();
|
||||
|
||||
|
||||
114
core/java/android/content/pm/PackageParserCacheHelper.java
Normal file
114
core/java/android/content/pm/PackageParserCacheHelper.java
Normal file
@@ -0,0 +1,114 @@
|
||||
/*
|
||||
* Copyright (C) 2017 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package android.content.pm;
|
||||
|
||||
import android.os.Parcel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Helper classes to read from and write to Parcel with pooled strings.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class PackageParserCacheHelper {
|
||||
private PackageParserCacheHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcel read helper with a string pool.
|
||||
*/
|
||||
public static class ReadHelper extends Parcel.ReadWriteHelper {
|
||||
private final ArrayList<String> mStrings = new ArrayList<>();
|
||||
|
||||
public ReadHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare a parcel.
|
||||
*/
|
||||
public void start(Parcel p) {
|
||||
mStrings.clear();
|
||||
|
||||
final int poolPosition = p.readInt();
|
||||
final int startPosition = p.dataPosition();
|
||||
|
||||
// The pool is at the end of the parcel.
|
||||
p.setDataPosition(poolPosition);
|
||||
p.readStringList(mStrings);
|
||||
|
||||
// Then move back.
|
||||
p.setDataPosition(startPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read an string index from a parcel, and returns the corresponding string from the pool.
|
||||
*/
|
||||
@Override
|
||||
public String readString(Parcel p) {
|
||||
return mStrings.get(p.readInt());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parcel write helper with a string pool.
|
||||
*/
|
||||
public static class WriteHelper extends Parcel.ReadWriteHelper {
|
||||
private final ArrayList<String> mStrings = new ArrayList<>();
|
||||
|
||||
private final HashMap<String, Integer> mIndexes = new HashMap<>();
|
||||
|
||||
public WriteHelper() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Instead of writing a string directly to a parcel, this method adds it to the pool,
|
||||
* and write the index in the pool to the parcel.
|
||||
*/
|
||||
@Override
|
||||
public void writeString(Parcel p, String s) {
|
||||
final Integer cur = mIndexes.get(s);
|
||||
if (cur != null) {
|
||||
// String already in the pool. Just write the index.
|
||||
p.writeInt(cur); // Already in the pool.
|
||||
} else {
|
||||
// Note in the pool. Add to the pool, and write the index.
|
||||
final int index = mStrings.size();
|
||||
mIndexes.put(s, index);
|
||||
mStrings.add(s);
|
||||
|
||||
p.writeInt(index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes a parcel by appending the string pool at the end and updating the pool offset,
|
||||
* which it assumes is at the first byte.
|
||||
*/
|
||||
public void finish(Parcel p) {
|
||||
final int poolPosition = p.readInt();
|
||||
p.writeStringList(mStrings);
|
||||
|
||||
p.setDataPosition(0);
|
||||
p.writeInt(poolPosition);
|
||||
|
||||
// Move back to the end.
|
||||
p.setDataPosition(p.dataSize());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -291,7 +291,7 @@ public final class Parcel {
|
||||
private static native void nativeWriteFloat(long nativePtr, float val);
|
||||
@FastNative
|
||||
private static native void nativeWriteDouble(long nativePtr, double val);
|
||||
private static native void nativeWriteString(long nativePtr, String val);
|
||||
static native void nativeWriteString(long nativePtr, String val);
|
||||
private static native void nativeWriteStrongBinder(long nativePtr, IBinder val);
|
||||
private static native long nativeWriteFileDescriptor(long nativePtr, FileDescriptor val);
|
||||
|
||||
@@ -306,7 +306,7 @@ public final class Parcel {
|
||||
private static native float nativeReadFloat(long nativePtr);
|
||||
@CriticalNative
|
||||
private static native double nativeReadDouble(long nativePtr);
|
||||
private static native String nativeReadString(long nativePtr);
|
||||
static native String nativeReadString(long nativePtr);
|
||||
private static native IBinder nativeReadStrongBinder(long nativePtr);
|
||||
private static native FileDescriptor nativeReadFileDescriptor(long nativePtr);
|
||||
|
||||
@@ -338,6 +338,33 @@ public final class Parcel {
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static class ReadWriteHelper {
|
||||
public static final ReadWriteHelper DEFAULT = new ReadWriteHelper();
|
||||
|
||||
/**
|
||||
* Called when writing a string to a parcel. Subclasses wanting to write a string
|
||||
* must use {@link #writeStringNoHelper(String)} to avoid
|
||||
* infinity recursive calls.
|
||||
*/
|
||||
public void writeString(Parcel p, String s) {
|
||||
nativeWriteString(p.mNativePtr, s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when reading a string to a parcel. Subclasses wanting to read a string
|
||||
* must use {@link #readStringNoHelper()} to avoid
|
||||
* infinity recursive calls.
|
||||
*/
|
||||
public String readString(Parcel p) {
|
||||
return nativeReadString(p.mNativePtr);
|
||||
}
|
||||
}
|
||||
|
||||
private ReadWriteHelper mReadWriteHelper = ReadWriteHelper.DEFAULT;
|
||||
|
||||
/**
|
||||
* Retrieve a new Parcel object from the pool.
|
||||
*/
|
||||
@@ -352,6 +379,7 @@ public final class Parcel {
|
||||
if (DEBUG_RECYCLE) {
|
||||
p.mStack = new RuntimeException();
|
||||
}
|
||||
p.mReadWriteHelper = ReadWriteHelper.DEFAULT;
|
||||
return p;
|
||||
}
|
||||
}
|
||||
@@ -385,6 +413,16 @@ public final class Parcel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a {@link ReadWriteHelper}, which can be used to avoid having duplicate strings, for
|
||||
* example.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void setReadWriteHelper(ReadWriteHelper helper) {
|
||||
mReadWriteHelper = helper != null ? helper : ReadWriteHelper.DEFAULT;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static native long getGlobalAllocSize();
|
||||
|
||||
@@ -625,6 +663,17 @@ public final class Parcel {
|
||||
* growing dataCapacity() if needed.
|
||||
*/
|
||||
public final void writeString(String val) {
|
||||
mReadWriteHelper.writeString(this, val);
|
||||
}
|
||||
|
||||
/**
|
||||
* Write a string without going though a {@link ReadWriteHelper}. Subclasses of
|
||||
* {@link ReadWriteHelper} must use this method instead of {@link #writeString} to avoid
|
||||
* infinity recursive calls.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void writeStringNoHelper(String val) {
|
||||
nativeWriteString(mNativePtr, val);
|
||||
}
|
||||
|
||||
@@ -1996,6 +2045,17 @@ public final class Parcel {
|
||||
* Read a string value from the parcel at the current dataPosition().
|
||||
*/
|
||||
public final String readString() {
|
||||
return mReadWriteHelper.readString(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a string without going though a {@link ReadWriteHelper}. Subclasses of
|
||||
* {@link ReadWriteHelper} must use this method instead of {@link #readString} to avoid
|
||||
* infinity recursive calls.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public String readStringNoHelper() {
|
||||
return nativeReadString(mNativePtr);
|
||||
}
|
||||
|
||||
@@ -2996,6 +3056,7 @@ public final class Parcel {
|
||||
if (mOwnsNativeParcelObject) {
|
||||
updateNativeSize(nativeFreeBuffer(mNativePtr));
|
||||
}
|
||||
mReadWriteHelper = ReadWriteHelper.DEFAULT;
|
||||
}
|
||||
|
||||
private void destroy() {
|
||||
@@ -3006,6 +3067,7 @@ public final class Parcel {
|
||||
}
|
||||
mNativePtr = 0;
|
||||
}
|
||||
mReadWriteHelper = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
Reference in New Issue
Block a user