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.FileNotFoundException;
300318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.FileOutputStream;
310318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.InputStreamReader;
320318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.IOException;
330318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.OutputStreamWriter;
340318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.Reader;
350318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.StringWriter;
360318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.io.Writer;
37535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravleimport java.util.Arrays;
3852a452cf685c56dc6872dbb19e822736484f672fCalin Juravleimport java.util.Collection;
39535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravleimport java.util.Collections;
400318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Iterator;
410318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.HashMap;
420318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.HashSet;
43535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravleimport java.util.List;
440318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Map;
45607223f3b7a1c4dc3ac995f742f8d2da50d85ffcNarayan Kamathimport java.util.Objects;
460318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport java.util.Set;
470318162abcbd07a0472989df43e00e353fac731bCalin Juravle
480318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport dalvik.system.VMRuntime;
490318162abcbd07a0472989df43e00e353fac731bCalin Juravleimport libcore.io.IoUtils;
500318162abcbd07a0472989df43e00e353fac731bCalin Juravle
510318162abcbd07a0472989df43e00e353fac731bCalin Juravle/**
520318162abcbd07a0472989df43e00e353fac731bCalin Juravle * Stat file which store usage information about dex files.
530318162abcbd07a0472989df43e00e353fac731bCalin Juravle */
540318162abcbd07a0472989df43e00e353fac731bCalin Juravlepublic class PackageDexUsage extends AbstractStatsBase<Void> {
550318162abcbd07a0472989df43e00e353fac731bCalin Juravle    private final static String TAG = "PackageDexUsage";
560318162abcbd07a0472989df43e00e353fac731bCalin Juravle
57f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    // We support previous version to ensure that the usage list remains valid cross OTAs.
58535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1 = 1;
5952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    // Version 2 added:
6052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    //  - the list of packages that load the dex files
6152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    //  - class loader contexts for secondary dex files
6252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    //  - usage for all code paths (including splits)
63f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    private final static int PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2 = 2;
64535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle
6552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    private final static int PACKAGE_DEX_USAGE_VERSION = PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2;
6652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
670318162abcbd07a0472989df43e00e353fac731bCalin Juravle    private final static String PACKAGE_DEX_USAGE_VERSION_HEADER =
680318162abcbd07a0472989df43e00e353fac731bCalin Juravle            "PACKAGE_MANAGER__PACKAGE_DEX_USAGE__";
690318162abcbd07a0472989df43e00e353fac731bCalin Juravle
700318162abcbd07a0472989df43e00e353fac731bCalin Juravle    private final static String SPLIT_CHAR = ",";
7152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    private final static String CODE_PATH_LINE_CHAR = "+";
720318162abcbd07a0472989df43e00e353fac731bCalin Juravle    private final static String DEX_LINE_CHAR = "#";
73535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    private final static String LOADING_PACKAGE_CHAR = "@";
74f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
75f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    // One of the things we record about dex files is the class loader context that was used to
76f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    // load them. That should be stable but if it changes we don't keep track of variable contexts.
77f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    // Instead we put a special marker in the dex usage file in order to recognize the case and
78f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    // skip optimizations on that dex files.
79f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    /*package*/ static final String VARIABLE_CLASS_LOADER_CONTEXT =
80f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            "=VariableClassLoaderContext=";
81f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    // The marker used for unsupported class loader contexts.
82f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    /*package*/ static final String UNSUPPORTED_CLASS_LOADER_CONTEXT =
83f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            "=UnsupportedClassLoaderContext=";
84f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    // The markers used for unknown class loader contexts. This can happen if the dex file was
85f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    // recorded in a previous version and we didn't have a chance to update its usage.
86f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    /*package*/ static final String UNKNOWN_CLASS_LOADER_CONTEXT =
87f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            "=UnknownClassLoaderContext=";
88f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
890318162abcbd07a0472989df43e00e353fac731bCalin Juravle    // Map which structures the information we have on a package.
900318162abcbd07a0472989df43e00e353fac731bCalin Juravle    // Maps package name to package data (which stores info about UsedByOtherApps and
910318162abcbd07a0472989df43e00e353fac731bCalin Juravle    // secondary dex files.).
920318162abcbd07a0472989df43e00e353fac731bCalin Juravle    // Access to this map needs synchronized.
930318162abcbd07a0472989df43e00e353fac731bCalin Juravle    @GuardedBy("mPackageUseInfoMap")
94535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    private final Map<String, PackageUseInfo> mPackageUseInfoMap;
950318162abcbd07a0472989df43e00e353fac731bCalin Juravle
960318162abcbd07a0472989df43e00e353fac731bCalin Juravle    public PackageDexUsage() {
970318162abcbd07a0472989df43e00e353fac731bCalin Juravle        super("package-dex-usage.list", "PackageDexUsage_DiskWriter", /*lock*/ false);
980318162abcbd07a0472989df43e00e353fac731bCalin Juravle        mPackageUseInfoMap = new HashMap<>();
990318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
1000318162abcbd07a0472989df43e00e353fac731bCalin Juravle
1010318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /**
1020318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * Record a dex file load.
1030318162abcbd07a0472989df43e00e353fac731bCalin Juravle     *
1040318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * Note this is called when apps load dex files and as such it should return
1050318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * as fast as possible.
1060318162abcbd07a0472989df43e00e353fac731bCalin Juravle     *
107535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     * @param owningPackageName the package owning the dex path
1080318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * @param dexPath the path of the dex files being loaded
1090318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * @param ownerUserId the user id which runs the code loading the dex files
1100318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * @param loaderIsa the ISA of the app loading the dex files
1110318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * @param isUsedByOtherApps whether or not this dex file was not loaded by its owning package
1120318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * @param primaryOrSplit whether or not the dex file is a primary/split dex. True indicates
1130318162abcbd07a0472989df43e00e353fac731bCalin Juravle     *        the file is either primary or a split. False indicates the file is secondary dex.
114535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     * @param loadingPackageName the package performing the load. Recorded only if it is different
115535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     *        than {@param owningPackageName}.
1160318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * @return true if the dex load constitutes new information, or false if this information
1170318162abcbd07a0472989df43e00e353fac731bCalin Juravle     *         has been seen before.
1180318162abcbd07a0472989df43e00e353fac731bCalin Juravle     */
1190318162abcbd07a0472989df43e00e353fac731bCalin Juravle    public boolean record(String owningPackageName, String dexPath, int ownerUserId,
120535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            String loaderIsa, boolean isUsedByOtherApps, boolean primaryOrSplit,
121f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            String loadingPackageName, String classLoaderContext) {
1220318162abcbd07a0472989df43e00e353fac731bCalin Juravle        if (!PackageManagerServiceUtils.checkISA(loaderIsa)) {
1230318162abcbd07a0472989df43e00e353fac731bCalin Juravle            throw new IllegalArgumentException("loaderIsa " + loaderIsa + " is unsupported");
1240318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
125f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        if (classLoaderContext == null) {
126f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            throw new IllegalArgumentException("Null classLoaderContext");
127f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        }
128f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
1290318162abcbd07a0472989df43e00e353fac731bCalin Juravle        synchronized (mPackageUseInfoMap) {
1300318162abcbd07a0472989df43e00e353fac731bCalin Juravle            PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(owningPackageName);
1310318162abcbd07a0472989df43e00e353fac731bCalin Juravle            if (packageUseInfo == null) {
1320318162abcbd07a0472989df43e00e353fac731bCalin Juravle                // This is the first time we see the package.
1330318162abcbd07a0472989df43e00e353fac731bCalin Juravle                packageUseInfo = new PackageUseInfo();
1340318162abcbd07a0472989df43e00e353fac731bCalin Juravle                if (primaryOrSplit) {
1350318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // If we have a primary or a split apk, set isUsedByOtherApps.
1360318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // We do not need to record the loaderIsa or the owner because we compile
1370318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // primaries for all users and all ISAs.
13852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    packageUseInfo.mergeCodePathUsedByOtherApps(dexPath, isUsedByOtherApps,
13952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                            owningPackageName, loadingPackageName);
1400318162abcbd07a0472989df43e00e353fac731bCalin Juravle                } else {
1410318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // For secondary dex files record the loaderISA and the owner. We'll need
1420318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // to know under which user to compile and for what ISA.
143f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                    DexUseInfo newData = new DexUseInfo(isUsedByOtherApps, ownerUserId,
144f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                            classLoaderContext, loaderIsa);
145535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                    packageUseInfo.mDexUseInfoMap.put(dexPath, newData);
146535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                    maybeAddLoadingPackage(owningPackageName, loadingPackageName,
147535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                            newData.mLoadingPackages);
1480318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
1490318162abcbd07a0472989df43e00e353fac731bCalin Juravle                mPackageUseInfoMap.put(owningPackageName, packageUseInfo);
1500318162abcbd07a0472989df43e00e353fac731bCalin Juravle                return true;
1510318162abcbd07a0472989df43e00e353fac731bCalin Juravle            } else {
1520318162abcbd07a0472989df43e00e353fac731bCalin Juravle                // We already have data on this package. Amend it.
1530318162abcbd07a0472989df43e00e353fac731bCalin Juravle                if (primaryOrSplit) {
1540318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // We have a possible update on the primary apk usage. Merge
1550318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // isUsedByOtherApps information and return if there was an update.
15652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    return packageUseInfo.mergeCodePathUsedByOtherApps(
15752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                            dexPath, isUsedByOtherApps, owningPackageName, loadingPackageName);
1580318162abcbd07a0472989df43e00e353fac731bCalin Juravle                } else {
1590318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    DexUseInfo newData = new DexUseInfo(
160f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                            isUsedByOtherApps, ownerUserId, classLoaderContext, loaderIsa);
161535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                    boolean updateLoadingPackages = maybeAddLoadingPackage(owningPackageName,
162535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                            loadingPackageName, newData.mLoadingPackages);
163535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle
1640318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    DexUseInfo existingData = packageUseInfo.mDexUseInfoMap.get(dexPath);
1650318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    if (existingData == null) {
1660318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        // It's the first time we see this dex file.
1670318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        packageUseInfo.mDexUseInfoMap.put(dexPath, newData);
1680318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        return true;
1690318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    } else {
1700318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        if (ownerUserId != existingData.mOwnerUserId) {
1710318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // Oups, this should never happen, the DexManager who calls this should
1720318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // do the proper checks and not call record if the user does not own the
1730318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // dex path.
1740318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // Secondary dex files are stored in the app user directory. A change in
1750318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // owningUser for the same path means that something went wrong at some
1760318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // higher level, and the loaderUser was allowed to cross
1770318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // user-boundaries and access data from what we know to be the owner
1780318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // user.
1790318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            throw new IllegalArgumentException("Trying to change ownerUserId for "
1800318162abcbd07a0472989df43e00e353fac731bCalin Juravle                                    + " dex path " + dexPath + " from " + existingData.mOwnerUserId
1810318162abcbd07a0472989df43e00e353fac731bCalin Juravle                                    + " to " + ownerUserId);
1820318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        }
1830318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        // Merge the information into the existing data.
1840318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        // Returns true if there was an update.
185535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                        return existingData.merge(newData) || updateLoadingPackages;
1860318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    }
1870318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
1880318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
1890318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
1900318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
1910318162abcbd07a0472989df43e00e353fac731bCalin Juravle
1920318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /**
1930318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * Convenience method for sync reads which does not force the user to pass a useless
1940318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * (Void) null.
1950318162abcbd07a0472989df43e00e353fac731bCalin Juravle     */
1960318162abcbd07a0472989df43e00e353fac731bCalin Juravle    public void read() {
1970318162abcbd07a0472989df43e00e353fac731bCalin Juravle      read((Void) null);
1980318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
1990318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2000318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /**
2010318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * Convenience method for async writes which does not force the user to pass a useless
2020318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * (Void) null.
2030318162abcbd07a0472989df43e00e353fac731bCalin Juravle     */
20414876bd21a4a4e7d78d36f910493269f14b2e905Calin Juravle    /*package*/ void maybeWriteAsync() {
20514876bd21a4a4e7d78d36f910493269f14b2e905Calin Juravle      maybeWriteAsync(null);
20614876bd21a4a4e7d78d36f910493269f14b2e905Calin Juravle    }
20714876bd21a4a4e7d78d36f910493269f14b2e905Calin Juravle
20814876bd21a4a4e7d78d36f910493269f14b2e905Calin Juravle    /*package*/ void writeNow() {
20914876bd21a4a4e7d78d36f910493269f14b2e905Calin Juravle        writeInternal(null);
2100318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
2110318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2120318162abcbd07a0472989df43e00e353fac731bCalin Juravle    @Override
2130318162abcbd07a0472989df43e00e353fac731bCalin Juravle    protected void writeInternal(Void data) {
2140318162abcbd07a0472989df43e00e353fac731bCalin Juravle        AtomicFile file = getFile();
2150318162abcbd07a0472989df43e00e353fac731bCalin Juravle        FileOutputStream f = null;
2160318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2170318162abcbd07a0472989df43e00e353fac731bCalin Juravle        try {
2180318162abcbd07a0472989df43e00e353fac731bCalin Juravle            f = file.startWrite();
2190318162abcbd07a0472989df43e00e353fac731bCalin Juravle            OutputStreamWriter osw = new OutputStreamWriter(f);
2200318162abcbd07a0472989df43e00e353fac731bCalin Juravle            write(osw);
2210318162abcbd07a0472989df43e00e353fac731bCalin Juravle            osw.flush();
2220318162abcbd07a0472989df43e00e353fac731bCalin Juravle            file.finishWrite(f);
2230318162abcbd07a0472989df43e00e353fac731bCalin Juravle        } catch (IOException e) {
2240318162abcbd07a0472989df43e00e353fac731bCalin Juravle            if (f != null) {
2250318162abcbd07a0472989df43e00e353fac731bCalin Juravle                file.failWrite(f);
2260318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
2270318162abcbd07a0472989df43e00e353fac731bCalin Juravle            Slog.e(TAG, "Failed to write usage for dex files", e);
2280318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
2290318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
2300318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2310318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /**
2320318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * File format:
2330318162abcbd07a0472989df43e00e353fac731bCalin Juravle     *
2340318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * file_magic_version
2350318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * package_name_1
23652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle     * +code_path1
237535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     * @ loading_package_1_1, loading_package_1_2...
23852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle     * +code_path2
23952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle     * @ loading_package_2_1, loading_package_2_2...
2400318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * #dex_file_path_1_1
2410318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * user_1_1, used_by_other_app_1_1, user_isa_1_1_1, user_isa_1_1_2
24252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle     * @ loading_package_1_1_1, loading_package_1_1_2...
24352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle     * class_loader_context_1_1
2440318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * #dex_file_path_1_2
2450318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * user_1_2, used_by_other_app_1_2, user_isa_1_2_1, user_isa_1_2_2
24652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle     * @ loading_package_1_2_1, loading_package_1_2_2...
24752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle     * class_loader_context_1_2
2480318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * ...
2490318162abcbd07a0472989df43e00e353fac731bCalin Juravle    */
2500318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /* package */ void write(Writer out) {
2510318162abcbd07a0472989df43e00e353fac731bCalin Juravle        // Make a clone to avoid locking while writing to disk.
2520318162abcbd07a0472989df43e00e353fac731bCalin Juravle        Map<String, PackageUseInfo> packageUseInfoMapClone = clonePackageUseInfoMap();
2530318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2540318162abcbd07a0472989df43e00e353fac731bCalin Juravle        FastPrintWriter fpw = new FastPrintWriter(out);
2550318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2560318162abcbd07a0472989df43e00e353fac731bCalin Juravle        // Write the header.
2570318162abcbd07a0472989df43e00e353fac731bCalin Juravle        fpw.print(PACKAGE_DEX_USAGE_VERSION_HEADER);
2580318162abcbd07a0472989df43e00e353fac731bCalin Juravle        fpw.println(PACKAGE_DEX_USAGE_VERSION);
2590318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2600318162abcbd07a0472989df43e00e353fac731bCalin Juravle        for (Map.Entry<String, PackageUseInfo> pEntry : packageUseInfoMapClone.entrySet()) {
2610318162abcbd07a0472989df43e00e353fac731bCalin Juravle            // Write the package line.
2620318162abcbd07a0472989df43e00e353fac731bCalin Juravle            String packageName = pEntry.getKey();
2630318162abcbd07a0472989df43e00e353fac731bCalin Juravle            PackageUseInfo packageUseInfo = pEntry.getValue();
26452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            fpw.println(packageName);
26552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
26652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            // Write the code paths used by other apps.
26752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            for (Map.Entry<String, Set<String>> codeEntry :
26852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    packageUseInfo.mCodePathsUsedByOtherApps.entrySet()) {
26952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                String codePath = codeEntry.getKey();
27052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                Set<String> loadingPackages = codeEntry.getValue();
27152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                fpw.println(CODE_PATH_LINE_CHAR + codePath);
27252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                fpw.println(LOADING_PACKAGE_CHAR + String.join(SPLIT_CHAR, loadingPackages));
27352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            }
2740318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2750318162abcbd07a0472989df43e00e353fac731bCalin Juravle            // Write dex file lines.
2760318162abcbd07a0472989df43e00e353fac731bCalin Juravle            for (Map.Entry<String, DexUseInfo> dEntry : packageUseInfo.mDexUseInfoMap.entrySet()) {
2770318162abcbd07a0472989df43e00e353fac731bCalin Juravle                String dexPath = dEntry.getKey();
2780318162abcbd07a0472989df43e00e353fac731bCalin Juravle                DexUseInfo dexUseInfo = dEntry.getValue();
2790318162abcbd07a0472989df43e00e353fac731bCalin Juravle                fpw.println(DEX_LINE_CHAR + dexPath);
2800318162abcbd07a0472989df43e00e353fac731bCalin Juravle                fpw.print(String.join(SPLIT_CHAR, Integer.toString(dexUseInfo.mOwnerUserId),
28152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    writeBoolean(dexUseInfo.mIsUsedByOtherApps)));
2820318162abcbd07a0472989df43e00e353fac731bCalin Juravle                for (String isa : dexUseInfo.mLoaderIsas) {
2830318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    fpw.print(SPLIT_CHAR + isa);
2840318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
2850318162abcbd07a0472989df43e00e353fac731bCalin Juravle                fpw.println();
28652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                fpw.println(LOADING_PACKAGE_CHAR
28752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                        + String.join(SPLIT_CHAR, dexUseInfo.mLoadingPackages));
28852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                fpw.println(dexUseInfo.getClassLoaderContext());
2890318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
2900318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
2910318162abcbd07a0472989df43e00e353fac731bCalin Juravle        fpw.flush();
2920318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
2930318162abcbd07a0472989df43e00e353fac731bCalin Juravle
2940318162abcbd07a0472989df43e00e353fac731bCalin Juravle    @Override
2950318162abcbd07a0472989df43e00e353fac731bCalin Juravle    protected void readInternal(Void data) {
2960318162abcbd07a0472989df43e00e353fac731bCalin Juravle        AtomicFile file = getFile();
2970318162abcbd07a0472989df43e00e353fac731bCalin Juravle        BufferedReader in = null;
2980318162abcbd07a0472989df43e00e353fac731bCalin Juravle        try {
2990318162abcbd07a0472989df43e00e353fac731bCalin Juravle            in = new BufferedReader(new InputStreamReader(file.openRead()));
3000318162abcbd07a0472989df43e00e353fac731bCalin Juravle            read(in);
3010318162abcbd07a0472989df43e00e353fac731bCalin Juravle        } catch (FileNotFoundException expected) {
3020318162abcbd07a0472989df43e00e353fac731bCalin Juravle            // The file may not be there. E.g. When we first take the OTA with this feature.
3030318162abcbd07a0472989df43e00e353fac731bCalin Juravle        } catch (IOException e) {
3040318162abcbd07a0472989df43e00e353fac731bCalin Juravle            Slog.w(TAG, "Failed to parse package dex usage.", e);
3050318162abcbd07a0472989df43e00e353fac731bCalin Juravle        } finally {
3060318162abcbd07a0472989df43e00e353fac731bCalin Juravle            IoUtils.closeQuietly(in);
3070318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
3080318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
3090318162abcbd07a0472989df43e00e353fac731bCalin Juravle
3100318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /* package */ void read(Reader reader) throws IOException {
3110318162abcbd07a0472989df43e00e353fac731bCalin Juravle        Map<String, PackageUseInfo> data = new HashMap<>();
3120318162abcbd07a0472989df43e00e353fac731bCalin Juravle        BufferedReader in = new BufferedReader(reader);
3130318162abcbd07a0472989df43e00e353fac731bCalin Juravle        // Read header, do version check.
3140318162abcbd07a0472989df43e00e353fac731bCalin Juravle        String versionLine = in.readLine();
315535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        int version;
3160318162abcbd07a0472989df43e00e353fac731bCalin Juravle        if (versionLine == null) {
3170318162abcbd07a0472989df43e00e353fac731bCalin Juravle            throw new IllegalStateException("No version line found.");
3180318162abcbd07a0472989df43e00e353fac731bCalin Juravle        } else {
3190318162abcbd07a0472989df43e00e353fac731bCalin Juravle            if (!versionLine.startsWith(PACKAGE_DEX_USAGE_VERSION_HEADER)) {
3200318162abcbd07a0472989df43e00e353fac731bCalin Juravle                // TODO(calin): the caller is responsible to clear the file.
3210318162abcbd07a0472989df43e00e353fac731bCalin Juravle                throw new IllegalStateException("Invalid version line: " + versionLine);
3220318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
323535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            version = Integer.parseInt(
3240318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    versionLine.substring(PACKAGE_DEX_USAGE_VERSION_HEADER.length()));
325535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            if (!isSupportedVersion(version)) {
3260318162abcbd07a0472989df43e00e353fac731bCalin Juravle                throw new IllegalStateException("Unexpected version: " + version);
3270318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
3280318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
3290318162abcbd07a0472989df43e00e353fac731bCalin Juravle
33052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        String line;
331535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        String currentPackage = null;
332535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        PackageUseInfo currentPackageData = null;
3330318162abcbd07a0472989df43e00e353fac731bCalin Juravle
3340318162abcbd07a0472989df43e00e353fac731bCalin Juravle        Set<String> supportedIsas = new HashSet<>();
3350318162abcbd07a0472989df43e00e353fac731bCalin Juravle        for (String abi : Build.SUPPORTED_ABIS) {
3360318162abcbd07a0472989df43e00e353fac731bCalin Juravle            supportedIsas.add(VMRuntime.getInstructionSet(abi));
3370318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
33852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        while ((line = in.readLine()) != null) {
33952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            if (line.startsWith(DEX_LINE_CHAR)) {
3400318162abcbd07a0472989df43e00e353fac731bCalin Juravle                // This is the start of the the dex lines.
341f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                // We expect 4 lines for each dex entry:
3420318162abcbd07a0472989df43e00e353fac731bCalin Juravle                // #dexPaths
343f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                // @loading_package_1,loading_package_2,...
344f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                // class_loader_context
3450318162abcbd07a0472989df43e00e353fac731bCalin Juravle                // onwerUserId,isUsedByOtherApps,isa1,isa2
346535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                if (currentPackage == null) {
3470318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    throw new IllegalStateException(
3480318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        "Malformed PackageDexUsage file. Expected package line before dex line.");
3490318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
3500318162abcbd07a0472989df43e00e353fac731bCalin Juravle
35152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                // Line 1 is the dex path.
35252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                String dexPath = line.substring(DEX_LINE_CHAR.length());
353535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle
35452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                // Line 2 is the dex data: (userId, isUsedByOtherApps, isa).
35552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                line = in.readLine();
35652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                if (line == null) {
357f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                    throw new IllegalStateException("Could not find dexUseInfo line");
3580318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
35952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                String[] elems = line.split(SPLIT_CHAR);
3600318162abcbd07a0472989df43e00e353fac731bCalin Juravle                if (elems.length < 3) {
36152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    throw new IllegalStateException("Invalid PackageDexUsage line: " + line);
3620318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
36352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
36452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                // In version 2 we added the loading packages and class loader context.
36552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                Set<String> loadingPackages = maybeReadLoadingPackages(in, version);
36652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                String classLoaderContext = maybeReadClassLoaderContext(in, version);
36752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
3680318162abcbd07a0472989df43e00e353fac731bCalin Juravle                int ownerUserId = Integer.parseInt(elems[0]);
3690318162abcbd07a0472989df43e00e353fac731bCalin Juravle                boolean isUsedByOtherApps = readBoolean(elems[1]);
370f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                DexUseInfo dexUseInfo = new DexUseInfo(isUsedByOtherApps, ownerUserId,
371f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                        classLoaderContext, /*isa*/ null);
372535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                dexUseInfo.mLoadingPackages.addAll(loadingPackages);
3730318162abcbd07a0472989df43e00e353fac731bCalin Juravle                for (int i = 2; i < elems.length; i++) {
3740318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    String isa = elems[i];
3750318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    if (supportedIsas.contains(isa)) {
3760318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        dexUseInfo.mLoaderIsas.add(elems[i]);
3770318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    } else {
3780318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        // Should never happen unless someone crafts the file manually.
3790318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        // In theory it could if we drop a supported ISA after an OTA but we don't
3800318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        // do that.
3810318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        Slog.wtf(TAG, "Unsupported ISA when parsing PackageDexUsage: " + isa);
3820318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    }
3830318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
3840318162abcbd07a0472989df43e00e353fac731bCalin Juravle                if (supportedIsas.isEmpty()) {
3850318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    Slog.wtf(TAG, "Ignore dexPath when parsing PackageDexUsage because of " +
3860318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            "unsupported isas. dexPath=" + dexPath);
3870318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    continue;
3880318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
389535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                currentPackageData.mDexUseInfoMap.put(dexPath, dexUseInfo);
39052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            } else if (line.startsWith(CODE_PATH_LINE_CHAR)) {
39152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                // This is a code path used by other apps line.
39252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                if (version < PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) {
39352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    throw new IllegalArgumentException("Unexpected code path line when parsing " +
39452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                            "PackageDexUseData: " + line);
39552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                }
39652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
39752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                // Expects 2 lines:
39852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                //    +code_paths
39952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                //    @loading_packages
40052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                String codePath = line.substring(CODE_PATH_LINE_CHAR.length());
40152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                Set<String> loadingPackages = maybeReadLoadingPackages(in, version);
40252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                currentPackageData.mCodePathsUsedByOtherApps.put(codePath, loadingPackages);
4030318162abcbd07a0472989df43e00e353fac731bCalin Juravle            } else {
4040318162abcbd07a0472989df43e00e353fac731bCalin Juravle                // This is a package line.
40552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) {
40652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    currentPackage = line;
40752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    currentPackageData = new PackageUseInfo();
40852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                } else {
40952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    // Old version (<2)
41052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    // We expect it to be: `packageName,isUsedByOtherApps`.
41152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    String[] elems = line.split(SPLIT_CHAR);
41252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    if (elems.length != 2) {
41352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                        throw new IllegalStateException("Invalid PackageDexUsage line: " + line);
41452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    }
41552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    currentPackage = elems[0];
41652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    currentPackageData = new PackageUseInfo();
41752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    currentPackageData.mUsedByOtherAppsBeforeUpgrade = readBoolean(elems[1]);
4180318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
419535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                data.put(currentPackage, currentPackageData);
4200318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
4210318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
4220318162abcbd07a0472989df43e00e353fac731bCalin Juravle
4230318162abcbd07a0472989df43e00e353fac731bCalin Juravle        synchronized (mPackageUseInfoMap) {
4240318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mPackageUseInfoMap.clear();
4250318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mPackageUseInfoMap.putAll(data);
4260318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
4270318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
4280318162abcbd07a0472989df43e00e353fac731bCalin Juravle
4290318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /**
430f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle     * Reads the class loader context encoding from the buffer {@code in} if
431535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     * {@code version} is at least {PACKAGE_DEX_USAGE_VERSION}.
432535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     */
433f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    private String maybeReadClassLoaderContext(BufferedReader in, int version) throws IOException {
434f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        String context = null;
43552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) {
436f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            context = in.readLine();
437f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            if (context == null) {
438f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                throw new IllegalStateException("Could not find the classLoaderContext line.");
439f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            }
440f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        }
441f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        // The context might be empty if we didn't have the chance to update it after a version
442f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        // upgrade. In this case return the special marker so that we recognize this is an unknown
443f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        // context.
444f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        return context == null ? UNKNOWN_CLASS_LOADER_CONTEXT : context;
445f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    }
446f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
447f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle    /**
448f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle     * Reads the list of loading packages from the buffer {@code in} if
449f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle     * {@code version} is at least {PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2}.
450f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle     */
45152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    private Set<String> maybeReadLoadingPackages(BufferedReader in, int version)
452535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            throws IOException {
453f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        if (version >= PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2) {
454535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            String line = in.readLine();
455535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            if (line == null) {
456535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                throw new IllegalStateException("Could not find the loadingPackages line.");
457535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            }
458535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            // We expect that most of the times the list of loading packages will be empty.
459535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            if (line.length() == LOADING_PACKAGE_CHAR.length()) {
46052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                return Collections.emptySet();
461535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            } else {
46252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                Set<String> result = new HashSet<>();
46352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                Collections.addAll(result,
464535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle                        line.substring(LOADING_PACKAGE_CHAR.length()).split(SPLIT_CHAR));
46552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                return result;
466535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            }
467535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        } else {
46852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            return Collections.emptySet();
469535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        }
470535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    }
471535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle
472535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    /**
473535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     * Utility method which adds {@param loadingPackage} to {@param loadingPackages} only if it's
474535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     * not equal to {@param owningPackage}
475535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle     */
476535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    private boolean maybeAddLoadingPackage(String owningPackage, String loadingPackage,
477535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            Set<String> loadingPackages) {
478535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        return !owningPackage.equals(loadingPackage) && loadingPackages.add(loadingPackage);
479535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    }
480535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle
481535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    private boolean isSupportedVersion(int version) {
48252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        return version == PACKAGE_DEX_USAGE_SUPPORTED_VERSION_1
48352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                || version == PACKAGE_DEX_USAGE_SUPPORTED_VERSION_2;
484535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    }
485535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle
486535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle    /**
4870318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * Syncs the existing data with the set of available packages by removing obsolete entries.
4880318162abcbd07a0472989df43e00e353fac731bCalin Juravle     */
48952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    /*package*/ void syncData(Map<String, Set<Integer>> packageToUsersMap,
49052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            Map<String, Set<String>> packageToCodePaths) {
4910318162abcbd07a0472989df43e00e353fac731bCalin Juravle        synchronized (mPackageUseInfoMap) {
4920318162abcbd07a0472989df43e00e353fac731bCalin Juravle            Iterator<Map.Entry<String, PackageUseInfo>> pIt =
4930318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    mPackageUseInfoMap.entrySet().iterator();
4940318162abcbd07a0472989df43e00e353fac731bCalin Juravle            while (pIt.hasNext()) {
4950318162abcbd07a0472989df43e00e353fac731bCalin Juravle                Map.Entry<String, PackageUseInfo> pEntry = pIt.next();
4960318162abcbd07a0472989df43e00e353fac731bCalin Juravle                String packageName = pEntry.getKey();
4970318162abcbd07a0472989df43e00e353fac731bCalin Juravle                PackageUseInfo packageUseInfo = pEntry.getValue();
4980318162abcbd07a0472989df43e00e353fac731bCalin Juravle                Set<Integer> users = packageToUsersMap.get(packageName);
4990318162abcbd07a0472989df43e00e353fac731bCalin Juravle                if (users == null) {
5000318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // The package doesn't exist anymore, remove the record.
5010318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    pIt.remove();
5020318162abcbd07a0472989df43e00e353fac731bCalin Juravle                } else {
5030318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // The package exists but we can prune the entries associated with non existing
5040318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    // users.
5050318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    Iterator<Map.Entry<String, DexUseInfo>> dIt =
5060318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            packageUseInfo.mDexUseInfoMap.entrySet().iterator();
5070318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    while (dIt.hasNext()) {
5080318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        DexUseInfo dexUseInfo = dIt.next().getValue();
5090318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        if (!users.contains(dexUseInfo.mOwnerUserId)) {
5100318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            // User was probably removed. Delete its dex usage info.
5110318162abcbd07a0472989df43e00e353fac731bCalin Juravle                            dIt.remove();
5120318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        }
5130318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    }
51452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
51552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    // Sync the code paths.
51652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    Set<String> codePaths = packageToCodePaths.get(packageName);
51752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    Iterator<Map.Entry<String, Set<String>>> codeIt =
51852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                        packageUseInfo.mCodePathsUsedByOtherApps.entrySet().iterator();
51952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    while (codeIt.hasNext()) {
52052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                        if (!codePaths.contains(codeIt.next().getKey())) {
52152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                            codeIt.remove();
52252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                        }
52352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    }
52452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
52552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    // In case the package was marked as used by other apps in a previous version
52652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    // propagate the flag to all the code paths.
52752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    // See mUsedByOtherAppsBeforeUpgrade docs on why it is important to do it.
52852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    if (packageUseInfo.mUsedByOtherAppsBeforeUpgrade) {
52952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                        for (String codePath : codePaths) {
53052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                            packageUseInfo.mergeCodePathUsedByOtherApps(codePath, true, null, null);
53152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                        }
53252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    } else if (!packageUseInfo.isAnyCodePathUsedByOtherApps()
53352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                        && packageUseInfo.mDexUseInfoMap.isEmpty()) {
5340318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        // The package is not used by other apps and we removed all its dex files
5350318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        // records. Remove the entire package record as well.
5360318162abcbd07a0472989df43e00e353fac731bCalin Juravle                        pIt.remove();
5370318162abcbd07a0472989df43e00e353fac731bCalin Juravle                    }
5380318162abcbd07a0472989df43e00e353fac731bCalin Juravle                }
5390318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
5400318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
5410318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
5420318162abcbd07a0472989df43e00e353fac731bCalin Juravle
5431aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle    /**
54499dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle     * Clears the {@code usesByOtherApps} marker for the package {@code packageName}.
54599dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle     * @return true if the package usage info was updated.
54699dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle     */
54752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    /*package*/ boolean clearUsedByOtherApps(String packageName) {
54899dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle        synchronized (mPackageUseInfoMap) {
54999dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle            PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName);
55052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            if (packageUseInfo == null) {
55199dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle                return false;
55299dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle            }
55352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            return packageUseInfo.clearCodePathUsedByOtherApps();
55499dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle        }
55599dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle    }
55699dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle
55799dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle    /**
55899dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle     * Remove the usage data associated with package {@code packageName}.
55999dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle     * @return true if the package usage was found and removed successfully.
56099dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle     */
56199dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle    public boolean removePackage(String packageName) {
56299dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle        synchronized (mPackageUseInfoMap) {
56399dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle            return mPackageUseInfoMap.remove(packageName) != null;
56499dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle        }
56599dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle    }
56699dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle
56799dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle    /**
5681aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle     * Remove all the records about package {@code packageName} belonging to user {@code userId}.
56999dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle     * If the package is left with no records of secondary dex usage and is not used by other
57099dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle     * apps it will be removed as well.
571b1097411028103b6c88ce325af23d2ff1ec746c8Calin Juravle     * @return true if the record was found and actually deleted,
572b1097411028103b6c88ce325af23d2ff1ec746c8Calin Juravle     *         false if the record doesn't exist
5731aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle     */
57452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    /*package*/ boolean removeUserPackage(String packageName, int userId) {
5751aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        synchronized (mPackageUseInfoMap) {
5761aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName);
5771aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            if (packageUseInfo == null) {
5781aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle                return false;
5791aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            }
5801aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            boolean updated = false;
5811aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            Iterator<Map.Entry<String, DexUseInfo>> dIt =
5821aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle                            packageUseInfo.mDexUseInfoMap.entrySet().iterator();
5831aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            while (dIt.hasNext()) {
5841aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle                DexUseInfo dexUseInfo = dIt.next().getValue();
5851aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle                if (dexUseInfo.mOwnerUserId == userId) {
5861aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle                    dIt.remove();
5871aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle                    updated = true;
5881aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle                }
5891aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            }
59099dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle            // If no secondary dex info is left and the package is not used by other apps
59199dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle            // remove the data since it is now useless.
59252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            if (packageUseInfo.mDexUseInfoMap.isEmpty()
59352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    && !packageUseInfo.isAnyCodePathUsedByOtherApps()) {
59499dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle                mPackageUseInfoMap.remove(packageName);
59599dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle                updated = true;
59699dd37b3c5262910150ef955d16a33d32da264ddCalin Juravle            }
5971aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            return updated;
5981aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        }
5991aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle    }
6001aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle
6011aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle    /**
6021aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle     * Remove the secondary dex file record belonging to the package {@code packageName}
6031aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle     * and user {@code userId}.
604b1097411028103b6c88ce325af23d2ff1ec746c8Calin Juravle     * @return true if the record was found and actually deleted,
605b1097411028103b6c88ce325af23d2ff1ec746c8Calin Juravle     *         false if the record doesn't exist
6061aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle     */
60752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    /*package*/ boolean removeDexFile(String packageName, String dexFile, int userId) {
6081aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        synchronized (mPackageUseInfoMap) {
6091aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            PackageUseInfo packageUseInfo = mPackageUseInfoMap.get(packageName);
6101aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            if (packageUseInfo == null) {
6111aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle                return false;
6121aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            }
6131aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            return removeDexFile(packageUseInfo, dexFile, userId);
6141aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        }
6151aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle    }
6161aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle
6171aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle    private boolean removeDexFile(PackageUseInfo packageUseInfo, String dexFile, int userId) {
6181aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        DexUseInfo dexUseInfo = packageUseInfo.mDexUseInfoMap.get(dexFile);
6191aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        if (dexUseInfo == null) {
6201aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            return false;
6211aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        }
6221aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        if (dexUseInfo.mOwnerUserId == userId) {
6231aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            packageUseInfo.mDexUseInfoMap.remove(dexFile);
6241aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            return true;
6251aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        }
6261aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle        return false;
6271aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle    }
6281aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle
62952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    /*package*/ PackageUseInfo getPackageUseInfo(String packageName) {
6300318162abcbd07a0472989df43e00e353fac731bCalin Juravle        synchronized (mPackageUseInfoMap) {
6311aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            PackageUseInfo useInfo = mPackageUseInfoMap.get(packageName);
6321aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            // The useInfo contains a map for secondary dex files which could be modified
6331aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            // concurrently after this method returns and thus outside the locking we do here.
6341aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            // (i.e. the map is updated when new class loaders are created, which can happen anytime
6351aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            // after this method returns)
6361aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            // Make a defensive copy to be sure we don't get concurrent modifications.
6371aa5f88e35734383e66ecd65e82e83d788e18ccbCalin Juravle            return useInfo == null ? null : new PackageUseInfo(useInfo);
6380318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
6390318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
6400318162abcbd07a0472989df43e00e353fac731bCalin Juravle
64151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle    /**
64251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle     * Return all packages that contain records of secondary dex files.
64351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle     */
64452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle    /*package*/ Set<String> getAllPackagesWithSecondaryDexFiles() {
64551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle        Set<String> packages = new HashSet<>();
64651f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle        synchronized (mPackageUseInfoMap) {
64751f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle            for (Map.Entry<String, PackageUseInfo> entry : mPackageUseInfoMap.entrySet()) {
64851f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle                if (!entry.getValue().mDexUseInfoMap.isEmpty()) {
64951f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle                    packages.add(entry.getKey());
65051f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle                }
65151f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle            }
65251f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle        }
65351f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle        return packages;
65451f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle    }
65551f521c3bf46e6040f36757bc53ea57ddc7be85eCalin Juravle
6560318162abcbd07a0472989df43e00e353fac731bCalin Juravle    public void clear() {
6570318162abcbd07a0472989df43e00e353fac731bCalin Juravle        synchronized (mPackageUseInfoMap) {
6580318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mPackageUseInfoMap.clear();
6590318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
6600318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
6610318162abcbd07a0472989df43e00e353fac731bCalin Juravle    // Creates a deep copy of the class' mPackageUseInfoMap.
6620318162abcbd07a0472989df43e00e353fac731bCalin Juravle    private Map<String, PackageUseInfo> clonePackageUseInfoMap() {
6630318162abcbd07a0472989df43e00e353fac731bCalin Juravle        Map<String, PackageUseInfo> clone = new HashMap<>();
6640318162abcbd07a0472989df43e00e353fac731bCalin Juravle        synchronized (mPackageUseInfoMap) {
6650318162abcbd07a0472989df43e00e353fac731bCalin Juravle            for (Map.Entry<String, PackageUseInfo> e : mPackageUseInfoMap.entrySet()) {
6660318162abcbd07a0472989df43e00e353fac731bCalin Juravle                clone.put(e.getKey(), new PackageUseInfo(e.getValue()));
6670318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
6680318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
6690318162abcbd07a0472989df43e00e353fac731bCalin Juravle        return clone;
6700318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
6710318162abcbd07a0472989df43e00e353fac731bCalin Juravle
6720318162abcbd07a0472989df43e00e353fac731bCalin Juravle    private String writeBoolean(boolean bool) {
6730318162abcbd07a0472989df43e00e353fac731bCalin Juravle        return bool ? "1" : "0";
6740318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
6750318162abcbd07a0472989df43e00e353fac731bCalin Juravle
6760318162abcbd07a0472989df43e00e353fac731bCalin Juravle    private boolean readBoolean(String bool) {
6770318162abcbd07a0472989df43e00e353fac731bCalin Juravle        if ("0".equals(bool)) return false;
6780318162abcbd07a0472989df43e00e353fac731bCalin Juravle        if ("1".equals(bool)) return true;
6790318162abcbd07a0472989df43e00e353fac731bCalin Juravle        throw new IllegalArgumentException("Unknown bool encoding: " + bool);
6800318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
6810318162abcbd07a0472989df43e00e353fac731bCalin Juravle
6820318162abcbd07a0472989df43e00e353fac731bCalin Juravle    public String dump() {
6830318162abcbd07a0472989df43e00e353fac731bCalin Juravle        StringWriter sw = new StringWriter();
6840318162abcbd07a0472989df43e00e353fac731bCalin Juravle        write(sw);
6850318162abcbd07a0472989df43e00e353fac731bCalin Juravle        return sw.toString();
6860318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
6870318162abcbd07a0472989df43e00e353fac731bCalin Juravle
6880318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /**
6890318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * Stores data on how a package and its dex files are used.
6900318162abcbd07a0472989df43e00e353fac731bCalin Juravle     */
6910318162abcbd07a0472989df43e00e353fac731bCalin Juravle    public static class PackageUseInfo {
69252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        // The app's code paths that are used by other apps.
69352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        // The key is the code path and the value is the set of loading packages.
69452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        private final Map<String, Set<String>> mCodePathsUsedByOtherApps;
6950318162abcbd07a0472989df43e00e353fac731bCalin Juravle        // Map dex paths to their data (isUsedByOtherApps, owner id, loader isa).
6960318162abcbd07a0472989df43e00e353fac731bCalin Juravle        private final Map<String, DexUseInfo> mDexUseInfoMap;
69752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
69852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        // Keeps track of whether or not this package was used by other apps before
69952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        // we upgraded to VERSION 4 which records the info for each code path separately.
70052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        // This is unwanted complexity but without it we risk to profile guide compile
70152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        // something that supposed to be shared. For example:
70252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        //   1) we determine that chrome is used by another app
70352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        //   2) we take an OTA which upgrades the way we keep track of usage data
70452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        //   3) chrome doesn't get used until the background job executes
70552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        //   4) as part of the backgound job we now think that chrome is not used by others
70652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        //      and we speed-profile.
70752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        //   5) as a result the next time someone uses chrome it will extract from apk since
70852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        //      the compiled code will be private.
70952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        private boolean mUsedByOtherAppsBeforeUpgrade;
7100318162abcbd07a0472989df43e00e353fac731bCalin Juravle
7110318162abcbd07a0472989df43e00e353fac731bCalin Juravle        public PackageUseInfo() {
71252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            mCodePathsUsedByOtherApps = new HashMap<>();
7130318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mDexUseInfoMap = new HashMap<>();
7140318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
7150318162abcbd07a0472989df43e00e353fac731bCalin Juravle
7160318162abcbd07a0472989df43e00e353fac731bCalin Juravle        // Creates a deep copy of the `other`.
7170318162abcbd07a0472989df43e00e353fac731bCalin Juravle        public PackageUseInfo(PackageUseInfo other) {
71852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            mCodePathsUsedByOtherApps = new HashMap<>();
71952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            for (Map.Entry<String, Set<String>> e : other.mCodePathsUsedByOtherApps.entrySet()) {
72052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                mCodePathsUsedByOtherApps.put(e.getKey(), new HashSet<>(e.getValue()));
72152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            }
72252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
7230318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mDexUseInfoMap = new HashMap<>();
7240318162abcbd07a0472989df43e00e353fac731bCalin Juravle            for (Map.Entry<String, DexUseInfo> e : other.mDexUseInfoMap.entrySet()) {
7250318162abcbd07a0472989df43e00e353fac731bCalin Juravle                mDexUseInfoMap.put(e.getKey(), new DexUseInfo(e.getValue()));
7260318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
7270318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
7280318162abcbd07a0472989df43e00e353fac731bCalin Juravle
72952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        private boolean mergeCodePathUsedByOtherApps(String codePath, boolean isUsedByOtherApps,
73052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                String owningPackageName, String loadingPackage) {
73152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            if (!isUsedByOtherApps) {
73252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                // Nothing to update if the the code path is not used by other apps.
73352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                return false;
73452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            }
73552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
73652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            boolean newCodePath = false;
73752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            Set<String> loadingPackages = mCodePathsUsedByOtherApps.get(codePath);
73852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            if (loadingPackages == null) {
73952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                loadingPackages = new HashSet<>();
74052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                mCodePathsUsedByOtherApps.put(codePath, loadingPackages);
74152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                newCodePath = true;
74252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            }
74352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            boolean newLoadingPackage = loadingPackage != null
74452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    && !loadingPackage.equals(owningPackageName)
74552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                    && loadingPackages.add(loadingPackage);
74652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            return newCodePath || newLoadingPackage;
7470318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
7480318162abcbd07a0472989df43e00e353fac731bCalin Juravle
74952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        public boolean isUsedByOtherApps(String codePath) {
75052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            return mCodePathsUsedByOtherApps.containsKey(codePath);
7510318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
7520318162abcbd07a0472989df43e00e353fac731bCalin Juravle
7530318162abcbd07a0472989df43e00e353fac731bCalin Juravle        public Map<String, DexUseInfo> getDexUseInfoMap() {
7540318162abcbd07a0472989df43e00e353fac731bCalin Juravle            return mDexUseInfoMap;
7550318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
756535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle
75752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        public Set<String> getLoadingPackages(String codePath) {
75852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            return mCodePathsUsedByOtherApps.getOrDefault(codePath, null);
75952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        }
76052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
76152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        public boolean isAnyCodePathUsedByOtherApps() {
76252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            return !mCodePathsUsedByOtherApps.isEmpty();
76352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        }
76452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
76552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        /**
76652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle         * Clears the usedByOtherApps markers from all code paths.
76752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle         * Returns whether or not there was an update.
76852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle         */
76952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle        /*package*/ boolean clearCodePathUsedByOtherApps() {
77052a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            // Update mUsedByOtherAppsBeforeUpgrade as well to be consistent with
77152a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            // the new data. This is not saved to disk so we don't need to return it.
77252a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            mUsedByOtherAppsBeforeUpgrade = true;
77352a452cf685c56dc6872dbb19e822736484f672fCalin Juravle
77452a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            if (mCodePathsUsedByOtherApps.isEmpty()) {
77552a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                return false;
77652a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            } else {
77752a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                mCodePathsUsedByOtherApps.clear();
77852a452cf685c56dc6872dbb19e822736484f672fCalin Juravle                return true;
77952a452cf685c56dc6872dbb19e822736484f672fCalin Juravle            }
780535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        }
7810318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
7820318162abcbd07a0472989df43e00e353fac731bCalin Juravle
7830318162abcbd07a0472989df43e00e353fac731bCalin Juravle    /**
7840318162abcbd07a0472989df43e00e353fac731bCalin Juravle     * Stores data about a loaded dex files.
7850318162abcbd07a0472989df43e00e353fac731bCalin Juravle     */
7860318162abcbd07a0472989df43e00e353fac731bCalin Juravle    public static class DexUseInfo {
7870318162abcbd07a0472989df43e00e353fac731bCalin Juravle        private boolean mIsUsedByOtherApps;
7880318162abcbd07a0472989df43e00e353fac731bCalin Juravle        private final int mOwnerUserId;
789f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        // The class loader context for the dex file. This encodes the class loader chain
790f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        // (class loader type + class path) in a format compatible to dex2oat.
791f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        // See {@code DexoptUtils.processContextForDexLoad}.
792f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        private String mClassLoaderContext;
793f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        // The instructions sets of the applications loading the dex file.
7940318162abcbd07a0472989df43e00e353fac731bCalin Juravle        private final Set<String> mLoaderIsas;
795535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        // Packages who load this dex file.
796535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        private final Set<String> mLoadingPackages;
7970318162abcbd07a0472989df43e00e353fac731bCalin Juravle
798f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        public DexUseInfo(boolean isUsedByOtherApps, int ownerUserId, String classLoaderContext,
799f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                String loaderIsa) {
8000318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mIsUsedByOtherApps = isUsedByOtherApps;
8010318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mOwnerUserId = ownerUserId;
802f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            mClassLoaderContext = classLoaderContext;
8030318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mLoaderIsas = new HashSet<>();
8040318162abcbd07a0472989df43e00e353fac731bCalin Juravle            if (loaderIsa != null) {
8050318162abcbd07a0472989df43e00e353fac731bCalin Juravle                mLoaderIsas.add(loaderIsa);
8060318162abcbd07a0472989df43e00e353fac731bCalin Juravle            }
807535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            mLoadingPackages = new HashSet<>();
8080318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
8090318162abcbd07a0472989df43e00e353fac731bCalin Juravle
8100318162abcbd07a0472989df43e00e353fac731bCalin Juravle        // Creates a deep copy of the `other`.
8110318162abcbd07a0472989df43e00e353fac731bCalin Juravle        public DexUseInfo(DexUseInfo other) {
8120318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mIsUsedByOtherApps = other.mIsUsedByOtherApps;
8130318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mOwnerUserId = other.mOwnerUserId;
814f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            mClassLoaderContext = other.mClassLoaderContext;
8150318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mLoaderIsas = new HashSet<>(other.mLoaderIsas);
816535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            mLoadingPackages = new HashSet<>(other.mLoadingPackages);
8170318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
8180318162abcbd07a0472989df43e00e353fac731bCalin Juravle
8190318162abcbd07a0472989df43e00e353fac731bCalin Juravle        private boolean merge(DexUseInfo dexUseInfo) {
8200318162abcbd07a0472989df43e00e353fac731bCalin Juravle            boolean oldIsUsedByOtherApps = mIsUsedByOtherApps;
8210318162abcbd07a0472989df43e00e353fac731bCalin Juravle            mIsUsedByOtherApps = mIsUsedByOtherApps || dexUseInfo.mIsUsedByOtherApps;
8220318162abcbd07a0472989df43e00e353fac731bCalin Juravle            boolean updateIsas = mLoaderIsas.addAll(dexUseInfo.mLoaderIsas);
823535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            boolean updateLoadingPackages = mLoadingPackages.addAll(dexUseInfo.mLoadingPackages);
824f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
825f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            String oldClassLoaderContext = mClassLoaderContext;
826f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            if (UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext)) {
827f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                // Can happen if we read a previous version.
828f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                mClassLoaderContext = dexUseInfo.mClassLoaderContext;
829f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            } else if (UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(dexUseInfo.mClassLoaderContext)) {
830f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                // We detected an unsupported context.
831f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                mClassLoaderContext = UNSUPPORTED_CLASS_LOADER_CONTEXT;
832f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            } else if (!UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext) &&
833607223f3b7a1c4dc3ac995f742f8d2da50d85ffcNarayan Kamath                    !Objects.equals(mClassLoaderContext, dexUseInfo.mClassLoaderContext)) {
834f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                // We detected a context change.
835f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                mClassLoaderContext = VARIABLE_CLASS_LOADER_CONTEXT;
836f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            }
837f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
838f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            return updateIsas ||
839f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                    (oldIsUsedByOtherApps != mIsUsedByOtherApps) ||
840f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle                    updateLoadingPackages
841607223f3b7a1c4dc3ac995f742f8d2da50d85ffcNarayan Kamath                    || !Objects.equals(oldClassLoaderContext, mClassLoaderContext);
8420318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
8430318162abcbd07a0472989df43e00e353fac731bCalin Juravle
8440318162abcbd07a0472989df43e00e353fac731bCalin Juravle        public boolean isUsedByOtherApps() {
8450318162abcbd07a0472989df43e00e353fac731bCalin Juravle            return mIsUsedByOtherApps;
8460318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
8470318162abcbd07a0472989df43e00e353fac731bCalin Juravle
8480318162abcbd07a0472989df43e00e353fac731bCalin Juravle        public int getOwnerUserId() {
8490318162abcbd07a0472989df43e00e353fac731bCalin Juravle            return mOwnerUserId;
8500318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
8510318162abcbd07a0472989df43e00e353fac731bCalin Juravle
8520318162abcbd07a0472989df43e00e353fac731bCalin Juravle        public Set<String> getLoaderIsas() {
8530318162abcbd07a0472989df43e00e353fac731bCalin Juravle            return mLoaderIsas;
8540318162abcbd07a0472989df43e00e353fac731bCalin Juravle        }
855535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle
856535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        public Set<String> getLoadingPackages() {
857535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle            return mLoadingPackages;
858535a4753e313bdc2ae3e8be9f50606b82edcce0cCalin Juravle        }
859f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
860f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        public String getClassLoaderContext() { return mClassLoaderContext; }
861f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
862f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        public boolean isUnsupportedClassLoaderContext() {
863f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            return UNSUPPORTED_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
864f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        }
865f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
866f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        public boolean isUnknownClassLoaderContext() {
867f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            // The class loader context may be unknown if we loaded the data from a previous version
868f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            // which didn't save the context.
869f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            return UNKNOWN_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
870f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        }
871f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle
872f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        public boolean isVariableClassLoaderContext() {
873f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle            return VARIABLE_CLASS_LOADER_CONTEXT.equals(mClassLoaderContext);
874f1ff36f0f99ebb41d0c7e0f3248506a56998fa3fCalin Juravle        }
8750318162abcbd07a0472989df43e00e353fac731bCalin Juravle    }
8760318162abcbd07a0472989df43e00e353fac731bCalin Juravle}
877