PackageDexUsage.java revision 535a4753e313bdc2ae3e8be9f50606b82edcce0c
10318162abcbd07a0472989df43e00e353fac731bCalin Juravle/* 20318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Copyright (C) 2016 The Android Open Source Project 30318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 40318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Licensed under the Apache License, Version 2.0 (the "License"); 50318162abcbd07a0472989df43e00e353fac731bCalin Juravle * you may not use this file except in compliance with the License. 60318162abcbd07a0472989df43e00e353fac731bCalin Juravle * You may obtain a copy of the License at 70318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 80318162abcbd07a0472989df43e00e353fac731bCalin Juravle * http://www.apache.org/licenses/LICENSE-2.0 90318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 100318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Unless required by applicable law or agreed to in writing, software 110318162abcbd07a0472989df43e00e353fac731bCalin Juravle * distributed under the License is distributed on an "AS IS" BASIS, 120318162abcbd07a0472989df43e00e353fac731bCalin Juravle * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 130318162abcbd07a0472989df43e00e353fac731bCalin Juravle * See the License for the specific language governing permissions and 140318162abcbd07a0472989df43e00e353fac731bCalin Juravle * limitations under the License 150318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 160318162abcbd07a0472989df43e00e353fac731bCalin Juravle 170318162abcbd07a0472989df43e00e353fac731bCalin Juravlepackage com.android.server.pm.dex; 180318162abcbd07a0472989df43e00e353fac731bCalin Juravle 190318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport android.util.AtomicFile; 200318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport android.util.Slog; 210318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport android.os.Build; 220318162abcbd07a0472989df43e00e353fac731bCalin Juravle 230318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport com.android.internal.annotations.GuardedBy; 240318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport com.android.internal.util.FastPrintWriter; 250318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport com.android.server.pm.AbstractStatsBase; 260318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport com.android.server.pm.PackageManagerServiceUtils; 270318162abcbd07a0472989df43e00e353fac731bCalin Juravle 280318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.BufferedReader; 290318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.File; 300318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.FileNotFoundException; 310318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.FileOutputStream; 320318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.InputStreamReader; 330318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.IOException; 340318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.OutputStreamWriter; 350318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.Reader; 360318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.StringWriter; 370318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.Writer; 38535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravleimport java.util.Arrays; 39535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravleimport java.util.Collection; 40535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravleimport java.util.Collections; 410318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Iterator; 420318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.HashMap; 430318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.HashSet; 44535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravleimport java.util.List; 450318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Map; 460318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Set; 470318162abcbd07a0472989df43e00e353fac731bCalin Juravle 480318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport dalvik.system.VMRuntime; 490318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport libcore.io.IoUtils; 50535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravleimport libcore.util.Objects; 510318162abcbd07a0472989df43e00e353fac731bCalin Juravle 520318162abcbd07a0472989df43e00e353fac731bCalin Juravle/** 530318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Stat file which store usage information about dex files. 540318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 550318162abcbd07a0472989df43e00e353fac731bCalin Juravlepublic class PackageDexUsage extends AbstractStatsBase<Void> { 560318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static String TAG = "PackageDexUsage"; 570318162abcbd07a0472989df43e00e353fac731bCalin Juravle 58535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle // The last version update: add the list of packages that load the dex files. 59535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private final static int PACKAGE_DEX_USAGE_VERSION = 2; 60535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle // We support VERSION 1 to ensure that the usage list remains valid cross OTAs. 61535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1 = 1; 62535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 630318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static String PACKAGE_DEX_USAGE_VERSION_HEADER = 640318162abcbd07a0472989df43e00e353fac731bCalin Juravle "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__"; 650318162abcbd07a0472989df43e00e353fac731bCalin Juravle 660318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static String SPLIT_CHAR = ","; 670318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static String DEX_LINE_CHAR = "#"; 68535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private final static String LOADING_PACKAGE_CHAR = "@"; 690318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Map which structures the information we have on a package. 700318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Maps package name to package data (which stores info about UsedByOtherApps and 710318162abcbd07a0472989df43e00e353fac731bCalin Juravle // secondary dex files.). 720318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Access to this map needs synchronized. 730318162abcbd07a0472989df43e00e353fac731bCalin Juravle @GuardedBy("mPackageUseInfoMap") 74535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private final Map<String, PackageUseInfo> mPackageUseInfoMap; 750318162abcbd07a0472989df43e00e353fac731bCalin Juravle 760318162abcbd07a0472989df43e00e353fac731bCalin Juravle public PackageDexUsage() { 770318162abcbd07a0472989df43e00e353fac731bCalin Juravle super("package-dex-usage.list", "PackageDexUsage_DiskWriter", /*lock*/ false); 780318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap = new HashMap<>(); 790318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 800318162abcbd07a0472989df43e00e353fac731bCalin Juravle 810318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 820318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Record a dex file load. 830318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 840318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Note this is called when apps load dex files and as such it should return 850318162abcbd07a0472989df43e00e353fac731bCalin Juravle * as fast as possible. 860318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 87535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * @param owningPackageName the package owning the dex path 880318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param dexPath the path of the dex files being loaded 890318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param ownerUserId the user id which runs the code loading the dex files 900318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param loaderIsa the ISA of the app loading the dex files 910318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param isUsedByOtherApps whether or not this dex file was not loaded by its owning package 920318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param primaryOrSplit whether or not the dex file is a primary/split dex. True indicates 930318162abcbd07a0472989df43e00e353fac731bCalin Juravle * the file is either primary or a split. False indicates the file is secondary dex. 94535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * @param loadingPackageName the package performing the load. Recorded only if it is different 95535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * than {@param owningPackageName}. 960318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @return true if the dex load constitutes new information, or false if this information 970318162abcbd07a0472989df43e00e353fac731bCalin Juravle * has been seen before. 980318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 990318162abcbd07a0472989df43e00e353fac731bCalin Juravle public boolean record(String owningPackageName, String dexPath, int ownerUserId, 100535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit, 101535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle String loadingPackageName) { 1020318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (!PackageManagerServiceUtils.checkISA(loaderIsa)) { 1030318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported"); 1040318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1050318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 1060318162abcbd07a0472989df43e00e353fac731bCalin Juravle PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName); 1070318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (packageUseInfo == null) { 1080318162abcbd07a0472989df43e00e353fac731bCalin Juravle // This is the first time we see the package. 1090318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo = new PackageUseInfo(); 1100318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (primaryOrSplit) { 1110318162abcbd07a0472989df43e00e353fac731bCalin Juravle // If we have a primary or a split apk, set isUsedByOtherApps. 1120318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We do not need to record the loaderIsa or the owner because we compile 1130318162abcbd07a0472989df43e00e353fac731bCalin Juravle // primaries for all users and all ISAs. 1140318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo.mIsUsedByOtherApps = isUsedByOtherApps; 115535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle maybeAddLoadingPackage(owningPackageName, loadingPackageName, 116535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle packageUseInfo.mLoadingPackages); 1170318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 1180318162abcbd07a0472989df43e00e353fac731bCalin Juravle // For secondary dex files record the loaderISA and the owner. We'll need 1190318162abcbd07a0472989df43e00e353fac731bCalin Juravle // to know under which user to compile and for what ISA. 120535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle DexUseInfo newData = new DexUseInfo(isUsedByOtherApps, ownerUserId, loaderIsa); 121535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle packageUseInfo.mDexUseInfoMap.put(dexPath, newData); 122535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle maybeAddLoadingPackage(owningPackageName, loadingPackageName, 123535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle newData.mLoadingPackages); 1240318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1250318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.put(owningPackageName, packageUseInfo); 1260318162abcbd07a0472989df43e00e353fac731bCalin Juravle return true; 1270318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 1280318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We already have data on this package. Amend it. 1290318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (primaryOrSplit) { 1300318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We have a possible update on the primary apk usage. Merge 1310318162abcbd07a0472989df43e00e353fac731bCalin Juravle // isUsedByOtherApps information and return if there was an update. 132535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle boolean updateLoadingPackages = maybeAddLoadingPackage(owningPackageName, 133535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle loadingPackageName, packageUseInfo.mLoadingPackages); 134535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return packageUseInfo.merge(isUsedByOtherApps) || updateLoadingPackages; 1350318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 1360318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo newData = new DexUseInfo( 1370318162abcbd07a0472989df43e00e353fac731bCalin Juravle isUsedByOtherApps, ownerUserId, loaderIsa); 138535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle boolean updateLoadingPackages = maybeAddLoadingPackage(owningPackageName, 139535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle loadingPackageName, newData.mLoadingPackages); 140535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 1410318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo existingData = packageUseInfo.mDexUseInfoMap.get(dexPath); 1420318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (existingData == null) { 1430318162abcbd07a0472989df43e00e353fac731bCalin Juravle // It's the first time we see this dex file. 1440318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo.mDexUseInfoMap.put(dexPath, newData); 1450318162abcbd07a0472989df43e00e353fac731bCalin Juravle return true; 1460318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 1470318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (ownerUserId != existingData.mOwnerUserId) { 1480318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Oups, this should never happen, the DexManager who calls this should 1490318162abcbd07a0472989df43e00e353fac731bCalin Juravle // do the proper checks and not call record if the user does not own the 1500318162abcbd07a0472989df43e00e353fac731bCalin Juravle // dex path. 1510318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Secondary dex files are stored in the app user directory. A change in 1520318162abcbd07a0472989df43e00e353fac731bCalin Juravle // owningUser for the same path means that something went wrong at some 1530318162abcbd07a0472989df43e00e353fac731bCalin Juravle // higher level, and the loaderUser was allowed to cross 1540318162abcbd07a0472989df43e00e353fac731bCalin Juravle // user-boundaries and access data from what we know to be the owner 1550318162abcbd07a0472989df43e00e353fac731bCalin Juravle // user. 1560318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalArgumentException("Trying to change ownerUserId for " 1570318162abcbd07a0472989df43e00e353fac731bCalin Juravle + " dex path " + dexPath + " from " + existingData.mOwnerUserId 1580318162abcbd07a0472989df43e00e353fac731bCalin Juravle + " to " + ownerUserId); 1590318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1600318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Merge the information into the existing data. 1610318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Returns true if there was an update. 162535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return existingData.merge(newData) || updateLoadingPackages; 1630318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1640318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1650318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1660318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1670318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1680318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1690318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 1700318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Convenience method for sync reads which does not force the user to pass a useless 1710318162abcbd07a0472989df43e00e353fac731bCalin Juravle * (Void) null. 1720318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 1730318162abcbd07a0472989df43e00e353fac731bCalin Juravle public void read() { 1740318162abcbd07a0472989df43e00e353fac731bCalin Juravle read((Void) null); 1750318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1760318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1770318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 1780318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Convenience method for async writes which does not force the user to pass a useless 1790318162abcbd07a0472989df43e00e353fac731bCalin Juravle * (Void) null. 1800318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 1810318162abcbd07a0472989df43e00e353fac731bCalin Juravle public void maybeWriteAsync() { 1820318162abcbd07a0472989df43e00e353fac731bCalin Juravle maybeWriteAsync((Void) null); 1830318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1840318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1850318162abcbd07a0472989df43e00e353fac731bCalin Juravle @Override 1860318162abcbd07a0472989df43e00e353fac731bCalin Juravle protected void writeInternal(Void data) { 1870318162abcbd07a0472989df43e00e353fac731bCalin Juravle AtomicFile file = getFile(); 1880318162abcbd07a0472989df43e00e353fac731bCalin Juravle FileOutputStream f = null; 1890318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1900318162abcbd07a0472989df43e00e353fac731bCalin Juravle try { 1910318162abcbd07a0472989df43e00e353fac731bCalin Juravle f = file.startWrite(); 1920318162abcbd07a0472989df43e00e353fac731bCalin Juravle OutputStreamWriter osw = new OutputStreamWriter(f); 1930318162abcbd07a0472989df43e00e353fac731bCalin Juravle write(osw); 1940318162abcbd07a0472989df43e00e353fac731bCalin Juravle osw.flush(); 1950318162abcbd07a0472989df43e00e353fac731bCalin Juravle file.finishWrite(f); 1960318162abcbd07a0472989df43e00e353fac731bCalin Juravle } catch (IOException e) { 1970318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (f != null) { 1980318162abcbd07a0472989df43e00e353fac731bCalin Juravle file.failWrite(f); 1990318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2000318162abcbd07a0472989df43e00e353fac731bCalin Juravle Slog.e(TAG, "Failed to write usage for dex files", e); 2010318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2020318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2030318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2040318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 2050318162abcbd07a0472989df43e00e353fac731bCalin Juravle * File format: 2060318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 2070318162abcbd07a0472989df43e00e353fac731bCalin Juravle * file_magic_version 2080318162abcbd07a0472989df43e00e353fac731bCalin Juravle * package_name_1 209535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * @ loading_package_1_1, loading_package_1_2... 2100318162abcbd07a0472989df43e00e353fac731bCalin Juravle * #dex_file_path_1_1 211535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * @ loading_package_1_1_1, loading_package_1_1_2... 2120318162abcbd07a0472989df43e00e353fac731bCalin Juravle * user_1_1, used_by_other_app_1_1, user_isa_1_1_1, user_isa_1_1_2 2130318162abcbd07a0472989df43e00e353fac731bCalin Juravle * #dex_file_path_1_2 214535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * @ loading_package_1_2_1, loading_package_1_2_2... 2150318162abcbd07a0472989df43e00e353fac731bCalin Juravle * user_1_2, used_by_other_app_1_2, user_isa_1_2_1, user_isa_1_2_2 2160318162abcbd07a0472989df43e00e353fac731bCalin Juravle * ... 2170318162abcbd07a0472989df43e00e353fac731bCalin Juravle * package_name_2 218535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * @ loading_package_2_1, loading_package_2_1_2... 2190318162abcbd07a0472989df43e00e353fac731bCalin Juravle * #dex_file_path_2_1 220535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * @ loading_package_2_1_1, loading_package_2_1_2... 2210318162abcbd07a0472989df43e00e353fac731bCalin Juravle * user_2_1, used_by_other_app_2_1, user_isa_2_1_1, user_isa_2_1_2 2220318162abcbd07a0472989df43e00e353fac731bCalin Juravle * #dex_file_path_2_2, 223535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * @ loading_package_2_2_1, loading_package_2_2_2... 2240318162abcbd07a0472989df43e00e353fac731bCalin Juravle * user_2_2, used_by_other_app_2_2, user_isa_2_2_1, user_isa_2_2_2 2250318162abcbd07a0472989df43e00e353fac731bCalin Juravle * ... 2260318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 2270318162abcbd07a0472989df43e00e353fac731bCalin Juravle /* package */ void write(Writer out) { 2280318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Make a clone to avoid locking while writing to disk. 2290318162abcbd07a0472989df43e00e353fac731bCalin Juravle Map<String, PackageUseInfo> packageUseInfoMapClone = clonePackageUseInfoMap(); 2300318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2310318162abcbd07a0472989df43e00e353fac731bCalin Juravle FastPrintWriter fpw = new FastPrintWriter(out); 2320318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2330318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Write the header. 2340318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.print(PACKAGE_DEX_USAGE_VERSION_HEADER); 2350318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.println(PACKAGE_DEX_USAGE_VERSION); 2360318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2370318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (Map.Entry<String, PackageUseInfo> pEntry : packageUseInfoMapClone.entrySet()) { 2380318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Write the package line. 2390318162abcbd07a0472989df43e00e353fac731bCalin Juravle String packageName = pEntry.getKey(); 2400318162abcbd07a0472989df43e00e353fac731bCalin Juravle PackageUseInfo packageUseInfo = pEntry.getValue(); 2410318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2420318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.println(String.join(SPLIT_CHAR, packageName, 2430318162abcbd07a0472989df43e00e353fac731bCalin Juravle writeBoolean(packageUseInfo.mIsUsedByOtherApps))); 244535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle fpw.println(LOADING_PACKAGE_CHAR + 245535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle String.join(SPLIT_CHAR, packageUseInfo.mLoadingPackages)); 2460318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2470318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Write dex file lines. 2480318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (Map.Entry<String, DexUseInfo> dEntry : packageUseInfo.mDexUseInfoMap.entrySet()) { 2490318162abcbd07a0472989df43e00e353fac731bCalin Juravle String dexPath = dEntry.getKey(); 2500318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo dexUseInfo = dEntry.getValue(); 2510318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.println(DEX_LINE_CHAR + dexPath); 252535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle fpw.println(LOADING_PACKAGE_CHAR + 253535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle String.join(SPLIT_CHAR, dexUseInfo.mLoadingPackages)); 254535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 2550318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.print(String.join(SPLIT_CHAR, Integer.toString(dexUseInfo.mOwnerUserId), 2560318162abcbd07a0472989df43e00e353fac731bCalin Juravle writeBoolean(dexUseInfo.mIsUsedByOtherApps))); 2570318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (String isa : dexUseInfo.mLoaderIsas) { 2580318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.print(SPLIT_CHAR + isa); 2590318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2600318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.println(); 2610318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2620318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2630318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.flush(); 2640318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2650318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2660318162abcbd07a0472989df43e00e353fac731bCalin Juravle @Override 2670318162abcbd07a0472989df43e00e353fac731bCalin Juravle protected void readInternal(Void data) { 2680318162abcbd07a0472989df43e00e353fac731bCalin Juravle AtomicFile file = getFile(); 2690318162abcbd07a0472989df43e00e353fac731bCalin Juravle BufferedReader in = null; 2700318162abcbd07a0472989df43e00e353fac731bCalin Juravle try { 2710318162abcbd07a0472989df43e00e353fac731bCalin Juravle in = new BufferedReader(new InputStreamReader(file.openRead())); 2720318162abcbd07a0472989df43e00e353fac731bCalin Juravle read(in); 2730318162abcbd07a0472989df43e00e353fac731bCalin Juravle } catch (FileNotFoundException expected) { 2740318162abcbd07a0472989df43e00e353fac731bCalin Juravle // The file may not be there. E.g. When we first take the OTA with this feature. 2750318162abcbd07a0472989df43e00e353fac731bCalin Juravle } catch (IOException e) { 2760318162abcbd07a0472989df43e00e353fac731bCalin Juravle Slog.w(TAG, "Failed to parse package dex usage.", e); 2770318162abcbd07a0472989df43e00e353fac731bCalin Juravle } finally { 2780318162abcbd07a0472989df43e00e353fac731bCalin Juravle IoUtils.closeQuietly(in); 2790318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2800318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2810318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2820318162abcbd07a0472989df43e00e353fac731bCalin Juravle /* package */ void read(Reader reader) throws IOException { 2830318162abcbd07a0472989df43e00e353fac731bCalin Juravle Map<String, PackageUseInfo> data = new HashMap<>(); 2840318162abcbd07a0472989df43e00e353fac731bCalin Juravle BufferedReader in = new BufferedReader(reader); 2850318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Read header, do version check. 2860318162abcbd07a0472989df43e00e353fac731bCalin Juravle String versionLine = in.readLine(); 287535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle int version; 2880318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (versionLine == null) { 2890318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("No version line found."); 2900318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 2910318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (!versionLine.startsWith(PACKAGE_DEX_USAGE_VERSION_HEADER)) { 2920318162abcbd07a0472989df43e00e353fac731bCalin Juravle // TODO(calin): the caller is responsible to clear the file. 2930318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Invalid version line: " + versionLine); 2940318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 295535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle version = Integer.parseInt( 2960318162abcbd07a0472989df43e00e353fac731bCalin Juravle versionLine.substring(PACKAGE_DEX_USAGE_VERSION_HEADER.length())); 297535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle if (!isSupportedVersion(version)) { 2980318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Unexpected version: " + version); 2990318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3000318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3010318162abcbd07a0472989df43e00e353fac731bCalin Juravle 302535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle String s; 303535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle String currentPackage = null; 304535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle PackageUseInfo currentPackageData = null; 3050318162abcbd07a0472989df43e00e353fac731bCalin Juravle 3060318162abcbd07a0472989df43e00e353fac731bCalin Juravle Set<String> supportedIsas = new HashSet<>(); 3070318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (String abi : Build.SUPPORTED_ABIS) { 3080318162abcbd07a0472989df43e00e353fac731bCalin Juravle supportedIsas.add(VMRuntime.getInstructionSet(abi)); 3090318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3100318162abcbd07a0472989df43e00e353fac731bCalin Juravle while ((s = in.readLine()) != null) { 3110318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (s.startsWith(DEX_LINE_CHAR)) { 3120318162abcbd07a0472989df43e00e353fac731bCalin Juravle // This is the start of the the dex lines. 3130318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We expect two lines for each dex entry: 3140318162abcbd07a0472989df43e00e353fac731bCalin Juravle // #dexPaths 3150318162abcbd07a0472989df43e00e353fac731bCalin Juravle // onwerUserId,isUsedByOtherApps,isa1,isa2 316535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle if (currentPackage == null) { 3170318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException( 3180318162abcbd07a0472989df43e00e353fac731bCalin Juravle "Malformed PackageDexUsage file. Expected package line before dex line."); 3190318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3200318162abcbd07a0472989df43e00e353fac731bCalin Juravle 3210318162abcbd07a0472989df43e00e353fac731bCalin Juravle // First line is the dex path. 3220318162abcbd07a0472989df43e00e353fac731bCalin Juravle String dexPath = s.substring(DEX_LINE_CHAR.length()); 323535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 324535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle // In version 2 the second line contains the list of packages that loaded the file. 325535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle List<String> loadingPackages = maybeReadLoadingPackages(in, version); 326535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 3270318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Next line is the dex data. 3280318162abcbd07a0472989df43e00e353fac731bCalin Juravle s = in.readLine(); 3290318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (s == null) { 330535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle throw new IllegalStateException("Could not find dexUseInfo for line: " + s); 3310318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3320318162abcbd07a0472989df43e00e353fac731bCalin Juravle 3330318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We expect at least 3 elements (isUsedByOtherApps, userId, isa). 3340318162abcbd07a0472989df43e00e353fac731bCalin Juravle String[] elems = s.split(SPLIT_CHAR); 3350318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (elems.length < 3) { 3360318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Invalid PackageDexUsage line: " + s); 3370318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3380318162abcbd07a0472989df43e00e353fac731bCalin Juravle int ownerUserId = Integer.parseInt(elems[0]); 3390318162abcbd07a0472989df43e00e353fac731bCalin Juravle boolean isUsedByOtherApps = readBoolean(elems[1]); 3400318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId); 341535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle dexUseInfo.mLoadingPackages.addAll(loadingPackages); 342535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 3430318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (int i = 2; i < elems.length; i++) { 3440318162abcbd07a0472989df43e00e353fac731bCalin Juravle String isa = elems[i]; 3450318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (supportedIsas.contains(isa)) { 3460318162abcbd07a0472989df43e00e353fac731bCalin Juravle dexUseInfo.mLoaderIsas.add(elems[i]); 3470318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 3480318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Should never happen unless someone crafts the file manually. 3490318162abcbd07a0472989df43e00e353fac731bCalin Juravle // In theory it could if we drop a supported ISA after an OTA but we don't 3500318162abcbd07a0472989df43e00e353fac731bCalin Juravle // do that. 3510318162abcbd07a0472989df43e00e353fac731bCalin Juravle Slog.wtf(TAG, "Unsupported ISA when parsing PackageDexUsage: " + isa); 3520318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3530318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3540318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (supportedIsas.isEmpty()) { 3550318162abcbd07a0472989df43e00e353fac731bCalin Juravle Slog.wtf(TAG, "Ignore dexPath when parsing PackageDexUsage because of " + 3560318162abcbd07a0472989df43e00e353fac731bCalin Juravle "unsupported isas. dexPath=" + dexPath); 3570318162abcbd07a0472989df43e00e353fac731bCalin Juravle continue; 3580318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 359535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle currentPackageData.mDexUseInfoMap.put(dexPath, dexUseInfo); 3600318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 3610318162abcbd07a0472989df43e00e353fac731bCalin Juravle // This is a package line. 3620318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We expect it to be: `packageName,isUsedByOtherApps`. 3630318162abcbd07a0472989df43e00e353fac731bCalin Juravle String[] elems = s.split(SPLIT_CHAR); 3640318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (elems.length != 2) { 3650318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Invalid PackageDexUsage line: " + s); 3660318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 367535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle currentPackage = elems[0]; 368535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle currentPackageData = new PackageUseInfo(); 369535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle currentPackageData.mIsUsedByOtherApps = readBoolean(elems[1]); 370535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle currentPackageData.mLoadingPackages.addAll(maybeReadLoadingPackages(in, version)); 371535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle data.put(currentPackage, currentPackageData); 3720318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3730318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3740318162abcbd07a0472989df43e00e353fac731bCalin Juravle 3750318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 3760318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.clear(); 3770318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.putAll(data); 3780318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3790318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3800318162abcbd07a0472989df43e00e353fac731bCalin Juravle 3810318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 382535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * Reads the list of loading packages from the buffer {@parm in} if 383535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * {@code version} is at least {PACKAGE_DEX_USAGE_VERSION}. 384535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle */ 385535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private List<String> maybeReadLoadingPackages(BufferedReader in, int version) 386535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle throws IOException { 387535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle if (version == PACKAGE_DEX_USAGE_VERSION) { 388535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle String line = in.readLine(); 389535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle if (line == null) { 390535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle throw new IllegalStateException("Could not find the loadingPackages line."); 391535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } 392535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle // We expect that most of the times the list of loading packages will be empty. 393535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle if (line.length() == LOADING_PACKAGE_CHAR.length()) { 394535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return Collections.emptyList(); 395535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } else { 396535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return Arrays.asList( 397535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle line.substring(LOADING_PACKAGE_CHAR.length()).split(SPLIT_CHAR)); 398535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } 399535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } else { 400535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return Collections.emptyList(); 401535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } 402535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } 403535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 404535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle /** 405535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * Utility method which adds {@param loadingPackage} to {@param loadingPackages} only if it's 406535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle * not equal to {@param owningPackage} 407535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle */ 408535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private boolean maybeAddLoadingPackage(String owningPackage, String loadingPackage, 409535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle Set<String> loadingPackages) { 410535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return !owningPackage.equals(loadingPackage) && loadingPackages.add(loadingPackage); 411535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } 412535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 413535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private boolean isSupportedVersion(int version) { 414535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return version == PACKAGE_DEX_USAGE_VERSION || 415535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle version == PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1; 416535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } 417535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 418535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle /** 4190318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Syncs the existing data with the set of available packages by removing obsolete entries. 4200318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 4210318162abcbd07a0472989df43e00e353fac731bCalin Juravle public void syncData(Map<String, Set<Integer>> packageToUsersMap) { 4220318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 4230318162abcbd07a0472989df43e00e353fac731bCalin Juravle Iterator<Map.Entry<String, PackageUseInfo>> pIt = 4240318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.entrySet().iterator(); 4250318162abcbd07a0472989df43e00e353fac731bCalin Juravle while (pIt.hasNext()) { 4260318162abcbd07a0472989df43e00e353fac731bCalin Juravle Map.Entry<String, PackageUseInfo> pEntry = pIt.next(); 4270318162abcbd07a0472989df43e00e353fac731bCalin Juravle String packageName = pEntry.getKey(); 4280318162abcbd07a0472989df43e00e353fac731bCalin Juravle PackageUseInfo packageUseInfo = pEntry.getValue(); 4290318162abcbd07a0472989df43e00e353fac731bCalin Juravle Set<Integer> users = packageToUsersMap.get(packageName); 4300318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (users == null) { 4310318162abcbd07a0472989df43e00e353fac731bCalin Juravle // The package doesn't exist anymore, remove the record. 4320318162abcbd07a0472989df43e00e353fac731bCalin Juravle pIt.remove(); 4330318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 4340318162abcbd07a0472989df43e00e353fac731bCalin Juravle // The package exists but we can prune the entries associated with non existing 4350318162abcbd07a0472989df43e00e353fac731bCalin Juravle // users. 4360318162abcbd07a0472989df43e00e353fac731bCalin Juravle Iterator<Map.Entry<String, DexUseInfo>> dIt = 4370318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo.mDexUseInfoMap.entrySet().iterator(); 4380318162abcbd07a0472989df43e00e353fac731bCalin Juravle while (dIt.hasNext()) { 4390318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo dexUseInfo = dIt.next().getValue(); 4400318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (!users.contains(dexUseInfo.mOwnerUserId)) { 4410318162abcbd07a0472989df43e00e353fac731bCalin Juravle // User was probably removed. Delete its dex usage info. 4420318162abcbd07a0472989df43e00e353fac731bCalin Juravle dIt.remove(); 4430318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4440318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4450318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (!packageUseInfo.mIsUsedByOtherApps 4460318162abcbd07a0472989df43e00e353fac731bCalin Juravle && packageUseInfo.mDexUseInfoMap.isEmpty()) { 4470318162abcbd07a0472989df43e00e353fac731bCalin Juravle // The package is not used by other apps and we removed all its dex files 4480318162abcbd07a0472989df43e00e353fac731bCalin Juravle // records. Remove the entire package record as well. 4490318162abcbd07a0472989df43e00e353fac731bCalin Juravle pIt.remove(); 4500318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4510318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4520318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4530318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4540318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4550318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4561aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle /** 45799dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle * Clears the {@code usesByOtherApps} marker for the package {@code packageName}. 45899dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle * @return true if the package usage info was updated. 45999dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle */ 46099dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle public boolean clearUsedByOtherApps(String packageName) { 46199dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle synchronized (mPackageUseInfoMap) { 46299dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName); 46399dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle if (packageUseInfo == null || !packageUseInfo.mIsUsedByOtherApps) { 46499dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle return false; 46599dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle } 46699dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle packageUseInfo.mIsUsedByOtherApps = false; 46799dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle return true; 46899dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle } 46999dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle } 47099dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle 47199dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle /** 47299dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle * Remove the usage data associated with package {@code packageName}. 47399dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle * @return true if the package usage was found and removed successfully. 47499dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle */ 47599dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle public boolean removePackage(String packageName) { 47699dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle synchronized (mPackageUseInfoMap) { 47799dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle return mPackageUseInfoMap.remove(packageName) != null; 47899dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle } 47999dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle } 48099dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle 48199dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle /** 4821aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle * Remove all the records about package {@code packageName} belonging to user {@code userId}. 48399dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle * If the package is left with no records of secondary dex usage and is not used by other 48499dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle * apps it will be removed as well. 485b1097411028103b6c88ce325af23d2ff1ec746c8Calin Juravle * @return true if the record was found and actually deleted, 486b1097411028103b6c88ce325af23d2ff1ec746c8Calin Juravle * false if the record doesn't exist 4871aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle */ 4881aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle public boolean removeUserPackage(String packageName, int userId) { 4891aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle synchronized (mPackageUseInfoMap) { 4901aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName); 4911aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (packageUseInfo == null) { 4921aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return false; 4931aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4941aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle boolean updated = false; 4951aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle Iterator<Map.Entry<String, DexUseInfo>> dIt = 4961aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle packageUseInfo.mDexUseInfoMap.entrySet().iterator(); 4971aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle while (dIt.hasNext()) { 4981aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle DexUseInfo dexUseInfo = dIt.next().getValue(); 4991aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (dexUseInfo.mOwnerUserId == userId) { 5001aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle dIt.remove(); 5011aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle updated = true; 5021aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5031aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 50499dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle // If no secondary dex info is left and the package is not used by other apps 50599dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle // remove the data since it is now useless. 50699dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle if (packageUseInfo.mDexUseInfoMap.isEmpty() && !packageUseInfo.mIsUsedByOtherApps) { 50799dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle mPackageUseInfoMap.remove(packageName); 50899dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle updated = true; 50999dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle } 5101aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return updated; 5111aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5121aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5131aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle 5141aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle /** 5151aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle * Remove the secondary dex file record belonging to the package {@code packageName} 5161aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle * and user {@code userId}. 517b1097411028103b6c88ce325af23d2ff1ec746c8Calin Juravle * @return true if the record was found and actually deleted, 518b1097411028103b6c88ce325af23d2ff1ec746c8Calin Juravle * false if the record doesn't exist 5191aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle */ 5201aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle public boolean removeDexFile(String packageName, String dexFile, int userId) { 5211aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle synchronized (mPackageUseInfoMap) { 5221aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName); 5231aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (packageUseInfo == null) { 5241aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return false; 5251aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5261aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return removeDexFile(packageUseInfo, dexFile, userId); 5271aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5281aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5291aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle 5301aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle private boolean removeDexFile(PackageUseInfo packageUseInfo, String dexFile, int userId) { 5311aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle DexUseInfo dexUseInfo = packageUseInfo.mDexUseInfoMap.get(dexFile); 5321aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (dexUseInfo == null) { 5331aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return false; 5341aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5351aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (dexUseInfo.mOwnerUserId == userId) { 5361aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle packageUseInfo.mDexUseInfoMap.remove(dexFile); 5371aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return true; 5381aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5391aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return false; 5401aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 5411aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle 5420318162abcbd07a0472989df43e00e353fac731bCalin Juravle public PackageUseInfo getPackageUseInfo(String packageName) { 5430318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 5441aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle PackageUseInfo useInfo = mPackageUseInfoMap.get(packageName); 5451aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // The useInfo contains a map for secondary dex files which could be modified 5461aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // concurrently after this method returns and thus outside the locking we do here. 5471aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // (i.e. the map is updated when new class loaders are created, which can happen anytime 5481aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // after this method returns) 5491aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // Make a defensive copy to be sure we don't get concurrent modifications. 5501aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return useInfo == null ? null : new PackageUseInfo(useInfo); 5510318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5520318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5530318162abcbd07a0472989df43e00e353fac731bCalin Juravle 55451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle /** 55551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle * Return all packages that contain records of secondary dex files. 55651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle */ 55751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle public Set<String> getAllPackagesWithSecondaryDexFiles() { 55851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle Set<String> packages = new HashSet<>(); 55951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle synchronized (mPackageUseInfoMap) { 56051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle for (Map.Entry<String, PackageUseInfo> entry : mPackageUseInfoMap.entrySet()) { 56151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle if (!entry.getValue().mDexUseInfoMap.isEmpty()) { 56251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle packages.add(entry.getKey()); 56351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 56451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 56551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 56651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle return packages; 56751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle } 56851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle 5690318162abcbd07a0472989df43e00e353fac731bCalin Juravle public void clear() { 5700318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 5710318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.clear(); 5720318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5730318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5740318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Creates a deep copy of the class' mPackageUseInfoMap. 5750318162abcbd07a0472989df43e00e353fac731bCalin Juravle private Map<String, PackageUseInfo> clonePackageUseInfoMap() { 5760318162abcbd07a0472989df43e00e353fac731bCalin Juravle Map<String, PackageUseInfo> clone = new HashMap<>(); 5770318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 5780318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (Map.Entry<String, PackageUseInfo> e : mPackageUseInfoMap.entrySet()) { 5790318162abcbd07a0472989df43e00e353fac731bCalin Juravle clone.put(e.getKey(), new PackageUseInfo(e.getValue())); 5800318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5810318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5820318162abcbd07a0472989df43e00e353fac731bCalin Juravle return clone; 5830318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5840318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5850318162abcbd07a0472989df43e00e353fac731bCalin Juravle private String writeBoolean(boolean bool) { 5860318162abcbd07a0472989df43e00e353fac731bCalin Juravle return bool ? "1" : "0"; 5870318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5880318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5890318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean readBoolean(String bool) { 5900318162abcbd07a0472989df43e00e353fac731bCalin Juravle if ("0".equals(bool)) return false; 5910318162abcbd07a0472989df43e00e353fac731bCalin Juravle if ("1".equals(bool)) return true; 5920318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalArgumentException("Unknown bool encoding: " + bool); 5930318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5940318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5950318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean contains(int[] array, int elem) { 5960318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (int i = 0; i < array.length; i++) { 5970318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (elem == array[i]) { 5980318162abcbd07a0472989df43e00e353fac731bCalin Juravle return true; 5990318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6000318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6010318162abcbd07a0472989df43e00e353fac731bCalin Juravle return false; 6020318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6030318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6040318162abcbd07a0472989df43e00e353fac731bCalin Juravle public String dump() { 6050318162abcbd07a0472989df43e00e353fac731bCalin Juravle StringWriter sw = new StringWriter(); 6060318162abcbd07a0472989df43e00e353fac731bCalin Juravle write(sw); 6070318162abcbd07a0472989df43e00e353fac731bCalin Juravle return sw.toString(); 6080318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6090318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6100318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 6110318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Stores data on how a package and its dex files are used. 6120318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 6130318162abcbd07a0472989df43e00e353fac731bCalin Juravle public static class PackageUseInfo { 6140318162abcbd07a0472989df43e00e353fac731bCalin Juravle // This flag is for the primary and split apks. It is set to true whenever one of them 6150318162abcbd07a0472989df43e00e353fac731bCalin Juravle // is loaded by another app. 6160318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean mIsUsedByOtherApps; 6170318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Map dex paths to their data (isUsedByOtherApps, owner id, loader isa). 6180318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final Map<String, DexUseInfo> mDexUseInfoMap; 619535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle // Packages who load this dex file. 620535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private final Set<String> mLoadingPackages; 6210318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6220318162abcbd07a0472989df43e00e353fac731bCalin Juravle public PackageUseInfo() { 6230318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = false; 6240318162abcbd07a0472989df43e00e353fac731bCalin Juravle mDexUseInfoMap = new HashMap<>(); 625535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle mLoadingPackages = new HashSet<>(); 6260318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6270318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6280318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Creates a deep copy of the `other`. 6290318162abcbd07a0472989df43e00e353fac731bCalin Juravle public PackageUseInfo(PackageUseInfo other) { 6300318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = other.mIsUsedByOtherApps; 6310318162abcbd07a0472989df43e00e353fac731bCalin Juravle mDexUseInfoMap = new HashMap<>(); 6320318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (Map.Entry<String, DexUseInfo> e : other.mDexUseInfoMap.entrySet()) { 6330318162abcbd07a0472989df43e00e353fac731bCalin Juravle mDexUseInfoMap.put(e.getKey(), new DexUseInfo(e.getValue())); 6340318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 635535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle mLoadingPackages = new HashSet<>(other.mLoadingPackages); 6360318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6370318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6380318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean merge(boolean isUsedByOtherApps) { 6390318162abcbd07a0472989df43e00e353fac731bCalin Juravle boolean oldIsUsedByOtherApps = mIsUsedByOtherApps; 6400318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = mIsUsedByOtherApps || isUsedByOtherApps; 6410318162abcbd07a0472989df43e00e353fac731bCalin Juravle return oldIsUsedByOtherApps != this.mIsUsedByOtherApps; 6420318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6430318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6440318162abcbd07a0472989df43e00e353fac731bCalin Juravle public boolean isUsedByOtherApps() { 6450318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mIsUsedByOtherApps; 6460318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6470318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6480318162abcbd07a0472989df43e00e353fac731bCalin Juravle public Map<String, DexUseInfo> getDexUseInfoMap() { 6490318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mDexUseInfoMap; 6500318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 651535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 652535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle public Set<String> getLoadingPackages() { 653535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return mLoadingPackages; 654535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } 6550318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6560318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6570318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 6580318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Stores data about a loaded dex files. 6590318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 6600318162abcbd07a0472989df43e00e353fac731bCalin Juravle public static class DexUseInfo { 6610318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean mIsUsedByOtherApps; 6620318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final int mOwnerUserId; 6630318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final Set<String> mLoaderIsas; 664535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle // Packages who load this dex file. 665535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle private final Set<String> mLoadingPackages; 6660318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6670318162abcbd07a0472989df43e00e353fac731bCalin Juravle public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId) { 6680318162abcbd07a0472989df43e00e353fac731bCalin Juravle this(isUsedByOtherApps, ownerUserId, null); 6690318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6700318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6710318162abcbd07a0472989df43e00e353fac731bCalin Juravle public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String loaderIsa) { 6720318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = isUsedByOtherApps; 6730318162abcbd07a0472989df43e00e353fac731bCalin Juravle mOwnerUserId = ownerUserId; 6740318162abcbd07a0472989df43e00e353fac731bCalin Juravle mLoaderIsas = new HashSet<>(); 6750318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (loaderIsa != null) { 6760318162abcbd07a0472989df43e00e353fac731bCalin Juravle mLoaderIsas.add(loaderIsa); 6770318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 678535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle mLoadingPackages = new HashSet<>(); 6790318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6800318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6810318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Creates a deep copy of the `other`. 6820318162abcbd07a0472989df43e00e353fac731bCalin Juravle public DexUseInfo(DexUseInfo other) { 6830318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = other.mIsUsedByOtherApps; 6840318162abcbd07a0472989df43e00e353fac731bCalin Juravle mOwnerUserId = other.mOwnerUserId; 6850318162abcbd07a0472989df43e00e353fac731bCalin Juravle mLoaderIsas = new HashSet<>(other.mLoaderIsas); 686535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle mLoadingPackages = new HashSet<>(other.mLoadingPackages); 6870318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6880318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6890318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean merge(DexUseInfo dexUseInfo) { 6900318162abcbd07a0472989df43e00e353fac731bCalin Juravle boolean oldIsUsedByOtherApps = mIsUsedByOtherApps; 6910318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = mIsUsedByOtherApps || dexUseInfo.mIsUsedByOtherApps; 6920318162abcbd07a0472989df43e00e353fac731bCalin Juravle boolean updateIsas = mLoaderIsas.addAll(dexUseInfo.mLoaderIsas); 693535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages); 694535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return updateIsas || (oldIsUsedByOtherApps != mIsUsedByOtherApps) || 695535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle updateLoadingPackages; 6960318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 6970318162abcbd07a0472989df43e00e353fac731bCalin Juravle 6980318162abcbd07a0472989df43e00e353fac731bCalin Juravle public boolean isUsedByOtherApps() { 6990318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mIsUsedByOtherApps; 7000318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 7010318162abcbd07a0472989df43e00e353fac731bCalin Juravle 7020318162abcbd07a0472989df43e00e353fac731bCalin Juravle public int getOwnerUserId() { 7030318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mOwnerUserId; 7040318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 7050318162abcbd07a0472989df43e00e353fac731bCalin Juravle 7060318162abcbd07a0472989df43e00e353fac731bCalin Juravle public Set<String> getLoaderIsas() { 7070318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mLoaderIsas; 7080318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 709535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle 710535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle public Set<String> getLoadingPackages() { 711535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle return mLoadingPackages; 712535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle } 7130318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 7140318162abcbd07a0472989df43e00e353fac731bCalin Juravle} 715