Merge "Dump cached services" into main
diff --git a/networksecurity/service/Android.bp b/networksecurity/service/Android.bp
index 66d201a..e33abd5 100644
--- a/networksecurity/service/Android.bp
+++ b/networksecurity/service/Android.bp
@@ -27,6 +27,7 @@
     ],
 
     libs: [
+        "framework-configinfrastructure",
         "framework-connectivity-pre-jarjar",
         "service-connectivity-pre-jarjar",
     ],
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java
new file mode 100644
index 0000000..8dd5951
--- /dev/null
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyFlagsListener.java
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.server.net.ct;
+
+import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
+
+import android.content.Context;
+import android.provider.DeviceConfig;
+import android.provider.DeviceConfig.Properties;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.modules.utils.build.SdkLevel;
+
+import java.util.concurrent.Executors;
+
+/** Listener class for the Certificate Transparency Phenotype flags. */
+class CertificateTransparencyFlagsListener implements DeviceConfig.OnPropertiesChangedListener {
+
+    private static final String TAG = "CertificateTransparency";
+
+    private static final String VERSION = "version";
+    private static final String CONTENT_URL = "content_url";
+    private static final String METADATA_URL = "metadata_url";
+
+    CertificateTransparencyFlagsListener(Context context) {}
+
+    void initialize() {
+        DeviceConfig.addOnPropertiesChangedListener(
+                NAMESPACE_TETHERING, Executors.newSingleThreadExecutor(), this);
+        // TODO: handle property changes triggering on boot before registering this listener.
+    }
+
+    @Override
+    public void onPropertiesChanged(Properties properties) {
+        if (!SdkLevel.isAtLeastV() || !NAMESPACE_TETHERING.equals(properties.getNamespace())) {
+            return;
+        }
+
+        String newVersion = DeviceConfig.getString(NAMESPACE_TETHERING, VERSION, "");
+        String newContentUrl = DeviceConfig.getString(NAMESPACE_TETHERING, CONTENT_URL, "");
+        String newMetadataUrl = DeviceConfig.getString(NAMESPACE_TETHERING, METADATA_URL, "");
+        if (TextUtils.isEmpty(newVersion)
+                || TextUtils.isEmpty(newContentUrl)
+                || TextUtils.isEmpty(newMetadataUrl)) {
+            return;
+        }
+
+        Log.d(TAG, "newVersion=" + newVersion);
+        Log.d(TAG, "newContentUrl=" + newContentUrl);
+        Log.d(TAG, "newMetadataUrl=" + newMetadataUrl);
+        // TODO: start download of URLs.
+    }
+}
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
index 8c53bf7..406a57f 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyService.java
@@ -23,6 +23,7 @@
 
 import com.android.net.ct.flags.Flags;
 import com.android.net.module.util.DeviceConfigUtils;
+import com.android.server.SystemService;
 
 /** Implementation of the Certificate Transparency service. */
 @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)
@@ -32,6 +33,8 @@
     private static final String CERTIFICATE_TRANSPARENCY_ENABLED =
             "certificate_transparency_service_enabled";
 
+    private final CertificateTransparencyFlagsListener mFlagsListener;
+
     /**
      * @return true if the CertificateTransparency service is enabled.
      */
@@ -43,7 +46,9 @@
     }
 
     /** Creates a new {@link CertificateTransparencyService} object. */
-    public CertificateTransparencyService(Context context) {}
+    public CertificateTransparencyService(Context context) {
+        mFlagsListener = new CertificateTransparencyFlagsListener(context);
+    }
 
     /**
      * Called by {@link com.android.server.ConnectivityServiceInitializer}.
@@ -51,6 +56,13 @@
      * @see com.android.server.SystemService#onBootPhase
      */
     public void onBootPhase(int phase) {
-        Log.d(TAG, "CertificateTransparencyService#onBootPhase " + phase);
+
+        switch (phase) {
+            case SystemService.PHASE_BOOT_COMPLETED:
+                Log.d(TAG, "setting up flags listeners");
+                mFlagsListener.initialize();
+                break;
+            default:
+        }
     }
 }
diff --git a/service/src/com/android/server/connectivity/DnsManager.java b/service/src/com/android/server/connectivity/DnsManager.java
index ac02229..b95e3b1 100644
--- a/service/src/com/android/server/connectivity/DnsManager.java
+++ b/service/src/com/android/server/connectivity/DnsManager.java
@@ -41,6 +41,7 @@
 import android.net.NetworkCapabilities;
 import android.net.ResolverParamsParcel;
 import android.net.Uri;
+import android.net.resolv.aidl.DohParamsParcel;
 import android.net.shared.PrivateDnsConfig;
 import android.os.Binder;
 import android.os.RemoteException;
@@ -52,16 +53,17 @@
 import android.util.Pair;
 
 import java.net.InetAddress;
+import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
-import java.util.stream.Collectors;
 
 /**
  * Encapsulate the management of DNS settings for networks.
@@ -382,15 +384,14 @@
         paramsParcel.domains = getDomainStrings(lp.getDomains());
         paramsParcel.tlsName = strictMode ? privateDnsCfg.hostname : "";
         paramsParcel.tlsServers =
-                strictMode ? makeStrings(
-                        Arrays.stream(privateDnsCfg.ips)
-                              .filter((ip) -> lp.isReachable(ip))
-                              .collect(Collectors.toList()))
+                strictMode ? makeStrings(getReachableAddressList(privateDnsCfg.ips, lp))
                 : useTls ? paramsParcel.servers  // Opportunistic
                 : new String[0];            // Off
         paramsParcel.transportTypes = nc.getTransportTypes();
         paramsParcel.meteredNetwork = nc.isMetered();
         paramsParcel.interfaceNames = lp.getAllInterfaceNames().toArray(new String[0]);
+        paramsParcel.dohParams = makeDohParamsParcel(privateDnsCfg, lp);
+
         // Prepare to track the validation status of the DNS servers in the
         // resolver config when private DNS is in opportunistic or strict mode.
         if (useTls) {
@@ -404,15 +405,16 @@
         }
 
         Log.d(TAG, String.format("sendDnsConfigurationForNetwork(%d, %s, %s, %d, %d, %d, %d, "
-                + "%d, %d, %s, %s, %s, %b, %s)", paramsParcel.netId,
+                + "%d, %d, %s, %s, %s, %b, %s, %s, %s, %s, %d)", paramsParcel.netId,
                 Arrays.toString(paramsParcel.servers), Arrays.toString(paramsParcel.domains),
                 paramsParcel.sampleValiditySeconds, paramsParcel.successThreshold,
                 paramsParcel.minSamples, paramsParcel.maxSamples, paramsParcel.baseTimeoutMsec,
                 paramsParcel.retryCount, paramsParcel.tlsName,
                 Arrays.toString(paramsParcel.tlsServers),
                 Arrays.toString(paramsParcel.transportTypes), paramsParcel.meteredNetwork,
-                Arrays.toString(paramsParcel.interfaceNames)));
-
+                Arrays.toString(paramsParcel.interfaceNames),
+                paramsParcel.dohParams.name, Arrays.toString(paramsParcel.dohParams.ips),
+                paramsParcel.dohParams.dohpath, paramsParcel.dohParams.port));
         try {
             mDnsResolver.setResolverConfiguration(paramsParcel);
         } catch (RemoteException | ServiceSpecificException e) {
@@ -498,4 +500,26 @@
     private static String[] getDomainStrings(String domains) {
         return (TextUtils.isEmpty(domains)) ? new String[0] : domains.split(" ");
     }
+
+    @NonNull
+    private List<InetAddress> getReachableAddressList(@NonNull InetAddress[] ips,
+            @NonNull LinkProperties lp) {
+        final ArrayList<InetAddress> out = new ArrayList<InetAddress>(Arrays.asList(ips));
+        out.removeIf(ip -> !lp.isReachable(ip));
+        return out;
+    }
+
+    @NonNull
+    private DohParamsParcel makeDohParamsParcel(@NonNull PrivateDnsConfig cfg,
+            @NonNull LinkProperties lp) {
+        if (cfg.mode == PRIVATE_DNS_MODE_OFF) {
+            return new DohParamsParcel.Builder().build();
+        }
+        return new DohParamsParcel.Builder()
+                .setName(cfg.dohName)
+                .setIps(makeStrings(getReachableAddressList(cfg.dohIps, lp)))
+                .setDohpath(cfg.dohPath)
+                .setPort(cfg.dohPort)
+                .build();
+    }
 }
diff --git a/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java b/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
index ea3d2dd..b47b97d 100644
--- a/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
+++ b/tests/unit/java/com/android/server/connectivity/DnsManagerTest.java
@@ -54,6 +54,7 @@
 import android.net.ResolverOptionsParcel;
 import android.net.ResolverParamsParcel;
 import android.net.RouteInfo;
+import android.net.resolv.aidl.DohParamsParcel;
 import android.net.shared.PrivateDnsConfig;
 import android.os.Build;
 import android.provider.Settings;
@@ -327,8 +328,16 @@
     @Test
     public void testSendDnsConfiguration() throws Exception {
         reset(mMockDnsResolver);
-        mDnsManager.updatePrivateDns(new Network(TEST_NETID),
-                mDnsManager.getPrivateDnsConfig());
+        final PrivateDnsConfig cfg = new PrivateDnsConfig(
+                PRIVATE_DNS_MODE_OPPORTUNISTIC /* mode */,
+                null /* hostname */,
+                null /* ips */,
+                "doh.com" /* dohName */,
+                null /* dohIps */,
+                "/some-path{?dns}" /* dohPath */,
+                5353 /* dohPort */);
+
+        mDnsManager.updatePrivateDns(new Network(TEST_NETID), cfg);
         final LinkProperties lp = new LinkProperties();
         lp.setInterfaceName(TEST_IFACENAME);
         lp.addDnsServer(InetAddress.getByName("3.3.3.3"));
@@ -352,7 +361,11 @@
         expectedParams.transportTypes = TEST_TRANSPORT_TYPES;
         expectedParams.resolverOptions = null;
         expectedParams.meteredNetwork = true;
-        expectedParams.dohParams = null;
+        expectedParams.dohParams = new DohParamsParcel.Builder()
+                .setName("doh.com")
+                .setDohpath("/some-path{?dns}")
+                .setPort(5353)
+                .build();
         expectedParams.interfaceNames = new String[]{TEST_IFACENAME};
         verify(mMockDnsResolver, times(1)).setResolverConfiguration(eq(expectedParams));
     }