Apply signed config on package upgrade/install.

Signature check is not implemented yet, so no configuration can be
applied yet.

Tested with CTS test & follow up changes in later CLs.

For future reference:
Test: atest CtsSignedConfigHostTestCases

Bug: 110509075
Change-Id: I2d2f15d38ec0f1755e21e6e5ab5c82d94aa592a4
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 64aa088..19b12b2 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -12821,6 +12821,13 @@
         public static final String HIDDEN_API_POLICY = "hidden_api_policy";
 
         /**
+         * Current version of signed configuration applied.
+         *
+         * @hide
+         */
+        public static final String SIGNED_CONFIG_VERSION = "signed_config_version";
+
+        /**
          * Timeout for a single {@link android.media.soundtrigger.SoundTriggerDetectionService}
          * operation (in ms).
          *
diff --git a/core/tests/coretests/src/android/provider/SettingsBackupTest.java b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
index f1ed1c2..69bc4a2 100644
--- a/core/tests/coretests/src/android/provider/SettingsBackupTest.java
+++ b/core/tests/coretests/src/android/provider/SettingsBackupTest.java
@@ -414,6 +414,7 @@
                     Settings.Global.SHOW_NOTIFICATION_CHANNEL_WARNINGS,
                     Settings.Global.SHOW_RESTART_IN_CRASH_DIALOG,
                     Settings.Global.SHOW_TEMPERATURE_WARNING,
+                    Settings.Global.SIGNED_CONFIG_VERSION,
                     Settings.Global.SMART_SELECTION_UPDATE_CONTENT_URL,
                     Settings.Global.SMART_SELECTION_UPDATE_METADATA_URL,
                     Settings.Global.SMS_ACCESS_RESTRICTION_ENABLED,
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java b/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java
index 7ce071f..2312f5f 100644
--- a/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigApplicator.java
@@ -17,12 +17,86 @@
 package com.android.server.signedconfig;
 
 import android.content.Context;
+import android.os.Build;
+import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.Slog;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Map;
+import java.util.Set;
 
 class SignedConfigApplicator {
 
-    static void applyConfig(Context context, String config, String signature) {
-        //TODO verify signature
-        //TODO parse & apply config
+    private static final String TAG = "SignedConfig";
+
+    private static final Set<String> ALLOWED_KEYS = Collections.unmodifiableSet(new ArraySet<>(
+            Arrays.asList(
+                    Settings.Global.HIDDEN_API_POLICY,
+                    Settings.Global.HIDDEN_API_BLACKLIST_EXEMPTIONS
+            )));
+
+    private final Context mContext;
+    private final String mSourcePackage;
+
+    SignedConfigApplicator(Context context, String sourcePackage) {
+        mContext = context;
+        mSourcePackage = sourcePackage;
     }
 
+    private boolean checkSignature(String data, String signature) {
+        Slog.w(TAG, "SIGNATURE CHECK NOT IMPLEMENTED YET!");
+        return false;
+    }
+
+    private int getCurrentConfigVersion() {
+        return Settings.Global.getInt(mContext.getContentResolver(),
+                Settings.Global.SIGNED_CONFIG_VERSION, 0);
+    }
+
+    private void updateCurrentConfig(int version, Map<String, String> values) {
+        for (Map.Entry<String, String> e: values.entrySet()) {
+            Settings.Global.putString(
+                    mContext.getContentResolver(),
+                    e.getKey(),
+                    e.getValue());
+        }
+        Settings.Global.putInt(
+                mContext.getContentResolver(), Settings.Global.SIGNED_CONFIG_VERSION, version);
+    }
+
+
+    void applyConfig(String configStr, String signature) {
+        if (!checkSignature(configStr, signature)) {
+            Slog.e(TAG, "Signature check on signed configuration in package " + mSourcePackage
+                    + " failed; ignoring");
+            return;
+        }
+        SignedConfig config;
+        try {
+            config = SignedConfig.parse(configStr, ALLOWED_KEYS);
+        } catch (InvalidConfigException e) {
+            Slog.e(TAG, "Failed to parse config from package " + mSourcePackage, e);
+            return;
+        }
+        int currentVersion = getCurrentConfigVersion();
+        if (currentVersion >= config.version) {
+            Slog.i(TAG, "Config from package " + mSourcePackage + " is older than existing: "
+                    + config.version + "<=" + currentVersion);
+            return;
+        }
+        // We have new config!
+        Slog.i(TAG, "Got new signed config from package " + mSourcePackage + ": version "
+                + config.version + " replacing existing version " + currentVersion);
+        SignedConfig.PerSdkConfig matchedConfig =
+                config.getMatchingConfig(Build.VERSION.SDK_INT);
+        if (matchedConfig == null) {
+            Slog.i(TAG, "Config is not applicable to current SDK version; ignoring");
+            return;
+        }
+
+        Slog.i(TAG, "Updating signed config to version " + config.version);
+        updateCurrentConfig(config.version, matchedConfig.values);
+    }
 }
diff --git a/services/core/java/com/android/server/signedconfig/SignedConfigService.java b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
index 1485686..be1d41d 100644
--- a/services/core/java/com/android/server/signedconfig/SignedConfigService.java
+++ b/services/core/java/com/android/server/signedconfig/SignedConfigService.java
@@ -85,7 +85,8 @@
                 Slog.d(TAG, "Got signed config: " + config);
                 Slog.d(TAG, "Got config signature: " + signature);
             }
-            SignedConfigApplicator.applyConfig(mContext, config, signature);
+            new SignedConfigApplicator(mContext, packageName).applyConfig(
+                    config, signature);
         } else {
             if (DBG) Slog.d(TAG, "Package has no config/signature.");
         }