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