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

Commit 745f948e authored by Patrick Baumann's avatar Patrick Baumann
Browse files

PackageAbiHepler no longer modifies Package

Bug: 137881067
Test: atest ScanTests
Change-Id: I060f2d1395886a9eebce703bd80149559f9c39bb
parent 6a064ada
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -22,11 +22,11 @@ import android.os.SystemProperties;
import android.text.TextUtils;
import android.util.ArraySet;

import dalvik.system.VMRuntime;

import java.util.ArrayList;
import java.util.List;

import dalvik.system.VMRuntime;

/**
 * Provides various methods for obtaining and converting of instruction sets.
 *
@@ -113,12 +113,15 @@ public class InstructionSets {
        return allInstructionSets;
    }

    public static String getPrimaryInstructionSet(ApplicationInfo info) {
        if (info.primaryCpuAbi == null) {
    /**
     * Calculates the primary instruction set based on the computed Abis of a given package.
     */
    public static String getPrimaryInstructionSet(PackageAbiHelper.Abis abis) {
        if (abis.primary == null) {
            return getPreferredInstructionSet();
        }

        return VMRuntime.getInstructionSet(info.primaryCpuAbi);
        return VMRuntime.getInstructionSet(abis.primary);
    }

}
+80 −30
Original line number Diff line number Diff line
@@ -18,56 +18,44 @@ package com.android.server.pm;

import android.annotation.Nullable;
import android.content.pm.PackageParser;
import android.util.Pair;

import com.android.internal.annotations.VisibleForTesting;

import java.io.File;
import java.util.List;
import java.util.Set;

@VisibleForTesting
interface PackageAbiHelper {
    /**
     * Derive and set the location of native libraries for the given package,
     * Derive and get the location of native libraries for the given package,
     * which varies depending on where and how the package was installed.
     *
     * WARNING: This API enables modifying of the package.
     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
     */
    void setNativeLibraryPaths(PackageParser.Package pkg, File appLib32InstallDir);
    NativeLibraryPaths getNativeLibraryPaths(
            PackageParser.Package pkg, File appLib32InstallDir);

    /**
     * Calculate the abis and roots for a bundled app. These can uniquely
     * be determined from the contents of the system partition, i.e whether
     * it contains 64 or 32 bit shared libraries etc. We do not validate any
     * of this information, and instead assume that the system was built
     * sensibly.
     *
     * WARNING: This API enables modifying of the package.
     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
     * Calculate the abis for a bundled app. These can uniquely be determined from the contents of
     * the system partition, i.e whether it contains 64 or 32 bit shared libraries etc. We do not
     * validate any of this information, and instead assume that the system was built sensibly.
     */
    void setBundledAppAbisAndRoots(PackageParser.Package pkg,
            PackageSetting pkgSetting);
    Abis getBundledAppAbis(PackageParser.Package pkg);

    /**
     * Derive the ABI of a non-system package located at {@code scanFile}. This information
     * is derived purely on the basis of the contents of {@code scanFile} and
     * {@code cpuAbiOverride}.
     * Derive the ABI of a non-system package located at {@code pkg}. This information
     * is derived purely on the basis of the contents of {@code pkg} and {@code cpuAbiOverride}.
     *
     * If {@code extractLibs} is true, native libraries are extracted from the app if required.
     *
     * WARNING: This API enables modifying of the package.
     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
     */
    void derivePackageAbi(PackageParser.Package pkg, String cpuAbiOverride,
            boolean extractLibs)
    Pair<Abis, NativeLibraryPaths> derivePackageAbi(
            PackageParser.Package pkg, String cpuAbiOverride, boolean extractLibs)
            throws PackageManagerException;

    /**
     * Adjusts ABIs for a set of packages belonging to a shared user so that they all match.
     * i.e, so that all packages can be run inside a single process if required.
     * Calculates adjusted ABIs for a set of packages belonging to a shared user so that they all
     * match. i.e, so that all packages can be run inside a single process if required.
     *
     * Optionally, callers can pass in a parsed package via {@code newPackage} in which case
     * Optionally, callers can pass in a parsed package via {@code scannedPackage} in which case
     * this function will either try and make the ABI for all packages in
     * {@code packagesForUser} match {@code scannedPackage} or will update the ABI of
     * {@code scannedPackage} to match the ABI selected for {@code packagesForUser}. This
@@ -76,10 +64,72 @@ interface PackageAbiHelper {
     * NOTE: We currently only match for the primary CPU abi string. Matching the secondary
     * adds unnecessary complexity.
     *
     * WARNING: This API enables modifying of the package.
     * TODO(b/137881067): Modify so that caller is responsible for setting pkg fields as necessary
     * @return the calculated primary abi that should be set for all non-specified packages
     *         belonging to the shared user.
     */
    @Nullable
    List<String> adjustCpuAbisForSharedUser(
    String getAdjustedAbiForSharedUser(
            Set<PackageSetting> packagesForUser, PackageParser.Package scannedPackage);

    /**
     * The native library paths and related properties that should be set on a
     * {@link android.content.pm.PackageParser.Package}.
     */
    final class NativeLibraryPaths {
        public final String nativeLibraryRootDir;
        public final boolean nativeLibraryRootRequiresIsa;
        public final String nativeLibraryDir;
        public final String secondaryNativeLibraryDir;

        @VisibleForTesting
        NativeLibraryPaths(String nativeLibraryRootDir,
                boolean nativeLibraryRootRequiresIsa, String nativeLibraryDir,
                String secondaryNativeLibraryDir) {
            this.nativeLibraryRootDir = nativeLibraryRootDir;
            this.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
            this.nativeLibraryDir = nativeLibraryDir;
            this.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
        }

        public void applyTo(PackageParser.Package pkg) {
            pkg.applicationInfo.nativeLibraryRootDir = nativeLibraryRootDir;
            pkg.applicationInfo.nativeLibraryRootRequiresIsa = nativeLibraryRootRequiresIsa;
            pkg.applicationInfo.nativeLibraryDir = nativeLibraryDir;
            pkg.applicationInfo.secondaryNativeLibraryDir = secondaryNativeLibraryDir;
        }
    }

    /**
     * The primary and secondary ABIs that should be set on a package and its package setting.
     */
    final class Abis {
        public final String primary;
        public final String secondary;

        @VisibleForTesting
        Abis(String primary, String secondary) {
            this.primary = primary;
            this.secondary = secondary;
        }

        Abis(PackageParser.Package pkg) {
            this(pkg.applicationInfo.primaryCpuAbi, pkg.applicationInfo.secondaryCpuAbi);
        }

        public void applyTo(PackageParser.Package pkg) {
            pkg.applicationInfo.primaryCpuAbi = primary;
            pkg.applicationInfo.secondaryCpuAbi = secondary;
        }
        public void applyTo(PackageSetting pkgSetting) {
            // pkgSetting might be null during rescan following uninstall of updates
            // to a bundled app, so accommodate that possibility.  The settings in
            // that case will be established later from the parsed package.
            //
            // If the settings aren't null, sync them up with what we've derived.
            if (pkgSetting != null) {
                pkgSetting.primaryCpuAbiString = primary;
                pkgSetting.secondaryCpuAbiString = secondary;
            }
        }
    }
}
+184 −198

File changed.

Preview size limit exceeded, changes collapsed.

+72 −10
Original line number Diff line number Diff line
@@ -3082,8 +3082,9 @@ public class PackageManagerService extends IPackageManager.Stub
                // the rest of the commands above) because there's precious little we
                // can do about it. A settings error is reported, though.
                final List<String> changedAbiCodePath =
                        mInjector.getAbiHelper().adjustCpuAbisForSharedUser(
                                setting.packages, null /*scannedPackage*/);
                        applyAdjustedAbiToSharedUser(setting, null /*scannedPackage*/,
                        mInjector.getAbiHelper().getAdjustedAbiForSharedUser(
                                setting.packages, null /*scannedPackage*/));
                if (changedAbiCodePath != null && changedAbiCodePath.size() > 0) {
                    for (int i = changedAbiCodePath.size() - 1; i >= 0; --i) {
                        final String codePathString = changedAbiCodePath.get(i);
@@ -10641,6 +10642,50 @@ public class PackageManagerService extends IPackageManager.Stub
        pkg.setPackageName(renamedPackageName);
    }
    /**
     * Applies the adjusted ABI calculated by
     * {@link PackageAbiHelper#getAdjustedAbiForSharedUser(Set, PackageParser.Package)} to all
     * relevant packages and settings.
     * @param sharedUserSetting The {@code SharedUserSetting} to adjust
     * @param scannedPackage the package being scanned or null
     * @param adjustedAbi the adjusted ABI calculated by {@link PackageAbiHelper}
     * @return the list of code paths that belong to packages that had their ABIs adjusted.
     */
    private static List<String> applyAdjustedAbiToSharedUser(SharedUserSetting sharedUserSetting,
            PackageParser.Package scannedPackage, String adjustedAbi) {
        if (scannedPackage != null)  {
            scannedPackage.applicationInfo.primaryCpuAbi = adjustedAbi;
        }
        List<String> changedAbiCodePath = null;
        for (PackageSetting ps : sharedUserSetting.packages) {
            if (scannedPackage == null || !scannedPackage.packageName.equals(ps.name)) {
                if (ps.primaryCpuAbiString != null) {
                    continue;
                }
                ps.primaryCpuAbiString = adjustedAbi;
                if (ps.pkg != null && ps.pkg.applicationInfo != null
                        && !TextUtils.equals(
                        adjustedAbi, ps.pkg.applicationInfo.primaryCpuAbi)) {
                    ps.pkg.applicationInfo.primaryCpuAbi = adjustedAbi;
                    if (DEBUG_ABI_SELECTION) {
                        Slog.i(TAG,
                                "Adjusting ABI for " + ps.name + " to " + adjustedAbi
                                        + " (scannedPackage="
                                        + (scannedPackage != null ? scannedPackage : "null")
                                        + ")");
                    }
                    if (changedAbiCodePath == null) {
                        changedAbiCodePath = new ArrayList<>();
                    }
                    changedAbiCodePath.add(ps.codePathString);
                }
            }
        }
        return changedAbiCodePath;
    }
    /**
     * Just scans the package without any side effects.
     * <p>Not entirely true at the moment. There is still one side effect -- this
@@ -10813,7 +10858,10 @@ public class PackageManagerService extends IPackageManager.Stub
            if (needToDeriveAbi) {
                Trace.traceBegin(TRACE_TAG_PACKAGE_MANAGER, "derivePackageAbi");
                final boolean extractNativeLibs = !pkg.isLibrary();
                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths> derivedAbi =
                        packageAbiHelper.derivePackageAbi(pkg, cpuAbiOverride, extractNativeLibs);
                derivedAbi.first.applyTo(pkg);
                derivedAbi.second.applyTo(pkg);
                Trace.traceEnd(TRACE_TAG_PACKAGE_MANAGER);
                // Some system apps still use directory structure for native libraries
@@ -10821,8 +10869,13 @@ public class PackageManagerService extends IPackageManager.Stub
                // structure. Try to detect abi based on directory structure.
                if (isSystemApp(pkg) && !pkg.isUpdatedSystemApp() &&
                        pkg.applicationInfo.primaryCpuAbi == null) {
                    packageAbiHelper.setBundledAppAbisAndRoots(pkg, pkgSetting);
                    packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
                    final PackageAbiHelper.Abis abis = packageAbiHelper.getBundledAppAbis(
                            pkg);
                    abis.applyTo(pkg);
                    abis.applyTo(pkgSetting);
                    final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                            packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
                    nativeLibraryPaths.applyTo(pkg);
                }
            } else {
                // This is not a first boot or an upgrade, don't bother deriving the
@@ -10831,7 +10884,9 @@ public class PackageManagerService extends IPackageManager.Stub
                pkg.applicationInfo.primaryCpuAbi = primaryCpuAbiFromSettings;
                pkg.applicationInfo.secondaryCpuAbi = secondaryCpuAbiFromSettings;
                packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
                final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                        packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
                nativeLibraryPaths.applyTo(pkg);
                if (DEBUG_ABI_SELECTION) {
                    Slog.i(TAG, "Using ABIS and native lib paths from settings : " +
@@ -10852,7 +10907,9 @@ public class PackageManagerService extends IPackageManager.Stub
            // ABIs we've determined above. For non-moves, the path will be updated based on the
            // ABIs we determined during compilation, but the path will depend on the final
            // package path (after the rename away from the stage path).
            packageAbiHelper.setNativeLibraryPaths(pkg, sAppLib32InstallDir);
            final PackageAbiHelper.NativeLibraryPaths nativeLibraryPaths =
                    packageAbiHelper.getNativeLibraryPaths(pkg, sAppLib32InstallDir);
            nativeLibraryPaths.applyTo(pkg);
        }
        // This is a special case for the "system" package, where the ABI is
@@ -10906,8 +10963,9 @@ public class PackageManagerService extends IPackageManager.Stub
            // We also do this *before* we perform dexopt on this package, so that
            // we can avoid redundant dexopts, and also to make sure we've got the
            // code and package path correct.
            changedAbiCodePath = packageAbiHelper.adjustCpuAbisForSharedUser(
                            pkgSetting.sharedUser.packages, pkg);
            changedAbiCodePath = applyAdjustedAbiToSharedUser(pkgSetting.sharedUser, pkg,
                    packageAbiHelper.getAdjustedAbiForSharedUser(
                            pkgSetting.sharedUser.packages, pkg));
        }
        if (isUnderFactoryTest && pkg.requestedPermissions.contains(
@@ -16506,7 +16564,11 @@ public class PackageManagerService extends IPackageManager.Stub
                String abiOverride = (TextUtils.isEmpty(pkg.cpuAbiOverride) ?
                        args.abiOverride : pkg.cpuAbiOverride);
                final boolean extractNativeLibs = !pkg.isLibrary();
                mInjector.getAbiHelper().derivePackageAbi(pkg, abiOverride, extractNativeLibs);
                final Pair<PackageAbiHelper.Abis, PackageAbiHelper.NativeLibraryPaths>
                        derivedAbi = mInjector.getAbiHelper().derivePackageAbi(
                                pkg, abiOverride, extractNativeLibs);
                derivedAbi.first.applyTo(pkg);
                derivedAbi.second.applyTo(pkg);
            } catch (PackageManagerException pme) {
                Slog.e(TAG, "Error deriving application ABI", pme);
                throw new PrepareFailure(INSTALL_FAILED_INTERNAL_ERROR,
+49 −18
Original line number Diff line number Diff line
@@ -34,9 +34,7 @@ import static org.hamcrest.core.Is.is;
import static org.junit.Assert.assertNotSame;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyBoolean;
import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.ArgumentMatchers.nullable;
import static org.mockito.Mockito.when;

import android.Manifest;
@@ -48,6 +46,7 @@ import android.os.Environment;
import android.os.UserHandle;
import android.os.UserManagerInternal;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;

import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
@@ -62,6 +61,7 @@ import java.io.File;

@RunWith(MockitoJUnitRunner.class)
@Presubmit
// TODO: shared user tests
public class ScanTests {

    private static final String DUMMY_PACKAGE_NAME = "some.app.to.test";
@@ -76,6 +76,24 @@ public class ScanTests {
        when(mMockUserManager.getUserIds()).thenReturn(new int[]{0});
    }

    @Before
    public void setupDefaultAbiBehavior() throws Exception {
        when(mMockPackageAbiHelper.derivePackageAbi(
                any(PackageParser.Package.class), nullable(String.class), anyBoolean()))
                .thenReturn(new Pair<>(
                        new PackageAbiHelper.Abis("derivedPrimary", "derivedSecondary"),
                        new PackageAbiHelper.NativeLibraryPaths(
                                "derivedRootDir", true, "derivedNativeDir", "derivedNativeDir2")));
        when(mMockPackageAbiHelper.getNativeLibraryPaths(
                any(PackageParser.Package.class), any(File.class)))
                .thenReturn(new PackageAbiHelper.NativeLibraryPaths(
                        "getRootDir", true, "getNativeDir", "getNativeDir2"
                ));
        when(mMockPackageAbiHelper.getBundledAppAbis(
                any(PackageParser.Package.class)))
                .thenReturn(new PackageAbiHelper.Abis("bundledPrimary", "bundledSecondary"));
    }

    @Test
    public void newInstallSimpleAllNominal() throws Exception {
        final PackageManagerService.ScanRequest scanRequest =
@@ -84,15 +102,11 @@ public class ScanTests {
                        .addScanFlag(PackageManagerService.SCAN_AS_FULL_APP)
                        .build();


        final PackageManagerService.ScanResult scanResult = executeScan(scanRequest);

        assertBasicPackageScanResult(scanResult, DUMMY_PACKAGE_NAME, false /*isInstant*/);
        assertThat(scanResult.existingSettingCopied, is(false));
        verify(mMockPackageAbiHelper, never()).derivePackageAbi(any(PackageParser.Package.class),
                anyString() /*abioverride*/, anyBoolean() /*extractNativeLibs*/);
        verify(mMockPackageAbiHelper).setNativeLibraryPaths(
                scanResult.pkgSetting.pkg, PackageManagerService.sAppLib32InstallDir);
        assertPathsNotDerived(scanResult);
    }

    @Test
@@ -162,10 +176,7 @@ public class ScanTests {
        assertThat(scanResult.pkgSetting.secondaryCpuAbiString, is("secondaryCpuAbi"));
        assertThat(scanResult.pkgSetting.cpuAbiOverrideString, nullValue());

        verify(mMockPackageAbiHelper, never()).derivePackageAbi(any(PackageParser.Package.class),
                anyString() /*abioverride*/, anyBoolean() /*extractNativeLibs*/);
        verify(mMockPackageAbiHelper).setNativeLibraryPaths(
                scanResult.pkgSetting.pkg, PackageManagerService.sAppLib32InstallDir);
        assertPathsNotDerived(scanResult);
    }

    @Test
@@ -293,12 +304,13 @@ public class ScanTests {
                        .build();


        executeScan(new ScanRequestBuilder(basicPackage)
        final PackageManagerService.ScanResult scanResult = executeScan(new ScanRequestBuilder(
                basicPackage)
                .setPkgSetting(pkgSetting)
                .addScanFlag(SCAN_FIRST_BOOT_OR_UPGRADE)
                .build());

        verify(mMockPackageAbiHelper).derivePackageAbi(basicPackage, "testOverride", true);
        assertAbiAndPathssDerived(scanResult);
    }

    @Test
@@ -484,7 +496,7 @@ public class ScanTests {
        assertBasicPackageSetting(scanResult, packageName, isInstant, pkgSetting);

        final ApplicationInfo applicationInfo = pkgSetting.pkg.applicationInfo;
        verifyBasicApplicationInfo(scanResult, applicationInfo);
        assertBasicApplicationInfo(scanResult, applicationInfo);

    }

@@ -497,14 +509,12 @@ public class ScanTests {
        assertThat(pkgSetting.usesStaticLibrariesVersions, is(new long[]{234L, 456L}));
        assertThat(pkgSetting.pkg, is(scanResult.request.pkg));
        assertThat(pkgSetting.pkg.mExtras, is(pkgSetting));
        assertThat(pkgSetting.legacyNativeLibraryPathString,
                is("/data/tmp/randompath/base.apk:/lib"));
        assertThat(pkgSetting.codePath, is(new File(createCodePath(packageName))));
        assertThat(pkgSetting.resourcePath, is(new File(createResourcePath(packageName))));
        assertThat(pkgSetting.versionCode, is(PackageInfo.composeLongVersionCode(1, 2345)));
    }

    private static void verifyBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
    private static void assertBasicApplicationInfo(PackageManagerService.ScanResult scanResult,
            ApplicationInfo applicationInfo) {
        assertThat(applicationInfo.processName, is(scanResult.request.pkg.packageName));

@@ -517,4 +527,25 @@ public class ScanTests {
        assertThat(applicationInfo.credentialProtectedDataDir, is(calculatedCredentialId));
        assertThat(applicationInfo.dataDir, is(applicationInfo.credentialProtectedDataDir));
    }

    private static void assertAbiAndPathssDerived(PackageManagerService.ScanResult scanResult) {
        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
        assertThat(applicationInfo.primaryCpuAbi, is("derivedPrimary"));
        assertThat(applicationInfo.secondaryCpuAbi, is("derivedSecondary"));

        assertThat(applicationInfo.nativeLibraryRootDir, is("derivedRootDir"));
        assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("derivedRootDir"));
        assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
        assertThat(applicationInfo.nativeLibraryDir, is("derivedNativeDir"));
        assertThat(applicationInfo.secondaryNativeLibraryDir, is("derivedNativeDir2"));
    }

    private static void assertPathsNotDerived(PackageManagerService.ScanResult scanResult) {
        final ApplicationInfo applicationInfo = scanResult.pkgSetting.pkg.applicationInfo;
        assertThat(applicationInfo.nativeLibraryRootDir, is("getRootDir"));
        assertThat(scanResult.pkgSetting.legacyNativeLibraryPathString, is("getRootDir"));
        assertThat(applicationInfo.nativeLibraryRootRequiresIsa, is(true));
        assertThat(applicationInfo.nativeLibraryDir, is("getNativeDir"));
        assertThat(applicationInfo.secondaryNativeLibraryDir, is("getNativeDir2"));
    }
}