PackageManagerServiceUtils.java revision 6b4736d604fd91aaedc6f3fe9be5a1e757aab86c
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 android.app.AppGlobals; 20import android.content.Intent; 21import android.content.pm.PackageParser; 22import android.content.pm.PackageParser.Package; 23import android.content.pm.ResolveInfo; 24import android.os.UserHandle; 25import android.os.RemoteException; 26import android.util.ArraySet; 27import android.util.Log; 28 29import java.util.ArrayList; 30import java.util.Collection; 31import java.util.Date; 32import java.util.HashSet; 33import java.util.Iterator; 34import java.util.LinkedList; 35import java.util.List; 36import java.util.Set; 37 38import static com.android.server.pm.PackageManagerService.DEBUG_DEXOPT; 39import static com.android.server.pm.PackageManagerService.TAG; 40 41/** 42 * Class containing helper methods for the PackageManagerService. 43 * 44 * {@hide} 45 */ 46public class PackageManagerServiceUtils { 47 // Apps used in the last 7 days. 48 private final static long DEXOPT_LRU_THRESHOLD_IN_MINUTES = 7 * 24 * 60; 49 50 private static ArraySet<String> getPackageNamesForIntent(Intent intent, int userId) { 51 List<ResolveInfo> ris = null; 52 try { 53 ris = AppGlobals.getPackageManager().queryIntentReceivers(intent, null, 0, userId); 54 } catch (RemoteException e) { 55 } 56 ArraySet<String> pkgNames = new ArraySet<String>(); 57 if (ris != null) { 58 for (ResolveInfo ri : ris) { 59 pkgNames.add(ri.activityInfo.packageName); 60 } 61 } 62 return pkgNames; 63 } 64 65 private static void filterRecentlyUsedApps(Collection<PackageParser.Package> pkgs, 66 long dexOptLRUThresholdInMills) { 67 // Filter out packages that aren't recently used. 68 int total = pkgs.size(); 69 int skipped = 0; 70 long now = System.currentTimeMillis(); 71 for (Iterator<PackageParser.Package> i = pkgs.iterator(); i.hasNext();) { 72 PackageParser.Package pkg = i.next(); 73 long then = pkg.mLastPackageUsageTimeInMills; 74 if (then + dexOptLRUThresholdInMills < now) { 75 if (DEBUG_DEXOPT) { 76 Log.i(TAG, "Skipping dexopt of " + pkg.packageName + " last resumed: " + 77 ((then == 0) ? "never" : new Date(then))); 78 } 79 i.remove(); 80 skipped++; 81 } 82 } 83 if (DEBUG_DEXOPT) { 84 Log.i(TAG, "Skipped optimizing " + skipped + " of " + total); 85 } 86 } 87 88 // Sort apps by importance for dexopt ordering. Important apps are given 89 // more priority in case the device runs out of space. 90 public static List<PackageParser.Package> getPackagesForDexopt( 91 Collection<PackageParser.Package> packages, 92 PackageManagerService packageManagerService) { 93 ArrayList<PackageParser.Package> remainingPkgs = new ArrayList<>(packages); 94 LinkedList<PackageParser.Package> result = new LinkedList<>(); 95 96 // Give priority to core apps. 97 for (PackageParser.Package pkg : remainingPkgs) { 98 if (pkg.coreApp) { 99 if (DEBUG_DEXOPT) { 100 Log.i(TAG, "Adding core app " + result.size() + ": " + pkg.packageName); 101 } 102 result.add(pkg); 103 } 104 } 105 remainingPkgs.removeAll(result); 106 107 // Give priority to system apps that listen for pre boot complete. 108 Intent intent = new Intent(Intent.ACTION_PRE_BOOT_COMPLETED); 109 ArraySet<String> pkgNames = getPackageNamesForIntent(intent, UserHandle.USER_SYSTEM); 110 for (PackageParser.Package pkg : remainingPkgs) { 111 if (pkgNames.contains(pkg.packageName)) { 112 if (DEBUG_DEXOPT) { 113 Log.i(TAG, "Adding pre boot system app " + result.size() + ": " + 114 pkg.packageName); 115 } 116 result.add(pkg); 117 } 118 } 119 remainingPkgs.removeAll(result); 120 121 // Filter out packages that aren't recently used, add all remaining apps. 122 // TODO: add a property to control this? 123 if (packageManagerService.isHistoricalPackageUsageAvailable()) { 124 filterRecentlyUsedApps(remainingPkgs, DEXOPT_LRU_THRESHOLD_IN_MINUTES * 60 * 1000); 125 } 126 result.addAll(remainingPkgs); 127 128 // Now go ahead and also add the libraries required for these packages. 129 // TODO: Think about interleaving things. 130 Set<PackageParser.Package> dependencies = new HashSet<>(); 131 for (PackageParser.Package p : result) { 132 dependencies.addAll(packageManagerService.findSharedNonSystemLibraries(p)); 133 } 134 if (!dependencies.isEmpty()) { 135 dependencies.removeAll(result); 136 } 137 result.addAll(dependencies); 138 139 if (DEBUG_DEXOPT) { 140 StringBuilder sb = new StringBuilder(); 141 for (PackageParser.Package pkg : result) { 142 if (sb.length() > 0) { 143 sb.append(", "); 144 } 145 sb.append(pkg.packageName); 146 } 147 Log.i(TAG, "Packages to be optimized: " + sb.toString()); 148 } 149 150 return result; 151 } 152}