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