Merge "Rework ParceledListSlice to be much easier to use."

This commit is contained in:
Dianne Hackborn
2013-01-19 00:18:38 +00:00
committed by Android (Google) Code Review
14 changed files with 282 additions and 305 deletions

View File

@@ -228,7 +228,7 @@ public class AppOpsManager {
}
public int noteOp(int op) {
return noteOp(op, Process.myUid(), mContext.getPackageName());
return noteOp(op, Process.myUid(), mContext.getBasePackageName());
}
public int startOp(int op, int uid, String packageName) {
@@ -252,7 +252,7 @@ public class AppOpsManager {
}
public int startOp(int op) {
return startOp(op, Process.myUid(), mContext.getPackageName());
return startOp(op, Process.myUid(), mContext.getBasePackageName());
}
public void finishOp(int op, int uid, String packageName) {
@@ -263,6 +263,6 @@ public class AppOpsManager {
}
public void finishOp(int op) {
finishOp(op, Process.myUid(), mContext.getPackageName());
finishOp(op, Process.myUid(), mContext.getBasePackageName());
}
}

View File

@@ -426,17 +426,8 @@ final class ApplicationPackageManager extends PackageManager {
@Override
public List<PackageInfo> getInstalledPackages(int flags, int userId) {
try {
final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
PackageInfo lastItem = null;
ParceledListSlice<PackageInfo> slice;
do {
final String lastKey = lastItem != null ? lastItem.packageName : null;
slice = mPM.getInstalledPackages(flags, lastKey, userId);
lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
} while (!slice.isLastSlice());
return packageInfos;
ParceledListSlice<PackageInfo> slice = mPM.getInstalledPackages(flags, userId);
return slice.getList();
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
@@ -448,17 +439,9 @@ final class ApplicationPackageManager extends PackageManager {
String[] permissions, int flags) {
final int userId = mContext.getUserId();
try {
final List<PackageInfo> packageInfos = new ArrayList<PackageInfo>();
PackageInfo lastItem = null;
ParceledListSlice<PackageInfo> slice;
do {
final String lastKey = lastItem != null ? lastItem.packageName : null;
slice = mPM.getPackagesHoldingPermissions(permissions, flags, lastKey, userId);
lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR);
} while (!slice.isLastSlice());
return packageInfos;
ParceledListSlice<PackageInfo> slice = mPM.getPackagesHoldingPermissions(
permissions, flags, userId);
return slice.getList();
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}
@@ -469,17 +452,8 @@ final class ApplicationPackageManager extends PackageManager {
public List<ApplicationInfo> getInstalledApplications(int flags) {
final int userId = mContext.getUserId();
try {
final List<ApplicationInfo> applicationInfos = new ArrayList<ApplicationInfo>();
ApplicationInfo lastItem = null;
ParceledListSlice<ApplicationInfo> slice;
do {
final String lastKey = lastItem != null ? lastItem.packageName : null;
slice = mPM.getInstalledApplications(flags, lastKey, userId);
lastItem = slice.populateList(applicationInfos, ApplicationInfo.CREATOR);
} while (!slice.isLastSlice());
return applicationInfos;
ParceledListSlice<ApplicationInfo> slice = mPM.getInstalledApplications(flags, userId);
return slice.getList();
} catch (RemoteException e) {
throw new RuntimeException("Package manager has died", e);
}

View File

@@ -628,6 +628,12 @@ class ContextImpl extends Context {
return "android";
}
/** @hide */
@Override
public String getBasePackageName() {
return mBasePackageName != null ? mBasePackageName : getPackageName();
}
@Override
public ApplicationInfo getApplicationInfo() {
if (mPackageInfo != null) {

View File

@@ -208,7 +208,7 @@ public abstract class ContentResolver {
public ContentResolver(Context context) {
mContext = context != null ? context : ActivityThread.currentApplication();
mPackageName = mContext.getPackageName();
mPackageName = context.getBasePackageName();
}
/** @hide */

View File

@@ -418,6 +418,9 @@ public abstract class Context {
/** Return the name of this application's package. */
public abstract String getPackageName();
/** @hide Return the name of the base context this context is derived from. */
public abstract String getBasePackageName();
/** Return the full application info for this context's package. */
public abstract ApplicationInfo getApplicationInfo();

View File

@@ -135,6 +135,12 @@ public class ContextWrapper extends Context {
return mBase.getPackageName();
}
/** @hide */
@Override
public String getBasePackageName() {
return mBase.getBasePackageName();
}
@Override
public ApplicationInfo getApplicationInfo() {
return mBase.getApplicationInfo();

View File

@@ -127,7 +127,7 @@ interface IPackageManager {
* limit that kicks in when flags are included that bloat up the data
* returned.
*/
ParceledListSlice getInstalledPackages(int flags, in String lastRead, in int userId);
ParceledListSlice getInstalledPackages(int flags, in int userId);
/**
* This implements getPackagesHoldingPermissions via a "last returned row"
@@ -136,7 +136,7 @@ interface IPackageManager {
* returned.
*/
ParceledListSlice getPackagesHoldingPermissions(in String[] permissions,
int flags, in String lastRead, int userId);
int flags, int userId);
/**
* This implements getInstalledApplications via a "last returned row"
@@ -144,7 +144,7 @@ interface IPackageManager {
* limit that kicks in when flags are included that bloat up the data
* returned.
*/
ParceledListSlice getInstalledApplications(int flags, in String lastRead, int userId);
ParceledListSlice getInstalledApplications(int flags, int userId);
/**
* Retrieve all applications that are marked as persistent.

View File

@@ -16,44 +16,92 @@
package android.content.pm;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.RemoteException;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
/**
* Builds up a parcel that is discarded when written to another parcel or
* written to a list. This is useful for API that sends huge lists across a
* Binder that may be larger than the IPC limit.
* Transfer a large list of Parcelable objects across an IPC. Splits into
* multiple transactions if needed.
*
* @hide
*/
public class ParceledListSlice<T extends Parcelable> implements Parcelable {
private static String TAG = "ParceledListSlice";
private static boolean DEBUG = false;
/*
* TODO get this number from somewhere else. For now set it to a quarter of
* the 1MB limit.
*/
private static final int MAX_IPC_SIZE = 256 * 1024;
private static final int MAX_FIRST_IPC_SIZE = MAX_IPC_SIZE / 2;
private Parcel mParcel;
private final List<T> mList;
private int mNumItems;
private boolean mIsLastSlice;
public ParceledListSlice() {
mParcel = Parcel.obtain();
public ParceledListSlice(List<T> list) {
mList = list;
}
private ParceledListSlice(Parcel p, int numItems, boolean lastSlice) {
mParcel = p;
mNumItems = numItems;
mIsLastSlice = lastSlice;
private ParceledListSlice(Parcel p, ClassLoader loader) {
final int N = p.readInt();
mList = new ArrayList<T>(N);
if (DEBUG) Log.d(TAG, "Retrieving " + N + " items");
if (N <= 0) {
return;
}
Parcelable.Creator<T> creator = p.readParcelableCreator(loader);
int i = 0;
while (i < N) {
if (p.readInt() == 0) {
break;
}
mList.add(p.readCreator(creator, loader));
if (DEBUG) Log.d(TAG, "Read inline #" + i + ": " + mList.get(mList.size()-1));
i++;
}
if (i >= N) {
return;
}
final IBinder retriever = p.readStrongBinder();
while (i < N) {
if (DEBUG) Log.d(TAG, "Reading more @" + i + " of " + N + ": retriever=" + retriever);
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
data.writeInt(i);
try {
retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);
} catch (RemoteException e) {
Log.w(TAG, "Failure retrieving array; only received " + i + " of " + N, e);
return;
}
while (i < N && reply.readInt() != 0) {
mList.add(reply.readCreator(creator, loader));
if (DEBUG) Log.d(TAG, "Read extra #" + i + ": " + mList.get(mList.size()-1));
i++;
}
reply.recycle();
data.recycle();
}
}
public List<T> getList() {
return mList;
}
@Override
public int describeContents() {
return 0;
int contents = 0;
for (int i=0; i<mList.size(); i++) {
contents |= mList.get(i).describeContents();
}
return contents;
}
/**
@@ -63,104 +111,59 @@ public class ParceledListSlice<T extends Parcelable> implements Parcelable {
*/
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(mNumItems);
dest.writeInt(mIsLastSlice ? 1 : 0);
if (mNumItems > 0) {
final int parcelSize = mParcel.dataSize();
dest.writeInt(parcelSize);
dest.appendFrom(mParcel, 0, parcelSize);
final int N = mList.size();
final int callFlags = flags;
dest.writeInt(N);
if (DEBUG) Log.d(TAG, "Writing " + N + " items");
if (N > 0) {
dest.writeParcelableCreator(mList.get(0));
int i = 0;
while (i < N && dest.dataSize() < MAX_FIRST_IPC_SIZE) {
dest.writeInt(1);
mList.get(i).writeToParcel(dest, callFlags);
if (DEBUG) Log.d(TAG, "Wrote inline #" + i + ": " + mList.get(i));
i++;
}
if (i < N) {
dest.writeInt(0);
Binder retriever = new Binder() {
@Override
protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
throws RemoteException {
if (code != FIRST_CALL_TRANSACTION) {
return super.onTransact(code, data, reply, flags);
}
int i = data.readInt();
if (DEBUG) Log.d(TAG, "Writing more @" + i + " of " + N);
while (i < N && reply.dataSize() < MAX_IPC_SIZE) {
reply.writeInt(1);
mList.get(i).writeToParcel(reply, callFlags);
if (DEBUG) Log.d(TAG, "Wrote extra #" + i + ": " + mList.get(i));
i++;
}
if (i < N) {
if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N);
reply.writeInt(0);
}
return true;
}
};
if (DEBUG) Log.d(TAG, "Breaking @" + i + " of " + N + ": retriever=" + retriever);
dest.writeStrongBinder(retriever);
}
}
mNumItems = 0;
mParcel.recycle();
mParcel = null;
}
/**
* Appends a parcel to this list slice.
*
* @param item Parcelable item to append to this list slice
* @return true when the list slice is full and should not be appended to
* anymore
*/
public boolean append(T item) {
if (mParcel == null) {
throw new IllegalStateException("ParceledListSlice has already been recycled");
}
item.writeToParcel(mParcel, PARCELABLE_WRITE_RETURN_VALUE);
mNumItems++;
return mParcel.dataSize() > MAX_IPC_SIZE;
}
/**
* Populates a list and discards the internal state of the
* ParceledListSlice in the process. The instance should
* not be used anymore.
*
* @param list list to insert items from this slice.
* @param creator creator that knows how to unparcel the
* target object type.
* @return the last item inserted into the list or null if none.
*/
public T populateList(List<T> list, Creator<T> creator) {
mParcel.setDataPosition(0);
T item = null;
for (int i = 0; i < mNumItems; i++) {
item = creator.createFromParcel(mParcel);
list.add(item);
}
mParcel.recycle();
mParcel = null;
return item;
}
/**
* Sets whether this is the last list slice in the series.
*
* @param lastSlice
*/
public void setLastSlice(boolean lastSlice) {
mIsLastSlice = lastSlice;
}
/**
* Returns whether this is the last slice in a series of slices.
*
* @return true if this is the last slice in the series.
*/
public boolean isLastSlice() {
return mIsLastSlice;
}
@SuppressWarnings("unchecked")
public static final Parcelable.Creator<ParceledListSlice> CREATOR =
new Parcelable.Creator<ParceledListSlice>() {
public static final Parcelable.ClassLoaderCreator<ParceledListSlice> CREATOR =
new Parcelable.ClassLoaderCreator<ParceledListSlice>() {
public ParceledListSlice createFromParcel(Parcel in) {
final int numItems = in.readInt();
final boolean lastSlice = in.readInt() == 1;
return new ParceledListSlice(in, null);
}
if (numItems > 0) {
final int parcelSize = in.readInt();
// Advance within this Parcel
int offset = in.dataPosition();
in.setDataPosition(offset + parcelSize);
Parcel p = Parcel.obtain();
p.setDataPosition(0);
p.appendFrom(in, offset, parcelSize);
p.setDataPosition(0);
return new ParceledListSlice(p, numItems, lastSlice);
} else {
return new ParceledListSlice();
}
@Override
public ParceledListSlice createFromParcel(Parcel in, ClassLoader loader) {
return new ParceledListSlice(in, loader);
}
public ParceledListSlice[] newArray(int size) {

View File

@@ -1254,6 +1254,12 @@ public final class Parcel {
p.writeToParcel(this, parcelableFlags);
}
/** @hide */
public final void writeParcelableCreator(Parcelable p) {
String name = p.getClass().getName();
writeString(name);
}
/**
* Write a generic serializable object in to a Parcel. It is strongly
* recommended that this method be avoided, since the serialization
@@ -2046,6 +2052,28 @@ public final class Parcel {
* was an error trying to instantiate the Parcelable.
*/
public final <T extends Parcelable> T readParcelable(ClassLoader loader) {
Parcelable.Creator<T> creator = readParcelableCreator(loader);
if (creator == null) {
return null;
}
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
}
return creator.createFromParcel(this);
}
/** @hide */
public final <T extends Parcelable> T readCreator(Parcelable.Creator<T> creator,
ClassLoader loader) {
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
}
return creator.createFromParcel(this);
}
/** @hide */
public final <T extends Parcelable> Parcelable.Creator<T> readParcelableCreator(
ClassLoader loader) {
String name = readString();
if (name == null) {
return null;
@@ -2101,10 +2129,7 @@ public final class Parcel {
}
}
if (creator instanceof Parcelable.ClassLoaderCreator<?>) {
return ((Parcelable.ClassLoaderCreator<T>)creator).createFromParcel(this, loader);
}
return creator.createFromParcel(this);
return creator;
}
/**

View File

@@ -38,7 +38,7 @@ public class SystemVibrator extends Vibrator {
}
public SystemVibrator(Context context) {
mPackageName = context.getPackageName();
mPackageName = context.getBasePackageName();
mService = IVibratorService.Stub.asInterface(
ServiceManager.getService("vibrator"));
}