PackageDexUsage.java revision 1aa5f88e35734383e66ecd65e82e83d788e18ccb
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; 380318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Iterator; 390318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.HashMap; 400318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.HashSet; 410318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Map; 420318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Set; 430318162abcbd07a0472989df43e00e353fac731bCalin Juravle 440318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport dalvik.system.VMRuntime; 450318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport libcore.io.IoUtils; 460318162abcbd07a0472989df43e00e353fac731bCalin Juravle 470318162abcbd07a0472989df43e00e353fac731bCalin Juravle/** 480318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Stat file which store usage information about dex files. 490318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 500318162abcbd07a0472989df43e00e353fac731bCalin Juravlepublic class PackageDexUsage extends AbstractStatsBase<Void> { 510318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static String TAG = "PackageDexUsage"; 520318162abcbd07a0472989df43e00e353fac731bCalin Juravle 530318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static int PACKAGE_DEX_USAGE_VERSION = 1; 540318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static String PACKAGE_DEX_USAGE_VERSION_HEADER = 550318162abcbd07a0472989df43e00e353fac731bCalin Juravle "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__"; 560318162abcbd07a0472989df43e00e353fac731bCalin Juravle 570318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static String SPLIT_CHAR = ","; 580318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final static String DEX_LINE_CHAR = "#"; 590318162abcbd07a0472989df43e00e353fac731bCalin Juravle 600318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Map which structures the information we have on a package. 610318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Maps package name to package data (which stores info about UsedByOtherApps and 620318162abcbd07a0472989df43e00e353fac731bCalin Juravle // secondary dex files.). 630318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Access to this map needs synchronized. 640318162abcbd07a0472989df43e00e353fac731bCalin Juravle @GuardedBy("mPackageUseInfoMap") 650318162abcbd07a0472989df43e00e353fac731bCalin Juravle private Map<String, PackageUseInfo> mPackageUseInfoMap; 660318162abcbd07a0472989df43e00e353fac731bCalin Juravle 670318162abcbd07a0472989df43e00e353fac731bCalin Juravle public PackageDexUsage() { 680318162abcbd07a0472989df43e00e353fac731bCalin Juravle super("package-dex-usage.list", "PackageDexUsage_DiskWriter", /*lock*/ false); 690318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap = new HashMap<>(); 700318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 710318162abcbd07a0472989df43e00e353fac731bCalin Juravle 720318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 730318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Record a dex file load. 740318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 750318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Note this is called when apps load dex files and as such it should return 760318162abcbd07a0472989df43e00e353fac731bCalin Juravle * as fast as possible. 770318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 780318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param loadingPackage the package performing the load 790318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param dexPath the path of the dex files being loaded 800318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param ownerUserId the user id which runs the code loading the dex files 810318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param loaderIsa the ISA of the app loading the dex files 820318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param isUsedByOtherApps whether or not this dex file was not loaded by its owning package 830318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @param primaryOrSplit whether or not the dex file is a primary/split dex. True indicates 840318162abcbd07a0472989df43e00e353fac731bCalin Juravle * the file is either primary or a split. False indicates the file is secondary dex. 850318162abcbd07a0472989df43e00e353fac731bCalin Juravle * @return true if the dex load constitutes new information, or false if this information 860318162abcbd07a0472989df43e00e353fac731bCalin Juravle * has been seen before. 870318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 880318162abcbd07a0472989df43e00e353fac731bCalin Juravle public boolean record(String owningPackageName, String dexPath, int ownerUserId, 890318162abcbd07a0472989df43e00e353fac731bCalin Juravle String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit) { 900318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (!PackageManagerServiceUtils.checkISA(loaderIsa)) { 910318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported"); 920318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 930318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 940318162abcbd07a0472989df43e00e353fac731bCalin Juravle PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName); 950318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (packageUseInfo == null) { 960318162abcbd07a0472989df43e00e353fac731bCalin Juravle // This is the first time we see the package. 970318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo = new PackageUseInfo(); 980318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (primaryOrSplit) { 990318162abcbd07a0472989df43e00e353fac731bCalin Juravle // If we have a primary or a split apk, set isUsedByOtherApps. 1000318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We do not need to record the loaderIsa or the owner because we compile 1010318162abcbd07a0472989df43e00e353fac731bCalin Juravle // primaries for all users and all ISAs. 1020318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo.mIsUsedByOtherApps = isUsedByOtherApps; 1030318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 1040318162abcbd07a0472989df43e00e353fac731bCalin Juravle // For secondary dex files record the loaderISA and the owner. We'll need 1050318162abcbd07a0472989df43e00e353fac731bCalin Juravle // to know under which user to compile and for what ISA. 1060318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo.mDexUseInfoMap.put( 1070318162abcbd07a0472989df43e00e353fac731bCalin Juravle dexPath, new DexUseInfo(isUsedByOtherApps, ownerUserId, loaderIsa)); 1080318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1090318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.put(owningPackageName, packageUseInfo); 1100318162abcbd07a0472989df43e00e353fac731bCalin Juravle return true; 1110318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 1120318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We already have data on this package. Amend it. 1130318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (primaryOrSplit) { 1140318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We have a possible update on the primary apk usage. Merge 1150318162abcbd07a0472989df43e00e353fac731bCalin Juravle // isUsedByOtherApps information and return if there was an update. 1160318162abcbd07a0472989df43e00e353fac731bCalin Juravle return packageUseInfo.merge(isUsedByOtherApps); 1170318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 1180318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo newData = new DexUseInfo( 1190318162abcbd07a0472989df43e00e353fac731bCalin Juravle isUsedByOtherApps, ownerUserId, loaderIsa); 1200318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo existingData = packageUseInfo.mDexUseInfoMap.get(dexPath); 1210318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (existingData == null) { 1220318162abcbd07a0472989df43e00e353fac731bCalin Juravle // It's the first time we see this dex file. 1230318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo.mDexUseInfoMap.put(dexPath, newData); 1240318162abcbd07a0472989df43e00e353fac731bCalin Juravle return true; 1250318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 1260318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (ownerUserId != existingData.mOwnerUserId) { 1270318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Oups, this should never happen, the DexManager who calls this should 1280318162abcbd07a0472989df43e00e353fac731bCalin Juravle // do the proper checks and not call record if the user does not own the 1290318162abcbd07a0472989df43e00e353fac731bCalin Juravle // dex path. 1300318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Secondary dex files are stored in the app user directory. A change in 1310318162abcbd07a0472989df43e00e353fac731bCalin Juravle // owningUser for the same path means that something went wrong at some 1320318162abcbd07a0472989df43e00e353fac731bCalin Juravle // higher level, and the loaderUser was allowed to cross 1330318162abcbd07a0472989df43e00e353fac731bCalin Juravle // user-boundaries and access data from what we know to be the owner 1340318162abcbd07a0472989df43e00e353fac731bCalin Juravle // user. 1350318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalArgumentException("Trying to change ownerUserId for " 1360318162abcbd07a0472989df43e00e353fac731bCalin Juravle + " dex path " + dexPath + " from " + existingData.mOwnerUserId 1370318162abcbd07a0472989df43e00e353fac731bCalin Juravle + " to " + ownerUserId); 1380318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1390318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Merge the information into the existing data. 1400318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Returns true if there was an update. 1410318162abcbd07a0472989df43e00e353fac731bCalin Juravle return existingData.merge(newData); 1420318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1430318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1440318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1450318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1460318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1470318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1480318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 1490318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Convenience method for sync reads which does not force the user to pass a useless 1500318162abcbd07a0472989df43e00e353fac731bCalin Juravle * (Void) null. 1510318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 1520318162abcbd07a0472989df43e00e353fac731bCalin Juravle public void read() { 1530318162abcbd07a0472989df43e00e353fac731bCalin Juravle read((Void) null); 1540318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1550318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1560318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 1570318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Convenience method for async writes which does not force the user to pass a useless 1580318162abcbd07a0472989df43e00e353fac731bCalin Juravle * (Void) null. 1590318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 1600318162abcbd07a0472989df43e00e353fac731bCalin Juravle public void maybeWriteAsync() { 1610318162abcbd07a0472989df43e00e353fac731bCalin Juravle maybeWriteAsync((Void) null); 1620318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1630318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1640318162abcbd07a0472989df43e00e353fac731bCalin Juravle @Override 1650318162abcbd07a0472989df43e00e353fac731bCalin Juravle protected void writeInternal(Void data) { 1660318162abcbd07a0472989df43e00e353fac731bCalin Juravle AtomicFile file = getFile(); 1670318162abcbd07a0472989df43e00e353fac731bCalin Juravle FileOutputStream f = null; 1680318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1690318162abcbd07a0472989df43e00e353fac731bCalin Juravle try { 1700318162abcbd07a0472989df43e00e353fac731bCalin Juravle f = file.startWrite(); 1710318162abcbd07a0472989df43e00e353fac731bCalin Juravle OutputStreamWriter osw = new OutputStreamWriter(f); 1720318162abcbd07a0472989df43e00e353fac731bCalin Juravle write(osw); 1730318162abcbd07a0472989df43e00e353fac731bCalin Juravle osw.flush(); 1740318162abcbd07a0472989df43e00e353fac731bCalin Juravle file.finishWrite(f); 1750318162abcbd07a0472989df43e00e353fac731bCalin Juravle } catch (IOException e) { 1760318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (f != null) { 1770318162abcbd07a0472989df43e00e353fac731bCalin Juravle file.failWrite(f); 1780318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1790318162abcbd07a0472989df43e00e353fac731bCalin Juravle Slog.e(TAG, "Failed to write usage for dex files", e); 1800318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1810318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 1820318162abcbd07a0472989df43e00e353fac731bCalin Juravle 1830318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 1840318162abcbd07a0472989df43e00e353fac731bCalin Juravle * File format: 1850318162abcbd07a0472989df43e00e353fac731bCalin Juravle * 1860318162abcbd07a0472989df43e00e353fac731bCalin Juravle * file_magic_version 1870318162abcbd07a0472989df43e00e353fac731bCalin Juravle * package_name_1 1880318162abcbd07a0472989df43e00e353fac731bCalin Juravle * #dex_file_path_1_1 1890318162abcbd07a0472989df43e00e353fac731bCalin Juravle * user_1_1, used_by_other_app_1_1, user_isa_1_1_1, user_isa_1_1_2 1900318162abcbd07a0472989df43e00e353fac731bCalin Juravle * #dex_file_path_1_2 1910318162abcbd07a0472989df43e00e353fac731bCalin Juravle * user_1_2, used_by_other_app_1_2, user_isa_1_2_1, user_isa_1_2_2 1920318162abcbd07a0472989df43e00e353fac731bCalin Juravle * ... 1930318162abcbd07a0472989df43e00e353fac731bCalin Juravle * package_name_2 1940318162abcbd07a0472989df43e00e353fac731bCalin Juravle * #dex_file_path_2_1 1950318162abcbd07a0472989df43e00e353fac731bCalin Juravle * user_2_1, used_by_other_app_2_1, user_isa_2_1_1, user_isa_2_1_2 1960318162abcbd07a0472989df43e00e353fac731bCalin Juravle * #dex_file_path_2_2, 1970318162abcbd07a0472989df43e00e353fac731bCalin Juravle * user_2_2, used_by_other_app_2_2, user_isa_2_2_1, user_isa_2_2_2 1980318162abcbd07a0472989df43e00e353fac731bCalin Juravle * ... 1990318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 2000318162abcbd07a0472989df43e00e353fac731bCalin Juravle /* package */ void write(Writer out) { 2010318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Make a clone to avoid locking while writing to disk. 2020318162abcbd07a0472989df43e00e353fac731bCalin Juravle Map<String, PackageUseInfo> packageUseInfoMapClone = clonePackageUseInfoMap(); 2030318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2040318162abcbd07a0472989df43e00e353fac731bCalin Juravle FastPrintWriter fpw = new FastPrintWriter(out); 2050318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2060318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Write the header. 2070318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.print(PACKAGE_DEX_USAGE_VERSION_HEADER); 2080318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.println(PACKAGE_DEX_USAGE_VERSION); 2090318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2100318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (Map.Entry<String, PackageUseInfo> pEntry : packageUseInfoMapClone.entrySet()) { 2110318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Write the package line. 2120318162abcbd07a0472989df43e00e353fac731bCalin Juravle String packageName = pEntry.getKey(); 2130318162abcbd07a0472989df43e00e353fac731bCalin Juravle PackageUseInfo packageUseInfo = pEntry.getValue(); 2140318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2150318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.println(String.join(SPLIT_CHAR, packageName, 2160318162abcbd07a0472989df43e00e353fac731bCalin Juravle writeBoolean(packageUseInfo.mIsUsedByOtherApps))); 2170318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2180318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Write dex file lines. 2190318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (Map.Entry<String, DexUseInfo> dEntry : packageUseInfo.mDexUseInfoMap.entrySet()) { 2200318162abcbd07a0472989df43e00e353fac731bCalin Juravle String dexPath = dEntry.getKey(); 2210318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo dexUseInfo = dEntry.getValue(); 2220318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.println(DEX_LINE_CHAR + dexPath); 2230318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.print(String.join(SPLIT_CHAR, Integer.toString(dexUseInfo.mOwnerUserId), 2240318162abcbd07a0472989df43e00e353fac731bCalin Juravle writeBoolean(dexUseInfo.mIsUsedByOtherApps))); 2250318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (String isa : dexUseInfo.mLoaderIsas) { 2260318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.print(SPLIT_CHAR + isa); 2270318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2280318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.println(); 2290318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2300318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2310318162abcbd07a0472989df43e00e353fac731bCalin Juravle fpw.flush(); 2320318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2330318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2340318162abcbd07a0472989df43e00e353fac731bCalin Juravle @Override 2350318162abcbd07a0472989df43e00e353fac731bCalin Juravle protected void readInternal(Void data) { 2360318162abcbd07a0472989df43e00e353fac731bCalin Juravle AtomicFile file = getFile(); 2370318162abcbd07a0472989df43e00e353fac731bCalin Juravle BufferedReader in = null; 2380318162abcbd07a0472989df43e00e353fac731bCalin Juravle try { 2390318162abcbd07a0472989df43e00e353fac731bCalin Juravle in = new BufferedReader(new InputStreamReader(file.openRead())); 2400318162abcbd07a0472989df43e00e353fac731bCalin Juravle read(in); 2410318162abcbd07a0472989df43e00e353fac731bCalin Juravle } catch (FileNotFoundException expected) { 2420318162abcbd07a0472989df43e00e353fac731bCalin Juravle // The file may not be there. E.g. When we first take the OTA with this feature. 2430318162abcbd07a0472989df43e00e353fac731bCalin Juravle } catch (IOException e) { 2440318162abcbd07a0472989df43e00e353fac731bCalin Juravle Slog.w(TAG, "Failed to parse package dex usage.", e); 2450318162abcbd07a0472989df43e00e353fac731bCalin Juravle } finally { 2460318162abcbd07a0472989df43e00e353fac731bCalin Juravle IoUtils.closeQuietly(in); 2470318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2480318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2490318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2500318162abcbd07a0472989df43e00e353fac731bCalin Juravle /* package */ void read(Reader reader) throws IOException { 2510318162abcbd07a0472989df43e00e353fac731bCalin Juravle Map<String, PackageUseInfo> data = new HashMap<>(); 2520318162abcbd07a0472989df43e00e353fac731bCalin Juravle BufferedReader in = new BufferedReader(reader); 2530318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Read header, do version check. 2540318162abcbd07a0472989df43e00e353fac731bCalin Juravle String versionLine = in.readLine(); 2550318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (versionLine == null) { 2560318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("No version line found."); 2570318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 2580318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (!versionLine.startsWith(PACKAGE_DEX_USAGE_VERSION_HEADER)) { 2590318162abcbd07a0472989df43e00e353fac731bCalin Juravle // TODO(calin): the caller is responsible to clear the file. 2600318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Invalid version line: " + versionLine); 2610318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2620318162abcbd07a0472989df43e00e353fac731bCalin Juravle int version = Integer.parseInt( 2630318162abcbd07a0472989df43e00e353fac731bCalin Juravle versionLine.substring(PACKAGE_DEX_USAGE_VERSION_HEADER.length())); 2640318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (version != PACKAGE_DEX_USAGE_VERSION) { 2650318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Unexpected version: " + version); 2660318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2670318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2680318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2690318162abcbd07a0472989df43e00e353fac731bCalin Juravle String s = null; 2700318162abcbd07a0472989df43e00e353fac731bCalin Juravle String currentPakage = null; 2710318162abcbd07a0472989df43e00e353fac731bCalin Juravle PackageUseInfo currentPakageData = null; 2720318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2730318162abcbd07a0472989df43e00e353fac731bCalin Juravle Set<String> supportedIsas = new HashSet<>(); 2740318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (String abi : Build.SUPPORTED_ABIS) { 2750318162abcbd07a0472989df43e00e353fac731bCalin Juravle supportedIsas.add(VMRuntime.getInstructionSet(abi)); 2760318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2770318162abcbd07a0472989df43e00e353fac731bCalin Juravle while ((s = in.readLine()) != null) { 2780318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (s.startsWith(DEX_LINE_CHAR)) { 2790318162abcbd07a0472989df43e00e353fac731bCalin Juravle // This is the start of the the dex lines. 2800318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We expect two lines for each dex entry: 2810318162abcbd07a0472989df43e00e353fac731bCalin Juravle // #dexPaths 2820318162abcbd07a0472989df43e00e353fac731bCalin Juravle // onwerUserId,isUsedByOtherApps,isa1,isa2 2830318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (currentPakage == null) { 2840318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException( 2850318162abcbd07a0472989df43e00e353fac731bCalin Juravle "Malformed PackageDexUsage file. Expected package line before dex line."); 2860318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2870318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2880318162abcbd07a0472989df43e00e353fac731bCalin Juravle // First line is the dex path. 2890318162abcbd07a0472989df43e00e353fac731bCalin Juravle String dexPath = s.substring(DEX_LINE_CHAR.length()); 2900318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Next line is the dex data. 2910318162abcbd07a0472989df43e00e353fac731bCalin Juravle s = in.readLine(); 2920318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (s == null) { 2930318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Could not fine dexUseInfo for line: " + s); 2940318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 2950318162abcbd07a0472989df43e00e353fac731bCalin Juravle 2960318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We expect at least 3 elements (isUsedByOtherApps, userId, isa). 2970318162abcbd07a0472989df43e00e353fac731bCalin Juravle String[] elems = s.split(SPLIT_CHAR); 2980318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (elems.length < 3) { 2990318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Invalid PackageDexUsage line: " + s); 3000318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3010318162abcbd07a0472989df43e00e353fac731bCalin Juravle int ownerUserId = Integer.parseInt(elems[0]); 3020318162abcbd07a0472989df43e00e353fac731bCalin Juravle boolean isUsedByOtherApps = readBoolean(elems[1]); 3030318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId); 3040318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (int i = 2; i < elems.length; i++) { 3050318162abcbd07a0472989df43e00e353fac731bCalin Juravle String isa = elems[i]; 3060318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (supportedIsas.contains(isa)) { 3070318162abcbd07a0472989df43e00e353fac731bCalin Juravle dexUseInfo.mLoaderIsas.add(elems[i]); 3080318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 3090318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Should never happen unless someone crafts the file manually. 3100318162abcbd07a0472989df43e00e353fac731bCalin Juravle // In theory it could if we drop a supported ISA after an OTA but we don't 3110318162abcbd07a0472989df43e00e353fac731bCalin Juravle // do that. 3120318162abcbd07a0472989df43e00e353fac731bCalin Juravle Slog.wtf(TAG, "Unsupported ISA when parsing PackageDexUsage: " + isa); 3130318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3140318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3150318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (supportedIsas.isEmpty()) { 3160318162abcbd07a0472989df43e00e353fac731bCalin Juravle Slog.wtf(TAG, "Ignore dexPath when parsing PackageDexUsage because of " + 3170318162abcbd07a0472989df43e00e353fac731bCalin Juravle "unsupported isas. dexPath=" + dexPath); 3180318162abcbd07a0472989df43e00e353fac731bCalin Juravle continue; 3190318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3200318162abcbd07a0472989df43e00e353fac731bCalin Juravle currentPakageData.mDexUseInfoMap.put(dexPath, dexUseInfo); 3210318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 3220318162abcbd07a0472989df43e00e353fac731bCalin Juravle // This is a package line. 3230318162abcbd07a0472989df43e00e353fac731bCalin Juravle // We expect it to be: `packageName,isUsedByOtherApps`. 3240318162abcbd07a0472989df43e00e353fac731bCalin Juravle String[] elems = s.split(SPLIT_CHAR); 3250318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (elems.length != 2) { 3260318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalStateException("Invalid PackageDexUsage line: " + s); 3270318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3280318162abcbd07a0472989df43e00e353fac731bCalin Juravle currentPakage = elems[0]; 3290318162abcbd07a0472989df43e00e353fac731bCalin Juravle currentPakageData = new PackageUseInfo(); 3300318162abcbd07a0472989df43e00e353fac731bCalin Juravle currentPakageData.mIsUsedByOtherApps = readBoolean(elems[1]); 3310318162abcbd07a0472989df43e00e353fac731bCalin Juravle data.put(currentPakage, currentPakageData); 3320318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3330318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3340318162abcbd07a0472989df43e00e353fac731bCalin Juravle 3350318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 3360318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.clear(); 3370318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.putAll(data); 3380318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3390318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3400318162abcbd07a0472989df43e00e353fac731bCalin Juravle 3410318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 3420318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Syncs the existing data with the set of available packages by removing obsolete entries. 3430318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 3440318162abcbd07a0472989df43e00e353fac731bCalin Juravle public void syncData(Map<String, Set<Integer>> packageToUsersMap) { 3450318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 3460318162abcbd07a0472989df43e00e353fac731bCalin Juravle Iterator<Map.Entry<String, PackageUseInfo>> pIt = 3470318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.entrySet().iterator(); 3480318162abcbd07a0472989df43e00e353fac731bCalin Juravle while (pIt.hasNext()) { 3490318162abcbd07a0472989df43e00e353fac731bCalin Juravle Map.Entry<String, PackageUseInfo> pEntry = pIt.next(); 3500318162abcbd07a0472989df43e00e353fac731bCalin Juravle String packageName = pEntry.getKey(); 3510318162abcbd07a0472989df43e00e353fac731bCalin Juravle PackageUseInfo packageUseInfo = pEntry.getValue(); 3520318162abcbd07a0472989df43e00e353fac731bCalin Juravle Set<Integer> users = packageToUsersMap.get(packageName); 3530318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (users == null) { 3540318162abcbd07a0472989df43e00e353fac731bCalin Juravle // The package doesn't exist anymore, remove the record. 3550318162abcbd07a0472989df43e00e353fac731bCalin Juravle pIt.remove(); 3560318162abcbd07a0472989df43e00e353fac731bCalin Juravle } else { 3570318162abcbd07a0472989df43e00e353fac731bCalin Juravle // The package exists but we can prune the entries associated with non existing 3580318162abcbd07a0472989df43e00e353fac731bCalin Juravle // users. 3590318162abcbd07a0472989df43e00e353fac731bCalin Juravle Iterator<Map.Entry<String, DexUseInfo>> dIt = 3600318162abcbd07a0472989df43e00e353fac731bCalin Juravle packageUseInfo.mDexUseInfoMap.entrySet().iterator(); 3610318162abcbd07a0472989df43e00e353fac731bCalin Juravle while (dIt.hasNext()) { 3620318162abcbd07a0472989df43e00e353fac731bCalin Juravle DexUseInfo dexUseInfo = dIt.next().getValue(); 3630318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (!users.contains(dexUseInfo.mOwnerUserId)) { 3640318162abcbd07a0472989df43e00e353fac731bCalin Juravle // User was probably removed. Delete its dex usage info. 3650318162abcbd07a0472989df43e00e353fac731bCalin Juravle dIt.remove(); 3660318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3670318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3680318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (!packageUseInfo.mIsUsedByOtherApps 3690318162abcbd07a0472989df43e00e353fac731bCalin Juravle && packageUseInfo.mDexUseInfoMap.isEmpty()) { 3700318162abcbd07a0472989df43e00e353fac731bCalin Juravle // The package is not used by other apps and we removed all its dex files 3710318162abcbd07a0472989df43e00e353fac731bCalin Juravle // records. Remove the entire package record as well. 3720318162abcbd07a0472989df43e00e353fac731bCalin Juravle pIt.remove(); 3730318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3740318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3750318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3760318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3770318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 3780318162abcbd07a0472989df43e00e353fac731bCalin Juravle 3791aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle /** 3801aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle * Remove all the records about package {@code packageName} belonging to user {@code userId}. 3811aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle */ 3821aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle public boolean removeUserPackage(String packageName, int userId) { 3831aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle synchronized (mPackageUseInfoMap) { 3841aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName); 3851aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (packageUseInfo == null) { 3861aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return false; 3871aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 3881aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle boolean updated = false; 3891aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle Iterator<Map.Entry<String, DexUseInfo>> dIt = 3901aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle packageUseInfo.mDexUseInfoMap.entrySet().iterator(); 3911aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle while (dIt.hasNext()) { 3921aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle DexUseInfo dexUseInfo = dIt.next().getValue(); 3931aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (dexUseInfo.mOwnerUserId == userId) { 3941aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle dIt.remove(); 3951aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle updated = true; 3961aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 3971aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 3981aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return updated; 3991aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4001aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4011aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle 4021aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle /** 4031aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle * Remove the secondary dex file record belonging to the package {@code packageName} 4041aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle * and user {@code userId}. 4051aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle */ 4061aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle public boolean removeDexFile(String packageName, String dexFile, int userId) { 4071aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle synchronized (mPackageUseInfoMap) { 4081aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName); 4091aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (packageUseInfo == null) { 4101aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return false; 4111aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4121aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return removeDexFile(packageUseInfo, dexFile, userId); 4131aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4141aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4151aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle 4161aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle private boolean removeDexFile(PackageUseInfo packageUseInfo, String dexFile, int userId) { 4171aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle DexUseInfo dexUseInfo = packageUseInfo.mDexUseInfoMap.get(dexFile); 4181aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (dexUseInfo == null) { 4191aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return false; 4201aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4211aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle if (dexUseInfo.mOwnerUserId == userId) { 4221aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle packageUseInfo.mDexUseInfoMap.remove(dexFile); 4231aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return true; 4241aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4251aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return false; 4261aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle } 4271aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle 4280318162abcbd07a0472989df43e00e353fac731bCalin Juravle public PackageUseInfo getPackageUseInfo(String packageName) { 4290318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 4301aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle PackageUseInfo useInfo = mPackageUseInfoMap.get(packageName); 4311aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // The useInfo contains a map for secondary dex files which could be modified 4321aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // concurrently after this method returns and thus outside the locking we do here. 4331aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // (i.e. the map is updated when new class loaders are created, which can happen anytime 4341aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // after this method returns) 4351aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle // Make a defensive copy to be sure we don't get concurrent modifications. 4361aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle return useInfo == null ? null : new PackageUseInfo(useInfo); 4370318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4380318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4390318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4400318162abcbd07a0472989df43e00e353fac731bCalin Juravle public void clear() { 4410318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 4420318162abcbd07a0472989df43e00e353fac731bCalin Juravle mPackageUseInfoMap.clear(); 4430318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4440318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4450318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Creates a deep copy of the class' mPackageUseInfoMap. 4460318162abcbd07a0472989df43e00e353fac731bCalin Juravle private Map<String, PackageUseInfo> clonePackageUseInfoMap() { 4470318162abcbd07a0472989df43e00e353fac731bCalin Juravle Map<String, PackageUseInfo> clone = new HashMap<>(); 4480318162abcbd07a0472989df43e00e353fac731bCalin Juravle synchronized (mPackageUseInfoMap) { 4490318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (Map.Entry<String, PackageUseInfo> e : mPackageUseInfoMap.entrySet()) { 4500318162abcbd07a0472989df43e00e353fac731bCalin Juravle clone.put(e.getKey(), new PackageUseInfo(e.getValue())); 4510318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4520318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4530318162abcbd07a0472989df43e00e353fac731bCalin Juravle return clone; 4540318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4550318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4560318162abcbd07a0472989df43e00e353fac731bCalin Juravle private String writeBoolean(boolean bool) { 4570318162abcbd07a0472989df43e00e353fac731bCalin Juravle return bool ? "1" : "0"; 4580318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4590318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4600318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean readBoolean(String bool) { 4610318162abcbd07a0472989df43e00e353fac731bCalin Juravle if ("0".equals(bool)) return false; 4620318162abcbd07a0472989df43e00e353fac731bCalin Juravle if ("1".equals(bool)) return true; 4630318162abcbd07a0472989df43e00e353fac731bCalin Juravle throw new IllegalArgumentException("Unknown bool encoding: " + bool); 4640318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4650318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4660318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean contains(int[] array, int elem) { 4670318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (int i = 0; i < array.length; i++) { 4680318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (elem == array[i]) { 4690318162abcbd07a0472989df43e00e353fac731bCalin Juravle return true; 4700318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4710318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4720318162abcbd07a0472989df43e00e353fac731bCalin Juravle return false; 4730318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4740318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4750318162abcbd07a0472989df43e00e353fac731bCalin Juravle public String dump() { 4760318162abcbd07a0472989df43e00e353fac731bCalin Juravle StringWriter sw = new StringWriter(); 4770318162abcbd07a0472989df43e00e353fac731bCalin Juravle write(sw); 4780318162abcbd07a0472989df43e00e353fac731bCalin Juravle return sw.toString(); 4790318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4800318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4810318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 4820318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Stores data on how a package and its dex files are used. 4830318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 4840318162abcbd07a0472989df43e00e353fac731bCalin Juravle public static class PackageUseInfo { 4850318162abcbd07a0472989df43e00e353fac731bCalin Juravle // This flag is for the primary and split apks. It is set to true whenever one of them 4860318162abcbd07a0472989df43e00e353fac731bCalin Juravle // is loaded by another app. 4870318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean mIsUsedByOtherApps; 4880318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Map dex paths to their data (isUsedByOtherApps, owner id, loader isa). 4890318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final Map<String, DexUseInfo> mDexUseInfoMap; 4900318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4910318162abcbd07a0472989df43e00e353fac731bCalin Juravle public PackageUseInfo() { 4920318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = false; 4930318162abcbd07a0472989df43e00e353fac731bCalin Juravle mDexUseInfoMap = new HashMap<>(); 4940318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 4950318162abcbd07a0472989df43e00e353fac731bCalin Juravle 4960318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Creates a deep copy of the `other`. 4970318162abcbd07a0472989df43e00e353fac731bCalin Juravle public PackageUseInfo(PackageUseInfo other) { 4980318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = other.mIsUsedByOtherApps; 4990318162abcbd07a0472989df43e00e353fac731bCalin Juravle mDexUseInfoMap = new HashMap<>(); 5000318162abcbd07a0472989df43e00e353fac731bCalin Juravle for (Map.Entry<String, DexUseInfo> e : other.mDexUseInfoMap.entrySet()) { 5010318162abcbd07a0472989df43e00e353fac731bCalin Juravle mDexUseInfoMap.put(e.getKey(), new DexUseInfo(e.getValue())); 5020318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5030318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5040318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5050318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean merge(boolean isUsedByOtherApps) { 5060318162abcbd07a0472989df43e00e353fac731bCalin Juravle boolean oldIsUsedByOtherApps = mIsUsedByOtherApps; 5070318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = mIsUsedByOtherApps || isUsedByOtherApps; 5080318162abcbd07a0472989df43e00e353fac731bCalin Juravle return oldIsUsedByOtherApps != this.mIsUsedByOtherApps; 5090318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5100318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5110318162abcbd07a0472989df43e00e353fac731bCalin Juravle public boolean isUsedByOtherApps() { 5120318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mIsUsedByOtherApps; 5130318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5140318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5150318162abcbd07a0472989df43e00e353fac731bCalin Juravle public Map<String, DexUseInfo> getDexUseInfoMap() { 5160318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mDexUseInfoMap; 5170318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5180318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5190318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5200318162abcbd07a0472989df43e00e353fac731bCalin Juravle /** 5210318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Stores data about a loaded dex files. 5220318162abcbd07a0472989df43e00e353fac731bCalin Juravle */ 5230318162abcbd07a0472989df43e00e353fac731bCalin Juravle public static class DexUseInfo { 5240318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean mIsUsedByOtherApps; 5250318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final int mOwnerUserId; 5260318162abcbd07a0472989df43e00e353fac731bCalin Juravle private final Set<String> mLoaderIsas; 5270318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5280318162abcbd07a0472989df43e00e353fac731bCalin Juravle public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId) { 5290318162abcbd07a0472989df43e00e353fac731bCalin Juravle this(isUsedByOtherApps, ownerUserId, null); 5300318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5310318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5320318162abcbd07a0472989df43e00e353fac731bCalin Juravle public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String loaderIsa) { 5330318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = isUsedByOtherApps; 5340318162abcbd07a0472989df43e00e353fac731bCalin Juravle mOwnerUserId = ownerUserId; 5350318162abcbd07a0472989df43e00e353fac731bCalin Juravle mLoaderIsas = new HashSet<>(); 5360318162abcbd07a0472989df43e00e353fac731bCalin Juravle if (loaderIsa != null) { 5370318162abcbd07a0472989df43e00e353fac731bCalin Juravle mLoaderIsas.add(loaderIsa); 5380318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5390318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5400318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5410318162abcbd07a0472989df43e00e353fac731bCalin Juravle // Creates a deep copy of the `other`. 5420318162abcbd07a0472989df43e00e353fac731bCalin Juravle public DexUseInfo(DexUseInfo other) { 5430318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = other.mIsUsedByOtherApps; 5440318162abcbd07a0472989df43e00e353fac731bCalin Juravle mOwnerUserId = other.mOwnerUserId; 5450318162abcbd07a0472989df43e00e353fac731bCalin Juravle mLoaderIsas = new HashSet<>(other.mLoaderIsas); 5460318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5470318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5480318162abcbd07a0472989df43e00e353fac731bCalin Juravle private boolean merge(DexUseInfo dexUseInfo) { 5490318162abcbd07a0472989df43e00e353fac731bCalin Juravle boolean oldIsUsedByOtherApps = mIsUsedByOtherApps; 5500318162abcbd07a0472989df43e00e353fac731bCalin Juravle mIsUsedByOtherApps = mIsUsedByOtherApps || dexUseInfo.mIsUsedByOtherApps; 5510318162abcbd07a0472989df43e00e353fac731bCalin Juravle boolean updateIsas = mLoaderIsas.addAll(dexUseInfo.mLoaderIsas); 5520318162abcbd07a0472989df43e00e353fac731bCalin Juravle return updateIsas || (oldIsUsedByOtherApps != mIsUsedByOtherApps); 5530318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5540318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5550318162abcbd07a0472989df43e00e353fac731bCalin Juravle public boolean isUsedByOtherApps() { 5560318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mIsUsedByOtherApps; 5570318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5580318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5590318162abcbd07a0472989df43e00e353fac731bCalin Juravle public int getOwnerUserId() { 5600318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mOwnerUserId; 5610318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5620318162abcbd07a0472989df43e00e353fac731bCalin Juravle 5630318162abcbd07a0472989df43e00e353fac731bCalin Juravle public Set<String> getLoaderIsas() { 5640318162abcbd07a0472989df43e00e353fac731bCalin Juravle return mLoaderIsas; 5650318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5660318162abcbd07a0472989df43e00e353fac731bCalin Juravle } 5670318162abcbd07a0472989df43e00e353fac731bCalin Juravle} 568