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

Commit 5a89f1a0 authored by Dario Freni's avatar Dario Freni Committed by Android (Google) Code Review
Browse files

Merge "Support non-privileged APKs in APEX."

parents f6be0e7f c3e1bb72
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -55,6 +55,7 @@ public class Environment {
    private static final String ENV_VENDOR_ROOT = "VENDOR_ROOT";
    private static final String ENV_PRODUCT_ROOT = "PRODUCT_ROOT";
    private static final String ENV_SYSTEM_EXT_ROOT = "SYSTEM_EXT_ROOT";
    private static final String ENV_APEX_ROOT = "APEX_ROOT";

    /** {@hide} */
    public static final String DIR_ANDROID = "Android";
@@ -79,6 +80,8 @@ public class Environment {
    private static final File DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, "/product");
    private static final File DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT,
            "/system_ext");
    private static final File DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT,
            "/apex");

    @UnsupportedAppUsage
    private static UserEnvironment sCurrentUser;
@@ -247,6 +250,16 @@ public class Environment {
        return DIR_SYSTEM_EXT_ROOT;
    }

    /**
     * Return root directory of the apex mount point, where all the apex modules are made available
     * to the rest of the system.
     *
     * @hide
     */
    public static @NonNull File getApexDirectory() {
        return DIR_APEX_ROOT;
    }

    /**
     * Return the system directory for a user. This is for use by system
     * services to store files relating to the user. This directory will be
+74 −5
Original line number Diff line number Diff line
@@ -32,6 +32,7 @@ import android.content.pm.PackageInfo;
import android.content.pm.PackageInstaller;
import android.content.pm.PackageManager;
import android.content.pm.PackageParser;
import android.os.Environment;
import android.os.RemoteException;
import android.os.ServiceManager;
import android.sysprop.ApexProperties;
@@ -47,6 +48,7 @@ import java.io.PrintWriter;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
@@ -64,9 +66,9 @@ abstract class ApexManager {
    static final int MATCH_FACTORY_PACKAGE = 1 << 1;

    /**
     * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerNoOp} depending
     * on whenever this device supports APEX, i.e. {@link ApexProperties#updatable()} evaluates to
     * {@code true}.
     * Returns an instance of either {@link ApexManagerImpl} or {@link ApexManagerFlattenedApex}
     * depending on whether this device supports APEX, i.e. {@link ApexProperties#updatable()}
     * evaluates to {@code true}.
     */
    static ApexManager create(Context systemContext) {
        if (ApexProperties.updatable().orElse(false)) {
@@ -77,10 +79,28 @@ abstract class ApexManager {
                throw new IllegalStateException("Required service apexservice not available");
            }
        } else {
            return new ApexManagerNoOp();
            return new ApexManagerFlattenedApex();
        }
    }

    /**
     * Minimal information about APEX mount points and the original APEX package they refer to.
     */
    static class ActiveApexInfo {
        public final File apexDirectory;
        public final File preinstalledApexPath;

        private ActiveApexInfo(File apexDirectory, File preinstalledApexPath) {
            this.apexDirectory = apexDirectory;
            this.preinstalledApexPath = preinstalledApexPath;
        }
    }

    /**
     * Returns {@link ActiveApexInfo} records relative to all active APEX packages.
     */
    abstract List<ActiveApexInfo> getActiveApexInfos();

    abstract void systemReady();

    /**
@@ -258,6 +278,22 @@ abstract class ApexManager {
            return (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;
        }

        @Override
        List<ActiveApexInfo> getActiveApexInfos() {
            try {
                return Arrays.stream(mApexService.getActivePackages())
                        .map(apexInfo -> new ActiveApexInfo(
                                new File(
                                Environment.getApexDirectory() + File.separator
                                        + apexInfo.moduleName),
                                new File(apexInfo.modulePath))).collect(
                                Collectors.toList());
            } catch (RemoteException e) {
                Slog.e(TAG, "Unable to retrieve packages from apexservice", e);
            }
            return Collections.emptyList();
        }

        @Override
        void systemReady() {
            mContext.registerReceiver(new BroadcastReceiver() {
@@ -549,7 +585,40 @@ abstract class ApexManager {
     * An implementation of {@link ApexManager} that should be used in case device does not support
     * updating APEX packages.
     */
    private static final class ApexManagerNoOp extends ApexManager {
    private static final class ApexManagerFlattenedApex extends ApexManager {

        @Override
        List<ActiveApexInfo> getActiveApexInfos() {
            // There is no apexd running in case of flattened apex
            // We look up the /apex directory and identify the active APEX modules from there.
            // As "preinstalled" path, we just report /system since in the case of flattened APEX
            // the /apex directory is just a symlink to /system/apex.
            List<ActiveApexInfo> result = new ArrayList<>();
            File apexDir = Environment.getApexDirectory();
            // In flattened configuration, init special-case the art directory and bind-mounts
            // com.android.art.{release|debug} to com.android.art. At the time of writing, these
            // directories are copied from the kArtApexDirNames variable in
            // system/core/init/mount_namespace.cpp.
            String[] skipDirs = {"com.android.art.release", "com.android.art.debug"};
            if (apexDir.isDirectory()) {
                File[] files = apexDir.listFiles();
                // listFiles might be null if system server doesn't have permission to read
                // a directory.
                if (files != null) {
                    for (File file : files) {
                        if (file.isDirectory() && !file.getName().contains("@")) {
                            for (String skipDir : skipDirs) {
                                if (file.getName().equals(skipDir)) {
                                    continue;
                                }
                            }
                            result.add(new ActiveApexInfo(file, Environment.getRootDirectory()));
                        }
                    }
                }
            }
            return result;
        }

        @Override
        void systemReady() {
+9 −0
Original line number Diff line number Diff line
@@ -67,6 +67,15 @@ final class PackageAbiHelperImpl implements PackageAbiHelper {
            codeRoot = Environment.getSystemExtDirectory();
        } else if (FileUtils.contains(Environment.getOdmDirectory(), codePath)) {
            codeRoot = Environment.getOdmDirectory();
        } else if (FileUtils.contains(Environment.getApexDirectory(), codePath)) {
            String fullPath = codePath.getAbsolutePath();
            String[] parts = fullPath.split(File.separator);
            if (parts.length > 2) {
                codeRoot = new File(parts[1] + File.separator + parts[2]);
            } else {
                Slog.w(PackageManagerService.TAG, "Can't canonicalize code path " + codePath);
                codeRoot = Environment.getApexDirectory();
            }
        } else {
            // Unrecognized code path; take its top real segment as the apk root:
            // e.g. /something/app/blah.apk => /something
+34 −8
Original line number Diff line number Diff line
@@ -370,6 +370,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.stream.Collectors;
/**
 * Keep track of all those APKs everywhere.
@@ -762,6 +763,8 @@ public class PackageManagerService extends IPackageManager.Stub
                    new SystemPartition(Environment.getSystemExtDirectory(), SCAN_AS_SYSTEM_EXT,
                            true /* hasPriv */, true /* hasOverlays */)));
    private final List<SystemPartition> mDirsToScanAsSystem;
    /**
     * Unit tests will instantiate, extend and/or mock to mock dependencies / behaviors.
     *
@@ -2552,6 +2555,16 @@ public class PackageManagerService extends IPackageManager.Stub
        mApexManager = ApexManager.create(mContext);
        mAppsFilter = mInjector.getAppsFilter();
        mDirsToScanAsSystem = new ArrayList<>();
        mDirsToScanAsSystem.addAll(SYSTEM_PARTITIONS);
        mDirsToScanAsSystem.addAll(mApexManager.getActiveApexInfos().stream()
                .map(ai -> resolveApexToSystemPartition(ai))
                .filter(Objects::nonNull).collect(Collectors.toList()));
        Slog.d(TAG,
                "Directories scanned as system partitions: [" + mDirsToScanAsSystem.stream().map(
                        d -> (d.folder.getAbsolutePath() + ":" + d.scanFlag))
                        .collect(Collectors.joining(",")) + "]");
        // CHECKSTYLE:OFF IndentationCheck
        synchronized (mInstallLock) {
        // writer
@@ -2684,8 +2697,8 @@ public class PackageManagerService extends IPackageManager.Stub
            // reside in the right directory.
            final int systemParseFlags = mDefParseFlags | PackageParser.PARSE_IS_SYSTEM_DIR;
            final int systemScanFlags = scanFlags | SCAN_AS_SYSTEM;
            for (int i = SYSTEM_PARTITIONS.size() - 1; i >= 0; i--) {
                final SystemPartition partition = SYSTEM_PARTITIONS.get(i);
            for (int i = mDirsToScanAsSystem.size() - 1; i >= 0; i--) {
                final SystemPartition partition = mDirsToScanAsSystem.get(i);
                if (partition.overlayFolder == null) {
                    continue;
                }
@@ -2699,8 +2712,8 @@ public class PackageManagerService extends IPackageManager.Stub
                throw new IllegalStateException(
                        "Failed to load frameworks package; check log for warnings");
            }
            for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
                final SystemPartition partition = SYSTEM_PARTITIONS.get(i);
            for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
                final SystemPartition partition = mDirsToScanAsSystem.get(i);
                if (partition.privAppFolder != null) {
                    scanDirTracedLI(partition.privAppFolder, systemParseFlags,
                            systemScanFlags | SCAN_AS_PRIVILEGED | partition.scanFlag, 0);
@@ -2878,8 +2891,8 @@ public class PackageManagerService extends IPackageManager.Stub
                        @ParseFlags int reparseFlags = 0;
                        @ScanFlags int rescanFlags = 0;
                        for (int i1 = 0, size = SYSTEM_PARTITIONS.size(); i1 < size; i1++) {
                            SystemPartition partition = SYSTEM_PARTITIONS.get(i1);
                        for (int i1 = 0, size = mDirsToScanAsSystem.size(); i1 < size; i1++) {
                            SystemPartition partition = mDirsToScanAsSystem.get(i1);
                            if (partition.containsPrivApp(scanFile)) {
                                reparseFlags = systemParseFlags;
                                rescanFlags = systemScanFlags | SCAN_AS_PRIVILEGED
@@ -17778,6 +17791,7 @@ public class PackageManagerService extends IPackageManager.Stub
    }
    static boolean locationIsPrivileged(String path) {
        // TODO(dariofreni): include APEX partitions when they will support priv apps.
        for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
            SystemPartition partition = SYSTEM_PARTITIONS.get(i);
            if (partition.containsPrivPath(path)) {
@@ -17787,6 +17801,18 @@ public class PackageManagerService extends IPackageManager.Stub
        return false;
    }
    private static @Nullable SystemPartition resolveApexToSystemPartition(
            ApexManager.ActiveApexInfo apexInfo) {
        for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
            SystemPartition sp = SYSTEM_PARTITIONS.get(i);
            if (apexInfo.preinstalledApexPath.getAbsolutePath().startsWith(
                    sp.folder.getAbsolutePath())) {
                return new SystemPartition(apexInfo.apexDirectory, sp.scanFlag,
                        false /* hasPriv */, false /* hasOverlays */);
            }
        }
        return null;
    }
    /*
     * Tries to delete system package.
@@ -17897,8 +17923,8 @@ public class PackageManagerService extends IPackageManager.Stub
                | PackageParser.PARSE_MUST_BE_APK
                | PackageParser.PARSE_IS_SYSTEM_DIR;
        @ScanFlags int scanFlags = SCAN_AS_SYSTEM;
        for (int i = 0, size = SYSTEM_PARTITIONS.size(); i < size; i++) {
            SystemPartition partition = SYSTEM_PARTITIONS.get(i);
        for (int i = 0, size = mDirsToScanAsSystem.size(); i < size; i++) {
            SystemPartition partition = mDirsToScanAsSystem.get(i);
            if (partition.containsPath(codePathString)) {
                scanFlags |= partition.scanFlag;
                if (partition.containsPrivPath(codePathString)) {