Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3275a6b2 authored by Nicolas Geoffray's avatar Nicolas Geoffray Committed by Gerrit Code Review
Browse files

Merge "Support dexopting shared libraries."

parents 7bb0bcd3 653356f1
Loading
Loading
Loading
Loading
+47 −0
Original line number Diff line number Diff line
@@ -25,10 +25,12 @@ import android.content.pm.dex.ArtManager;
import android.content.pm.dex.DexMetadataHelper;
import android.os.FileUtils;
import android.os.PowerManager;
import android.os.Process;
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.os.WorkSource;
import android.os.storage.StorageManager;
import android.util.Log;
import android.util.Slog;

@@ -148,6 +150,51 @@ public class PackageDexOptimizer {
        }
    }

    int performDexOpt(SharedLibraryInfo info, String[] instructionSets, DexoptOptions options) {
        String classLoaderContext = DexoptUtils.getClassLoaderContext(info);
        final String[] dexCodeInstructionSets = getDexCodeInstructionSets(instructionSets);
        String compilerFilter = PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
                PackageManagerService.REASON_SHARED);
        int result = DEX_OPT_SKIPPED;
        for (String instructionSet : dexCodeInstructionSets) {
            int dexoptNeeded = getDexoptNeeded(
                        info.getPath(), instructionSet, compilerFilter,
                        classLoaderContext, false /* newProfile */,
                        false /* downgrade */);
            if (Math.abs(dexoptNeeded) == DexFile.NO_DEXOPT_NEEDED) {
                continue;
            }
            // Special string recognized by installd.
            final String packageName = "*";
            final String outputPath = null;
            int dexFlags = DEXOPT_PUBLIC
                    | (options.isBootComplete() ? DEXOPT_BOOTCOMPLETE : 0)
                    | (options.isDexoptIdleBackgroundJob() ? DEXOPT_IDLE_BACKGROUND_JOB : 0);
            dexFlags = adjustDexoptFlags(dexFlags);
            final String uuid = StorageManager.UUID_SYSTEM;
            final String seInfo = null;
            final int targetSdkVersion = 0;  // Builtin libraries targets the system's SDK version
            try {
                mInstaller.dexopt(info.getPath(), Process.SYSTEM_UID, packageName,
                        instructionSet, dexoptNeeded, outputPath, dexFlags, compilerFilter,
                        uuid, classLoaderContext, seInfo, false /* downgrade */,
                        targetSdkVersion, /*profileName*/ null, /*dexMetadataPath*/ null,
                        getReasonName(options.getCompilationReason()));
                // The end result is:
                //  - FAILED if any path failed,
                //  - PERFORMED if at least one path needed compilation,
                //  - SKIPPED when all paths are up to date
                if (result != DEX_OPT_FAILED) {
                    result = DEX_OPT_PERFORMED;
                }
            } catch (InstallerException e) {
                Slog.w(TAG, "Failed to dexopt", e);
                result = DEX_OPT_FAILED;
            }
        }
        return result;
    }

    /**
     * Performs dexopt on all code paths of the given package.
     * It assumes the install lock is held.
+44 −50
Original line number Diff line number Diff line
@@ -9443,18 +9443,27 @@ public class PackageManagerService extends IPackageManager.Stub
        // at boot, or background job), the passed 'targetCompilerFilter' stays the same,
        // and the first package that uses the library will dexopt it. The
        // others will see that the compiled code for the library is up to date.
        Collection<PackageParser.Package> deps = findSharedNonSystemLibraries(p);
        Collection<SharedLibraryInfo> deps = findSharedLibraries(p);
        final String[] instructionSets = getAppDexInstructionSets(p.applicationInfo);
        if (!deps.isEmpty()) {
            DexoptOptions libraryOptions = new DexoptOptions(options.getPackageName(),
                    options.getCompilationReason(), options.getCompilerFilter(),
                    options.getSplitName(),
                    options.getFlags() | DexoptOptions.DEXOPT_AS_SHARED_LIBRARY);
            for (PackageParser.Package depPackage : deps) {
            for (SharedLibraryInfo info : deps) {
                PackageParser.Package depPackage = null;
                synchronized (mPackages) {
                    depPackage = mPackages.get(info.getPackageName());
                }
                if (depPackage != null) {
                    // TODO: Analyze and investigate if we (should) profile libraries.
                    pdo.performDexOpt(depPackage, instructionSets,
                            getOrCreateCompilerPackageStats(depPackage),
                    mDexManager.getPackageUseInfoOrDefault(depPackage.packageName), libraryOptions);
                            mDexManager.getPackageUseInfoOrDefault(depPackage.packageName),
                            libraryOptions);
                } else {
                    pdo.performDexOpt(info, instructionSets, libraryOptions);
                }
            }
        }
        return pdo.performDexOpt(p, instructionSets,
@@ -9494,63 +9503,48 @@ public class PackageManagerService extends IPackageManager.Stub
        return BackgroundDexOptService.runIdleOptimizationsNow(this, mContext, packageNames);
    }
    List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package p) {
        if (p.usesLibraries != null || p.usesOptionalLibraries != null
                || p.usesStaticLibraries != null) {
            ArrayList<PackageParser.Package> retValue = new ArrayList<>();
    private static List<SharedLibraryInfo> findSharedLibraries(PackageParser.Package p) {
        if (p.usesLibraryInfos != null) {
            ArrayList<SharedLibraryInfo> retValue = new ArrayList<>();
            Set<String> collectedNames = new HashSet<>();
            findSharedNonSystemLibrariesRecursive(p, retValue, collectedNames);
            retValue.remove(p);
            for (SharedLibraryInfo info : p.usesLibraryInfos) {
                findSharedLibrariesRecursive(info, retValue, collectedNames);
            }
            return retValue;
        } else {
            return Collections.emptyList();
        }
    }
    private void findSharedNonSystemLibrariesRecursive(PackageParser.Package p,
            ArrayList<PackageParser.Package> collected, Set<String> collectedNames) {
        if (!collectedNames.contains(p.packageName)) {
            collectedNames.add(p.packageName);
            collected.add(p);
    private static void findSharedLibrariesRecursive(SharedLibraryInfo info,
            ArrayList<SharedLibraryInfo> collected, Set<String> collectedNames) {
        if (!collectedNames.contains(info.getName())) {
            collectedNames.add(info.getName());
            collected.add(info);
            if (p.usesLibraries != null) {
                findSharedNonSystemLibrariesRecursive(p.usesLibraries,
                        null, collected, collectedNames);
            }
            if (p.usesOptionalLibraries != null) {
                findSharedNonSystemLibrariesRecursive(p.usesOptionalLibraries,
                        null, collected, collectedNames);
            if (info.getDependencies() != null) {
                for (SharedLibraryInfo dep : info.getDependencies()) {
                    findSharedLibrariesRecursive(dep, collected, collectedNames);
                }
            if (p.usesStaticLibraries != null) {
                findSharedNonSystemLibrariesRecursive(p.usesStaticLibraries,
                        p.usesStaticLibrariesVersions, collected, collectedNames);
            }
        }
    }
    private void findSharedNonSystemLibrariesRecursive(ArrayList<String> libs, long[] versions,
            ArrayList<PackageParser.Package> collected, Set<String> collectedNames) {
        final int libNameCount = libs.size();
        for (int i = 0; i < libNameCount; i++) {
            String libName = libs.get(i);
            long version = (versions != null && versions.length == libNameCount)
                    ? versions[i] : PackageManager.VERSION_CODE_HIGHEST;
            PackageParser.Package libPkg = findSharedNonSystemLibrary(libName, version);
            if (libPkg != null) {
                findSharedNonSystemLibrariesRecursive(libPkg, collected, collectedNames);
            }
    List<PackageParser.Package> findSharedNonSystemLibraries(PackageParser.Package pkg) {
        List<SharedLibraryInfo> deps = findSharedLibraries(pkg);
        if (!deps.isEmpty()) {
            ArrayList<PackageParser.Package> retValue = new ArrayList<>();
            synchronized (mPackages) {
                for (SharedLibraryInfo info : deps) {
                    PackageParser.Package depPackage = mPackages.get(info.getPackageName());
                    if (depPackage != null) {
                        retValue.add(depPackage);
                    }
                }
    private PackageParser.Package findSharedNonSystemLibrary(String name, long version) {
        synchronized (mPackages) {
            SharedLibraryInfo libraryInfo = getSharedLibraryInfoLPr(name, version);
            if (libraryInfo != null) {
                return mPackages.get(libraryInfo.getPackageName());
            }
            return null;
            return retValue;
        } else {
            return Collections.emptyList();
        }
    }
+12 −0
Original line number Diff line number Diff line
@@ -173,6 +173,18 @@ public final class DexoptUtils {
        return classLoaderContexts;
    }

    /**
     * Creates the class loader context for the given shared library.
     */
    public static String getClassLoaderContext(SharedLibraryInfo info) {
        String sharedLibrariesContext = "";
        if (info.getDependencies() != null) {
            sharedLibrariesContext = encodeSharedLibraries(info.getDependencies());
        }
        return encodeClassLoader(
                "", SHARED_LIBRARY_LOADER_TYPE, sharedLibrariesContext);
    }

    /**
     * Recursive method to generate the class loader context dependencies for the split with the
     * given index. {@param classLoaderContexts} acts as an accumulator. Upton return
+14 −0
Original line number Diff line number Diff line
@@ -331,6 +331,20 @@ public class DexoptUtilsTest {
        assertEquals(null, contexts[7]);
    }

    @Test
    public void testSharedLibraryContext() {
        SharedLibraryInfo sharedLibrary =
                createMockSharedLibrary(new String[] {"a.dex", "b.dex"}).get(0);
        String context = DexoptUtils.getClassLoaderContext(sharedLibrary);
        assertEquals("PCL[]", context);

        SharedLibraryInfo otherSharedLibrary =
                createMockSharedLibrary(new String[] {"c.dex"}).get(0);
        otherSharedLibrary.addDependency(sharedLibrary);
        context = DexoptUtils.getClassLoaderContext(otherSharedLibrary);
        assertEquals("PCL[]{PCL[a.dex:b.dex]}", context);
    }

    @Test
    public void testProcessContextForDexLoad() {
        List<String> classLoaders = Arrays.asList(