Merge changes I32434588,I61efbedb into main

* changes:
  Mark blanket offer as transport primary
  Add createL2capNetwork helper
diff --git a/service/src/com/android/server/L2capNetworkProvider.java b/service/src/com/android/server/L2capNetworkProvider.java
index 787cab5..15c860b 100644
--- a/service/src/com/android/server/L2capNetworkProvider.java
+++ b/service/src/com/android/server/L2capNetworkProvider.java
@@ -30,11 +30,15 @@
 import static android.net.NetworkCapabilities.RES_ID_MATCH_ALL_RESERVATIONS;
 import static android.net.NetworkCapabilities.TRANSPORT_BLUETOOTH;
 import static android.content.pm.PackageManager.FEATURE_BLUETOOTH_LE;
+import static android.system.OsConstants.F_GETFL;
+import static android.system.OsConstants.F_SETFL;
+import static android.system.OsConstants.O_NONBLOCK;
 
 import android.annotation.Nullable;
 import android.bluetooth.BluetoothAdapter;
 import android.bluetooth.BluetoothManager;
 import android.bluetooth.BluetoothServerSocket;
+import android.bluetooth.BluetoothSocket;
 import android.content.Context;
 import android.content.pm.PackageManager;
 import android.net.ConnectivityManager;
@@ -48,10 +52,14 @@
 import android.os.Handler;
 import android.os.HandlerThread;
 import android.os.Looper;
+import android.os.ParcelFileDescriptor;
+import android.system.Os;
 import android.util.ArraySet;
 import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.net.module.util.ServiceConnectivityJni;
+import com.android.server.net.L2capNetwork;
 
 import java.io.IOException;
 import java.util.Set;
@@ -84,6 +92,10 @@
     @Nullable
     private BluetoothManager mBluetoothManager;
 
+    // Note: IFNAMSIZ is 16.
+    private static final String TUN_IFNAME = "l2cap-tun";
+    private static int sTunIndex = 0;
+
     /**
      * The blanket reservation offer is used to create an L2CAP server network, i.e. a network
      * based on a BluetoothServerSocket.
@@ -92,10 +104,12 @@
      * requests that do not have a NetworkSpecifier set.
      */
     private class BlanketReservationOffer implements NetworkOfferCallback {
-        // TODO: ensure that once the incoming request is satisfied, the blanket offer does not get
-        // unneeded. This means the blanket offer must always outscore the reserved offer. This
-        // might require setting the blanket offer as setTransportPrimary().
-        public static final NetworkScore SCORE = new NetworkScore.Builder().build();
+        // Set as transport primary to ensure that the BlanketReservationOffer always outscores the
+        // ReservedServerOffer, because as soon as the BlanketReservationOffer receives an
+        // onNetworkUnneeded() callback, it will tear down the associated reserved offer.
+        public static final NetworkScore SCORE = new NetworkScore.Builder()
+                .setTransportPrimary(true)
+                .build();
         // Note the missing NET_CAPABILITY_NOT_RESTRICTED marking the network as restricted.
         public static final NetworkCapabilities CAPABILITIES;
         static {
@@ -222,6 +236,40 @@
         mProvider.unregisterNetworkOffer(reservedOffer);
     }
 
+    @Nullable
+    private static ParcelFileDescriptor createTunInterface(String ifname) {
+        final ParcelFileDescriptor fd;
+        try {
+            fd = ParcelFileDescriptor.adoptFd(
+                    ServiceConnectivityJni.createTunTap(
+                            true /*isTun*/, true /*hasCarrier*/, true /*setIffMulticast*/, ifname));
+            ServiceConnectivityJni.bringUpInterface(ifname);
+            // TODO: consider adding a parameter to createTunTap() (or the Builder that should
+            // be added) to configure i/o blocking.
+            final int flags = Os.fcntlInt(fd.getFileDescriptor(), F_GETFL, 0);
+            Os.fcntlInt(fd.getFileDescriptor(), F_SETFL, flags & ~O_NONBLOCK);
+        } catch (Exception e) {
+            // Note: createTunTap currently throws an IllegalStateException on failure.
+            // TODO: native functions should throw ErrnoException.
+            Log.e(TAG, "Failed to create tun interface", e);
+            return null;
+        }
+        return fd;
+    }
+
+    @Nullable
+    private L2capNetwork createL2capNetwork(BluetoothSocket socket, NetworkCapabilities caps,
+            L2capNetwork.ICallback cb) {
+        final String ifname = TUN_IFNAME + String.valueOf(sTunIndex++);
+        final ParcelFileDescriptor tunFd = createTunInterface(ifname);
+        if (tunFd == null) {
+            return null;
+        }
+
+        return new L2capNetwork(mHandler, mContext, mProvider, ifname, socket, tunFd, caps, cb);
+    }
+
+
     private class ReservedServerOffer implements NetworkOfferCallback {
         private final NetworkCapabilities mReservedCapabilities;
         private final BluetoothServerSocket mServerSocket;