• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.connectivity.mdns;
18 
19 import static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;
20 import static android.net.NetworkCapabilities.TRANSPORT_VPN;
21 import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
22 
23 import static com.android.net.module.util.HandlerUtils.ensureRunningOnHandlerThread;
24 import static com.android.server.connectivity.mdns.util.MdnsUtils.isNetworkMatched;
25 
26 import android.annotation.NonNull;
27 import android.annotation.Nullable;
28 import android.annotation.RequiresApi;
29 import android.annotation.SuppressLint;
30 import android.content.BroadcastReceiver;
31 import android.content.Context;
32 import android.content.Intent;
33 import android.content.IntentFilter;
34 import android.net.ConnectivityManager;
35 import android.net.ConnectivityManager.NetworkCallback;
36 import android.net.LinkAddress;
37 import android.net.LinkProperties;
38 import android.net.Network;
39 import android.net.NetworkCapabilities;
40 import android.net.NetworkRequest;
41 import android.net.TetheringManager;
42 import android.net.TetheringManager.TetheringEventCallback;
43 import android.net.wifi.p2p.WifiP2pGroup;
44 import android.net.wifi.p2p.WifiP2pInfo;
45 import android.net.wifi.p2p.WifiP2pManager;
46 import android.os.Build;
47 import android.os.Handler;
48 import android.os.Looper;
49 import android.util.ArrayMap;
50 import android.util.SparseArray;
51 
52 import com.android.internal.annotations.VisibleForTesting;
53 import com.android.net.module.util.CollectionUtils;
54 import com.android.net.module.util.LinkPropertiesUtils.CompareResult;
55 import com.android.net.module.util.SharedLog;
56 
57 import java.io.IOException;
58 import java.net.NetworkInterface;
59 import java.net.SocketException;
60 import java.util.ArrayList;
61 import java.util.List;
62 import java.util.Objects;
63 
64 /**
65  * The {@link MdnsSocketProvider} manages the multiple sockets for mDns.
66  *
67  * <p>This class is not thread safe, it is intended to be used only from the looper thread.
68  * However, the constructor is an exception, as it is called on another thread;
69  * therefore for thread safety all members of this class MUST either be final or initialized
70  * to their default value (0, false or null).
71  *
72  */
73 @RequiresApi(Build.VERSION_CODES.TIRAMISU)
74 public class MdnsSocketProvider {
75     private static final String TAG = MdnsSocketProvider.class.getSimpleName();
76     private static final boolean DBG = MdnsDiscoveryManager.DBG;
77     // This buffer size matches what MdnsSocketClient uses currently.
78     // But 1440 should generally be enough because of standard Ethernet.
79     // Note: mdnsresponder mDNSEmbeddedAPI.h uses 8940 for Ethernet jumbo frames.
80     private static final int READ_BUFFER_SIZE = 2048;
81     private static final int IFACE_IDX_NOT_EXIST = -1;
82     @NonNull private final Context mContext;
83     @NonNull private final Looper mLooper;
84     @NonNull private final Handler mHandler;
85     @NonNull private final Dependencies mDependencies;
86     @NonNull private final NetworkCallback mNetworkCallback;
87     @NonNull private final TetheringEventCallback mTetheringEventCallback;
88     @NonNull private final AbstractSocketNetlinkMonitor mSocketNetlinkMonitor;
89     @NonNull private final SharedLog mSharedLog;
90     private final ArrayMap<Network, SocketInfo> mNetworkSockets = new ArrayMap<>();
91     private final ArrayMap<String, SocketInfo> mTetherInterfaceSockets = new ArrayMap<>();
92     private final ArrayMap<Network, LinkProperties> mActiveNetworksLinkProperties =
93             new ArrayMap<>();
94     private final ArrayMap<Network, int[]> mActiveNetworksTransports = new ArrayMap<>();
95     private final ArrayMap<SocketCallback, Network> mCallbacksToRequestedNetworks =
96             new ArrayMap<>();
97     private final List<String> mLocalOnlyInterfaces = new ArrayList<>();
98     private final List<String> mTetheredInterfaces = new ArrayList<>();
99     // mIfaceIdxToLinkProperties should not be cleared in maybeStopMonitoringSockets() because
100     // the netlink monitor is never stop and the old states must be kept.
101     private final SparseArray<LinkProperties> mIfaceIdxToLinkProperties = new SparseArray<>();
102     private final byte[] mPacketReadBuffer = new byte[READ_BUFFER_SIZE];
103     @NonNull
104     private final SocketRequestMonitor mSocketRequestMonitor;
105     private boolean mMonitoringSockets = false;
106     private boolean mRequestStop = false;
107     private String mWifiP2pTetherInterface = null;
108 
109     private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
110         @Override
111         public void onReceive(Context context, Intent intent) {
112             final String newP2pIface = getWifiP2pInterface(intent);
113 
114             if (!mMonitoringSockets || !hasAllNetworksRequest()) {
115                 mWifiP2pTetherInterface = newP2pIface;
116                 return;
117             }
118 
119             // If already serving from the correct interface, nothing to do.
120             if (Objects.equals(mWifiP2pTetherInterface, newP2pIface)) return;
121 
122             if (mWifiP2pTetherInterface != null) {
123                 if (newP2pIface != null) {
124                     mSharedLog.wtf("Wifi p2p interface is changed from " + mWifiP2pTetherInterface
125                             + " to " + newP2pIface + " without null broadcast");
126                 }
127                 // Remove the socket.
128                 removeTetherInterfaceSocket(mWifiP2pTetherInterface);
129             }
130 
131             // Update mWifiP2pTetherInterface
132             mWifiP2pTetherInterface = newP2pIface;
133 
134             // Check whether the socket for wifi p2p interface is created or not.
135             final boolean socketAlreadyExists = mTetherInterfaceSockets.get(newP2pIface) != null;
136             if (newP2pIface != null && !socketAlreadyExists) {
137                 // Create a socket for wifi p2p interface.
138                 final int ifaceIndex =
139                         mDependencies.getNetworkInterfaceIndexByName(newP2pIface, mSharedLog);
140                 createSocket(LOCAL_NET, createLPForTetheredInterface(newP2pIface, ifaceIndex));
141             }
142         }
143     };
144 
145     @Nullable
getWifiP2pInterface(final Intent intent)146     private static String getWifiP2pInterface(final Intent intent) {
147         final WifiP2pGroup group =
148                 intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_GROUP);
149         final WifiP2pInfo p2pInfo =
150                 intent.getParcelableExtra(WifiP2pManager.EXTRA_WIFI_P2P_INFO);
151         if (group == null || p2pInfo == null) {
152             return null;
153         }
154 
155         if (!p2pInfo.groupFormed) {
156             return null;
157         } else {
158             return group.getInterface();
159         }
160     }
161 
MdnsSocketProvider(@onNull Context context, @NonNull Looper looper, @NonNull SharedLog sharedLog, @NonNull SocketRequestMonitor socketRequestMonitor)162     public MdnsSocketProvider(@NonNull Context context, @NonNull Looper looper,
163             @NonNull SharedLog sharedLog,
164             @NonNull SocketRequestMonitor socketRequestMonitor) {
165         this(context, looper, new Dependencies(), sharedLog, socketRequestMonitor);
166     }
167 
168     @SuppressLint("NewApi")
MdnsSocketProvider(@onNull Context context, @NonNull Looper looper, @NonNull Dependencies deps, @NonNull SharedLog sharedLog, @NonNull SocketRequestMonitor socketRequestMonitor)169     MdnsSocketProvider(@NonNull Context context, @NonNull Looper looper,
170             @NonNull Dependencies deps, @NonNull SharedLog sharedLog,
171             @NonNull SocketRequestMonitor socketRequestMonitor) {
172         mContext = context;
173         mLooper = looper;
174         mHandler = new Handler(looper);
175         mDependencies = deps;
176         mSharedLog = sharedLog;
177         mSocketRequestMonitor = socketRequestMonitor;
178         mNetworkCallback = new NetworkCallback() {
179             @Override
180             public void onLost(Network network) {
181                 mActiveNetworksLinkProperties.remove(network);
182                 mActiveNetworksTransports.remove(network);
183                 removeNetworkSocket(network);
184             }
185 
186             @Override
187             public void onCapabilitiesChanged(@NonNull Network network,
188                     @NonNull NetworkCapabilities networkCapabilities) {
189                 mActiveNetworksTransports.put(network, networkCapabilities.getTransportTypes());
190             }
191 
192             @Override
193             public void onLinkPropertiesChanged(Network network, LinkProperties lp) {
194                 handleLinkPropertiesChanged(network, lp);
195             }
196         };
197         mTetheringEventCallback = new TetheringEventCallback() {
198             @Override
199             public void onLocalOnlyInterfacesChanged(@NonNull List<String> interfaces) {
200                 handleTetherInterfacesChanged(mLocalOnlyInterfaces, interfaces);
201             }
202 
203             @Override
204             public void onTetheredInterfacesChanged(@NonNull List<String> interfaces) {
205                 handleTetherInterfacesChanged(mTetheredInterfaces, interfaces);
206             }
207         };
208 
209         mSocketNetlinkMonitor = mDependencies.createSocketNetlinkMonitor(mHandler,
210                 mSharedLog.forSubComponent("NetlinkMonitor"), new NetLinkMessageProcessor());
211 
212         // Register a intent receiver to listen wifi p2p interface changes.
213         // Note: The wifi p2p interface change is only notified via
214         // TetheringEventCallback#onLocalOnlyInterfacesChanged if the device is the wifi p2p group
215         // owner. In this case, MdnsSocketProvider will receive duplicate interface changes and must
216         // ignore the later notification because the socket has already been created. There is only
217         // one notification from the wifi p2p connection change intent if the device is not the wifi
218         // p2p group owner.
219         final IntentFilter intentFilter =
220                 new IntentFilter(WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION);
221         mContext.registerReceiver(
222                 mIntentReceiver, intentFilter, null /* broadcastPermission */, mHandler);
223     }
224 
225     /**
226      * Dependencies of MdnsSocketProvider, for injection in tests.
227      */
228     @VisibleForTesting
229     public static class Dependencies {
230         /*** Get network interface by given interface name */
getNetworkInterfaceByName(@onNull String interfaceName)231         public NetworkInterfaceWrapper getNetworkInterfaceByName(@NonNull String interfaceName)
232                 throws SocketException {
233             final NetworkInterface ni = NetworkInterface.getByName(interfaceName);
234             return ni == null ? null : new NetworkInterfaceWrapper(ni);
235         }
236 
237         /*** Create a MdnsInterfaceSocket */
createMdnsInterfaceSocket( @onNull NetworkInterface networkInterface, int port, @NonNull Looper looper, @NonNull byte[] packetReadBuffer, @NonNull SharedLog sharedLog)238         public MdnsInterfaceSocket createMdnsInterfaceSocket(
239                 @NonNull NetworkInterface networkInterface, int port, @NonNull Looper looper,
240                 @NonNull byte[] packetReadBuffer, @NonNull SharedLog sharedLog) throws IOException {
241             return new MdnsInterfaceSocket(networkInterface, port, looper, packetReadBuffer,
242                     sharedLog);
243         }
244 
245         /*** Get network interface by given interface name */
getNetworkInterfaceIndexByName(@onNull final String ifaceName, @NonNull SharedLog sharedLog)246         public int getNetworkInterfaceIndexByName(@NonNull final String ifaceName,
247                 @NonNull SharedLog sharedLog) {
248             final NetworkInterface iface;
249             try {
250                 iface = NetworkInterface.getByName(ifaceName);
251             } catch (SocketException e) {
252                 sharedLog.e("Error querying interface", e);
253                 return IFACE_IDX_NOT_EXIST;
254             }
255             if (iface == null) {
256                 sharedLog.e("Interface not found: " + ifaceName);
257                 return IFACE_IDX_NOT_EXIST;
258             }
259             return iface.getIndex();
260         }
261         /*** Creates a SocketNetlinkMonitor */
createSocketNetlinkMonitor( @onNull final Handler handler, @NonNull final SharedLog log, @NonNull final NetLinkMonitorCallBack cb)262         public AbstractSocketNetlinkMonitor createSocketNetlinkMonitor(
263                 @NonNull final Handler handler,
264                 @NonNull final SharedLog log,
265                 @NonNull final NetLinkMonitorCallBack cb) {
266             return SocketNetLinkMonitorFactory.createNetLinkMonitor(handler, log, cb);
267         }
268     }
269     /**
270      * The callback interface for the netlink monitor messages.
271      */
272     public interface NetLinkMonitorCallBack {
273         /**
274          * Handles the interface address add or update.
275          */
addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull LinkAddress newAddress)276         void addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull LinkAddress newAddress);
277 
278 
279         /**
280          * Handles the interface address delete.
281          */
deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress)282         void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress);
283     }
284     private class NetLinkMessageProcessor implements NetLinkMonitorCallBack {
285 
286         @Override
addOrUpdateInterfaceAddress(int ifaceIdx, @NonNull final LinkAddress newAddress)287         public void addOrUpdateInterfaceAddress(int ifaceIdx,
288                 @NonNull final LinkAddress newAddress) {
289 
290             LinkProperties linkProperties;
291             linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx);
292             if (linkProperties == null) {
293                 linkProperties = new LinkProperties();
294                 mIfaceIdxToLinkProperties.put(ifaceIdx, linkProperties);
295             }
296             boolean updated = linkProperties.addLinkAddress(newAddress);
297 
298             if (!updated) {
299                 return;
300             }
301             maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses());
302         }
303 
304         @Override
deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress)305         public void deleteInterfaceAddress(int ifaceIdx, @NonNull LinkAddress deleteAddress) {
306             LinkProperties linkProperties;
307             boolean updated = false;
308             linkProperties = mIfaceIdxToLinkProperties.get(ifaceIdx);
309             if (linkProperties != null) {
310                 updated = linkProperties.removeLinkAddress(deleteAddress);
311                 if (linkProperties.getLinkAddresses().isEmpty()) {
312                     mIfaceIdxToLinkProperties.remove(ifaceIdx);
313                 }
314             }
315 
316             if (linkProperties == null || !updated) {
317                 return;
318             }
319             maybeUpdateTetheringSocketAddress(ifaceIdx, linkProperties.getLinkAddresses());
320 
321         }
322     }
323     /*** Data class for storing socket related info  */
324     private static class SocketInfo {
325         final MdnsInterfaceSocket mSocket;
326         final List<LinkAddress> mAddresses;
327         final int[] mTransports;
328         @NonNull final SocketKey mSocketKey;
329 
SocketInfo(MdnsInterfaceSocket socket, List<LinkAddress> addresses, int[] transports, @NonNull SocketKey socketKey)330         SocketInfo(MdnsInterfaceSocket socket, List<LinkAddress> addresses, int[] transports,
331                 @NonNull SocketKey socketKey) {
332             mSocket = socket;
333             mAddresses = new ArrayList<>(addresses);
334             mTransports = transports;
335             mSocketKey = socketKey;
336         }
337     }
338 
339     /*** Start monitoring sockets by listening callbacks for sockets creation or removal */
340     @SuppressLint("NewApi")
startMonitoringSockets()341     public void startMonitoringSockets() {
342         ensureRunningOnHandlerThread(mHandler);
343         mRequestStop = false; // Reset stop request flag.
344         if (mMonitoringSockets) {
345             mSharedLog.v("Already monitoring sockets.");
346             return;
347         }
348         mSharedLog.i("Start monitoring sockets.");
349         mContext.getSystemService(ConnectivityManager.class).registerNetworkCallback(
350                 new NetworkRequest.Builder().clearCapabilities().build(),
351                 mNetworkCallback, mHandler);
352 
353         final TetheringManager tetheringManager = mContext.getSystemService(TetheringManager.class);
354         tetheringManager.registerTetheringEventCallback(mHandler::post, mTetheringEventCallback);
355 
356         if (mSocketNetlinkMonitor.isSupported()) {
357             mHandler.post(mSocketNetlinkMonitor::startMonitoring);
358         }
359         mMonitoringSockets = true;
360     }
361     /**
362      * Start netlink monitor.
363      */
startNetLinkMonitor()364     public void startNetLinkMonitor() {
365         ensureRunningOnHandlerThread(mHandler);
366         if (mSocketNetlinkMonitor.isSupported()) {
367             mSocketNetlinkMonitor.startMonitoring();
368         }
369     }
370 
371     @SuppressLint("NewApi")
maybeStopMonitoringSockets()372     private void maybeStopMonitoringSockets() {
373         if (!mMonitoringSockets) return; // Already unregistered.
374         if (!mRequestStop) return; // No stop request.
375 
376         // Only unregister the network callback if there is no socket request.
377         if (mCallbacksToRequestedNetworks.isEmpty()) {
378             mSharedLog.i("Stop monitoring sockets.");
379             mContext.getSystemService(ConnectivityManager.class)
380                     .unregisterNetworkCallback(mNetworkCallback);
381 
382             final TetheringManager tetheringManager = mContext.getSystemService(
383                     TetheringManager.class);
384             tetheringManager.unregisterTetheringEventCallback(mTetheringEventCallback);
385             // Clear all saved status.
386             mActiveNetworksLinkProperties.clear();
387             mNetworkSockets.clear();
388             mTetherInterfaceSockets.clear();
389             mLocalOnlyInterfaces.clear();
390             mTetheredInterfaces.clear();
391             mMonitoringSockets = false;
392         }
393         // The netlink monitor is not stopped here because the MdnsSocketProvider need to listen
394         // to all the netlink updates when the system is up and running.
395     }
396 
397     /*** Request to stop monitoring sockets and unregister callbacks */
requestStopWhenInactive()398     public void requestStopWhenInactive() {
399         ensureRunningOnHandlerThread(mHandler);
400         if (!mMonitoringSockets) {
401             mSharedLog.v("Monitoring sockets hasn't been started.");
402             return;
403         }
404         mRequestStop = true;
405         maybeStopMonitoringSockets();
406     }
407 
matchRequestedNetwork(Network network)408     private boolean matchRequestedNetwork(Network network) {
409         return hasAllNetworksRequest()
410                 || mCallbacksToRequestedNetworks.containsValue(network);
411     }
412 
hasAllNetworksRequest()413     private boolean hasAllNetworksRequest() {
414         return mCallbacksToRequestedNetworks.containsValue(null);
415     }
416 
handleLinkPropertiesChanged(Network network, LinkProperties lp)417     private void handleLinkPropertiesChanged(Network network, LinkProperties lp) {
418         mActiveNetworksLinkProperties.put(network, lp);
419         if (!matchRequestedNetwork(network)) {
420             if (DBG) {
421                 mSharedLog.v("Ignore LinkProperties change. There is no request for the"
422                         + " Network:" + network);
423             }
424             return;
425         }
426 
427         final NetworkAsKey networkKey = new NetworkAsKey(network);
428         final SocketInfo socketInfo = mNetworkSockets.get(network);
429         if (socketInfo == null) {
430             createSocket(networkKey, lp);
431         } else {
432             updateSocketInfoAddress(network, socketInfo, lp.getLinkAddresses());
433         }
434     }
maybeUpdateTetheringSocketAddress(int ifaceIndex, @NonNull final List<LinkAddress> updatedAddresses)435     private void maybeUpdateTetheringSocketAddress(int ifaceIndex,
436             @NonNull final List<LinkAddress> updatedAddresses) {
437         for (int i = 0; i < mTetherInterfaceSockets.size(); ++i) {
438             String tetheringInterfaceName = mTetherInterfaceSockets.keyAt(i);
439             if (mDependencies.getNetworkInterfaceIndexByName(tetheringInterfaceName, mSharedLog)
440                     == ifaceIndex) {
441                 updateSocketInfoAddress(null /* network */,
442                         mTetherInterfaceSockets.valueAt(i), updatedAddresses);
443                 return;
444             }
445         }
446     }
447 
updateSocketInfoAddress(@ullable final Network network, @NonNull final SocketInfo socketInfo, @NonNull final List<LinkAddress> addresses)448     private void updateSocketInfoAddress(@Nullable final Network network,
449             @NonNull final SocketInfo socketInfo,
450             @NonNull final List<LinkAddress> addresses) {
451         // Update the addresses of this socket.
452         socketInfo.mAddresses.clear();
453         socketInfo.mAddresses.addAll(addresses);
454         // Try to join the group again.
455         socketInfo.mSocket.joinGroup(addresses);
456 
457         notifyAddressesChanged(network, socketInfo, addresses);
458     }
createLPForTetheredInterface(@onNull final String interfaceName, int ifaceIndex)459     private LinkProperties createLPForTetheredInterface(@NonNull final String interfaceName,
460             int ifaceIndex) {
461         final LinkProperties linkProperties =
462                 new LinkProperties(mIfaceIdxToLinkProperties.get(ifaceIndex));
463         linkProperties.setInterfaceName(interfaceName);
464         return linkProperties;
465     }
466 
handleTetherInterfacesChanged(List<String> current, List<String> updated)467     private void handleTetherInterfacesChanged(List<String> current, List<String> updated) {
468         if (!hasAllNetworksRequest()) {
469             // Currently, the network for tethering can not be requested, so the sockets for
470             // tethering are only created if there is a request for all networks (interfaces).
471             // Therefore, only update the interface list and skip this change if no such request.
472             if (DBG) {
473                 mSharedLog.v("Ignore tether interfaces change. There is no request for all"
474                         + " networks.");
475             }
476             current.clear();
477             current.addAll(updated);
478             return;
479         }
480 
481         final CompareResult<String> interfaceDiff = new CompareResult<>(
482                 current, updated);
483         for (String name : interfaceDiff.added) {
484             // Check if a socket has been created for the interface
485             final SocketInfo socketInfo = mTetherInterfaceSockets.get(name);
486             if (socketInfo != null) {
487                 if (DBG) {
488                     mSharedLog.i("Socket is existed for interface:" + name);
489                 }
490                 continue;
491             }
492 
493             int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(name, mSharedLog);
494             createSocket(LOCAL_NET, createLPForTetheredInterface(name, ifaceIndex));
495         }
496         for (String name : interfaceDiff.removed) {
497             removeTetherInterfaceSocket(name);
498         }
499         current.clear();
500         current.addAll(updated);
501     }
502 
createSocket(NetworkKey networkKey, LinkProperties lp)503     private void createSocket(NetworkKey networkKey, LinkProperties lp) {
504         final String interfaceName = lp.getInterfaceName();
505         if (interfaceName == null) {
506             mSharedLog.e("Can not create socket with null interface name.");
507             return;
508         }
509 
510         try {
511             final NetworkInterfaceWrapper networkInterface =
512                     mDependencies.getNetworkInterfaceByName(interfaceName);
513             // There are no transports for tethered interfaces. Other interfaces should always
514             // have transports since LinkProperties updates are always sent after
515             // NetworkCapabilities updates.
516             final int[] transports;
517             if (networkKey == LOCAL_NET) {
518                 transports = new int[0];
519             } else {
520                 final int[] knownTransports =
521                         mActiveNetworksTransports.get(((NetworkAsKey) networkKey).mNetwork);
522                 if (knownTransports != null) {
523                     transports = knownTransports;
524                 } else {
525                     mSharedLog.wtf("transports is missing for key: " + networkKey);
526                     transports = new int[0];
527                 }
528             }
529             if (networkInterface == null || !isMdnsCapableInterface(networkInterface, transports)) {
530                 return;
531             }
532 
533             mSharedLog.log("Create socket on net:" + networkKey + ", ifName:" + interfaceName);
534             final MdnsInterfaceSocket socket = mDependencies.createMdnsInterfaceSocket(
535                     networkInterface.getNetworkInterface(), MdnsConstants.MDNS_PORT, mLooper,
536                     mPacketReadBuffer, mSharedLog.forSubComponent(
537                             MdnsInterfaceSocket.class.getSimpleName() + "/" + interfaceName));
538             final List<LinkAddress> addresses = lp.getLinkAddresses();
539             final Network network =
540                     networkKey == LOCAL_NET ? null : ((NetworkAsKey) networkKey).mNetwork;
541             final SocketKey socketKey = new SocketKey(network, networkInterface.getIndex());
542             // TODO: technically transport types are mutable, although generally not in ways that
543             // would meaningfully impact the logic using it here. Consider updating logic to
544             // support transports being added/removed.
545             final SocketInfo socketInfo = new SocketInfo(socket, addresses, transports, socketKey);
546             if (networkKey == LOCAL_NET) {
547                 mTetherInterfaceSockets.put(interfaceName, socketInfo);
548             } else {
549                 mNetworkSockets.put(network, socketInfo);
550             }
551             // Try to join IPv4/IPv6 group.
552             socket.joinGroup(addresses);
553 
554             // Notify the listeners which need this socket.
555             notifySocketCreated(network, socketInfo);
556         } catch (IOException e) {
557             mSharedLog.e("Create socket failed ifName:" + interfaceName, e);
558         }
559     }
560 
isMdnsCapableInterface( @onNull NetworkInterfaceWrapper iface, @NonNull int[] transports)561     private boolean isMdnsCapableInterface(
562             @NonNull NetworkInterfaceWrapper iface, @NonNull int[] transports) {
563         try {
564             // Never try mDNS on cellular, or on interfaces with incompatible flags
565             if (CollectionUtils.contains(transports, TRANSPORT_CELLULAR)
566                     || iface.isLoopback()
567                     || iface.isVirtual()
568                     || !iface.isUp()) {
569                 return false;
570             }
571 
572             // Otherwise, always try mDNS on non-VPN Wifi.
573             if (!CollectionUtils.contains(transports, TRANSPORT_VPN)
574                     && CollectionUtils.contains(transports, TRANSPORT_WIFI)) {
575                 return true;
576             }
577 
578             // For other transports, or no transports (tethering downstreams), do mDNS based on the
579             // interface flags. This is not always reliable (for example some Wifi interfaces may
580             // not have the MULTICAST flag even though they can do mDNS, and some cellular
581             // interfaces may have the BROADCAST or MULTICAST flags), so checks are done based on
582             // transports above in priority.
583             return iface.supportsMulticast();
584         } catch (SocketException e) {
585             mSharedLog.e("Error checking interface flags", e);
586             return false;
587         }
588     }
589 
removeNetworkSocket(Network network)590     private void removeNetworkSocket(Network network) {
591         final SocketInfo socketInfo = mNetworkSockets.remove(network);
592         if (socketInfo == null) return;
593 
594         socketInfo.mSocket.destroy();
595         notifyInterfaceDestroyed(network, socketInfo);
596         mSocketRequestMonitor.onSocketDestroyed(network, socketInfo.mSocket);
597         mSharedLog.log("Remove socket on net:" + network);
598     }
599 
removeTetherInterfaceSocket(String interfaceName)600     private void removeTetherInterfaceSocket(String interfaceName) {
601         final SocketInfo socketInfo = mTetherInterfaceSockets.remove(interfaceName);
602         if (socketInfo == null) return;
603         socketInfo.mSocket.destroy();
604         notifyInterfaceDestroyed(null /* network */, socketInfo);
605         mSocketRequestMonitor.onSocketDestroyed(null /* network */, socketInfo.mSocket);
606         mSharedLog.log("Remove socket on ifName:" + interfaceName);
607     }
608 
notifySocketCreated(Network network, SocketInfo socketInfo)609     private void notifySocketCreated(Network network, SocketInfo socketInfo) {
610         for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) {
611             final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i);
612             if (isNetworkMatched(requestedNetwork, network)) {
613                 mCallbacksToRequestedNetworks.keyAt(i).onSocketCreated(socketInfo.mSocketKey,
614                         socketInfo.mSocket, socketInfo.mAddresses);
615                 mSocketRequestMonitor.onSocketRequestFulfilled(network, socketInfo.mSocket,
616                         socketInfo.mTransports);
617             }
618         }
619     }
620 
notifyInterfaceDestroyed(Network network, SocketInfo socketInfo)621     private void notifyInterfaceDestroyed(Network network, SocketInfo socketInfo) {
622         for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) {
623             final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i);
624             if (isNetworkMatched(requestedNetwork, network)) {
625                 mCallbacksToRequestedNetworks.keyAt(i)
626                         .onInterfaceDestroyed(socketInfo.mSocketKey, socketInfo.mSocket);
627             }
628         }
629     }
630 
notifyAddressesChanged(Network network, SocketInfo socketInfo, List<LinkAddress> addresses)631     private void notifyAddressesChanged(Network network, SocketInfo socketInfo,
632             List<LinkAddress> addresses) {
633         for (int i = 0; i < mCallbacksToRequestedNetworks.size(); i++) {
634             final Network requestedNetwork = mCallbacksToRequestedNetworks.valueAt(i);
635             if (isNetworkMatched(requestedNetwork, network)) {
636                 mCallbacksToRequestedNetworks.keyAt(i)
637                         .onAddressesChanged(socketInfo.mSocketKey, socketInfo.mSocket, addresses);
638             }
639         }
640     }
641 
retrieveAndNotifySocketFromNetwork(Network network, SocketCallback cb)642     private void retrieveAndNotifySocketFromNetwork(Network network, SocketCallback cb) {
643         final SocketInfo socketInfo = mNetworkSockets.get(network);
644         if (socketInfo == null) {
645             final LinkProperties lp = mActiveNetworksLinkProperties.get(network);
646             if (lp == null) {
647                 // The requested network is not existed. Maybe wait for LinkProperties change later.
648                 if (DBG) mSharedLog.v("There is no LinkProperties for this network:" + network);
649                 return;
650             }
651             createSocket(new NetworkAsKey(network), lp);
652         } else {
653             // Notify the socket for requested network.
654             cb.onSocketCreated(socketInfo.mSocketKey, socketInfo.mSocket, socketInfo.mAddresses);
655             mSocketRequestMonitor.onSocketRequestFulfilled(network, socketInfo.mSocket,
656                     socketInfo.mTransports);
657         }
658     }
659 
retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb)660     private void retrieveAndNotifySocketFromInterface(String interfaceName, SocketCallback cb) {
661         final SocketInfo socketInfo = mTetherInterfaceSockets.get(interfaceName);
662         if (socketInfo == null) {
663             int ifaceIndex = mDependencies.getNetworkInterfaceIndexByName(interfaceName,
664                     mSharedLog);
665             createSocket(
666                     LOCAL_NET,
667                     createLPForTetheredInterface(interfaceName, ifaceIndex));
668         } else {
669             // Notify the socket for requested network.
670             cb.onSocketCreated(socketInfo.mSocketKey, socketInfo.mSocket, socketInfo.mAddresses);
671             mSocketRequestMonitor.onSocketRequestFulfilled(null /* socketNetwork */,
672                     socketInfo.mSocket, socketInfo.mTransports);
673         }
674     }
675 
676     /**
677      * Request a socket for given network.
678      *
679      * @param network the required network for a socket. Null means create sockets on all possible
680      *                networks (interfaces).
681      * @param cb the callback to listen the socket creation.
682      */
requestSocket(@ullable Network network, @NonNull SocketCallback cb)683     public void requestSocket(@Nullable Network network, @NonNull SocketCallback cb) {
684         ensureRunningOnHandlerThread(mHandler);
685         mSharedLog.log("requestSocket for net:" + network);
686         mCallbacksToRequestedNetworks.put(cb, network);
687         if (network == null) {
688             // Does not specify a required network, create sockets for all possible
689             // networks (interfaces).
690             for (int i = 0; i < mActiveNetworksLinkProperties.size(); i++) {
691                 retrieveAndNotifySocketFromNetwork(mActiveNetworksLinkProperties.keyAt(i), cb);
692             }
693 
694             for (String localInterface : mLocalOnlyInterfaces) {
695                 retrieveAndNotifySocketFromInterface(localInterface, cb);
696             }
697 
698             for (String tetheredInterface : mTetheredInterfaces) {
699                 retrieveAndNotifySocketFromInterface(tetheredInterface, cb);
700             }
701 
702             if (mWifiP2pTetherInterface != null
703                     && !mLocalOnlyInterfaces.contains(mWifiP2pTetherInterface)) {
704                 retrieveAndNotifySocketFromInterface(mWifiP2pTetherInterface, cb);
705             }
706         } else {
707             retrieveAndNotifySocketFromNetwork(network, cb);
708         }
709     }
710 
711     /*** Unrequest the socket */
unrequestSocket(@onNull SocketCallback cb)712     public void unrequestSocket(@NonNull SocketCallback cb) {
713         ensureRunningOnHandlerThread(mHandler);
714         mSharedLog.log("unrequestSocket");
715         mCallbacksToRequestedNetworks.remove(cb);
716         if (hasAllNetworksRequest()) {
717             // Still has a request for all networks (interfaces).
718             return;
719         }
720 
721         // Check if remaining requests are matched any of sockets.
722         for (int i = mNetworkSockets.size() - 1; i >= 0; i--) {
723             final Network network = mNetworkSockets.keyAt(i);
724             if (matchRequestedNetwork(network)) continue;
725             final SocketInfo info = mNetworkSockets.removeAt(i);
726             info.mSocket.destroy();
727             mSocketRequestMonitor.onSocketDestroyed(network, info.mSocket);
728             mSharedLog.log("Remove socket on net:" + network + " after unrequestSocket");
729         }
730 
731         // Remove all sockets for tethering interface because these sockets do not have associated
732         // networks, and they should invoke by a request for all networks (interfaces). If there is
733         // no such request, the sockets for tethering interface should be removed.
734         for (int i = mTetherInterfaceSockets.size() - 1; i >= 0; i--) {
735             final SocketInfo info = mTetherInterfaceSockets.valueAt(i);
736             info.mSocket.destroy();
737             mSocketRequestMonitor.onSocketDestroyed(null /* network */, info.mSocket);
738             mSharedLog.log("Remove socket on ifName:" + mTetherInterfaceSockets.keyAt(i)
739                     + " after unrequestSocket");
740         }
741         mTetherInterfaceSockets.clear();
742 
743         // Try to unregister network callback.
744         maybeStopMonitoringSockets();
745     }
746 
747 
748     /**
749      * Callback used to register socket requests.
750      */
751     public interface SocketCallback {
752         /**
753          * Notify the socket was created for the registered request.
754          *
755          * This may be called immediately when the request is registered with an existing socket,
756          * if it had been created previously for other requests.
757          */
onSocketCreated(@onNull SocketKey socketKey, @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses)758         default void onSocketCreated(@NonNull SocketKey socketKey,
759                 @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {}
760 
761         /**
762          * Notify that the interface was destroyed, so the provided socket cannot be used anymore.
763          *
764          * This indicates that although the socket was still requested, it had to be destroyed.
765          */
onInterfaceDestroyed(@onNull SocketKey socketKey, @NonNull MdnsInterfaceSocket socket)766         default void onInterfaceDestroyed(@NonNull SocketKey socketKey,
767                 @NonNull MdnsInterfaceSocket socket) {}
768 
769         /**
770          * Notify the interface addresses have changed for the network.
771          */
onAddressesChanged(@onNull SocketKey socketKey, @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses)772         default void onAddressesChanged(@NonNull SocketKey socketKey,
773                 @NonNull MdnsInterfaceSocket socket, @NonNull List<LinkAddress> addresses) {}
774     }
775 
776     /**
777      * Global callback indicating when sockets are created or destroyed for requests.
778      */
779     public interface SocketRequestMonitor {
780         /**
781          * Indicates that the socket was used to fulfill the request of one requester.
782          *
783          * There is always at most one socket created for each interface. The interface is available
784          * in {@link MdnsInterfaceSocket#getInterface()}.
785          * @param socketNetwork The network of the socket interface, if any.
786          * @param socket The socket that was provided to a requester.
787          * @param transports Array of TRANSPORT_* from {@link NetworkCapabilities}. Empty if the
788          *                   interface is not part of a network with known transports.
789          */
onSocketRequestFulfilled(@ullable Network socketNetwork, @NonNull MdnsInterfaceSocket socket, @NonNull int[] transports)790         default void onSocketRequestFulfilled(@Nullable Network socketNetwork,
791                 @NonNull MdnsInterfaceSocket socket, @NonNull int[] transports) {}
792 
793         /**
794          * Indicates that a previously created socket was destroyed.
795          *
796          * @param socketNetwork The network of the socket interface, if any.
797          * @param socket The destroyed socket.
798          */
onSocketDestroyed(@ullable Network socketNetwork, @NonNull MdnsInterfaceSocket socket)799         default void onSocketDestroyed(@Nullable Network socketNetwork,
800                 @NonNull MdnsInterfaceSocket socket) {}
801     }
802 
803     private interface NetworkKey {
804     }
805 
806     private static final NetworkKey LOCAL_NET = new NetworkKey() {
807         @Override
808         public String toString() {
809             return "NetworkKey:LOCAL_NET";
810         }
811     };
812 
813     private static class NetworkAsKey implements NetworkKey {
814         private final Network mNetwork;
815 
NetworkAsKey(Network network)816         NetworkAsKey(Network network) {
817             this.mNetwork = network;
818         }
819 
820         @Override
hashCode()821         public int hashCode() {
822             return mNetwork.hashCode();
823         }
824 
825         @Override
equals(@ullable Object other)826         public boolean equals(@Nullable Object other) {
827             if (!(other instanceof NetworkAsKey)) {
828                 return false;
829             }
830             return mNetwork.equals(((NetworkAsKey) other).mNetwork);
831         }
832 
833         @Override
toString()834         public String toString() {
835             return "NetworkAsKey{ network=" + mNetwork + " }";
836         }
837     }
838 }
839