diff options
Diffstat (limited to 'core/java')
| -rw-r--r-- | core/java/android/app/ContextImpl.java | 28 | ||||
| -rw-r--r-- | core/java/android/content/pm/IPackageManager.aidl | 17 | ||||
| -rwxr-xr-x | core/java/android/content/pm/ParceledListSlice.aidl | 19 | ||||
| -rw-r--r-- | core/java/android/content/pm/ParceledListSlice.java | 170 |
4 files changed, 230 insertions, 4 deletions
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 0e473c9..fe4bfcf 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -48,6 +48,7 @@ import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; import android.content.pm.PackageManager; +import android.content.pm.ParceledListSlice; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; import android.content.pm.ProviderInfo; @@ -83,6 +84,7 @@ import android.os.Handler; import android.os.IBinder; import android.os.IPowerManager; import android.os.Looper; +import android.os.Parcel; import android.os.PowerManager; import android.os.Process; import android.os.RemoteException; @@ -1998,19 +2000,41 @@ class ContextImpl extends Context { throw new NameNotFoundException("No shared userid for user:"+sharedUserName); } + @SuppressWarnings("unchecked") @Override public List<PackageInfo> getInstalledPackages(int flags) { try { - return mPM.getInstalledPackages(flags); + 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); + lastItem = slice.populateList(packageInfos, PackageInfo.CREATOR); + } while (!slice.isLastSlice()); + + return packageInfos; } catch (RemoteException e) { throw new RuntimeException("Package manager has died", e); } } + @SuppressWarnings("unchecked") @Override public List<ApplicationInfo> getInstalledApplications(int flags) { try { - return mPM.getInstalledApplications(flags); + 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); + lastItem = slice.populateList(applicationInfos, ApplicationInfo.CREATOR); + } while (!slice.isLastSlice()); + + return applicationInfos; } catch (RemoteException e) { throw new RuntimeException("Package manager has died", e); } diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl index bfc9185..5df5eba 100644 --- a/core/java/android/content/pm/IPackageManager.aidl +++ b/core/java/android/content/pm/IPackageManager.aidl @@ -30,6 +30,7 @@ import android.content.pm.IPackageMoveObserver; import android.content.pm.IPackageStatsObserver; import android.content.pm.InstrumentationInfo; import android.content.pm.PackageInfo; +import android.content.pm.ParceledListSlice; import android.content.pm.ProviderInfo; import android.content.pm.PermissionGroupInfo; import android.content.pm.PermissionInfo; @@ -109,9 +110,21 @@ interface IPackageManager { List<ResolveInfo> queryIntentServices(in Intent intent, String resolvedType, int flags); - List<PackageInfo> getInstalledPackages(int flags); + /** + * This implements getInstalledPackages via a "last returned row" + * mechanism that is not exposed in the API. This is to get around the IPC + * limit that kicks in when flags are included that bloat up the data + * returned. + */ + ParceledListSlice getInstalledPackages(int flags, in String lastRead); - List<ApplicationInfo> getInstalledApplications(int flags); + /** + * This implements getInstalledApplications via a "last returned row" + * mechanism that is not exposed in the API. This is to get around the IPC + * limit that kicks in when flags are included that bloat up the data + * returned. + */ + ParceledListSlice getInstalledApplications(int flags, in String lastRead); /** * Retrieve all applications that are marked as persistent. diff --git a/core/java/android/content/pm/ParceledListSlice.aidl b/core/java/android/content/pm/ParceledListSlice.aidl new file mode 100755 index 0000000..c02cc6a --- /dev/null +++ b/core/java/android/content/pm/ParceledListSlice.aidl @@ -0,0 +1,19 @@ +/* + * Copyright 2011, 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; + +parcelable ParceledListSlice; diff --git a/core/java/android/content/pm/ParceledListSlice.java b/core/java/android/content/pm/ParceledListSlice.java new file mode 100644 index 0000000..f3a98db --- /dev/null +++ b/core/java/android/content/pm/ParceledListSlice.java @@ -0,0 +1,170 @@ +/* + * Copyright (C) 2011 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 android.os.Parcelable; + +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. + * + * @hide + */ +public class ParceledListSlice<T extends Parcelable> implements Parcelable { + /* + * 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 Parcel mParcel; + + private int mNumItems; + + private boolean mIsLastSlice; + + public ParceledListSlice() { + mParcel = Parcel.obtain(); + } + + private ParceledListSlice(Parcel p, int numItems, boolean lastSlice) { + mParcel = p; + mNumItems = numItems; + mIsLastSlice = lastSlice; + } + + @Override + public int describeContents() { + return 0; + } + + /** + * Write this to another Parcel. Note that this discards the internal Parcel + * and should not be used anymore. This is so we can pass this to a Binder + * where we won't have a chance to call recycle on this. + */ + @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); + } + + 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 ParceledListSlice createFromParcel(Parcel in) { + final int numItems = in.readInt(); + final boolean lastSlice = in.readInt() == 1; + + 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(); + } + } + + public ParceledListSlice[] newArray(int size) { + return new ParceledListSlice[size]; + } + }; +} |
