Loading core/java/android/content/pm/IPackageManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -854,4 +854,6 @@ interface IPackageManager { boolean isPageSizeCompatEnabled(in String packageName); String getPageSizeCompatWarningMessage(in String packageName); List<String> getAllApexDirectories(); } packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +63 −1 Original line number Diff line number Diff line Loading @@ -130,10 +130,12 @@ import com.google.android.collect.Sets; import libcore.util.HexEncoding; import java.io.BufferedReader; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; Loading Loading @@ -380,6 +382,8 @@ public class SettingsProvider extends ContentProvider { @GuardedBy("mLock") private Handler mHandler; private static final Set<String> sDeviceConfigAllowlistedNamespaces = new ArraySet<>(); // We have to call in the user manager with no lock held, private volatile UserManager mUserManager; Loading Loading @@ -2442,6 +2446,10 @@ public class SettingsProvider extends ContentProvider { if (!isRestrictedShell && hasWritePermission) { assertCallingUserDenyList(flags); } else if (hasAllowlistPermission) { Set<String> allowlistedDeviceConfigNamespaces = null; if (isRestrictedShell) { allowlistedDeviceConfigNamespaces = getAllowlistedDeviceConfigNamespaces(); } for (String flag : flags) { boolean namespaceAllowed = false; if (isRestrictedShell) { Loading @@ -2452,7 +2460,7 @@ public class SettingsProvider extends ContentProvider { } else { flagNamespace = flag; } if (WritableNamespaces.ALLOWLIST.contains(flagNamespace)) { if (allowlistedDeviceConfigNamespaces.contains(flagNamespace)) { namespaceAllowed = true; } } else { Loading Loading @@ -2513,6 +2521,60 @@ public class SettingsProvider extends ContentProvider { } } /** * Returns a Set of DeviceConfig allowlisted namespaces in which all flags can be modified * by a caller with the {@code WRITE_ALLOWLISTED_DEVICE_CONFIG} permission. * <p> * This method also supports mainline modules that introduce their own allowlisted * namespaces within the {@code etc/writable_namespaces} file under their directory. */ private Set<String> getAllowlistedDeviceConfigNamespaces() { synchronized (sDeviceConfigAllowlistedNamespaces) { if (!sDeviceConfigAllowlistedNamespaces.isEmpty()) { return sDeviceConfigAllowlistedNamespaces; } if (android.provider.flags.Flags.deviceConfigWritableNamespacesApi()) { sDeviceConfigAllowlistedNamespaces.addAll(DeviceConfig.getAdbWritableNamespaces()); } else { sDeviceConfigAllowlistedNamespaces.addAll(WritableNamespaces.ALLOWLIST); } final long identity = Binder.clearCallingIdentity(); try { List<String> apexDirectories; try { apexDirectories = mPackageManager.getAllApexDirectories(); } catch (RemoteException e) { Slog.e(LOG_TAG, "Caught a RemoteException obtaining APEX directories: ", e); return sDeviceConfigAllowlistedNamespaces; } for (int i = 0; i < apexDirectories.size(); i++) { String apexDirectory = apexDirectories.get(i); File namespaceFile = Environment.buildPath(new File(apexDirectory), "etc", "writable_namespaces"); if (namespaceFile.exists() && namespaceFile.isFile()) { try (BufferedReader reader = new BufferedReader( new FileReader(namespaceFile))) { String namespace; while ((namespace = reader.readLine()) != null) { namespace = namespace.trim(); // Support comments by ignoring any lines that start with '#'. if (!namespace.isEmpty() && !namespace.startsWith("#")) { sDeviceConfigAllowlistedNamespaces.add(namespace); } } } catch (IOException e) { Slog.e(LOG_TAG, "Caught an exception parsing file: " + namespaceFile, e); } } } } finally { Binder.restoreCallingIdentity(identity); } return sDeviceConfigAllowlistedNamespaces; } } private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk( int targetSdkVersion, String name) { // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash. Loading services/core/java/com/android/server/pm/PackageManagerService.java +14 −0 Original line number Diff line number Diff line Loading @@ -6639,6 +6639,20 @@ public class PackageManagerService implements PackageSender, TestUtilityService return agent; } @Override @NonNull public List<String> getAllApexDirectories() { PackageManagerServiceUtils.enforceSystemOrRoot( "getAllApexDirectories can only be called by system or root"); List<String> apexDirectories = new ArrayList<>(); List<ApexManager.ActiveApexInfo> apexes = mApexManager.getActiveApexInfos(); for (int i = 0; i < apexes.size(); i++) { ApexManager.ActiveApexInfo apex = apexes.get(i); apexDirectories.add(apex.apexDirectory.getAbsolutePath()); } return apexDirectories; } @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Loading Loading
core/java/android/content/pm/IPackageManager.aidl +2 −0 Original line number Diff line number Diff line Loading @@ -854,4 +854,6 @@ interface IPackageManager { boolean isPageSizeCompatEnabled(in String packageName); String getPageSizeCompatWarningMessage(in String packageName); List<String> getAllApexDirectories(); }
packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java +63 −1 Original line number Diff line number Diff line Loading @@ -130,10 +130,12 @@ import com.google.android.collect.Sets; import libcore.util.HexEncoding; import java.io.BufferedReader; import java.io.File; import java.io.FileDescriptor; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; Loading Loading @@ -380,6 +382,8 @@ public class SettingsProvider extends ContentProvider { @GuardedBy("mLock") private Handler mHandler; private static final Set<String> sDeviceConfigAllowlistedNamespaces = new ArraySet<>(); // We have to call in the user manager with no lock held, private volatile UserManager mUserManager; Loading Loading @@ -2442,6 +2446,10 @@ public class SettingsProvider extends ContentProvider { if (!isRestrictedShell && hasWritePermission) { assertCallingUserDenyList(flags); } else if (hasAllowlistPermission) { Set<String> allowlistedDeviceConfigNamespaces = null; if (isRestrictedShell) { allowlistedDeviceConfigNamespaces = getAllowlistedDeviceConfigNamespaces(); } for (String flag : flags) { boolean namespaceAllowed = false; if (isRestrictedShell) { Loading @@ -2452,7 +2460,7 @@ public class SettingsProvider extends ContentProvider { } else { flagNamespace = flag; } if (WritableNamespaces.ALLOWLIST.contains(flagNamespace)) { if (allowlistedDeviceConfigNamespaces.contains(flagNamespace)) { namespaceAllowed = true; } } else { Loading Loading @@ -2513,6 +2521,60 @@ public class SettingsProvider extends ContentProvider { } } /** * Returns a Set of DeviceConfig allowlisted namespaces in which all flags can be modified * by a caller with the {@code WRITE_ALLOWLISTED_DEVICE_CONFIG} permission. * <p> * This method also supports mainline modules that introduce their own allowlisted * namespaces within the {@code etc/writable_namespaces} file under their directory. */ private Set<String> getAllowlistedDeviceConfigNamespaces() { synchronized (sDeviceConfigAllowlistedNamespaces) { if (!sDeviceConfigAllowlistedNamespaces.isEmpty()) { return sDeviceConfigAllowlistedNamespaces; } if (android.provider.flags.Flags.deviceConfigWritableNamespacesApi()) { sDeviceConfigAllowlistedNamespaces.addAll(DeviceConfig.getAdbWritableNamespaces()); } else { sDeviceConfigAllowlistedNamespaces.addAll(WritableNamespaces.ALLOWLIST); } final long identity = Binder.clearCallingIdentity(); try { List<String> apexDirectories; try { apexDirectories = mPackageManager.getAllApexDirectories(); } catch (RemoteException e) { Slog.e(LOG_TAG, "Caught a RemoteException obtaining APEX directories: ", e); return sDeviceConfigAllowlistedNamespaces; } for (int i = 0; i < apexDirectories.size(); i++) { String apexDirectory = apexDirectories.get(i); File namespaceFile = Environment.buildPath(new File(apexDirectory), "etc", "writable_namespaces"); if (namespaceFile.exists() && namespaceFile.isFile()) { try (BufferedReader reader = new BufferedReader( new FileReader(namespaceFile))) { String namespace; while ((namespace = reader.readLine()) != null) { namespace = namespace.trim(); // Support comments by ignoring any lines that start with '#'. if (!namespace.isEmpty() && !namespace.startsWith("#")) { sDeviceConfigAllowlistedNamespaces.add(namespace); } } } catch (IOException e) { Slog.e(LOG_TAG, "Caught an exception parsing file: " + namespaceFile, e); } } } } finally { Binder.restoreCallingIdentity(identity); } return sDeviceConfigAllowlistedNamespaces; } } private static void warnOrThrowForUndesiredSecureSettingsMutationForTargetSdk( int targetSdkVersion, String name) { // If the app targets Lollipop MR1 or older SDK we warn, otherwise crash. Loading
services/core/java/com/android/server/pm/PackageManagerService.java +14 −0 Original line number Diff line number Diff line Loading @@ -6639,6 +6639,20 @@ public class PackageManagerService implements PackageSender, TestUtilityService return agent; } @Override @NonNull public List<String> getAllApexDirectories() { PackageManagerServiceUtils.enforceSystemOrRoot( "getAllApexDirectories can only be called by system or root"); List<String> apexDirectories = new ArrayList<>(); List<ApexManager.ActiveApexInfo> apexes = mApexManager.getActiveApexInfos(); for (int i = 0; i < apexes.size(); i++) { ApexManager.ActiveApexInfo apex = apexes.get(i); apexDirectories.add(apex.apexDirectory.getAbsolutePath()); } return apexDirectories; } @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { Loading