Merge "Update debug counter in `testReplyPing`" into main
diff --git a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
index 764300c..ce14fc6 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CertificateTransparencyDownloader.java
@@ -29,6 +29,7 @@
 import android.content.IntentFilter;
 import android.net.Uri;
 import android.os.Build;
+import android.provider.DeviceConfig;
 import android.util.Log;
 
 import androidx.annotation.VisibleForTesting;
@@ -231,25 +232,17 @@
         }
 
         boolean success = false;
-        boolean failureLogged = false;
+        int failureReason = -1;
 
         try {
             success = mSignatureVerifier.verify(contentUri, metadataUri);
         } catch (MissingPublicKeyException e) {
             if (updateFailureCount()) {
-                failureLogged = true;
-                mLogger.logCTLogListUpdateFailedEvent(
-                        CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND,
-                        mDataStore.getPropertyInt(
-                                Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0));
+                failureReason = CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND;
             }
         } catch (InvalidKeyException e) {
             if (updateFailureCount()) {
-                failureLogged = true;
-                mLogger.logCTLogListUpdateFailedEvent(
-                        CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
-                        mDataStore.getPropertyInt(
-                                Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0));
+                failureReason = CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION;
             }
         } catch (IOException | GeneralSecurityException e) {
             Log.e(TAG, "Could not verify new log list", e);
@@ -259,9 +252,13 @@
             Log.w(TAG, "Log list did not pass verification");
 
             // Avoid logging failure twice
-            if (!failureLogged && updateFailureCount()) {
+            if (failureReason == -1 && updateFailureCount()) {
+                failureReason = CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION;
+            }
+
+            if (failureReason != -1) {
                 mLogger.logCTLogListUpdateFailedEvent(
-                        CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
+                        failureReason,
                         mDataStore.getPropertyInt(
                                 Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0));
             }
@@ -324,7 +321,12 @@
         mDataStore.setPropertyInt(Config.LOG_LIST_UPDATE_FAILURE_COUNT, new_failure_count);
         mDataStore.store();
 
-        boolean shouldReport = new_failure_count >= Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD;
+        int threshold = DeviceConfig.getInt(
+                Config.NAMESPACE_NETWORK_SECURITY,
+                Config.FLAG_LOG_FAILURE_THRESHOLD,
+                Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+
+        boolean shouldReport = new_failure_count >= threshold;
         if (shouldReport) {
             Log.d(TAG, "Log list update failure count exceeds threshold: " + new_failure_count);
         }
diff --git a/networksecurity/service/src/com/android/server/net/ct/Config.java b/networksecurity/service/src/com/android/server/net/ct/Config.java
index 592bc4e..bc4efab 100644
--- a/networksecurity/service/src/com/android/server/net/ct/Config.java
+++ b/networksecurity/service/src/com/android/server/net/ct/Config.java
@@ -45,6 +45,7 @@
     static final String FLAG_METADATA_URL = FLAGS_PREFIX + "metadata_url";
     static final String FLAG_VERSION = FLAGS_PREFIX + "version";
     static final String FLAG_PUBLIC_KEY = FLAGS_PREFIX + "public_key";
+    static final String FLAG_LOG_FAILURE_THRESHOLD = FLAGS_PREFIX + "log_list_failure_threshold";
 
     // properties
     static final String VERSION = "version";
@@ -60,5 +61,5 @@
     static final String URL_PUBLIC_KEY = URL_PREFIX + "log_list.pub";
 
     // Threshold amounts
-    static final int LOG_LIST_UPDATE_FAILURE_THRESHOLD = 10;
+    static final int DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD = 10;
 }
diff --git a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
index 34f8dd1..2f57fc9 100644
--- a/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
+++ b/networksecurity/tests/unit/src/com/android/server/net/ct/CertificateTransparencyDownloaderTest.java
@@ -203,7 +203,8 @@
         mCertificateTransparencyDownloader.startPublicKeyDownload();
         // Set the failure count to just below the threshold
         mDataStore.setPropertyInt(
-                Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+                Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+                Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
 
         mCertificateTransparencyDownloader.onReceive(
                 mContext,
@@ -212,11 +213,11 @@
         assertThat(
                         mDataStore.getPropertyInt(
                                 Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
-                .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                .isEqualTo(Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
         verify(mLogger, times(1))
                 .logCTLogListUpdateFailedEventWithDownloadStatus(
                         DownloadManager.ERROR_INSUFFICIENT_SPACE,
-                        Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                        Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
     }
 
     @Test
@@ -273,7 +274,8 @@
         mCertificateTransparencyDownloader.startMetadataDownload();
         // Set the failure count to just below the threshold
         mDataStore.setPropertyInt(
-                Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+                Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+                Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
 
         mCertificateTransparencyDownloader.onReceive(
                 mContext,
@@ -283,11 +285,11 @@
         assertThat(
                         mDataStore.getPropertyInt(
                                 Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
-                .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                .isEqualTo(Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
         verify(mLogger, times(1))
                 .logCTLogListUpdateFailedEventWithDownloadStatus(
                         DownloadManager.ERROR_INSUFFICIENT_SPACE,
-                        Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                        Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
     }
 
     @Test
@@ -350,7 +352,8 @@
         mCertificateTransparencyDownloader.startContentDownload(mCompatVersion);
         // Set the failure count to just below the threshold
         mDataStore.setPropertyInt(
-                Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+                Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+                Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
 
         mCertificateTransparencyDownloader.onReceive(
                 mContext,
@@ -360,11 +363,11 @@
         assertThat(
                         mDataStore.getPropertyInt(
                                 Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
-                .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                .isEqualTo(Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
         verify(mLogger, times(1))
                 .logCTLogListUpdateFailedEventWithDownloadStatus(
                         DownloadManager.ERROR_INSUFFICIENT_SPACE,
-                        Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                        Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
     }
 
     @Test
@@ -415,7 +418,8 @@
         mCertificateTransparencyDownloader.startMetadataDownload();
         // Set the failure count to just below the threshold
         mDataStore.setPropertyInt(
-                Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+                Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+                Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
 
         // Set the public key to be missing
         mSignatureVerifier.resetPublicKey();
@@ -427,11 +431,11 @@
         assertThat(
                         mDataStore.getPropertyInt(
                                 Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
-                .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                .isEqualTo(Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
         verify(mLogger, times(1))
                 .logCTLogListUpdateFailedEvent(
                         CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_NOT_FOUND,
-                        Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                        Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
         verify(mLogger, never())
                 .logCTLogListUpdateFailedEvent(
                         eq(
@@ -453,7 +457,8 @@
 
         // Set the failure count to just below the threshold
         mDataStore.setPropertyInt(
-                Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+                Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+                Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
 
         // Act
         mCertificateTransparencyDownloader.startMetadataDownload();
@@ -466,7 +471,7 @@
         assertThat(
                         mDataStore.getPropertyInt(
                                 Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
-                .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                .isEqualTo(Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
         verify(mLogger, never())
                 .logCTLogListUpdateFailedEvent(
                         eq(
@@ -475,7 +480,7 @@
         verify(mLogger, times(1))
                 .logCTLogListUpdateFailedEvent(
                         CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
-                        Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                        Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
     }
 
     @Test
@@ -492,7 +497,8 @@
 
         // Set the failure count to just below the threshold
         mDataStore.setPropertyInt(
-                Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+                Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+                Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
 
         // Act
         mCertificateTransparencyDownloader.startMetadataDownload();
@@ -505,7 +511,7 @@
         assertThat(
                         mDataStore.getPropertyInt(
                                 Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
-                .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                .isEqualTo(Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
         verify(mLogger, never())
                 .logCTLogListUpdateFailedEvent(
                         eq(
@@ -514,7 +520,7 @@
         verify(mLogger, times(1))
                 .logCTLogListUpdateFailedEvent(
                         CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_SIGNATURE_VERIFICATION,
-                        Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                        Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
     }
 
     @Test
@@ -560,7 +566,8 @@
         mSignatureVerifier.setPublicKey(mPublicKey);
         // Set the failure count to just below the threshold
         mDataStore.setPropertyInt(
-                Config.LOG_LIST_UPDATE_FAILURE_COUNT, Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
+                Config.LOG_LIST_UPDATE_FAILURE_COUNT,
+                Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD - 1);
 
         mCertificateTransparencyDownloader.startMetadataDownload();
         mCertificateTransparencyDownloader.onReceive(
@@ -571,11 +578,11 @@
         assertThat(
                         mDataStore.getPropertyInt(
                                 Config.LOG_LIST_UPDATE_FAILURE_COUNT, /* defaultValue= */ 0))
-                .isEqualTo(Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                .isEqualTo(Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
         verify(mLogger, times(1))
                 .logCTLogListUpdateFailedEvent(
                         CERTIFICATE_TRANSPARENCY_LOG_LIST_UPDATE_FAILED__FAILURE_REASON__FAILURE_VERSION_ALREADY_EXISTS,
-                        Config.LOG_LIST_UPDATE_FAILURE_THRESHOLD);
+                        Config.DEFAULT_LOG_LIST_UPDATE_FAILURE_THRESHOLD);
     }
 
     @Test
diff --git a/service/ServiceConnectivityResources/res/values/config_thread.xml b/service/ServiceConnectivityResources/res/values/config_thread.xml
index 3627157..d1d9e52 100644
--- a/service/ServiceConnectivityResources/res/values/config_thread.xml
+++ b/service/ServiceConnectivityResources/res/values/config_thread.xml
@@ -79,4 +79,10 @@
     to the devices, or reaching to Thread end devices doesn't require border routing to work.
     -->
     <bool name="config_thread_srp_server_wait_for_border_routing_enabled">true</bool>
+
+    <!-- Whether this border router will automatically join the previous connected network after
+    device reboots. Setting this value to false can allow the user to control the lifecycle of
+    the Thread border router state on this device.
+    -->
+    <bool name="config_thread_border_router_auto_join_enabled">true</bool>
 </resources>
diff --git a/service/ServiceConnectivityResources/res/values/overlayable.xml b/service/ServiceConnectivityResources/res/values/overlayable.xml
index 121cbc4..7ac86aa 100644
--- a/service/ServiceConnectivityResources/res/values/overlayable.xml
+++ b/service/ServiceConnectivityResources/res/values/overlayable.xml
@@ -53,6 +53,7 @@
             <item type="string" name="config_thread_model_name" />
             <item type="array" name="config_thread_mdns_vendor_specific_txts" />
             <item type="bool" name="config_thread_srp_server_wait_for_border_routing_enabled" />
+            <item type="bool" name="config_thread_border_router_auto_join_enabled" />
         </policy>
     </overlayable>
 </resources>
diff --git a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
index c2959f4..af16d19 100644
--- a/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
+++ b/thread/service/java/com/android/server/thread/ThreadNetworkControllerService.java
@@ -626,11 +626,14 @@
     private OtDaemonConfiguration newOtDaemonConfig(ThreadConfiguration threadConfig) {
         int srpServerConfig = R.bool.config_thread_srp_server_wait_for_border_routing_enabled;
         boolean srpServerWaitEnabled = mResources.get().getBoolean(srpServerConfig);
+        int autoJoinConfig = R.bool.config_thread_border_router_auto_join_enabled;
+        boolean autoJoinEnabled = mResources.get().getBoolean(autoJoinConfig);
         return new OtDaemonConfiguration.Builder()
                 .setBorderRouterEnabled(threadConfig.isBorderRouterEnabled())
                 .setNat64Enabled(threadConfig.isNat64Enabled())
                 .setDhcpv6PdEnabled(threadConfig.isDhcpv6PdEnabled())
                 .setSrpServerWaitForBorderRoutingEnabled(srpServerWaitEnabled)
+                .setBorderRouterAutoJoinEnabled(autoJoinEnabled)
                 .build();
     }
 
diff --git a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
index 1d44ccb..bc8da8b 100644
--- a/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
+++ b/thread/tests/unit/src/com/android/server/thread/ThreadNetworkControllerServiceTest.java
@@ -234,6 +234,8 @@
         when(mResources.getBoolean(
                         eq(R.bool.config_thread_srp_server_wait_for_border_routing_enabled)))
                 .thenReturn(true);
+        when(mResources.getBoolean(eq(R.bool.config_thread_border_router_auto_join_enabled)))
+                .thenReturn(true);
         when(mResources.getString(eq(R.string.config_thread_vendor_name)))
                 .thenReturn(TEST_VENDOR_NAME);
         when(mResources.getString(eq(R.string.config_thread_vendor_oui)))
@@ -291,6 +293,8 @@
         when(mResources.getBoolean(
                         eq(R.bool.config_thread_srp_server_wait_for_border_routing_enabled)))
                 .thenReturn(false);
+        when(mResources.getBoolean(eq(R.bool.config_thread_border_router_auto_join_enabled)))
+                .thenReturn(false);
         when(mResources.getString(eq(R.string.config_thread_vendor_name)))
                 .thenReturn(TEST_VENDOR_NAME);
         when(mResources.getString(eq(R.string.config_thread_vendor_oui)))
@@ -304,6 +308,7 @@
         mTestLooper.dispatchAll();
 
         assertThat(mFakeOtDaemon.getConfiguration().srpServerWaitForBorderRoutingEnabled).isFalse();
+        assertThat(mFakeOtDaemon.getConfiguration().borderRouterAutoJoinEnabled).isFalse();
         MeshcopTxtAttributes meshcopTxts = mFakeOtDaemon.getOverriddenMeshcopTxtAttributes();
         assertThat(meshcopTxts.vendorName).isEqualTo(TEST_VENDOR_NAME);
         assertThat(meshcopTxts.vendorOui).isEqualTo(TEST_VENDOR_OUI_BYTES);