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

Commit bc3291d1 authored by Songchun Fan's avatar Songchun Fan
Browse files

[pm] add dexopt helper

+ Also moved out PackageManagerNative

BUG: 202559536
Test: manual
Change-Id: I564aa75f90afd266486d08a321728c4698a70f80
parent a829c20c
Loading
Loading
Loading
Loading
+40 −32
Original line number Diff line number Diff line
@@ -251,13 +251,15 @@ public final class BackgroundDexOptService {
                resetStatesForNewDexOptRunLocked(Thread.currentThread());
            }
            PackageManagerService pm = mInjector.getPackageManagerService();
            DexOptHelper dexOptHelper = new DexOptHelper(pm);
            ArraySet<String> packagesToOptimize;
            if (packageNames == null) {
                packagesToOptimize = pm.getOptimizablePackages();
                packagesToOptimize = dexOptHelper.getOptimizablePackages();
            } else {
                packagesToOptimize = new ArraySet<>(packageNames);
            }
            return runIdleOptimization(pm, packagesToOptimize, /* isPostBootUpdate= */ false);
            return runIdleOptimization(pm, dexOptHelper, packagesToOptimize,
                    /* isPostBootUpdate= */ false);
        } finally {
            Binder.restoreCallingIdentity(identity);
            markDexOptCompleted();
@@ -318,7 +320,8 @@ public final class BackgroundDexOptService {
            return false;
        }

        ArraySet<String> pkgs = pm.getOptimizablePackages();
        DexOptHelper dexOptHelper = new DexOptHelper(pm);
        ArraySet<String> pkgs = dexOptHelper.getOptimizablePackages();
        if (pkgs.isEmpty()) {
            Slog.i(TAG, "No packages to optimize");
            markPostBootUpdateCompleted(params);
@@ -344,7 +347,7 @@ public final class BackgroundDexOptService {
                        tr.traceBegin("jobExecution");
                        boolean completed = false;
                        try {
                            completed = runIdleOptimization(pm, pkgs,
                            completed = runIdleOptimization(pm, dexOptHelper, pkgs,
                                    params.getJobId() == JOB_POST_BOOT_UPDATE);
                        } finally { // Those cleanup should be done always.
                            tr.traceEnd();
@@ -457,7 +460,8 @@ public final class BackgroundDexOptService {

    @GuardedBy("mLock")
    private void controlDexOptBlockingLocked(boolean block) {
        mInjector.getPackageManagerService().controlDexOptBlocking(block);
        PackageManagerService pm = mInjector.getPackageManagerService();
        new DexOptHelper(pm).controlDexOptBlocking(block);
    }

    private void scheduleAJob(int jobId) {
@@ -507,10 +511,11 @@ public final class BackgroundDexOptService {
    }

    /** Returns true if completed */
    private boolean runIdleOptimization(PackageManagerService pm, ArraySet<String> pkgs,
            boolean isPostBootUpdate) {
    private boolean runIdleOptimization(PackageManagerService pm, DexOptHelper dexOptHelper,
            ArraySet<String> pkgs, boolean isPostBootUpdate) {
        long lowStorageThreshold = getLowStorageThreshold();
        int status = idleOptimizePackages(pm, pkgs, lowStorageThreshold, isPostBootUpdate);
        int status = idleOptimizePackages(pm, dexOptHelper, pkgs, lowStorageThreshold,
                isPostBootUpdate);
        logStatus(status);
        synchronized (mLock) {
            mLastExecutionStatus = status;
@@ -557,8 +562,8 @@ public final class BackgroundDexOptService {
    }

    @Status
    private int idleOptimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
            long lowStorageThreshold, boolean isPostBootUpdate) {
    private int idleOptimizePackages(PackageManagerService pm, DexOptHelper dexOptHelper,
            ArraySet<String> pkgs, long lowStorageThreshold, boolean isPostBootUpdate) {
        ArraySet<String> updatedPackages = new ArraySet<>();
        ArraySet<String> updatedPackagesDueToSecondaryDex = new ArraySet<>();

@@ -595,7 +600,7 @@ public final class BackgroundDexOptService {
                            // Should be aborted by the scheduler.
                            return abortCode;
                        }
                        @DexOptResult int downgradeResult = downgradePackage(pm, pkg,
                        @DexOptResult int downgradeResult = downgradePackage(pm, dexOptHelper, pkg,
                                /* isForPrimaryDex= */ true, isPostBootUpdate);
                        if (downgradeResult == PackageDexOptimizer.DEX_OPT_PERFORMED) {
                            updatedPackages.add(pkg);
@@ -606,7 +611,7 @@ public final class BackgroundDexOptService {
                            return status;
                        }
                        if (supportSecondaryDex) {
                            downgradeResult = downgradePackage(pm, pkg,
                            downgradeResult = downgradePackage(pm, dexOptHelper, pkg,
                                    /* isForPrimaryDex= */false, isPostBootUpdate);
                            status = convertPackageDexOptimizerStatusToInternal(downgradeResult);
                            if (status != STATUS_OK) {
@@ -620,8 +625,9 @@ public final class BackgroundDexOptService {
                }
            }

            @Status int primaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
                    /*isForPrimaryDex=*/ true, updatedPackages, isPostBootUpdate);
            @Status int primaryResult = optimizePackages(dexOptHelper, pkgs,
                    lowStorageThreshold, /*isForPrimaryDex=*/ true, updatedPackages,
                    isPostBootUpdate);
            if (primaryResult != STATUS_OK) {
                return primaryResult;
            }
@@ -630,9 +636,9 @@ public final class BackgroundDexOptService {
                return STATUS_OK;
            }

            @Status int secondaryResult = optimizePackages(pm, pkgs, lowStorageThreshold,
                    /*isForPrimaryDex*/ false, updatedPackagesDueToSecondaryDex,
                    isPostBootUpdate);
            @Status int secondaryResult = optimizePackages(dexOptHelper, pkgs,
                    lowStorageThreshold, /*isForPrimaryDex*/ false,
                    updatedPackagesDueToSecondaryDex, isPostBootUpdate);
            return secondaryResult;
        } finally {
            // Always let the pinner service know about changes.
@@ -645,9 +651,9 @@ public final class BackgroundDexOptService {
    }

    @Status
    private int optimizePackages(PackageManagerService pm, ArraySet<String> pkgs,
            long lowStorageThreshold, boolean isForPrimaryDex, ArraySet<String> updatedPackages,
            boolean isPostBootUpdate) {
    private int optimizePackages(DexOptHelper dexOptHelper,
            ArraySet<String> pkgs, long lowStorageThreshold, boolean isForPrimaryDex,
            ArraySet<String> updatedPackages, boolean isPostBootUpdate) {
        for (String pkg : pkgs) {
            int abortCode = abortIdleOptimizations(lowStorageThreshold);
            if (abortCode != STATUS_OK) {
@@ -655,7 +661,8 @@ public final class BackgroundDexOptService {
                return abortCode;
            }

            @DexOptResult int result = optimizePackage(pm, pkg, isForPrimaryDex, isPostBootUpdate);
            @DexOptResult int result = optimizePackage(dexOptHelper, pkg, isForPrimaryDex,
                    isPostBootUpdate);
            if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
                updatedPackages.add(pkg);
            } else if (result != PackageDexOptimizer.DEX_OPT_SKIPPED) {
@@ -674,7 +681,7 @@ public final class BackgroundDexOptService {
     * @return PackageDexOptimizer.DEX_*
     */
    @DexOptResult
    private int downgradePackage(PackageManagerService pm, String pkg,
    private int downgradePackage(PackageManagerService pm, DexOptHelper dexOptHelper, String pkg,
            boolean isForPrimaryDex, boolean isPostBootUpdate) {
        if (DEBUG) {
            Slog.d(TAG, "Downgrading " + pkg);
@@ -697,10 +704,10 @@ public final class BackgroundDexOptService {
                // remove their compiler artifacts from dalvik cache.
                pm.deleteOatArtifactsOfPackage(pkg);
            } else {
                result = performDexOptPrimary(pm, pkg, reason, dexoptFlags);
                result = performDexOptPrimary(dexOptHelper, pkg, reason, dexoptFlags);
            }
        } else {
            result = performDexOptSecondary(pm, pkg, reason, dexoptFlags);
            result = performDexOptSecondary(dexOptHelper, pkg, reason, dexoptFlags);
        }

        if (result == PackageDexOptimizer.DEX_OPT_PERFORMED) {
@@ -726,14 +733,14 @@ public final class BackgroundDexOptService {
     *
     * Optimize package if needed. Note that there can be no race between
     * concurrent jobs because PackageDexOptimizer.performDexOpt is synchronized.
     * @param pm An instance of PackageManagerService
     * @param dexOptHelper An instance of DexOptHelper
     * @param pkg The package to be downgraded.
     * @param isForPrimaryDex Apps can have several dex file, primary and secondary.
     * @param isPostBootUpdate is post boot update or not.
     * @return PackageDexOptimizer#DEX_OPT_*
     */
    @DexOptResult
    private int optimizePackage(PackageManagerService pm, String pkg,
    private int optimizePackage(DexOptHelper dexOptHelper, String pkg,
            boolean isForPrimaryDex, boolean isPostBootUpdate) {
        int reason = isPostBootUpdate ? PackageManagerService.REASON_POST_BOOT
                : PackageManagerService.REASON_BACKGROUND_DEXOPT;
@@ -746,26 +753,27 @@ public final class BackgroundDexOptService {
        // System server share the same code path as primary dex files.
        // PackageManagerService will select the right optimization path for it.
        if (isForPrimaryDex || PLATFORM_PACKAGE_NAME.equals(pkg)) {
            return performDexOptPrimary(pm, pkg, reason, dexoptFlags);
            return performDexOptPrimary(dexOptHelper, pkg, reason, dexoptFlags);
        } else {
            return performDexOptSecondary(pm, pkg, reason, dexoptFlags);
            return performDexOptSecondary(dexOptHelper, pkg, reason, dexoptFlags);
        }
    }

    @DexOptResult
    private int performDexOptPrimary(PackageManagerService pm, String pkg, int reason,
    private int performDexOptPrimary(DexOptHelper dexOptHelper, String pkg, int reason,
            int dexoptFlags) {
        return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ true,
                () -> pm.performDexOptWithStatus(new DexoptOptions(pkg, reason, dexoptFlags)));
                () -> dexOptHelper.performDexOptWithStatus(
                        new DexoptOptions(pkg, reason, dexoptFlags)));
    }

    @DexOptResult
    private int performDexOptSecondary(PackageManagerService pm, String pkg, int reason,
    private int performDexOptSecondary(DexOptHelper dexOptHelper, String pkg, int reason,
            int dexoptFlags) {
        DexoptOptions dexoptOptions = new DexoptOptions(pkg, reason,
                dexoptFlags | DexoptOptions.DEXOPT_ONLY_SECONDARY_DEX);
        return trackPerformDexOpt(pkg, /*isForPrimaryDex=*/ false,
                () -> pm.performDexOpt(dexoptOptions)
                () -> dexOptHelper.performDexOpt(dexoptOptions)
                    ? PackageDexOptimizer.DEX_OPT_PERFORMED : PackageDexOptimizer.DEX_OPT_FAILED
        );
    }
+667 −0

File added.

Preview size limit exceeded, changes collapsed.

+2 −2
Original line number Diff line number Diff line
@@ -128,7 +128,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
                PLATFORM_PACKAGE_NAME.equals(pkgSetting.getPkg().getPackageName());
        synchronized (mPackageManagerService.mLock) {
            // Important: the packages we need to run with ab-ota compiler-reason.
            important = PackageManagerServiceUtils.getPackagesForDexopt(
            important = DexOptHelper.getPackagesForDexopt(
                    mPackageManagerService.mSettings.getPackagesLocked().values(),
                    mPackageManagerService, DEBUG_DEXOPT);
            // Remove Platform Package from A/B OTA b/160735835.
@@ -160,7 +160,7 @@ public class OtaDexoptService extends IOtaDexopt.Stub {
        long spaceAvailable = getAvailableSpace();
        if (spaceAvailable < BULK_DELETE_THRESHOLD) {
            Log.i(TAG, "Low on space, deleting oat files in an attempt to free up space: "
                    + PackageManagerServiceUtils.packagesToString(others));
                    + DexOptHelper.packagesToString(others));
            for (PackageSetting pkg : others) {
                mPackageManagerService.deleteOatArtifactsOfPackage(pkg.getPackageName());
            }
+237 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.pm;

import static android.content.pm.PackageManager.CERT_INPUT_SHA256;

import static com.android.server.pm.PackageManagerService.TAG;

import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.pm.ApplicationInfo;
import android.content.pm.IPackageChangeObserver;
import android.content.pm.IPackageManagerNative;
import android.content.pm.IStagedApexObserver;
import android.content.pm.PackageInfo;
import android.content.pm.StagedApexInfo;
import android.os.Binder;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.text.TextUtils;
import android.util.Log;
import android.util.Slog;

import java.util.Arrays;

final class PackageManagerNative extends IPackageManagerNative.Stub {
    private final PackageManagerService mPm;

    PackageManagerNative(PackageManagerService pm) {
        mPm = pm;
    }

    @Override
    public void registerPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
        synchronized (mPm.mPackageChangeObservers) {
            try {
                observer.asBinder().linkToDeath(
                        new PackageChangeObserverDeathRecipient(observer), 0);
            } catch (RemoteException e) {
                Log.e(TAG, e.getMessage());
            }
            mPm.mPackageChangeObservers.add(observer);
            Log.d(TAG, "Size of mPackageChangeObservers after registry is "
                    + mPm.mPackageChangeObservers.size());
        }
    }

    @Override
    public void unregisterPackageChangeObserver(@NonNull IPackageChangeObserver observer) {
        synchronized (mPm.mPackageChangeObservers) {
            mPm.mPackageChangeObservers.remove(observer);
            Log.d(TAG, "Size of mPackageChangeObservers after unregistry is "
                    + mPm.mPackageChangeObservers.size());
        }
    }

    @Override
    public String[] getAllPackages() {
        return mPm.getAllPackages().toArray(new String[0]);
    }

    @Override
    public String[] getNamesForUids(int[] uids) throws RemoteException {
        String[] names = null;
        String[] results = null;
        try {
            if (uids == null || uids.length == 0) {
                return null;
            }
            names = mPm.getNamesForUids(uids);
            results = (names != null) ? names : new String[uids.length];
            // massage results so they can be parsed by the native binder
            for (int i = results.length - 1; i >= 0; --i) {
                if (results[i] == null) {
                    results[i] = "";
                }
            }
            return results;
        } catch (Throwable t) {
            // STOPSHIP(186558987): revert addition of try/catch/log
            Slog.e(TAG, "uids: " + Arrays.toString(uids));
            Slog.e(TAG, "names: " + Arrays.toString(names));
            Slog.e(TAG, "results: " + Arrays.toString(results));
            Slog.e(TAG, "throwing exception", t);
            throw t;
        }
    }

    // NB: this differentiates between preloads and sideloads
    @Override
    public String getInstallerForPackage(String packageName) throws RemoteException {
        final String installerName = mPm.getInstallerPackageName(packageName);
        if (!TextUtils.isEmpty(installerName)) {
            return installerName;
        }
        // differentiate between preload and sideload
        int callingUser = UserHandle.getUserId(Binder.getCallingUid());
        ApplicationInfo appInfo = mPm.getApplicationInfo(packageName,
                /*flags*/ 0,
                /*userId*/ callingUser);
        if (appInfo != null && (appInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
            return "preload";
        }
        return "";
    }

    @Override
    public long getVersionCodeForPackage(String packageName) throws RemoteException {
        try {
            int callingUser = UserHandle.getUserId(Binder.getCallingUid());
            PackageInfo pInfo = mPm.getPackageInfo(packageName, 0, callingUser);
            if (pInfo != null) {
                return pInfo.getLongVersionCode();
            }
        } catch (Exception e) {
        }
        return 0;
    }

    @Override
    public int getTargetSdkVersionForPackage(String packageName) throws RemoteException {
        int targetSdk = mPm.getTargetSdkVersion(packageName);
        if (targetSdk != -1) {
            return targetSdk;
        }

        throw new RemoteException("Couldn't get targetSdkVersion for package " + packageName);
    }

    @Override
    public boolean isPackageDebuggable(String packageName) throws RemoteException {
        int callingUser = UserHandle.getCallingUserId();
        ApplicationInfo appInfo = mPm.getApplicationInfo(packageName, 0, callingUser);
        if (appInfo != null) {
            return (0 != (appInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE));
        }

        throw new RemoteException("Couldn't get debug flag for package " + packageName);
    }

    @Override
    public boolean[] isAudioPlaybackCaptureAllowed(String[] packageNames)
            throws RemoteException {
        int callingUser = UserHandle.getUserId(Binder.getCallingUid());
        boolean[] results = new boolean[packageNames.length];
        for (int i = results.length - 1; i >= 0; --i) {
            ApplicationInfo appInfo = mPm.getApplicationInfo(packageNames[i], 0, callingUser);
            results[i] = appInfo != null && appInfo.isAudioPlaybackCaptureAllowed();
        }
        return results;
    }

    @Override
    public int getLocationFlags(String packageName) throws RemoteException {
        int callingUser = UserHandle.getUserId(Binder.getCallingUid());
        ApplicationInfo appInfo = mPm.getApplicationInfo(packageName,
                /*flags*/ 0,
                /*userId*/ callingUser);
        if (appInfo == null) {
            throw new RemoteException(
                    "Couldn't get ApplicationInfo for package " + packageName);
        }
        return ((appInfo.isSystemApp() ? IPackageManagerNative.LOCATION_SYSTEM : 0)
                | (appInfo.isVendor() ? IPackageManagerNative.LOCATION_VENDOR : 0)
                | (appInfo.isProduct() ? IPackageManagerNative.LOCATION_PRODUCT : 0));
    }

    @Override
    public String getModuleMetadataPackageName() throws RemoteException {
        return mPm.getModuleMetadataPackageName();
    }

    @Override
    public boolean hasSha256SigningCertificate(String packageName, byte[] certificate)
            throws RemoteException {
        return mPm.hasSigningCertificate(packageName, certificate, CERT_INPUT_SHA256);
    }

    @Override
    public boolean hasSystemFeature(String featureName, int version) {
        return mPm.hasSystemFeature(featureName, version);
    }

    @Override
    public void registerStagedApexObserver(IStagedApexObserver observer) {
        mPm.mInstallerService.getStagingManager().registerStagedApexObserver(observer);
    }

    @Override
    public void unregisterStagedApexObserver(IStagedApexObserver observer) {
        mPm.mInstallerService.getStagingManager().unregisterStagedApexObserver(observer);
    }

    @Override
    public String[] getStagedApexModuleNames() {
        return mPm.mInstallerService.getStagingManager()
                .getStagedApexModuleNames().toArray(new String[0]);
    }

    @Override
    @Nullable
    public StagedApexInfo getStagedApexInfo(String moduleName) {
        return mPm.mInstallerService.getStagingManager().getStagedApexInfo(moduleName);
    }

    private final class PackageChangeObserverDeathRecipient implements IBinder.DeathRecipient {
        private final IPackageChangeObserver mObserver;

        PackageChangeObserverDeathRecipient(IPackageChangeObserver observer) {
            mObserver = observer;
        }

        @Override
        public void binderDied() {
            synchronized (mPm.mPackageChangeObservers) {
                mPm.mPackageChangeObservers.remove(mObserver);
                Log.d(TAG, "Size of mPackageChangeObservers after removing dead observer is "
                        + mPm.mPackageChangeObservers.size());
            }
        }
    }
}
+40 −789

File changed.

Preview size limit exceeded, changes collapsed.

Loading