From 1bb6cf18c0039cb9d2a60713ea34d3709af58c5c Mon Sep 17 00:00:00 2001 From: Kenny Root Date: Fri, 15 Apr 2011 17:50:10 -0700 Subject: Break apart queries to getInstalled* API DO NOT MERGE To avoid blowing past the Binder IPC limit, change the PackageManagerService to have a DB-like interaction where the client tells the service the last "row" that it read. The fact that we use a HashMap instead of a TreeMap makes this problematic. For now we're just making a new ArrayList for the keys and then sorting them for each call. This can make the API slower for callers of this, but it's probably greatly overshadowed by the cost of the data transfer itself. Bug: 4064282 Change-Id: Ia3a8cdaa94581ed9336f2e05694b8c8a5f757bce --- .../com/android/server/PackageManagerService.java | 140 ++++++++++++++------- 1 file changed, 95 insertions(+), 45 deletions(-) (limited to 'services') diff --git a/services/java/com/android/server/PackageManagerService.java b/services/java/com/android/server/PackageManagerService.java index 4a66a40..dd5c2a9 100644 --- a/services/java/com/android/server/PackageManagerService.java +++ b/services/java/com/android/server/PackageManagerService.java @@ -55,6 +55,8 @@ import android.content.pm.PackageInfo; import android.content.pm.PackageInfoLite; import android.content.pm.PackageManager; import android.content.pm.PackageStats; +import android.content.pm.ParceledListSlice; + import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED; import static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED; @@ -75,6 +77,7 @@ import android.os.IBinder; import android.os.Looper; import android.os.Message; import android.os.Parcel; +import android.os.Parcelable; import android.os.RemoteException; import android.os.Environment; import android.os.FileObserver; @@ -2331,63 +2334,110 @@ class PackageManagerService extends IPackageManager.Stub { } } - public List getInstalledPackages(int flags) { - ArrayList finalList = new ArrayList(); + private static final int getContinuationPoint(final String[] keys, final String key) { + final int index; + if (key == null) { + index = 0; + } else { + final int insertPoint = Arrays.binarySearch(keys, key); + if (insertPoint < 0) { + index = -insertPoint; + } else { + index = insertPoint + 1; + } + } + return index; + } + + public ParceledListSlice getInstalledPackages(int flags, String lastRead) { + final ParceledListSlice list = new ParceledListSlice(); + final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + final String[] keys; synchronized (mPackages) { - if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - Iterator i = mSettings.mPackages.values().iterator(); - while (i.hasNext()) { - final PackageSetting ps = i.next(); - PackageInfo psPkg = generatePackageInfoFromSettingsLP(ps.name, flags); - if(psPkg != null) { - finalList.add(psPkg); - } - } - } - else { - Iterator i = mPackages.values().iterator(); - while (i.hasNext()) { - final PackageParser.Package p = i.next(); - if (p.applicationInfo != null) { - PackageInfo pi = generatePackageInfo(p, flags); - if(pi != null) { - finalList.add(pi); - } + if (listUninstalled) { + keys = mSettings.mPackages.keySet().toArray(new String[mSettings.mPackages.size()]); + } else { + keys = mPackages.keySet().toArray(new String[mPackages.size()]); + } + + Arrays.sort(keys); + int i = getContinuationPoint(keys, lastRead); + final int N = keys.length; + + while (i < N) { + final String packageName = keys[i++]; + + PackageInfo pi = null; + if (listUninstalled) { + final PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps != null) { + pi = generatePackageInfoFromSettingsLP(ps.name, flags); + } + } else { + final PackageParser.Package p = mPackages.get(packageName); + if (p != null) { + pi = generatePackageInfo(p, flags); } } + + if (pi != null && !list.append(pi)) { + break; + } + } + + if (i == N) { + list.setLastSlice(true); } } - return finalList; + + return list; } - public List getInstalledApplications(int flags) { - ArrayList finalList = new ArrayList(); - synchronized(mPackages) { - if((flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0) { - Iterator i = mSettings.mPackages.values().iterator(); - while (i.hasNext()) { - final PackageSetting ps = i.next(); - ApplicationInfo ai = generateApplicationInfoFromSettingsLP(ps.name, flags); - if(ai != null) { - finalList.add(ai); - } - } - } - else { - Iterator i = mPackages.values().iterator(); - while (i.hasNext()) { - final PackageParser.Package p = i.next(); - if (p.applicationInfo != null) { - ApplicationInfo ai = PackageParser.generateApplicationInfo(p, flags); - if(ai != null) { - finalList.add(ai); - } + public ParceledListSlice getInstalledApplications(int flags, + String lastRead) { + final ParceledListSlice list = new ParceledListSlice(); + final boolean listUninstalled = (flags & PackageManager.GET_UNINSTALLED_PACKAGES) != 0; + final String[] keys; + + synchronized (mPackages) { + if (listUninstalled) { + keys = mSettings.mPackages.keySet().toArray(new String[mSettings.mPackages.size()]); + } else { + keys = mPackages.keySet().toArray(new String[mPackages.size()]); + } + + Arrays.sort(keys); + int i = getContinuationPoint(keys, lastRead); + final int N = keys.length; + + while (i < N) { + final String packageName = keys[i++]; + + ApplicationInfo ai = null; + if (listUninstalled) { + final PackageSetting ps = mSettings.mPackages.get(packageName); + if (ps != null) { + ai = generateApplicationInfoFromSettingsLP(ps.name, flags); + } + } else { + final PackageParser.Package p = mPackages.get(packageName); + if (p != null) { + ai = PackageParser.generateApplicationInfo(p, flags); } } + + if (ai != null && !list.append(ai)) { + break; + } + } + + if (i == N) { + list.setLastSlice(true); } } - return finalList; + + return list; } public List getPersistentApplications(int flags) { -- cgit v1.1