Merge "Update code for Rust 1.83.0" into main
diff --git a/framework/src/android/net/L2capNetworkSpecifier.java b/framework/src/android/net/L2capNetworkSpecifier.java
index 3c95dd0..cfc9ed9 100644
--- a/framework/src/android/net/L2capNetworkSpecifier.java
+++ b/framework/src/android/net/L2capNetworkSpecifier.java
@@ -308,6 +308,41 @@
                 && mPsm == rhs.mPsm;
     }
 
+    /** @hide */
+    @Override
+    public String toString() {
+        final String role;
+        switch (mRole) {
+            case ROLE_CLIENT:
+                role = "ROLE_CLIENT";
+                break;
+            case ROLE_SERVER:
+                role = "ROLE_SERVER";
+                break;
+            default:
+                role = "ROLE_ANY";
+                break;
+        }
+
+        final String headerCompression;
+        switch (mHeaderCompression) {
+            case HEADER_COMPRESSION_NONE:
+                headerCompression = "HEADER_COMPRESSION_NONE";
+                break;
+            case HEADER_COMPRESSION_6LOWPAN:
+                headerCompression = "HEADER_COMPRESSION_6LOWPAN";
+                break;
+            default:
+                headerCompression = "HEADER_COMPRESSION_ANY";
+                break;
+        }
+
+        final String psm = (mPsm == PSM_ANY) ? "PSM_ANY" : String.valueOf(mPsm);
+
+        return String.format("L2capNetworkSpecifier(%s, %s, RemoteAddress=%s, PSM=%s)",
+                role, headerCompression, Objects.toString(mRemoteAddress), psm);
+    }
+
     @Override
     public int describeContents() {
         return 0;
diff --git a/networksecurity/TEST_MAPPING b/networksecurity/TEST_MAPPING
index 20ecbce..f9238c3 100644
--- a/networksecurity/TEST_MAPPING
+++ b/networksecurity/TEST_MAPPING
@@ -1,5 +1,14 @@
 {
-  "postsubmit": [
+  "presubmit": [
+    {
+      "name": "CtsNetSecConfigCertificateTransparencyTestCases"
+    },
+    {
+      "name": "CtsNetSecConfigCertificateTransparencyDefaultTestCases"
+    },
+    {
+      "name": "NetSecConfigCertificateTransparencySctLogListTestCases"
+    },
     {
       "name": "NetworkSecurityUnitTests"
     }
diff --git a/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java b/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
index fdeb746..9d60163 100644
--- a/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
+++ b/networksecurity/service/src/com/android/server/net/ct/CompatibilityVersion.java
@@ -46,6 +46,7 @@
 
     private final String mMetadataUrl;
     private final String mContentUrl;
+    private final File mRootDirectory;
     private final File mVersionDirectory;
     private final File mCurrentLogsDirSymlink;
 
@@ -54,6 +55,7 @@
         mCompatVersion = compatVersion;
         mMetadataUrl = metadataUrl;
         mContentUrl = contentUrl;
+        mRootDirectory = rootDirectory;
         mVersionDirectory = new File(rootDirectory, compatVersion);
         mCurrentLogsDirSymlink = new File(mVersionDirectory, CURRENT_LOGS_DIR_SYMLINK_NAME);
     }
@@ -86,7 +88,8 @@
         // To support atomically replacing the old configuration directory with the new
         // there's a bunch of steps. We create a new directory with the logs and then do
         // an atomic update of the current symlink to point to the new directory.
-        // 1. Ensure the path to the root directory exists and is readable.
+        // 1. Ensure the path to the root and version directories exist and are readable.
+        DirectoryUtils.makeDir(mRootDirectory);
         DirectoryUtils.makeDir(mVersionDirectory);
 
         File newLogsDir = new File(mVersionDirectory, LOGS_DIR_PREFIX + version);
diff --git a/networksecurity/service/src/com/android/server/net/ct/DirectoryUtils.java b/networksecurity/service/src/com/android/server/net/ct/DirectoryUtils.java
index 54e277a..ba42a82 100644
--- a/networksecurity/service/src/com/android/server/net/ct/DirectoryUtils.java
+++ b/networksecurity/service/src/com/android/server/net/ct/DirectoryUtils.java
@@ -25,7 +25,7 @@
 class DirectoryUtils {
 
     static void makeDir(File dir) throws IOException {
-        dir.mkdirs();
+        dir.mkdir();
         if (!dir.isDirectory()) {
             throw new IOException("Unable to make directory " + dir.getCanonicalPath());
         }
diff --git a/service/src/com/android/server/L2capNetworkProvider.java b/service/src/com/android/server/L2capNetworkProvider.java
index 34968e7..c5ec9ee 100644
--- a/service/src/com/android/server/L2capNetworkProvider.java
+++ b/service/src/com/android/server/L2capNetworkProvider.java
@@ -20,6 +20,7 @@
 import static android.net.L2capNetworkSpecifier.HEADER_COMPRESSION_ANY;
 import static android.net.L2capNetworkSpecifier.PSM_ANY;
 import static android.net.L2capNetworkSpecifier.ROLE_SERVER;
+import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_CONGESTED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_METERED;
 import static android.net.NetworkCapabilities.NET_CAPABILITY_NOT_ROAMING;
@@ -32,6 +33,7 @@
 
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
 import android.net.L2capNetworkSpecifier;
 import android.net.NetworkCapabilities;
@@ -41,6 +43,7 @@
 import android.net.NetworkScore;
 import android.net.NetworkSpecifier;
 import android.os.Handler;
+import android.os.HandlerThread;
 import android.os.Looper;
 import android.util.ArrayMap;
 import android.util.Log;
@@ -53,6 +56,8 @@
 public class L2capNetworkProvider {
     private static final String TAG = L2capNetworkProvider.class.getSimpleName();
     private final Dependencies mDeps;
+    private final Context mContext;
+    private final HandlerThread mHandlerThread;
     private final Handler mHandler;
     private final NetworkProvider mProvider;
     private final BlanketReservationOffer mBlanketOffer;
@@ -78,6 +83,8 @@
                     .build();
             NetworkCapabilities caps = NetworkCapabilities.Builder.withoutDefaultCapabilities()
                     .addTransportType(TRANSPORT_BLUETOOTH)
+                    // TODO: consider removing NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED.
+                    .addCapability(NET_CAPABILITY_NOT_BANDWIDTH_CONSTRAINED)
                     .addCapability(NET_CAPABILITY_NOT_CONGESTED)
                     .addCapability(NET_CAPABILITY_NOT_METERED)
                     .addCapability(NET_CAPABILITY_NOT_ROAMING)
@@ -198,26 +205,40 @@
         public NetworkProvider getNetworkProvider(Context context, Looper looper) {
             return new NetworkProvider(context, looper, TAG);
         }
+
+        /** Get the HandlerThread for L2capNetworkProvider to run on */
+        public HandlerThread getHandlerThread() {
+            final HandlerThread thread = new HandlerThread("L2capNetworkProviderThread");
+            thread.start();
+            return thread;
+        }
     }
 
-    public L2capNetworkProvider(Context context, Handler handler) {
-        this(new Dependencies(), context, handler);
+    public L2capNetworkProvider(Context context) {
+        this(new Dependencies(), context);
     }
 
     @VisibleForTesting
-    public L2capNetworkProvider(Dependencies deps, Context context, Handler handler) {
+    public L2capNetworkProvider(Dependencies deps, Context context) {
         mDeps = deps;
-        mHandler = handler;
-        mProvider = mDeps.getNetworkProvider(context, handler.getLooper());
+        mContext = context;
+        mHandlerThread = mDeps.getHandlerThread();
+        mHandler = new Handler(mHandlerThread.getLooper());
+        mProvider = mDeps.getNetworkProvider(context, mHandlerThread.getLooper());
         mBlanketOffer = new BlanketReservationOffer();
+    }
 
-        final boolean isBleSupported =
-                context.getPackageManager().hasSystemFeature(FEATURE_BLUETOOTH_LE);
-        if (isBleSupported) {
-            context.getSystemService(ConnectivityManager.class).registerNetworkProvider(mProvider);
+    /**
+     * Start L2capNetworkProvider.
+     *
+     * Called on CS Handler thread.
+     */
+    public void start() {
+        final PackageManager pm = mContext.getPackageManager();
+        if (pm.hasSystemFeature(FEATURE_BLUETOOTH_LE)) {
+            mContext.getSystemService(ConnectivityManager.class).registerNetworkProvider(mProvider);
             mProvider.registerNetworkOffer(BlanketReservationOffer.SCORE,
                     BlanketReservationOffer.CAPABILITIES, mHandler::post, mBlanketOffer);
         }
     }
 }
-
diff --git a/tests/cts/net/Android.bp b/tests/cts/net/Android.bp
index a9ac29c..7327f1b 100644
--- a/tests/cts/net/Android.bp
+++ b/tests/cts/net/Android.bp
@@ -95,6 +95,7 @@
         "NetworkStackApiCurrentShims",
     ],
     test_suites: [
+        "automotive-general-tests",
         "cts",
         "mts-tethering",
         "mcts-tethering",
diff --git a/tests/cts/net/src/android/net/cts/NetworkReservationTest.kt b/tests/cts/net/src/android/net/cts/NetworkReservationTest.kt
index 0b10ef6..f05bf15 100644
--- a/tests/cts/net/src/android/net/cts/NetworkReservationTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkReservationTest.kt
@@ -33,6 +33,7 @@
 import android.os.Build
 import android.os.Handler
 import android.os.HandlerThread
+import android.platform.test.annotations.AppModeFull
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.testutils.ConnectivityModuleTest
 import com.android.testutils.DevSdkIgnoreRule
@@ -71,6 +72,7 @@
 private const val NO_CB_TIMEOUT_MS = 200L
 
 // TODO: integrate with CSNetworkReservationTest and move to common tests.
+@AppModeFull(reason = "CHANGE_NETWORK_STATE, MANAGE_TEST_NETWORKS not grantable to instant apps")
 @ConnectivityModuleTest
 @RunWith(DevSdkIgnoreRunner::class)
 @DevSdkIgnoreRule.IgnoreUpTo(Build.VERSION_CODES.R)
diff --git a/tests/cts/netpermission/updatestatspermission/Android.bp b/tests/cts/netpermission/updatestatspermission/Android.bp
index b324dc8..0ff98e7 100644
--- a/tests/cts/netpermission/updatestatspermission/Android.bp
+++ b/tests/cts/netpermission/updatestatspermission/Android.bp
@@ -33,6 +33,7 @@
 
     // Tag this module as a cts test artifact
     test_suites: [
+        "automotive-general-tests",
         "cts",
         "general-tests",
     ],
diff --git a/tests/unit/java/com/android/server/L2capNetworkProviderTest.kt b/tests/unit/java/com/android/server/L2capNetworkProviderTest.kt
index ffa9828..5a7515e 100644
--- a/tests/unit/java/com/android/server/L2capNetworkProviderTest.kt
+++ b/tests/unit/java/com/android/server/L2capNetworkProviderTest.kt
@@ -81,6 +81,7 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         doReturn(provider).`when`(deps).getNetworkProvider(any(), any())
+        doReturn(handlerThread).`when`(deps).getHandlerThread()
         doReturn(cm).`when`(context).getSystemService(eq(ConnectivityManager::class.java))
         doReturn(pm).`when`(context).getPackageManager()
         doReturn(true).`when`(pm).hasSystemFeature(FEATURE_BLUETOOTH_LE)
@@ -94,7 +95,7 @@
 
     @Test
     fun testNetworkProvider_registeredWhenSupported() {
-        L2capNetworkProvider(deps, context, handler)
+        L2capNetworkProvider(deps, context).start()
         verify(cm).registerNetworkProvider(eq(provider))
         verify(provider).registerNetworkOffer(any(), any(), any(), any())
     }
@@ -102,13 +103,13 @@
     @Test
     fun testNetworkProvider_notRegisteredWhenNotSupported() {
         doReturn(false).`when`(pm).hasSystemFeature(FEATURE_BLUETOOTH_LE)
-        L2capNetworkProvider(deps, context, handler)
+        L2capNetworkProvider(deps, context).start()
         verify(cm, never()).registerNetworkProvider(eq(provider))
     }
 
     fun doTestBlanketOfferIgnoresRequest(request: NetworkRequest) {
         clearInvocations(provider)
-        L2capNetworkProvider(deps, context, handler)
+        L2capNetworkProvider(deps, context).start()
 
         val blanketOfferCaptor = ArgumentCaptor.forClass(NetworkOfferCallback::class.java)
         verify(provider).registerNetworkOffer(any(), any(), any(), blanketOfferCaptor.capture())
@@ -122,7 +123,7 @@
             reservation: NetworkCapabilities
     ) {
         clearInvocations(provider)
-        L2capNetworkProvider(deps, context, handler)
+        L2capNetworkProvider(deps, context).start()
 
         val blanketOfferCaptor = ArgumentCaptor.forClass(NetworkOfferCallback::class.java)
         verify(provider).registerNetworkOffer(any(), any(), any(), blanketOfferCaptor.capture())