Merge "Rework ParceledListSlice to be much easier to use."
This commit is contained in:
committed by
Android (Google) Code Review
commit
8fea4e72e4
@@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user