PackageManagerServiceUtils.java revision c6494490939768ab86d88abd2e562e0e591d7a8e
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.annotation.NonNull; 23import android.app.AppGlobals; 24import android.content.Intent; 25import android.content.pm.PackageParser; 26import android.content.pm.ResolveInfo; 27import android.os.Build; 28import android.os.RemoteException; 29import android.os.UserHandle; 30import android.system.ErrnoException; 31import android.util.ArraySet; 32import android.util.Log; 33import dalvik.system.VMRuntime; 34import libcore.io.Libcore; 35 36import java.io.File; 37import java.io.IOException; 38import java.util.ArrayList; 39import java.util.Collection; 40import java.util.Collections; 41import java.util.LinkedList; 42import java.util.List; 43import java.util.function.Predicate; 44 45/** 46 * Class containing helper methods for the PackageManagerService. 47 * 48 * {@hide} 49 */ 50public class PackageManagerServiceUtils { 51 private final static long SEVEN_DAYS_IN_MILLISECONDS = 7 * 24 * 60 * 60 * 1000; 52 53 private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) { 54 List<ResolveInfo> ris = null; 55 try { 56 ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId) 57 .getList(); 58 } catch (RemoteException e) { 59 } 60 ArraySet<String> pkgNames = new ArraySet<String>(); 61 if (ris != null) { 62 for (ResolveInfo ri : ris) { 63 pkgNames.add(ri.activityInfo.packageName); 64 } 65 } 66 return pkgNames; 67 } 68 69 // Sort a list of apps by their last usage, most recently used apps first. The order of 70 // packages without usage data is undefined (but they will be sorted after the packages 71 // that do have usage data). 72 public static void sortPackagesByUsageDate(List<PackageParser.Package> pkgs, 73 PackageManagerService packageManagerService) { 74 if (!packageManagerService.isHistoricalPackageUsageAvailable()) { 75 return; 76 } 77 78 Collections.sort(pkgs, (pkg1, pkg2) -> 79 Long.compare(pkg2.getLatestForegroundPackageUseTimeInMills(), 80 pkg1.getLatestForegroundPackageUseTimeInMills())); 81 } 82 83 // Apply the given {@code filter} to all packages in {@code packages}. If tested positive, the 84 // package will be removed from {@code packages} and added to {@code result} with its 85 // dependencies. If usage data is available, the positive packages will be sorted by usage 86 // data (with {@code sortTemp} as temporary storage). 87 private static void applyPackageFilter(Predicate<PackageParser.Package> filter, 88 Collection<PackageParser.Package> result, 89 Collection<PackageParser.Package> packages, 90 @NonNull List<PackageParser.Package> sortTemp, 91 PackageManagerService packageManagerService) { 92 for (PackageParser.Package pkg : packages) { 93 if (filter.test(pkg)) { 94 sortTemp.add(pkg); 95 } 96 } 97 98 sortPackagesByUsageDate(sortTemp, packageManagerService); 99 packages.removeAll(sortTemp); 100 101 for (PackageParser.Package pkg : sortTemp) { 102 result.add(pkg); 103 104 Collection<PackageParser.Package> deps = 105 packageManagerService.findSharedNonSystemLibraries(pkg); 106 if (!deps.isEmpty()) { 107 deps.removeAll(result); 108 result.addAll(deps); 109 packages.removeAll(deps); 110 } 111 } 112 113 sortTemp.clear(); 114 } 115 116 // Sort apps by importance for dexopt ordering. Important apps are given 117 // more priority in case the device runs out of space. 118 public static List<PackageParser.Package> getPackagesForDexopt( 119 Collection<PackageParser.Package> packages, 120 PackageManagerService packageManagerService) { 121 ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages); 122 LinkedList<PackageParser.Package> result = new LinkedList<>(); 123 ArrayList<PackageParser.Package> sortTemp = new ArrayList<>(remainingPkgs.size()); 124 125 // Give priority to core apps. 126 applyPackageFilter((pkg) -> pkg.coreApp, result, remainingPkgs, sortTemp, 127 packageManagerService); 128 129 // Give priority to system apps that listen for pre boot complete. 130 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); 131 final ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); 132 applyPackageFilter((pkg) -> pkgNames.contains(pkg.packageName), result, remainingPkgs, 133 sortTemp, packageManagerService); 134 135 // Give priority to apps used by other apps. 136 applyPackageFilter((pkg) -> 137 packageManagerService.getDexManager().isUsedByOtherApps(pkg.packageName), result, 138 remainingPkgs, sortTemp, packageManagerService); 139 140 // Filter out packages that aren't recently used, add all remaining apps. 141 // TODO: add a property to control this? 142 Predicate<PackageParser.Package> remainingPredicate; 143 if (!remainingPkgs.isEmpty() && packageManagerService.isHistoricalPackageUsageAvailable()) { 144 if (DEBUG_DEXOPT) { 145 Log.i(TAG, "Looking at historical package use"); 146 } 147 // Get the package that was used last. 148 PackageParser.Package lastUsed = Collections.max(remainingPkgs, (pkg1, pkg2) -> 149 Long.compare(pkg1.getLatestForegroundPackageUseTimeInMills(), 150 pkg2.getLatestForegroundPackageUseTimeInMills())); 151 if (DEBUG_DEXOPT) { 152 Log.i(TAG, "Taking package " + lastUsed.packageName + " as reference in time use"); 153 } 154 long estimatedPreviousSystemUseTime = 155 lastUsed.getLatestForegroundPackageUseTimeInMills(); 156 // Be defensive if for some reason package usage has bogus data. 157 if (estimatedPreviousSystemUseTime != 0) { 158 final long cutoffTime = estimatedPreviousSystemUseTime - SEVEN_DAYS_IN_MILLISECONDS; 159 remainingPredicate = 160 (pkg) -> pkg.getLatestForegroundPackageUseTimeInMills() >= cutoffTime; 161 } else { 162 // No meaningful historical info. Take all. 163 remainingPredicate = (pkg) -> true; 164 } 165 sortPackagesByUsageDate(remainingPkgs, packageManagerService); 166 } else { 167 // No historical info. Take all. 168 remainingPredicate = (pkg) -> true; 169 } 170 applyPackageFilter(remainingPredicate, result, remainingPkgs, sortTemp, 171 packageManagerService); 172 173 if (DEBUG_DEXOPT) { 174 Log.i(TAG, "Packages to be dexopted: " + packagesToString(result)); 175 Log.i(TAG, "Packages skipped from dexopt: " + packagesToString(remainingPkgs)); 176 } 177 178 return result; 179 } 180 181 /** 182 * Returns the canonicalized path of {@code path} as per {@code realpath(3)} 183 * semantics. 184 */ 185 public static String realpath(File path) throws IOException { 186 try { 187 return Libcore.os.realpath(path.getAbsolutePath()); 188 } catch (ErrnoException ee) { 189 throw ee.rethrowAsIOException(); 190 } 191 } 192 193 public static String packagesToString(Collection<PackageParser.Package> c) { 194 StringBuilder sb = new StringBuilder(); 195 for (PackageParser.Package pkg : c) { 196 if (sb.length() > 0) { 197 sb.append(", "); 198 } 199 sb.append(pkg.packageName); 200 } 201 return sb.toString(); 202 } 203 204 /** 205 * Verifies that the given string {@code isa} is a valid supported isa on 206 * the running device. 207 */ 208 public static boolean checkISA(String isa) { 209 for (String abi : Build.SUPPORTED_ABIS) { 210 if (VMRuntime.getInstructionSet(abi).equals(isa)) { 211 return true; 212 } 213 } 214 return false; 215 } 216} 217