Loading core/java/android/os/Environment.java +14 −1 Original line number Diff line number Diff line Loading @@ -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"; Loading @@ -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; Loading Loading @@ -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 Loading services/core/java/com/android/server/pm/ApexManager.java +74 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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)) { Loading @@ -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(); /** Loading Loading @@ -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() { Loading Loading @@ -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() { Loading services/core/java/com/android/server/pm/PackageAbiHelperImpl.java +9 −0 Original line number Diff line number Diff line Loading @@ -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 Loading services/core/java/com/android/server/pm/PackageManagerService.java +34 −8 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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. * Loading Loading @@ -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 Loading Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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)) { Loading @@ -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. Loading Loading @@ -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)) { Loading
core/java/android/os/Environment.java +14 −1 Original line number Diff line number Diff line Loading @@ -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"; Loading @@ -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; Loading Loading @@ -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 Loading
services/core/java/com/android/server/pm/ApexManager.java +74 −5 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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)) { Loading @@ -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(); /** Loading Loading @@ -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() { Loading Loading @@ -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() { Loading
services/core/java/com/android/server/pm/PackageAbiHelperImpl.java +9 −0 Original line number Diff line number Diff line Loading @@ -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 Loading
services/core/java/com/android/server/pm/PackageManagerService.java +34 −8 Original line number Diff line number Diff line Loading @@ -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. Loading Loading @@ -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. * Loading Loading @@ -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 Loading Loading @@ -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; } Loading @@ -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); Loading Loading @@ -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 Loading Loading @@ -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)) { Loading @@ -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. Loading Loading @@ -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)) {