Merge "Reduce duplicate strings due to the package cache." into oc-mr1-dev

This commit is contained in:
TreeHugger Robot
2017-07-31 17:52:41 +00:00
committed by Android (Google) Code Review
3 changed files with 195 additions and 4 deletions

View File

@@ -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();

View 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());
}
}
}

View File

@@ -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