PackageManagerServiceUtils.java revision ca82e616d3131570bf2ee29778f4796f343720d5
1/* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.server.pm; 18 19import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT; 20import static com.android.server.pm.PackageManagerService.TAG; 21 22import android.app.AppGlobals; 23import android.content.Intent; 24import android.content.pm.PackageParser; 25import android.content.pm.ResolveInfo; 26import android.os.RemoteException; 27import android.os.UserHandle; 28import android.util.ArraySet; 29import android.util.Log; 30 31import java.util.ArrayList; 32import java.util.Collection; 33import java.util.Date; 34import java.util.HashSet; 35import java.util.Iterator; 36import java.util.LinkedList; 37import java.util.List; 38import java.util.Set; 39 40/** 41 * Class containing helper methods for the PackageManagerService. 42 * 43 * {@hide} 44 */ 45public class PackageManagerServiceUtils { 46 private final static long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000; 47 48 private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) { 49 List<ResolveInfo> ris = null; 50 try { 51 ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId) 52 .getList(); 53 } catch (RemoteException e) { 54 } 55 ArraySet<String> pkgNames = new ArraySet<String>(); 56 if (ris != null) { 57 for (ResolveInfo ri : ris) { 58 pkgNames.add(ri.activityInfo.packageName); 59 } 60 } 61 return pkgNames; 62 } 63 64 private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs, 65 long dexOptLRUThresholdInMills) { 66 // Filter out packages that aren't recently used. 67 int total = pkgs.size(); 68 int skipped = 0; 69 long now = System.currentTimeMillis(); 70 for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) { 71 PackageParser.Package pkg = i.next(); 72 long then = pkg.getLatestPackageUseTimeInMills(); 73 if (then + dexOptLRUThresholdInMills < now) { 74 if (DEBUG_DEXOPT) { 75 Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " + 76 ((then == 0) ? "never" : new Date(then))); 77 } 78 i.remove(); 79 skipped++; 80 } 81 } 82 if (DEBUG_DEXOPT) { 83 Log.i(TAG, "Skipped dexopt " + skipped + " of " + total); 84 } 85 } 86 87 // Sort apps by importance for dexopt ordering. Important apps are given 88 // more priority in case the device runs out of space. 89 public static List<PackageParser.Package> getPackagesForDexopt( 90 Collection<PackageParser.Package> packages, 91 PackageManagerService packageManagerService) { 92 ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages); 93 LinkedList<PackageParser.Package> result = new LinkedList<>(); 94 95 // Give priority to core apps. 96 for (PackageParser.Package pkg : remainingPkgs) { 97 if (pkg.coreApp) { 98 if (DEBUG_DEXOPT) { 99 Log.i(TAG, "Adding core app " + result.size() + ": " + pkg.packageName); 100 } 101 result.add(pkg); 102 } 103 } 104 remainingPkgs.removeAll(result); 105 106 // Give priority to system apps that listen for pre boot complete. 107 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); 108 ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); 109 for (PackageParser.Package pkg : remainingPkgs) { 110 if (pkgNames.contains(pkg.packageName)) { 111 if (DEBUG_DEXOPT) { 112 Log.i(TAG, "Adding pre boot system app " + result.size() + ": " + 113 pkg.packageName); 114 } 115 result.add(pkg); 116 } 117 } 118 remainingPkgs.removeAll(result); 119 120 // Filter out packages that aren't recently used, add all remaining apps. 121 // TODO: add a property to control this? 122 if (packageManagerService.isHistoricalPackageUsageAvailable()) { 123 filterRecentlyUsedApps(remainingPkgs, SEVEN_DAYS_IN_MILLISECONDS); 124 } 125 result.addAll(remainingPkgs); 126 127 // Now go ahead and also add the libraries required for these packages. 128 // TODO: Think about interleaving things. 129 Set<PackageParser.Package> dependencies = new HashSet<>(); 130 for (PackageParser.Package p : result) { 131 dependencies.addAll(packageManagerService.findSharedNonSystemLibraries(p)); 132 } 133 if (!dependencies.isEmpty()) { 134 // We might have packages already in `result` that are dependencies 135 // of other packages. Make sure we don't add those to the list twice. 136 dependencies.removeAll(result); 137 } 138 result.addAll(dependencies); 139 140 if (DEBUG_DEXOPT) { 141 StringBuilder sb = new StringBuilder(); 142 for (PackageParser.Package pkg : result) { 143 if (sb.length() > 0) { 144 sb.append(", "); 145 } 146 sb.append(pkg.packageName); 147 } 148 Log.i(TAG, "Packages to be dexopted: " + sb.toString()); 149 } 150 151 return result; 152 } 153}