Merge "[Ravenwood] Remove RavenwoodConfig and un-deprecate RavenwoodRule" into main
diff --git a/core/java/android/os/ServiceManager.java b/core/java/android/os/ServiceManager.java
index 8aec7eb..9085fe0 100644
--- a/core/java/android/os/ServiceManager.java
+++ b/core/java/android/os/ServiceManager.java
@@ -277,7 +277,8 @@
             if (service != null) {
                 return service;
             } else {
-                return Binder.allowBlocking(getIServiceManager().checkService(name).getBinder());
+                return Binder.allowBlocking(
+                        getIServiceManager().checkService(name).getServiceWithMetadata().service);
             }
         } catch (RemoteException e) {
             Log.e(TAG, "error in checkService", e);
@@ -425,7 +426,8 @@
     private static IBinder rawGetService(String name) throws RemoteException {
         final long start = sStatLogger.getTime();
 
-        final IBinder binder = getIServiceManager().getService2(name).getBinder();
+        final IBinder binder =
+                getIServiceManager().getService2(name).getServiceWithMetadata().service;
 
         final int time = (int) sStatLogger.logDurationStat(Stats.GET_SERVICE, start);
 
diff --git a/core/java/android/os/ServiceManagerNative.java b/core/java/android/os/ServiceManagerNative.java
index 5a9c878..49b696d 100644
--- a/core/java/android/os/ServiceManagerNative.java
+++ b/core/java/android/os/ServiceManagerNative.java
@@ -61,7 +61,7 @@
     @UnsupportedAppUsage
     public IBinder getService(String name) throws RemoteException {
         // Same as checkService (old versions of servicemanager had both methods).
-        return checkService(name).getBinder();
+        return checkService(name).getServiceWithMetadata().service;
     }
 
     public Service getService2(String name) throws RemoteException {
diff --git a/core/java/android/security/net/config/CertificatesEntryRef.java b/core/java/android/security/net/config/CertificatesEntryRef.java
index 45cd0f0..a46049f 100644
--- a/core/java/android/security/net/config/CertificatesEntryRef.java
+++ b/core/java/android/security/net/config/CertificatesEntryRef.java
@@ -17,6 +17,7 @@
 package android.security.net.config;
 
 import android.util.ArraySet;
+
 import java.security.cert.X509Certificate;
 import java.util.Set;
 
@@ -24,16 +25,23 @@
 public final class CertificatesEntryRef {
     private final CertificateSource mSource;
     private final boolean mOverridesPins;
+    private final boolean mDisableCT;
 
-    public CertificatesEntryRef(CertificateSource source, boolean overridesPins) {
+    public CertificatesEntryRef(CertificateSource source, boolean overridesPins,
+            boolean disableCT) {
         mSource = source;
         mOverridesPins = overridesPins;
+        mDisableCT = disableCT;
     }
 
     boolean overridesPins() {
         return mOverridesPins;
     }
 
+    boolean disableCT() {
+        return mDisableCT;
+    }
+
     public Set<TrustAnchor> getTrustAnchors() {
         // TODO: cache this [but handle mutable sources]
         Set<TrustAnchor> anchors = new ArraySet<TrustAnchor>();
diff --git a/core/java/android/security/net/config/KeyStoreConfigSource.java b/core/java/android/security/net/config/KeyStoreConfigSource.java
index 8d4f098..a54d8d0 100644
--- a/core/java/android/security/net/config/KeyStoreConfigSource.java
+++ b/core/java/android/security/net/config/KeyStoreConfigSource.java
@@ -17,8 +17,8 @@
 package android.security.net.config;
 
 import android.util.Pair;
+
 import java.security.KeyStore;
-import java.security.KeyStoreException;
 import java.util.Set;
 
 /**
@@ -32,7 +32,7 @@
         mConfig = new NetworkSecurityConfig.Builder()
                 .addCertificatesEntryRef(
                         // Use the KeyStore and do not override pins (of which there are none).
-                        new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false))
+                        new CertificatesEntryRef(new KeyStoreCertificateSource(ks), false, false))
                 .build();
     }
 
diff --git a/core/java/android/security/net/config/NetworkSecurityConfig.java b/core/java/android/security/net/config/NetworkSecurityConfig.java
index 129ae63..410c68b 100644
--- a/core/java/android/security/net/config/NetworkSecurityConfig.java
+++ b/core/java/android/security/net/config/NetworkSecurityConfig.java
@@ -112,7 +112,6 @@
         return mHstsEnforced;
     }
 
-    // TODO(b/28746284): add exceptions for user-added certificates and enterprise overrides.
     public boolean isCertificateTransparencyVerificationRequired() {
         return mCertificateTransparencyVerificationRequired;
     }
@@ -192,20 +191,21 @@
      * @hide
      */
     public static Builder getDefaultBuilder(ApplicationInfo info) {
+        // System certificate store, does not bypass static pins, does not disable CT.
+        CertificatesEntryRef systemRef = new CertificatesEntryRef(
+                SystemCertificateSource.getInstance(), false, false);
         Builder builder = new Builder()
                 .setHstsEnforced(DEFAULT_HSTS_ENFORCED)
-                // System certificate store, does not bypass static pins.
-                .addCertificatesEntryRef(
-                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), false));
+                .addCertificatesEntryRef(systemRef);
         final boolean cleartextTrafficPermitted = info.targetSdkVersion < Build.VERSION_CODES.P
                 && !info.isInstantApp();
         builder.setCleartextTrafficPermitted(cleartextTrafficPermitted);
         // Applications targeting N and above must opt in into trusting the user added certificate
         // store.
         if (info.targetSdkVersion <= Build.VERSION_CODES.M && !info.isPrivilegedApp()) {
-            // User certificate store, does not bypass static pins.
+            // User certificate store, does not bypass static pins. CT is disabled.
             builder.addCertificatesEntryRef(
-                    new CertificatesEntryRef(UserCertificateSource.getInstance(), false));
+                    new CertificatesEntryRef(UserCertificateSource.getInstance(), false, true));
         }
         return builder;
     }
@@ -339,6 +339,16 @@
             if (mCertificateTransparencyVerificationRequiredSet) {
                 return mCertificateTransparencyVerificationRequired;
             }
+            // CT verification has not been set explicitly. Before deferring to
+            // the parent, check if any of the CertificatesEntryRef requires it
+            // to be disabled (i.e., user store or inline certificate).
+            if (hasCertificatesEntryRefs()) {
+                for (CertificatesEntryRef ref : getCertificatesEntryRefs()) {
+                    if (ref.disableCT()) {
+                        return false;
+                    }
+                }
+            }
             if (mParentBuilder != null) {
                 return mParentBuilder.getCertificateTransparencyVerificationRequired();
             }
diff --git a/core/java/android/security/net/config/XmlConfigSource.java b/core/java/android/security/net/config/XmlConfigSource.java
index b1c1479..95e579f 100644
--- a/core/java/android/security/net/config/XmlConfigSource.java
+++ b/core/java/android/security/net/config/XmlConfigSource.java
@@ -182,6 +182,7 @@
         boolean overridePins =
                 parser.getAttributeBooleanValue(null, "overridePins", defaultOverridePins);
         int sourceId = parser.getAttributeResourceValue(null, "src", -1);
+        boolean disableCT = false;
         String sourceString = parser.getAttributeValue(null, "src");
         CertificateSource source = null;
         if (sourceString == null) {
@@ -190,10 +191,12 @@
         if (sourceId != -1) {
             // TODO: Cache ResourceCertificateSources by sourceId
             source = new ResourceCertificateSource(sourceId, mContext);
+            disableCT = true;
         } else if ("system".equals(sourceString)) {
             source = SystemCertificateSource.getInstance();
         } else if ("user".equals(sourceString)) {
             source = UserCertificateSource.getInstance();
+            disableCT = true;
         } else if ("wfa".equals(sourceString)) {
             source = WfaCertificateSource.getInstance();
         } else {
@@ -201,7 +204,7 @@
                     + "Should be one of system|user|@resourceVal");
         }
         XmlUtils.skipCurrentTag(parser);
-        return new CertificatesEntryRef(source, overridePins);
+        return new CertificatesEntryRef(source, overridePins, disableCT);
     }
 
     private Collection<CertificatesEntryRef> parseTrustAnchors(XmlResourceParser parser,
diff --git a/keystore/java/android/security/KeyStore2HalLatest.java b/keystore/java/android/security/KeyStore2HalLatest.java
index b6e1cbb..123f1c0 100644
--- a/keystore/java/android/security/KeyStore2HalLatest.java
+++ b/keystore/java/android/security/KeyStore2HalLatest.java
@@ -23,7 +23,7 @@
 * and KeyMint (V4) are used.
 */
 class KeyStore2HalVersion {
-    public byte[] getSupplementaryAttestationInfoHelper(int tag, KeyStore2 ks)
+    public static byte[] getSupplementaryAttestationInfoHelper(int tag, KeyStore2 ks)
             throws KeyStoreException {
         return ks.handleRemoteExceptionWithRetry(
             (service) -> service.getSupplementaryAttestationInfo(tag));
diff --git a/ravenwood/Android.bp b/ravenwood/Android.bp
index 66c8d0f..59043a83 100644
--- a/ravenwood/Android.bp
+++ b/ravenwood/Android.bp
@@ -182,21 +182,6 @@
     visibility: [":__subpackages__"],
 }
 
-// Separated out from ravenwood-junit-impl since it needs to compile
-// against `module_current`
-java_library {
-    name: "ravenwood-junit-impl-flag",
-    srcs: [
-        "junit-flag-src/**/*.java",
-    ],
-    sdk_version: "module_current",
-    libs: [
-        "junit",
-        "flag-junit",
-    ],
-    visibility: ["//visibility:public"],
-}
-
 // Carefully compiles against only module_current to support tests that
 // want to verify they're unbundled.  The "impl" library above is what
 // ships inside the Ravenwood environment to actually drive any API
@@ -651,7 +636,6 @@
         "flag-junit",
         "ravenwood-framework",
         "ravenwood-junit-impl",
-        "ravenwood-junit-impl-flag",
         "mockito-ravenwood-prebuilt",
         "inline-mockito-ravenwood-prebuilt",
 
diff --git a/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java b/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java
deleted file mode 100644
index 9d62774..0000000
--- a/ravenwood/junit-flag-src/android/platform/test/flag/junit/RavenwoodFlagsValueProvider.java
+++ /dev/null
@@ -1,54 +0,0 @@
-/*
- * 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 android.platform.test.flag.junit;
-
-import android.platform.test.flag.junit.CheckFlagsRule;
-import android.platform.test.flag.junit.IFlagsValueProvider;
-
-/**
- * Offer to create {@link CheckFlagsRule} instances that are useful on the Ravenwood deviceless
- * testing environment.
- *
- * At the moment, default flag values are not available on Ravenwood, so the only options offered
- * here are "all-on" and "all-off" options. Tests that want to exercise specific flag states should
- * use {@link android.platform.test.flag.junit.SetFlagsRule}.
- */
-public class RavenwoodFlagsValueProvider {
-    /**
-     * Create a {@link CheckFlagsRule} instance where flags are in an "all-on" state.
-     */
-    public static CheckFlagsRule createAllOnCheckFlagsRule() {
-        return new CheckFlagsRule(new IFlagsValueProvider() {
-            @Override
-            public boolean getBoolean(String flag) {
-                return true;
-            }
-        });
-    }
-
-    /**
-     * Create a {@link CheckFlagsRule} instance where flags are in an "all-off" state.
-     */
-    public static CheckFlagsRule createAllOffCheckFlagsRule() {
-        return new CheckFlagsRule(new IFlagsValueProvider() {
-            @Override
-            public boolean getBoolean(String flag) {
-                return false;
-            }
-        });
-    }
-}
diff --git a/tests/NetworkSecurityConfigTest/res/xml/ct_domains.xml b/tests/NetworkSecurityConfigTest/res/xml/ct_domains.xml
new file mode 100644
index 0000000..67d4397a
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/ct_domains.xml
@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+  <base-config>
+      <certificateTransparency enabled="true" />
+  </base-config>
+  <domain-config>
+    <domain>android.com</domain>
+    <trust-anchors>
+      <certificates src="system" />
+    </trust-anchors>
+  </domain-config>
+  <domain-config>
+    <domain>subdomain_user.android.com</domain>
+    <trust-anchors>
+      <certificates src="user" />
+    </trust-anchors>
+  </domain-config>
+  <domain-config>
+    <certificateTransparency enabled="true" />
+    <domain>subdomain_user_ct.android.com</domain>
+    <trust-anchors>
+      <certificates src="user" />
+    </trust-anchors>
+  </domain-config>
+  <domain-config>
+    <domain>subdomain_inline.android.com</domain>
+    <trust-anchors>
+      <certificates src="@raw/ca_certs_pem" />
+    </trust-anchors>
+  </domain-config>
+  <domain-config>
+    <certificateTransparency enabled="true" />
+    <domain>subdomain_inline_ct.android.com</domain>
+    <trust-anchors>
+      <certificates src="@raw/ca_certs_pem" />
+    </trust-anchors>
+  </domain-config>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/res/xml/ct_users.xml b/tests/NetworkSecurityConfigTest/res/xml/ct_users.xml
new file mode 100644
index 0000000..c35fd71
--- /dev/null
+++ b/tests/NetworkSecurityConfigTest/res/xml/ct_users.xml
@@ -0,0 +1,15 @@
+<?xml version="1.0" encoding="utf-8"?>
+<network-security-config>
+  <base-config>
+    <trust-anchors>
+      <certificates src="user" />
+    </trust-anchors>
+  </base-config>
+  <domain-config>
+    <domain>android.com</domain>
+  </domain-config>
+  <domain-config>
+    <certificateTransparency enabled="true" />
+    <domain>subdomain.android.com</domain>
+  </domain-config>
+</network-security-config>
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
index 0494f17..c6fe068 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/NetworkSecurityConfigTests.java
@@ -111,7 +111,8 @@
     private NetworkSecurityConfig getSystemStoreConfig() {
         return new NetworkSecurityConfig.Builder()
                 .addCertificatesEntryRef(
-                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), false))
+                        new CertificatesEntryRef(
+                              SystemCertificateSource.getInstance(), false, false))
                 .build();
     }
 
@@ -141,7 +142,8 @@
         NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder()
                 .setPinSet(new PinSet(pins, Long.MAX_VALUE))
                 .addCertificatesEntryRef(
-                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), false))
+                        new CertificatesEntryRef(
+                              SystemCertificateSource.getInstance(), false, false))
                 .build();
         ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
                 = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
@@ -159,7 +161,8 @@
         NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder()
                 .setPinSet(new PinSet(pins, Long.MAX_VALUE))
                 .addCertificatesEntryRef(
-                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), false))
+                        new CertificatesEntryRef(
+                              SystemCertificateSource.getInstance(), false, false))
                 .build();
         ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
                 = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
@@ -178,7 +181,8 @@
         NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder()
                 .setPinSet(new PinSet(pins, Long.MAX_VALUE))
                 .addCertificatesEntryRef(
-                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), true))
+                        new CertificatesEntryRef(
+                              SystemCertificateSource.getInstance(), true, false))
                 .build();
         ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
                 = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
@@ -245,7 +249,8 @@
         NetworkSecurityConfig domain = new NetworkSecurityConfig.Builder()
                 .setPinSet(new PinSet(pins, Long.MAX_VALUE))
                 .addCertificatesEntryRef(
-                        new CertificatesEntryRef(SystemCertificateSource.getInstance(), false))
+                        new CertificatesEntryRef(
+                              SystemCertificateSource.getInstance(), false, false))
                 .build();
         ArraySet<Pair<Domain, NetworkSecurityConfig>> domainMap
                 = new ArraySet<Pair<Domain, NetworkSecurityConfig>>();
diff --git a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
index 81e05c1..542465d 100644
--- a/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
+++ b/tests/NetworkSecurityConfigTest/src/android/security/net/config/XmlConfigTests.java
@@ -502,4 +502,47 @@
         TestUtils.assertConnectionSucceeds(context, "android.com", 443);
         TestUtils.assertConnectionSucceeds(context, "developer.android.com", 443);
     }
+
+    public void testCertificateTransparencyDomainConfig() throws Exception {
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.ct_domains,
+                TestUtils.makeApplicationInfo());
+        ApplicationConfig appConfig = new ApplicationConfig(source);
+        assertTrue(appConfig.hasPerDomainConfigs());
+        NetworkSecurityConfig config = appConfig.getConfigForHostname("");
+        assertNotNull(config);
+        // Check defaults.
+        assertTrue(config.isCertificateTransparencyVerificationRequired());
+
+        config = appConfig.getConfigForHostname("android.com");
+        assertTrue(config.isCertificateTransparencyVerificationRequired());
+
+        config = appConfig.getConfigForHostname("subdomain_user.android.com");
+        assertFalse(config.isCertificateTransparencyVerificationRequired());
+
+        config = appConfig.getConfigForHostname("subdomain_user_ct.android.com");
+        assertTrue(config.isCertificateTransparencyVerificationRequired());
+
+        config = appConfig.getConfigForHostname("subdomain_inline.android.com");
+        assertFalse(config.isCertificateTransparencyVerificationRequired());
+
+        config = appConfig.getConfigForHostname("subdomain_inline_ct.android.com");
+        assertTrue(config.isCertificateTransparencyVerificationRequired());
+    }
+
+    public void testCertificateTransparencyUserConfig() throws Exception {
+        XmlConfigSource source = new XmlConfigSource(getContext(), R.xml.ct_users,
+                TestUtils.makeApplicationInfo());
+        ApplicationConfig appConfig = new ApplicationConfig(source);
+        assertTrue(appConfig.hasPerDomainConfigs());
+        NetworkSecurityConfig config = appConfig.getConfigForHostname("");
+        assertNotNull(config);
+        // Check defaults.
+        assertFalse(config.isCertificateTransparencyVerificationRequired());
+
+        config = appConfig.getConfigForHostname("android.com");
+        assertFalse(config.isCertificateTransparencyVerificationRequired());
+
+        config = appConfig.getConfigForHostname("subdomain.android.com");
+        assertTrue(config.isCertificateTransparencyVerificationRequired());
+    }
 }