17487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov/*
27487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * Copyright (C) 2015 The Android Open Source Project
37487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov *
47487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * Licensed under the Apache License, Version 2.0 (the "License");
57487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * you may not use this file except in compliance with the License.
67487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * You may obtain a copy of the License at
77487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov *
87487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov *      http://www.apache.org/licenses/LICENSE-2.0
97487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov *
107487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * Unless required by applicable law or agreed to in writing, software
117487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * distributed under the License is distributed on an "AS IS" BASIS,
127487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * See the License for the specific language governing permissions and
147487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * limitations under the License
157487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov */
167487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
177487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovpackage com.android.server.pm;
187487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
19b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolovimport android.annotation.Nullable;
20a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolovimport android.content.Context;
217487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport android.content.pm.ApplicationInfo;
227487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport android.content.pm.PackageParser;
23d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravleimport android.os.Environment;
24a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolovimport android.os.PowerManager;
257487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport android.os.UserHandle;
26a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolovimport android.os.WorkSource;
277487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport android.util.Log;
287487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport android.util.Slog;
297487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
30fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkeyimport com.android.internal.os.InstallerConnection.InstallerException;
3188eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamathimport com.android.internal.util.IndentingPrintWriter;
32fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey
33b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolovimport java.io.File;
347487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport java.io.IOException;
357487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport java.util.List;
367487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
377487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport dalvik.system.DexFile;
387487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
39fa54ab7950b7ad7605cb842b47826b71a685bc28Todd Kennedyimport static com.android.server.pm.Installer.DEXOPT_BOOTCOMPLETE;
40fa54ab7950b7ad7605cb842b47826b71a685bc28Todd Kennedyimport static com.android.server.pm.Installer.DEXOPT_DEBUGGABLE;
41bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampeimport static com.android.server.pm.Installer.DEXOPT_PROFILE_GUIDED;
42fa54ab7950b7ad7605cb842b47826b71a685bc28Todd Kennedyimport static com.android.server.pm.Installer.DEXOPT_PUBLIC;
43fa54ab7950b7ad7605cb842b47826b71a685bc28Todd Kennedyimport static com.android.server.pm.Installer.DEXOPT_SAFEMODE;
447487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport static com.android.server.pm.InstructionSets.getAppDexInstructionSets;
457487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolovimport static com.android.server.pm.InstructionSets.getDexCodeInstructionSets;
4647c170a7460e8455ffc07981916c400fa980433aAndreas Gampeimport static com.android.server.pm.PackageManagerServiceCompilerMapping.getNonProfileGuidedCompilerFilter;
477487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
487487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov/**
497487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov * Helper class for running dexopt command on packages.
507487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov */
51a89087542f774c585b6a6ec535fc294721710521Andreas Gampeclass PackageDexOptimizer {
52b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov    private static final String TAG = "PackageManager.DexOptimizer";
53b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov    static final String OAT_DIR_NAME = "oat";
54b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov    // TODO b/19550105 Remove error codes and use exceptions
557487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov    static final int DEX_OPT_SKIPPED = 0;
567487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov    static final int DEX_OPT_PERFORMED = 1;
577487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov    static final int DEX_OPT_FAILED = -1;
587487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
59a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    private final Installer mInstaller;
60a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    private final Object mInstallLock;
617487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
62a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov    private final PowerManager.WakeLock mDexoptWakeLock;
63a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov    private volatile boolean mSystemReady;
64a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov
65a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    PackageDexOptimizer(Installer installer, Object installLock, Context context,
66a89087542f774c585b6a6ec535fc294721710521Andreas Gampe            String wakeLockTag) {
67a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        this.mInstaller = installer;
68a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        this.mInstallLock = installLock;
69a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
70a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        PowerManager powerManager = (PowerManager)context.getSystemService(Context.POWER_SERVICE);
71a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        mDexoptWakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, wakeLockTag);
72a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    }
73a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
74a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    protected PackageDexOptimizer(PackageDexOptimizer from) {
75a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        this.mInstaller = from.mInstaller;
76a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        this.mInstallLock = from.mInstallLock;
77a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        this.mDexoptWakeLock = from.mDexoptWakeLock;
78a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        this.mSystemReady = from.mSystemReady;
797487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov    }
807487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
81db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle    static boolean canOptimizePackage(PackageParser.Package pkg) {
826dfd83dbe88bd461f5aab224ced0830b07db1c03Calin Juravle        return (pkg.applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;
83db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle    }
84db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle
857487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov    /**
867487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov     * Performs dexopt on all code paths and libraries of the specified package for specified
877487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov     * instruction sets.
887487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov     *
89a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     * <p>Calls to {@link com.android.server.pm.Installer#dexopt} on {@link #mInstaller} are
90a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     * synchronized on {@link #mInstallLock}.
917487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov     */
92c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao    int performDexOpt(PackageParser.Package pkg, String[] sharedLibraries,
9337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe            String[] instructionSets, boolean checkProfiles, String targetCompilationFilter,
9437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe            CompilerStats.PackageStats packageStats) {
95a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        synchronized (mInstallLock) {
96a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov            final boolean useLock = mSystemReady;
97a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov            if (useLock) {
98a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov                mDexoptWakeLock.setWorkSource(new WorkSource(pkg.applicationInfo.uid));
99a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov                mDexoptWakeLock.acquire();
100a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov            }
101a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov            try {
102c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                return performDexOptLI(pkg, sharedLibraries, instructionSets, checkProfiles,
10337e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe                        targetCompilationFilter, packageStats);
104a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov            } finally {
105a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov                if (useLock) {
106a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov                    mDexoptWakeLock.release();
107a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov                }
108a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov            }
1097487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        }
1107487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov    }
1117487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
112a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    /**
113a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     * Adjust the given dexopt-needed value. Can be overridden to influence the decision to
114a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     * optimize or not (and in what way).
115a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     */
116a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    protected int adjustDexoptNeeded(int dexoptNeeded) {
117a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        return dexoptNeeded;
118a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    }
119a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
120a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    /**
121a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     * Adjust the given dexopt flags that will be passed to the installer.
122a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     */
123a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    protected int adjustDexoptFlags(int dexoptFlags) {
124a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        return dexoptFlags;
125a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    }
126a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
12788eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath    /**
12888eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath     * Dumps the dexopt state of the given package {@code pkg} to the given {@code PrintWriter}.
12988eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath     */
13088eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath    void dumpDexoptState(IndentingPrintWriter pw, PackageParser.Package pkg) {
13188eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath        final String[] instructionSets = getAppDexInstructionSets(pkg.applicationInfo);
13288eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
13388eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath
13488eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
13588eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath
13688eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath        for (String instructionSet : dexCodeInstructionSets) {
13788eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath             pw.println("Instruction Set: " + instructionSet);
13888eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath             pw.increaseIndent();
13988eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath             for (String path : paths) {
14088eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath                  String status = null;
14188eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath                  try {
14288eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath                      status = DexFile.getDexFileStatus(path, instructionSet);
14388eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath                  } catch (IOException ioe) {
14488eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath                      status = "[Exception]: " + ioe.getMessage();
14588eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath                  }
14688eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath                  pw.println("path: " + path);
14788eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath                  pw.println("status: " + status);
14888eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath             }
14988eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath             pw.decreaseIndent();
15088eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath        }
15188eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath    }
15288eea9e580a6b2ee804a092f851b5325355fcdceNarayan Kamath
153c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao    private int performDexOptLI(PackageParser.Package pkg, String[] sharedLibraries,
15437e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe            String[] targetInstructionSets, boolean checkProfiles, String targetCompilerFilter,
15537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe            CompilerStats.PackageStats packageStats) {
1567487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        final String[] instructionSets = targetInstructionSets != null ?
1577487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov                targetInstructionSets : getAppDexInstructionSets(pkg.applicationInfo);
1587487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
159db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle        if (!canOptimizePackage(pkg)) {
1607487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov            return DEX_OPT_SKIPPED;
1617487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        }
1627487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
163bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        final List<String> paths = pkg.getAllCodePathsExcludingResourceOnly();
164bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        final int sharedGid = UserHandle.getSharedAppGid(pkg.applicationInfo.uid);
165bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe
166bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        boolean isProfileGuidedFilter = DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter);
167bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        // If any part of the app is used by other apps, we cannot use profile-guided
168bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        // compilation.
16990e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil        if (isProfileGuidedFilter && isUsedByOtherApps(pkg)) {
17090e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            checkProfiles = false;
171bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe
17290e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            targetCompilerFilter = getNonProfileGuidedCompilerFilter(targetCompilerFilter);
17390e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            if (DexFile.isProfileGuidedCompilerFilter(targetCompilerFilter)) {
17490e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                throw new IllegalStateException(targetCompilerFilter);
175bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe            }
17690e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            isProfileGuidedFilter = false;
177bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        }
178bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe
179bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        // If we're asked to take profile updates into account, check now.
180bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        boolean newProfile = false;
181bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        if (checkProfiles && isProfileGuidedFilter) {
182bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe            // Merge profiles, see if we need to do anything.
183bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe            try {
184bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe                newProfile = mInstaller.mergeProfiles(sharedGid, pkg.packageName);
185bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe            } catch (InstallerException e) {
186bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe                Slog.w(TAG, "Failed to merge profiles", e);
187bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe            }
188bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe        }
189bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe
1907487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        final boolean vmSafeMode = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0;
1917487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        final boolean debuggable = (pkg.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;
1927487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
1937487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        boolean performedDexOpt = false;
1946a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil        boolean successfulDexOpt = true;
1956a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil
1967487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
1977487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        for (String dexCodeInstructionSet : dexCodeInstructionSets) {
1987487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov            for (String path : paths) {
199db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                int dexoptNeeded;
200a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                try {
201693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                    dexoptNeeded = DexFile.getDexOptNeeded(path,
202bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe                            dexCodeInstructionSet, targetCompilerFilter, newProfile);
203a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                } catch (IOException ioe) {
204a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                    Slog.w(TAG, "IOException reading apk: " + path, ioe);
205a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                    return DEX_OPT_FAILED;
20601dcb76fec4ee2ff3a3dc4516a37c144d771f18cNarayan Kamath                }
207a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                dexoptNeeded = adjustDexoptNeeded(dexoptNeeded);
20847c170a7460e8455ffc07981916c400fa980433aAndreas Gampe                if (PackageManagerService.DEBUG_DEXOPT) {
20947c170a7460e8455ffc07981916c400fa980433aAndreas Gampe                    Log.i(TAG, "DexoptNeeded for " + path + "@" + targetCompilerFilter + " is " +
21047c170a7460e8455ffc07981916c400fa980433aAndreas Gampe                            dexoptNeeded);
21147c170a7460e8455ffc07981916c400fa980433aAndreas Gampe                }
2127b08b35bde3df58816b171b88712bcc6d21dcbe8Richard Uhler
213db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                final String dexoptType;
214db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                String oatDir = null;
215693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                switch (dexoptNeeded) {
216693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                    case DexFile.NO_DEXOPT_NEEDED:
217693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        continue;
218693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                    case DexFile.DEX2OAT_NEEDED:
219693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        dexoptType = "dex2oat";
220693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        oatDir = createOatDirIfSupported(pkg, dexCodeInstructionSet);
221693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        break;
222693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                    case DexFile.PATCHOAT_NEEDED:
223693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        dexoptType = "patchoat";
224693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        break;
225693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                    case DexFile.SELF_PATCHOAT_NEEDED:
226693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        dexoptType = "self patchoat";
227693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        break;
228693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                    default:
229693f997cc8b8c2ba8d3ed29627b2641dd86392a5Calin Juravle                        throw new IllegalStateException("Invalid dexopt:" + dexoptNeeded);
230db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                }
23101dcb76fec4ee2ff3a3dc4516a37c144d771f18cNarayan Kamath
232c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                String sharedLibrariesPath = null;
233c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                if (sharedLibraries != null && sharedLibraries.length != 0) {
234c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                    StringBuilder sb = new StringBuilder();
235c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                    for (String lib : sharedLibraries) {
236c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                        if (sb.length() != 0) {
237c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                            sb.append(":");
238c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                        }
239c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                        sb.append(lib);
240c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                    }
241c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                    sharedLibrariesPath = sb.toString();
242c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                }
243db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                Log.i(TAG, "Running dexopt (" + dexoptType + ") on: " + path + " pkg="
244db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                        + pkg.applicationInfo.packageName + " isa=" + dexCodeInstructionSet
245db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                        + " vmSafeMode=" + vmSafeMode + " debuggable=" + debuggable
246c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                        + " target-filter=" + targetCompilerFilter + " oatDir = " + oatDir
247c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                        + " sharedLibraries=" + sharedLibrariesPath);
248d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravle                // Profile guide compiled oat files should not be public.
249bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe                final boolean isPublic = !pkg.isForwardLocked() && !isProfileGuidedFilter;
250bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe                final int profileFlag = isProfileGuidedFilter ? DEXOPT_PROFILE_GUIDED : 0;
251a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                final int dexFlags = adjustDexoptFlags(
252d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravle                        ( isPublic ? DEXOPT_PUBLIC : 0)
253db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                        | (vmSafeMode ? DEXOPT_SAFEMODE : 0)
254db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                        | (debuggable ? DEXOPT_DEBUGGABLE : 0)
255bdd30d86ef98456161069d11481b2ccd25a11b4eAndreas Gampe                        | profileFlag
256a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                        | DEXOPT_BOOTCOMPLETE);
257a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
258db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                try {
25937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe                    long startTime = System.currentTimeMillis();
26037e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe
261a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                    mInstaller.dexopt(path, sharedGid, pkg.packageName, dexCodeInstructionSet,
262c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                            dexoptNeeded, oatDir, dexFlags, targetCompilerFilter, pkg.volumeUuid,
263c7b9482b0c4bb2d378e63541b96be45c50094e05Jeff Hao                            sharedLibrariesPath);
264db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                    performedDexOpt = true;
26537e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe
26637e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe                    if (packageStats != null) {
26737e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe                        long endTime = System.currentTimeMillis();
26837e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe                        packageStats.setCompileTime(path, (int)(endTime - startTime));
26937e5fdc6b4963f3533caecdd92b129f79da69dd8Andreas Gampe                    }
270db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                } catch (InstallerException e) {
271db4a79a5d7d348e9d2286d95d4e5a59dd484456fCalin Juravle                    Slog.w(TAG, "Failed to dexopt", e);
2726a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil                    successfulDexOpt = false;
2737487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov                }
2747487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov            }
2757487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov        }
2767487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
2776a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil        if (successfulDexOpt) {
2786a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil            // If we've gotten here, we're sure that no error occurred. We've either
2796a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil            // dex-opted one or more paths or instruction sets or we've skipped
2806a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil            // all of them because they are up to date. In both cases this package
2816a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil            // doesn't need dexopt any longer.
2826a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil            return performedDexOpt ? DEX_OPT_PERFORMED : DEX_OPT_SKIPPED;
2836a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil        } else {
2846a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil            return DEX_OPT_FAILED;
2856a3b2d2bc63254a412eb546ed371fce8f4337434David Brazdil        }
2867487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov    }
2877487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov
288b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov    /**
289b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov     * Creates oat dir for the specified package. In certain cases oat directory
290b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov     * <strong>cannot</strong> be created:
291b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov     * <ul>
292b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov     *      <li>{@code pkg} is a system app, which is not updated.</li>
293b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov     *      <li>Package location is not a directory, i.e. monolithic install.</li>
294b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov     * </ul>
295b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov     *
2967b08b35bde3df58816b171b88712bcc6d21dcbe8Richard Uhler     * @return Absolute path to the oat directory or null, if oat directory
2977b08b35bde3df58816b171b88712bcc6d21dcbe8Richard Uhler     * cannot be created.
298b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov     */
299b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov    @Nullable
30027c24fb8b85c36298de053699b1967a808c6d308Todd Kennedy    private String createOatDirIfSupported(PackageParser.Package pkg, String dexInstructionSet) {
301ebcac16cb1405bf7d0b570e11a287df078edfc1cFyodor Kupolov        if (!pkg.canHaveOatDir()) {
302b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov            return null;
303b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov        }
304b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov        File codePath = new File(pkg.codePath);
305b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov        if (codePath.isDirectory()) {
306b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov            File oatDir = getOatDir(codePath);
307fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            try {
308a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                mInstaller.createOatDir(oatDir.getAbsolutePath(), dexInstructionSet);
309fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            } catch (InstallerException e) {
310fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                Slog.w(TAG, "Failed to create oat dir", e);
311fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey                return null;
312fdeeeea6cfdebdb98dd70a7dd48965743af01750Jeff Sharkey            }
3137b08b35bde3df58816b171b88712bcc6d21dcbe8Richard Uhler            return oatDir.getAbsolutePath();
314b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov        }
315b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov        return null;
316b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov    }
317b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov
318b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov    static File getOatDir(File codePath) {
319b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov        return new File(codePath, OAT_DIR_NAME);
320b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov    }
321b94c1657eb0140f7b91f5372a9f76de5a3d87e36Fyodor Kupolov
322a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov    void systemReady() {
323a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov        mSystemReady = true;
324a627c094e67f640dfe3b2ac0b633edcf51270cf4Fyodor Kupolov    }
325a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
32690e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil    /**
32790e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil     * Returns true if the profiling data collected for the given app indicate
32890e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil     * that the apps's APK has been loaded by another app.
32990e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil     * Note that this returns false for all forward-locked apps and apps without
33090e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil     * any collected profiling data.
33190e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil     */
33290e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil    public static boolean isUsedByOtherApps(PackageParser.Package pkg) {
33390e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil        if (pkg.isForwardLocked()) {
33490e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            // Skip the check for forward locked packages since they don't share their code.
33590e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            return false;
336d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravle        }
33790e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil
33890e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil        for (String apkPath : pkg.getAllCodePathsExcludingResourceOnly()) {
33990e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            try {
3406d99f796711882ba60977c211d0f92252fe7ad4aNarayan Kamath                apkPath = PackageManagerServiceUtils.realpath(new File(apkPath));
34190e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            } catch (IOException e) {
34290e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                // Log an error but continue without it.
34390e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                Slog.w(TAG, "Failed to get canonical path", e);
3446d99f796711882ba60977c211d0f92252fe7ad4aNarayan Kamath                continue;
34590e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            }
34690e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            String useMarker = apkPath.replace('/', '@');
34790e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            final int[] currentUserIds = UserManagerService.getInstance().getUserIds();
34890e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil            for (int i = 0; i < currentUserIds.length; i++) {
34990e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                File profileDir =
35090e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                        Environment.getDataProfilesDeForeignDexDirectory(currentUserIds[i]);
35190e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                File foreignUseMark = new File(profileDir, useMarker);
35290e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                if (foreignUseMark.exists()) {
35390e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                    return true;
35490e269917e1d8f9fadb12c3528b8c360b2271e82David Brazdil                }
355d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravle            }
356d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravle        }
357d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravle        return false;
358d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravle    }
359d479b52d12fc782f18df6b5ae15c19e022f0ec14Calin Juravle
360a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    /**
361a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     * A specialized PackageDexOptimizer that overrides already-installed checks, forcing a
362a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     * dexopt path.
363a89087542f774c585b6a6ec535fc294721710521Andreas Gampe     */
364a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    public static class ForcedUpdatePackageDexOptimizer extends PackageDexOptimizer {
365a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
366a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        public ForcedUpdatePackageDexOptimizer(Installer installer, Object installLock,
367a89087542f774c585b6a6ec535fc294721710521Andreas Gampe                Context context, String wakeLockTag) {
368a89087542f774c585b6a6ec535fc294721710521Andreas Gampe            super(installer, installLock, context, wakeLockTag);
369a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        }
370a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
371a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        public ForcedUpdatePackageDexOptimizer(PackageDexOptimizer from) {
372a89087542f774c585b6a6ec535fc294721710521Andreas Gampe            super(from);
373a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        }
374a89087542f774c585b6a6ec535fc294721710521Andreas Gampe
375a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        @Override
376a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        protected int adjustDexoptNeeded(int dexoptNeeded) {
377a89087542f774c585b6a6ec535fc294721710521Andreas Gampe            // Ensure compilation, no matter the current state.
378a89087542f774c585b6a6ec535fc294721710521Andreas Gampe            // TODO: The return value is wrong when patchoat is needed.
379a89087542f774c585b6a6ec535fc294721710521Andreas Gampe            return DexFile.DEX2OAT_NEEDED;
380a89087542f774c585b6a6ec535fc294721710521Andreas Gampe        }
381a89087542f774c585b6a6ec535fc294721710521Andreas Gampe    }
3827487657ee9f3f91a1fb4e52ce2a03b56496ac1f4Fyodor Kupolov}
383