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

Commit 4fc36762 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Add support for module specified DeviceConfig namespace allowlists" into main

parents 2698fa17 a4da588e
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -854,4 +854,6 @@ interface IPackageManager {
    boolean isPageSizeCompatEnabled(in String packageName);

    String getPageSizeCompatWarningMessage(in String packageName);

    List<String> getAllApexDirectories();
}
+63 −1
Original line number Diff line number Diff line
@@ -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;
@@ -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;

@@ -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) {
@@ -2452,7 +2460,7 @@ public class SettingsProvider extends ContentProvider {
                    } else {
                        flagNamespace = flag;
                    }
                    if (WritableNamespaces.ALLOWLIST.contains(flagNamespace)) {
                    if (allowlistedDeviceConfigNamespaces.contains(flagNamespace)) {
                        namespaceAllowed = true;
                    }
                } else {
@@ -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.
+14 −0
Original line number Diff line number Diff line
@@ -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 {