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

Commit 9726215c authored by Jiakai Zhang's avatar Jiakai Zhang
Browse files

Fail adb install on external profile errors.

This is to warn app developers if they have provided bad external
profiles, including the profile in the DM file and the profile embedded
in the dex container file.

This change does not affect normal (non-adb) app install workflow.

Bug: 278080573
Test: atest CtsCompilationTestCases
Change-Id: I92529030cd13030df9effb5edc8e81374a06728b
parent 55334b50
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -370,6 +370,13 @@ public class PackageInstaller {
    public static final String EXTRA_UNARCHIVE_ALL_USERS =
    public static final String EXTRA_UNARCHIVE_ALL_USERS =
            "android.content.pm.extra.UNARCHIVE_ALL_USERS";
            "android.content.pm.extra.UNARCHIVE_ALL_USERS";


    /**
     * A list of warnings that occurred during installation.
     *
     * @hide
     */
    public static final String EXTRA_WARNINGS = "android.content.pm.extra.WARNINGS";

    /**
    /**
     * Streaming installation pending.
     * Streaming installation pending.
     * Caller should make sure DataLoader is able to prepare image and reinitiate the operation.
     * Caller should make sure DataLoader is able to prepare image and reinitiate the operation.
+43 −13
Original line number Original line Diff line number Diff line
@@ -22,6 +22,8 @@ import static android.content.pm.PackageManager.INSTALL_SCENARIO_DEFAULT;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.content.pm.PackageManager.INSTALL_SUCCEEDED;
import static android.os.Process.INVALID_UID;
import static android.os.Process.INVALID_UID;


import static com.android.server.art.model.DexoptResult.DexContainerFileDexoptResult;
import static com.android.server.art.model.DexoptResult.PackageDexoptResult;
import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
import static com.android.server.pm.PackageManagerService.EMPTY_INT_ARRAY;
import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
import static com.android.server.pm.PackageManagerService.SCAN_AS_INSTANT_APP;
import static com.android.server.pm.PackageManagerService.TAG;
import static com.android.server.pm.PackageManagerService.TAG;
@@ -57,6 +59,7 @@ import com.android.server.pm.pkg.parsing.ParsingPackageUtils;
import java.io.File;
import java.io.File;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.List;


final class InstallRequest {
final class InstallRequest {
@@ -148,6 +151,9 @@ final class InstallRequest {
    @NonNull
    @NonNull
    private int[] mUpdateBroadcastInstantUserIds = EMPTY_INT_ARRAY;
    private int[] mUpdateBroadcastInstantUserIds = EMPTY_INT_ARRAY;


    @NonNull
    private ArrayList<String> mWarnings = new ArrayList<>();

    // New install
    // New install
    InstallRequest(InstallingSession params) {
    InstallRequest(InstallingSession params) {
        mUserId = params.getUser().getIdentifier();
        mUserId = params.getUser().getIdentifier();
@@ -658,6 +664,11 @@ final class InstallRequest {
        return mUpdateBroadcastInstantUserIds;
        return mUpdateBroadcastInstantUserIds;
    }
    }


    @NonNull
    public ArrayList<String> getWarnings() {
        return mWarnings;
    }

    public void setScanFlags(int scanFlags) {
    public void setScanFlags(int scanFlags) {
        mScanFlags = scanFlags;
        mScanFlags = scanFlags;
    }
    }
@@ -855,6 +866,10 @@ final class InstallRequest {
        }
        }
    }
    }


    public void addWarning(@NonNull String warning) {
        mWarnings.add(warning);
    }

    public void onPrepareStarted() {
    public void onPrepareStarted() {
        if (mPackageMetrics != null) {
        if (mPackageMetrics != null) {
            mPackageMetrics.onStepStarted(PackageMetrics.STEP_PREPARE);
            mPackageMetrics.onStepStarted(PackageMetrics.STEP_PREPARE);
@@ -904,23 +919,38 @@ final class InstallRequest {
    }
    }


    public void onDexoptFinished(DexoptResult dexoptResult) {
    public void onDexoptFinished(DexoptResult dexoptResult) {
        if (mPackageMetrics == null) {
        // Only report external profile warnings when installing from adb. The goal is to warn app
            return;
        // developers if they have provided bad external profiles, so it's not beneficial to report
        // those warnings in the normal app install workflow.
        if (isInstallFromAdb()) {
            var externalProfileErrors = new LinkedHashSet<String>();
            for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) {
                for (DexContainerFileDexoptResult fileResult :
                        packageResult.getDexContainerFileDexoptResults()) {
                    externalProfileErrors.addAll(fileResult.getExternalProfileErrors());
                }
                }
        mDexoptStatus = dexoptResult.getFinalStatus();
        if (mDexoptStatus != DexoptResult.DEXOPT_PERFORMED) {
            return;
            }
            }
            if (!externalProfileErrors.isEmpty()) {
                addWarning("Error occurred during dexopt when processing external profiles:\n  "
                        + String.join("\n  ", externalProfileErrors));
            }
        }

        // Report dexopt metrics.
        if (mPackageMetrics != null) {
            mDexoptStatus = dexoptResult.getFinalStatus();
            if (mDexoptStatus == DexoptResult.DEXOPT_PERFORMED) {
                long durationMillis = 0;
                long durationMillis = 0;
        for (DexoptResult.PackageDexoptResult packageResult :
                for (PackageDexoptResult packageResult : dexoptResult.getPackageDexoptResults()) {
                dexoptResult.getPackageDexoptResults()) {
                    for (DexContainerFileDexoptResult fileResult :
            for (DexoptResult.DexContainerFileDexoptResult fileResult :
                            packageResult.getDexContainerFileDexoptResults()) {
                            packageResult.getDexContainerFileDexoptResults()) {
                        durationMillis += fileResult.getDex2oatWallTimeMillis();
                        durationMillis += fileResult.getDex2oatWallTimeMillis();
                    }
                    }
                }
                }
                mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis);
                mPackageMetrics.onStepFinished(PackageMetrics.STEP_DEXOPT, durationMillis);
            }
            }
        }
    }


    public void onInstallCompleted() {
    public void onInstallCompleted() {
        if (getReturnCode() == INSTALL_SUCCEEDED) {
        if (getReturnCode() == INSTALL_SUCCEEDED) {
+4 −0
Original line number Original line Diff line number Diff line
@@ -5138,6 +5138,10 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
            if (!TextUtils.isEmpty(existing)) {
            if (!TextUtils.isEmpty(existing)) {
                fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
                fillIn.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, existing);
            }
            }
            ArrayList<String> warnings = extras.getStringArrayList(PackageInstaller.EXTRA_WARNINGS);
            if (!ArrayUtils.isEmpty(warnings)) {
                fillIn.putStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS, warnings);
            }
        }
        }
        try {
        try {
            final BroadcastOptions options = BroadcastOptions.makeBasic();
            final BroadcastOptions options = BroadcastOptions.makeBasic();
+3 −0
Original line number Original line Diff line number Diff line
@@ -1433,6 +1433,9 @@ public class PackageManagerService implements PackageSender, TestUtilityService
                break;
                break;
            }
            }
        }
        }
        if (!request.getWarnings().isEmpty()) {
            extras.putStringArrayList(PackageInstaller.EXTRA_WARNINGS, request.getWarnings());
        }
        return extras;
        return extras;
    }
    }


+14 −3
Original line number Original line Diff line number Diff line
@@ -4397,10 +4397,21 @@ class PackageManagerShellCommand extends ShellCommand {
            session.commit(receiver.getIntentSender());
            session.commit(receiver.getIntentSender());
            if (!session.isStaged()) {
            if (!session.isStaged()) {
                final Intent result = receiver.getResult();
                final Intent result = receiver.getResult();
                final int status = result.getIntExtra(PackageInstaller.EXTRA_STATUS,
                int status = result.getIntExtra(
                        PackageInstaller.STATUS_FAILURE);
                        PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);
                List<String> warnings =
                        result.getStringArrayListExtra(PackageInstaller.EXTRA_WARNINGS);
                if (status == PackageInstaller.STATUS_SUCCESS) {
                if (status == PackageInstaller.STATUS_SUCCESS) {
                    if (logSuccess) {
                    if (!ArrayUtils.isEmpty(warnings)) {
                        // Don't start the output string with "Success" because that will make adb
                        // treat this as a success.
                        for (String warning : warnings) {
                            pw.println("Warning: " + warning);
                        }
                        // Treat warnings as failure to draw app developers' attention.
                        status = PackageInstaller.STATUS_FAILURE;
                        pw.println("Completed with warning(s)");
                    } else if (logSuccess) {
                        pw.println("Success");
                        pw.println("Success");
                    }
                    }
                } else {
                } else {