blob: 95717c2cdbe29d8e6e89569ba1a6559946e1c40f [file] [log] [blame]
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001/*
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002 * Copyright (C) 2021 The Android Open Source Project
Irfan Sheriff77ec5582012-03-22 17:01:39 -07003 *
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
17package com.android.server;
18
paulhu2b9ed952022-02-10 21:58:32 +080019import static android.net.ConnectivityManager.NETID_UNSET;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090020import static android.net.NetworkCapabilities.TRANSPORT_VPN;
21import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
Paul Hu019621e2023-01-13 23:26:49 +080022import static android.net.nsd.NsdManager.MDNS_DISCOVERY_MANAGER_EVENT;
paulhu2b9ed952022-02-10 21:58:32 +080023import static android.net.nsd.NsdManager.MDNS_SERVICE_EVENT;
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +090024import static android.net.nsd.NsdManager.RESOLVE_SERVICE_SUCCEEDED;
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +090025import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
paulhu2b9ed952022-02-10 21:58:32 +080026
Remi NGUYEN VANbeb03f12023-03-08 19:03:27 +090027import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
Yuyang Huangde802c82023-05-02 17:14:22 +090028import static com.android.server.connectivity.mdns.MdnsRecord.MAX_LABEL_LENGTH;
Paul Hucdef3532023-06-18 14:47:35 +000029import static com.android.server.connectivity.mdns.util.MdnsUtils.Clock;
Remi NGUYEN VANbeb03f12023-03-08 19:03:27 +090030
Paul Hu23fa2022023-01-13 22:57:24 +080031import android.annotation.NonNull;
Paul Hu4bd98ef2023-01-12 13:42:07 +080032import android.annotation.Nullable;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090033import android.app.ActivityManager;
paulhua262cc12019-08-12 16:25:11 +080034import android.content.Context;
Irfan Sheriff75006652012-04-17 23:15:29 -070035import android.content.Intent;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +090036import android.net.ConnectivityManager;
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +090037import android.net.INetd;
Paul Hu75069ed2023-01-14 00:31:09 +080038import android.net.InetAddresses;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +090039import android.net.LinkProperties;
40import android.net.Network;
paulhu2b9ed952022-02-10 21:58:32 +080041import android.net.mdns.aidl.DiscoveryInfo;
42import android.net.mdns.aidl.GetAddressInfo;
43import android.net.mdns.aidl.IMDnsEventListener;
44import android.net.mdns.aidl.RegistrationInfo;
45import android.net.mdns.aidl.ResolutionInfo;
Irfan Sheriff77ec5582012-03-22 17:01:39 -070046import android.net.nsd.INsdManager;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +090047import android.net.nsd.INsdManagerCallback;
48import android.net.nsd.INsdServiceConnector;
paulhu2b9ed952022-02-10 21:58:32 +080049import android.net.nsd.MDnsManager;
Irfan Sheriff77ec5582012-03-22 17:01:39 -070050import android.net.nsd.NsdManager;
paulhua262cc12019-08-12 16:25:11 +080051import android.net.nsd.NsdServiceInfo;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090052import android.net.wifi.WifiManager;
Paul Hub2e67d32023-04-18 05:50:14 +000053import android.os.Binder;
Hugo Benichi803a2f02017-04-24 11:35:06 +090054import android.os.Handler;
paulhua262cc12019-08-12 16:25:11 +080055import android.os.HandlerThread;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +090056import android.os.IBinder;
Paul Hu4bd98ef2023-01-12 13:42:07 +080057import android.os.Looper;
Irfan Sheriff77ec5582012-03-22 17:01:39 -070058import android.os.Message;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +090059import android.os.RemoteException;
Dianne Hackborn692107e2012-08-29 18:32:08 -070060import android.os.UserHandle;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090061import android.provider.DeviceConfig;
Paul Hu23fa2022023-01-13 22:57:24 +080062import android.text.TextUtils;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090063import android.util.ArraySet;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +090064import android.util.Log;
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +090065import android.util.Pair;
Irfan Sheriffe4c42f42012-05-03 16:44:27 -070066import android.util.SparseArray;
Irfan Sheriff77ec5582012-03-22 17:01:39 -070067
paulhua262cc12019-08-12 16:25:11 +080068import com.android.internal.annotations.VisibleForTesting;
Paul Hub2e67d32023-04-18 05:50:14 +000069import com.android.internal.util.IndentingPrintWriter;
paulhua262cc12019-08-12 16:25:11 +080070import com.android.internal.util.State;
71import com.android.internal.util.StateMachine;
Paul Hucdef3532023-06-18 14:47:35 +000072import com.android.metrics.NetworkNsdReportedMetrics;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090073import com.android.net.module.util.CollectionUtils;
Paul Hu4bd98ef2023-01-12 13:42:07 +080074import com.android.net.module.util.DeviceConfigUtils;
Yuyang Huanga6a6ff92023-04-24 13:33:34 +090075import com.android.net.module.util.InetAddressUtils;
paulhu3ffffe72021-09-16 10:15:22 +080076import com.android.net.module.util.PermissionUtils;
Paul Hub2e67d32023-04-18 05:50:14 +000077import com.android.net.module.util.SharedLog;
Paul Hu4bd98ef2023-01-12 13:42:07 +080078import com.android.server.connectivity.mdns.ExecutorProvider;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +090079import com.android.server.connectivity.mdns.MdnsAdvertiser;
Paul Hu4bd98ef2023-01-12 13:42:07 +080080import com.android.server.connectivity.mdns.MdnsDiscoveryManager;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090081import com.android.server.connectivity.mdns.MdnsInterfaceSocket;
Paul Hu4bd98ef2023-01-12 13:42:07 +080082import com.android.server.connectivity.mdns.MdnsMultinetworkSocketClient;
Paul Hu23fa2022023-01-13 22:57:24 +080083import com.android.server.connectivity.mdns.MdnsSearchOptions;
84import com.android.server.connectivity.mdns.MdnsServiceBrowserListener;
85import com.android.server.connectivity.mdns.MdnsServiceInfo;
Paul Hu4bd98ef2023-01-12 13:42:07 +080086import com.android.server.connectivity.mdns.MdnsSocketProvider;
Yuyang Huangde802c82023-05-02 17:14:22 +090087import com.android.server.connectivity.mdns.util.MdnsUtils;
paulhua262cc12019-08-12 16:25:11 +080088
Irfan Sheriff77ec5582012-03-22 17:01:39 -070089import java.io.FileDescriptor;
90import java.io.PrintWriter;
Yuyang Huangaa0e9602023-03-17 12:43:09 +090091import java.net.Inet6Address;
Irfan Sheriffe8de2462012-04-11 14:52:19 -070092import java.net.InetAddress;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +090093import java.net.NetworkInterface;
94import java.net.SocketException;
95import java.net.UnknownHostException;
Paul Hu2b865912023-03-06 14:27:53 +080096import java.util.ArrayList;
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +090097import java.util.Arrays;
Irfan Sheriffe8de2462012-04-11 14:52:19 -070098import java.util.HashMap;
Paul Hu23fa2022023-01-13 22:57:24 +080099import java.util.List;
Paul Hu75069ed2023-01-14 00:31:09 +0800100import java.util.Map;
Paul Hu23fa2022023-01-13 22:57:24 +0800101import java.util.regex.Matcher;
102import java.util.regex.Pattern;
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700103
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700104/**
105 * Network Service Discovery Service handles remote service discovery operation requests by
106 * implementing the INsdManager interface.
107 *
108 * @hide
109 */
110public class NsdService extends INsdManager.Stub {
111 private static final String TAG = "NsdService";
112 private static final String MDNS_TAG = "mDnsConnector";
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900113 /**
114 * Enable discovery using the Java DiscoveryManager, instead of the legacy mdnsresponder
115 * implementation.
116 */
Paul Hu4bd98ef2023-01-12 13:42:07 +0800117 private static final String MDNS_DISCOVERY_MANAGER_VERSION = "mdns_discovery_manager_version";
Paul Hu23fa2022023-01-13 22:57:24 +0800118 private static final String LOCAL_DOMAIN_NAME = "local";
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700119
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900120 /**
121 * Enable advertising using the Java MdnsAdvertiser, instead of the legacy mdnsresponder
122 * implementation.
123 */
124 private static final String MDNS_ADVERTISER_VERSION = "mdns_advertiser_version";
125
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900126 /**
127 * Comma-separated list of type:flag mappings indicating the flags to use to allowlist
128 * discovery/advertising using MdnsDiscoveryManager / MdnsAdvertiser for a given type.
129 *
130 * For example _mytype._tcp.local and _othertype._tcp.local would be configured with:
131 * _mytype._tcp:mytype,_othertype._tcp.local:othertype
132 *
133 * In which case the flags:
134 * "mdns_discovery_manager_allowlist_mytype_version",
135 * "mdns_advertiser_allowlist_mytype_version",
136 * "mdns_discovery_manager_allowlist_othertype_version",
137 * "mdns_advertiser_allowlist_othertype_version"
138 * would be used to toggle MdnsDiscoveryManager / MdnsAdvertiser for each type. The flags will
139 * be read with
140 * {@link DeviceConfigUtils#isFeatureEnabled(Context, String, String, String, boolean)}.
141 *
142 * @see #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX
143 * @see #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX
144 * @see #MDNS_ALLOWLIST_FLAG_SUFFIX
145 */
146 private static final String MDNS_TYPE_ALLOWLIST_FLAGS = "mdns_type_allowlist_flags";
147
148 private static final String MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX =
149 "mdns_discovery_manager_allowlist_";
150 private static final String MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX =
151 "mdns_advertiser_allowlist_";
152 private static final String MDNS_ALLOWLIST_FLAG_SUFFIX = "_version";
153
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900154 @VisibleForTesting
155 static final String MDNS_CONFIG_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF =
156 "mdns_config_running_app_active_importance_cutoff";
157 @VisibleForTesting
158 static final int DEFAULT_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF =
159 ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
160 private final int mRunningAppActiveImportanceCutoff;
161
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900162 public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Luke Huang92860f92021-06-23 06:29:30 +0000163 private static final long CLEANUP_DELAY_MS = 10000;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +0900164 private static final int IFACE_IDX_ANY = 0;
Paul Hu14667de2023-04-17 22:42:47 +0800165 private static final SharedLog LOGGER = new SharedLog("serviceDiscovery");
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700166
Hugo Benichi32be63d2017-04-05 14:06:11 +0900167 private final Context mContext;
Hugo Benichi32be63d2017-04-05 14:06:11 +0900168 private final NsdStateMachine mNsdStateMachine;
paulhu2b9ed952022-02-10 21:58:32 +0800169 private final MDnsManager mMDnsManager;
170 private final MDnsEventCallback mMDnsEventCallback;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900171 @NonNull
172 private final Dependencies mDeps;
173 @NonNull
Paul Hu4bd98ef2023-01-12 13:42:07 +0800174 private final MdnsMultinetworkSocketClient mMdnsSocketClient;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900175 @NonNull
Paul Hu4bd98ef2023-01-12 13:42:07 +0800176 private final MdnsDiscoveryManager mMdnsDiscoveryManager;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900177 @NonNull
Paul Hu4bd98ef2023-01-12 13:42:07 +0800178 private final MdnsSocketProvider mMdnsSocketProvider;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900179 @NonNull
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900180 private final MdnsAdvertiser mAdvertiser;
Paul Hu14667de2023-04-17 22:42:47 +0800181 private final SharedLog mServiceLogs = LOGGER.forSubComponent(TAG);
Paul Hu23fa2022023-01-13 22:57:24 +0800182 // WARNING : Accessing these values in any thread is not safe, it must only be changed in the
paulhu2b9ed952022-02-10 21:58:32 +0800183 // state machine thread. If change this outside state machine, it will need to introduce
184 // synchronization.
185 private boolean mIsDaemonStarted = false;
Paul Hu23fa2022023-01-13 22:57:24 +0800186 private boolean mIsMonitoringSocketsStarted = false;
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700187
188 /**
189 * Clients receiving asynchronous messages
190 */
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900191 private final HashMap<NsdServiceConnector, ClientInfo> mClients = new HashMap<>();
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700192
Paul Hud44e1b72023-06-16 02:07:42 +0000193 /* A map from transaction(unique) id to client info */
194 private final SparseArray<ClientInfo> mTransactionIdToClientInfoMap = new SparseArray<>();
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700195
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900196 // Note this is not final to avoid depending on the Wi-Fi service starting before NsdService
197 @Nullable
198 private WifiManager.MulticastLock mHeldMulticastLock;
199 // Fulfilled network requests that require the Wi-Fi lock: key is the obtained Network
200 // (non-null), value is the requested Network (nullable)
201 @NonNull
202 private final ArraySet<Network> mWifiLockRequiredNetworks = new ArraySet<>();
203 @NonNull
204 private final ArraySet<Integer> mRunningAppActiveUids = new ArraySet<>();
205
Luke Huang05298582021-06-13 16:52:05 +0000206 private final long mCleanupDelayMs;
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700207
Hugo Benichi32be63d2017-04-05 14:06:11 +0900208 private static final int INVALID_ID = 0;
Irfan Sheriffe8de2462012-04-11 14:52:19 -0700209 private int mUniqueId = 1;
Luke Huangf7277ed2021-07-12 21:15:10 +0800210 // The count of the connected legacy clients.
211 private int mLegacyClientCount = 0;
Paul Hub2e67d32023-04-18 05:50:14 +0000212 // The number of client that ever connected.
213 private int mClientNumberId = 1;
Irfan Sheriffe8de2462012-04-11 14:52:19 -0700214
Paul Hu23fa2022023-01-13 22:57:24 +0800215 private static class MdnsListener implements MdnsServiceBrowserListener {
Paul Hud44e1b72023-06-16 02:07:42 +0000216 protected final int mClientRequestId;
Paul Hu23fa2022023-01-13 22:57:24 +0800217 protected final int mTransactionId;
218 @NonNull
219 protected final NsdServiceInfo mReqServiceInfo;
220 @NonNull
221 protected final String mListenedServiceType;
222
Paul Hud44e1b72023-06-16 02:07:42 +0000223 MdnsListener(int clientRequestId, int transactionId, @NonNull NsdServiceInfo reqServiceInfo,
Paul Hu23fa2022023-01-13 22:57:24 +0800224 @NonNull String listenedServiceType) {
Paul Hud44e1b72023-06-16 02:07:42 +0000225 mClientRequestId = clientRequestId;
Paul Hu23fa2022023-01-13 22:57:24 +0800226 mTransactionId = transactionId;
227 mReqServiceInfo = reqServiceInfo;
228 mListenedServiceType = listenedServiceType;
229 }
230
231 @NonNull
232 public String getListenedServiceType() {
233 return mListenedServiceType;
234 }
235
236 @Override
237 public void onServiceFound(@NonNull MdnsServiceInfo serviceInfo) { }
238
239 @Override
240 public void onServiceUpdated(@NonNull MdnsServiceInfo serviceInfo) { }
241
242 @Override
243 public void onServiceRemoved(@NonNull MdnsServiceInfo serviceInfo) { }
244
245 @Override
246 public void onServiceNameDiscovered(@NonNull MdnsServiceInfo serviceInfo) { }
247
248 @Override
249 public void onServiceNameRemoved(@NonNull MdnsServiceInfo serviceInfo) { }
250
251 @Override
252 public void onSearchStoppedWithError(int error) { }
253
254 @Override
255 public void onSearchFailedToStart() { }
256
257 @Override
258 public void onDiscoveryQuerySent(@NonNull List<String> subtypes, int transactionId) { }
259
260 @Override
261 public void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) { }
262 }
263
264 private class DiscoveryListener extends MdnsListener {
265
Paul Hud44e1b72023-06-16 02:07:42 +0000266 DiscoveryListener(int clientRequestId, int transactionId,
267 @NonNull NsdServiceInfo reqServiceInfo, @NonNull String listenServiceType) {
268 super(clientRequestId, transactionId, reqServiceInfo, listenServiceType);
Paul Hu23fa2022023-01-13 22:57:24 +0800269 }
270
271 @Override
272 public void onServiceNameDiscovered(@NonNull MdnsServiceInfo serviceInfo) {
Paul Hu019621e2023-01-13 23:26:49 +0800273 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
274 NsdManager.SERVICE_FOUND,
Paul Hud44e1b72023-06-16 02:07:42 +0000275 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu23fa2022023-01-13 22:57:24 +0800276 }
277
278 @Override
279 public void onServiceNameRemoved(@NonNull MdnsServiceInfo serviceInfo) {
Paul Hu319751a2023-01-13 23:56:34 +0800280 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
281 NsdManager.SERVICE_LOST,
Paul Hud44e1b72023-06-16 02:07:42 +0000282 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu23fa2022023-01-13 22:57:24 +0800283 }
284 }
285
Paul Hu75069ed2023-01-14 00:31:09 +0800286 private class ResolutionListener extends MdnsListener {
287
Paul Hud44e1b72023-06-16 02:07:42 +0000288 ResolutionListener(int clientRequestId, int transactionId,
289 @NonNull NsdServiceInfo reqServiceInfo, @NonNull String listenServiceType) {
290 super(clientRequestId, transactionId, reqServiceInfo, listenServiceType);
Paul Hu75069ed2023-01-14 00:31:09 +0800291 }
292
293 @Override
294 public void onServiceFound(MdnsServiceInfo serviceInfo) {
295 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
296 NsdManager.RESOLVE_SERVICE_SUCCEEDED,
Paul Hud44e1b72023-06-16 02:07:42 +0000297 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu75069ed2023-01-14 00:31:09 +0800298 }
299 }
300
Paul Hu30bd70d2023-02-07 13:20:56 +0000301 private class ServiceInfoListener extends MdnsListener {
302
Paul Hud44e1b72023-06-16 02:07:42 +0000303 ServiceInfoListener(int clientRequestId, int transactionId,
304 @NonNull NsdServiceInfo reqServiceInfo, @NonNull String listenServiceType) {
305 super(clientRequestId, transactionId, reqServiceInfo, listenServiceType);
Paul Hu30bd70d2023-02-07 13:20:56 +0000306 }
307
308 @Override
309 public void onServiceFound(@NonNull MdnsServiceInfo serviceInfo) {
310 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
311 NsdManager.SERVICE_UPDATED,
Paul Hud44e1b72023-06-16 02:07:42 +0000312 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu30bd70d2023-02-07 13:20:56 +0000313 }
314
315 @Override
316 public void onServiceUpdated(@NonNull MdnsServiceInfo serviceInfo) {
317 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
318 NsdManager.SERVICE_UPDATED,
Paul Hud44e1b72023-06-16 02:07:42 +0000319 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu30bd70d2023-02-07 13:20:56 +0000320 }
321
322 @Override
323 public void onServiceRemoved(@NonNull MdnsServiceInfo serviceInfo) {
324 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
325 NsdManager.SERVICE_UPDATED_LOST,
Paul Hud44e1b72023-06-16 02:07:42 +0000326 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu30bd70d2023-02-07 13:20:56 +0000327 }
328 }
329
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900330 private class SocketRequestMonitor implements MdnsSocketProvider.SocketRequestMonitor {
331 @Override
332 public void onSocketRequestFulfilled(@Nullable Network socketNetwork,
333 @NonNull MdnsInterfaceSocket socket, @NonNull int[] transports) {
334 // The network may be null for Wi-Fi SoftAp interfaces (tethering), but there is no APF
335 // filtering on such interfaces, so taking the multicast lock is not necessary to
336 // disable APF filtering of multicast.
337 if (socketNetwork == null
338 || !CollectionUtils.contains(transports, TRANSPORT_WIFI)
339 || CollectionUtils.contains(transports, TRANSPORT_VPN)) {
340 return;
341 }
342
343 if (mWifiLockRequiredNetworks.add(socketNetwork)) {
344 updateMulticastLock();
345 }
346 }
347
348 @Override
349 public void onSocketDestroyed(@Nullable Network socketNetwork,
350 @NonNull MdnsInterfaceSocket socket) {
351 if (mWifiLockRequiredNetworks.remove(socketNetwork)) {
352 updateMulticastLock();
353 }
354 }
355 }
356
357 private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
358 private final Handler mHandler;
359
360 private UidImportanceListener(Handler handler) {
361 mHandler = handler;
362 }
363
364 @Override
365 public void onUidImportance(int uid, int importance) {
366 mHandler.post(() -> handleUidImportanceChanged(uid, importance));
367 }
368 }
369
370 private void handleUidImportanceChanged(int uid, int importance) {
371 // Lower importance values are more "important"
372 final boolean modified = importance <= mRunningAppActiveImportanceCutoff
373 ? mRunningAppActiveUids.add(uid)
374 : mRunningAppActiveUids.remove(uid);
375 if (modified) {
376 updateMulticastLock();
377 }
378 }
379
380 /**
381 * Take or release the lock based on updated internal state.
382 *
383 * This determines whether the lock needs to be held based on
384 * {@link #mWifiLockRequiredNetworks}, {@link #mRunningAppActiveUids} and
385 * {@link ClientInfo#mClientRequests}, so it must be called after any of the these have been
386 * updated.
387 */
388 private void updateMulticastLock() {
389 final int needsLockUid = getMulticastLockNeededUid();
390 if (needsLockUid >= 0 && mHeldMulticastLock == null) {
391 final WifiManager wm = mContext.getSystemService(WifiManager.class);
392 if (wm == null) {
393 Log.wtf(TAG, "Got a TRANSPORT_WIFI network without WifiManager");
394 return;
395 }
396 mHeldMulticastLock = wm.createMulticastLock(TAG);
397 mHeldMulticastLock.acquire();
398 mServiceLogs.log("Taking multicast lock for uid " + needsLockUid);
399 } else if (needsLockUid < 0 && mHeldMulticastLock != null) {
400 mHeldMulticastLock.release();
401 mHeldMulticastLock = null;
402 mServiceLogs.log("Released multicast lock");
403 }
404 }
405
406 /**
407 * @return The UID of an app requiring the multicast lock, or -1 if none.
408 */
409 private int getMulticastLockNeededUid() {
410 if (mWifiLockRequiredNetworks.size() == 0) {
411 // Return early if NSD is not active, or not on any relevant network
412 return -1;
413 }
Paul Hud44e1b72023-06-16 02:07:42 +0000414 for (int i = 0; i < mTransactionIdToClientInfoMap.size(); i++) {
415 final ClientInfo clientInfo = mTransactionIdToClientInfoMap.valueAt(i);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900416 if (!mRunningAppActiveUids.contains(clientInfo.mUid)) {
417 // Ignore non-active UIDs
418 continue;
419 }
420
421 if (clientInfo.hasAnyJavaBackendRequestForNetworks(mWifiLockRequiredNetworks)) {
422 return clientInfo.mUid;
423 }
424 }
425 return -1;
426 }
427
Paul Hu019621e2023-01-13 23:26:49 +0800428 /**
429 * Data class of mdns service callback information.
430 */
431 private static class MdnsEvent {
Paul Hud44e1b72023-06-16 02:07:42 +0000432 final int mClientRequestId;
Paul Hu019621e2023-01-13 23:26:49 +0800433 @NonNull
Paul Hu019621e2023-01-13 23:26:49 +0800434 final MdnsServiceInfo mMdnsServiceInfo;
435
Paul Hud44e1b72023-06-16 02:07:42 +0000436 MdnsEvent(int clientRequestId, @NonNull MdnsServiceInfo mdnsServiceInfo) {
437 mClientRequestId = clientRequestId;
Paul Hu019621e2023-01-13 23:26:49 +0800438 mMdnsServiceInfo = mdnsServiceInfo;
439 }
440 }
441
Irfan Sheriff75006652012-04-17 23:15:29 -0700442 private class NsdStateMachine extends StateMachine {
443
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700444 private final DefaultState mDefaultState = new DefaultState();
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700445 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff75006652012-04-17 23:15:29 -0700446
447 @Override
Wink Saville358f5d42012-05-29 12:40:46 -0700448 protected String getWhatToString(int what) {
Hugo Benichi32be63d2017-04-05 14:06:11 +0900449 return NsdManager.nameOf(what);
Irfan Sheriff75006652012-04-17 23:15:29 -0700450 }
451
Luke Huang92860f92021-06-23 06:29:30 +0000452 private void maybeStartDaemon() {
paulhu2b9ed952022-02-10 21:58:32 +0800453 if (mIsDaemonStarted) {
454 if (DBG) Log.d(TAG, "Daemon is already started.");
455 return;
456 }
457 mMDnsManager.registerEventListener(mMDnsEventCallback);
458 mMDnsManager.startDaemon();
459 mIsDaemonStarted = true;
Luke Huang05298582021-06-13 16:52:05 +0000460 maybeScheduleStop();
Paul Hub2e67d32023-04-18 05:50:14 +0000461 mServiceLogs.log("Start mdns_responder daemon");
Luke Huang05298582021-06-13 16:52:05 +0000462 }
463
paulhu2b9ed952022-02-10 21:58:32 +0800464 private void maybeStopDaemon() {
465 if (!mIsDaemonStarted) {
466 if (DBG) Log.d(TAG, "Daemon has not been started.");
467 return;
468 }
469 mMDnsManager.unregisterEventListener(mMDnsEventCallback);
470 mMDnsManager.stopDaemon();
471 mIsDaemonStarted = false;
Paul Hub2e67d32023-04-18 05:50:14 +0000472 mServiceLogs.log("Stop mdns_responder daemon");
paulhu2b9ed952022-02-10 21:58:32 +0800473 }
474
Luke Huang92860f92021-06-23 06:29:30 +0000475 private boolean isAnyRequestActive() {
Paul Hud44e1b72023-06-16 02:07:42 +0000476 return mTransactionIdToClientInfoMap.size() != 0;
Luke Huang92860f92021-06-23 06:29:30 +0000477 }
478
479 private void scheduleStop() {
480 sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs);
481 }
482 private void maybeScheduleStop() {
Luke Huangf7277ed2021-07-12 21:15:10 +0800483 // The native daemon should stay alive and can't be cleanup
484 // if any legacy client connected.
485 if (!isAnyRequestActive() && mLegacyClientCount == 0) {
Luke Huang92860f92021-06-23 06:29:30 +0000486 scheduleStop();
Luke Huang05298582021-06-13 16:52:05 +0000487 }
488 }
489
Luke Huang92860f92021-06-23 06:29:30 +0000490 private void cancelStop() {
Luke Huang05298582021-06-13 16:52:05 +0000491 this.removeMessages(NsdManager.DAEMON_CLEANUP);
492 }
493
Paul Hu23fa2022023-01-13 22:57:24 +0800494 private void maybeStartMonitoringSockets() {
495 if (mIsMonitoringSocketsStarted) {
496 if (DBG) Log.d(TAG, "Socket monitoring is already started.");
497 return;
498 }
499
500 mMdnsSocketProvider.startMonitoringSockets();
501 mIsMonitoringSocketsStarted = true;
502 }
503
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900504 private void maybeStopMonitoringSocketsIfNoActiveRequest() {
505 if (!mIsMonitoringSocketsStarted) return;
506 if (isAnyRequestActive()) return;
507
Paul Hu58f20602023-02-18 11:41:07 +0800508 mMdnsSocketProvider.requestStopWhenInactive();
Paul Hu23fa2022023-01-13 22:57:24 +0800509 mIsMonitoringSocketsStarted = false;
510 }
511
Hugo Benichi803a2f02017-04-24 11:35:06 +0900512 NsdStateMachine(String name, Handler handler) {
513 super(name, handler);
Irfan Sheriff75006652012-04-17 23:15:29 -0700514 addState(mDefaultState);
Irfan Sheriff75006652012-04-17 23:15:29 -0700515 addState(mEnabledState, mDefaultState);
paulhu5568f452021-11-30 13:31:29 +0800516 State initialState = mEnabledState;
Hugo Benichi912db992017-04-24 16:41:03 +0900517 setInitialState(initialState);
Wink Saville358f5d42012-05-29 12:40:46 -0700518 setLogRecSize(25);
Irfan Sheriff75006652012-04-17 23:15:29 -0700519 }
520
521 class DefaultState extends State {
522 @Override
523 public boolean processMessage(Message msg) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900524 final ClientInfo cInfo;
Paul Hud44e1b72023-06-16 02:07:42 +0000525 final int clientRequestId = msg.arg2;
Irfan Sheriff75006652012-04-17 23:15:29 -0700526 switch (msg.what) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900527 case NsdManager.REGISTER_CLIENT:
Paul Hu2e0a88c2023-03-09 16:05:01 +0800528 final ConnectorArgs arg = (ConnectorArgs) msg.obj;
529 final INsdManagerCallback cb = arg.callback;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900530 try {
Paul Hu2e0a88c2023-03-09 16:05:01 +0800531 cb.asBinder().linkToDeath(arg.connector, 0);
Paul Hub2e67d32023-04-18 05:50:14 +0000532 final String tag = "Client" + arg.uid + "-" + mClientNumberId++;
Paul Hucdef3532023-06-18 14:47:35 +0000533 final NetworkNsdReportedMetrics metrics = new NetworkNsdReportedMetrics(
534 !arg.useJavaBackend, (int) new Clock().elapsedRealtime());
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900535 cInfo = new ClientInfo(cb, arg.uid, arg.useJavaBackend,
Paul Hucdef3532023-06-18 14:47:35 +0000536 mServiceLogs.forSubComponent(tag), metrics);
Paul Hu2e0a88c2023-03-09 16:05:01 +0800537 mClients.put(arg.connector, cInfo);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900538 } catch (RemoteException e) {
Paul Hud44e1b72023-06-16 02:07:42 +0000539 Log.w(TAG, "Client request id " + clientRequestId
540 + " has already died");
Irfan Sheriff75006652012-04-17 23:15:29 -0700541 }
542 break;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900543 case NsdManager.UNREGISTER_CLIENT:
544 final NsdServiceConnector connector = (NsdServiceConnector) msg.obj;
545 cInfo = mClients.remove(connector);
Dave Plattfeff2af2014-03-07 14:48:22 -0800546 if (cInfo != null) {
547 cInfo.expungeAllRequests();
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900548 if (cInfo.isPreSClient()) {
Luke Huangf7277ed2021-07-12 21:15:10 +0800549 mLegacyClientCount -= 1;
550 }
Dave Plattfeff2af2014-03-07 14:48:22 -0800551 }
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900552 maybeStopMonitoringSocketsIfNoActiveRequest();
Luke Huangf7277ed2021-07-12 21:15:10 +0800553 maybeScheduleStop();
Irfan Sheriff75006652012-04-17 23:15:29 -0700554 break;
Irfan Sheriff75006652012-04-17 23:15:29 -0700555 case NsdManager.DISCOVER_SERVICES:
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900556 cInfo = getClientInfoForReply(msg);
557 if (cInfo != null) {
558 cInfo.onDiscoverServicesFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000559 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900560 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700561 break;
562 case NsdManager.STOP_DISCOVERY:
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900563 cInfo = getClientInfoForReply(msg);
564 if (cInfo != null) {
565 cInfo.onStopDiscoveryFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000566 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900567 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700568 break;
569 case NsdManager.REGISTER_SERVICE:
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900570 cInfo = getClientInfoForReply(msg);
571 if (cInfo != null) {
572 cInfo.onRegisterServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000573 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900574 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700575 break;
576 case NsdManager.UNREGISTER_SERVICE:
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900577 cInfo = getClientInfoForReply(msg);
578 if (cInfo != null) {
579 cInfo.onUnregisterServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000580 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900581 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700582 break;
583 case NsdManager.RESOLVE_SERVICE:
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900584 cInfo = getClientInfoForReply(msg);
585 if (cInfo != null) {
586 cInfo.onResolveServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000587 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900588 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700589 break;
Paul Hub58deb72022-12-26 09:24:42 +0000590 case NsdManager.STOP_RESOLUTION:
591 cInfo = getClientInfoForReply(msg);
592 if (cInfo != null) {
593 cInfo.onStopResolutionFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000594 clientRequestId, NsdManager.FAILURE_OPERATION_NOT_RUNNING);
Paul Hub58deb72022-12-26 09:24:42 +0000595 }
596 break;
Paul Hu18aeccc2022-12-27 08:48:48 +0000597 case NsdManager.REGISTER_SERVICE_CALLBACK:
598 cInfo = getClientInfoForReply(msg);
599 if (cInfo != null) {
600 cInfo.onServiceInfoCallbackRegistrationFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000601 clientRequestId, NsdManager.FAILURE_BAD_PARAMETERS);
Paul Hu18aeccc2022-12-27 08:48:48 +0000602 }
603 break;
Luke Huang05298582021-06-13 16:52:05 +0000604 case NsdManager.DAEMON_CLEANUP:
paulhu2b9ed952022-02-10 21:58:32 +0800605 maybeStopDaemon();
Luke Huang05298582021-06-13 16:52:05 +0000606 break;
Luke Huangf7277ed2021-07-12 21:15:10 +0800607 // This event should be only sent by the legacy (target SDK < S) clients.
608 // Mark the sending client as legacy.
609 case NsdManager.DAEMON_STARTUP:
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900610 cInfo = getClientInfoForReply(msg);
Luke Huangf7277ed2021-07-12 21:15:10 +0800611 if (cInfo != null) {
612 cancelStop();
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900613 cInfo.setPreSClient();
Luke Huangf7277ed2021-07-12 21:15:10 +0800614 mLegacyClientCount += 1;
615 maybeStartDaemon();
616 }
617 break;
Irfan Sheriff75006652012-04-17 23:15:29 -0700618 default:
paulhub2225702021-11-17 09:35:33 +0800619 Log.e(TAG, "Unhandled " + msg);
Irfan Sheriff75006652012-04-17 23:15:29 -0700620 return NOT_HANDLED;
621 }
622 return HANDLED;
623 }
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900624
625 private ClientInfo getClientInfoForReply(Message msg) {
626 final ListenerArgs args = (ListenerArgs) msg.obj;
627 return mClients.get(args.connector);
628 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700629 }
630
Irfan Sheriff75006652012-04-17 23:15:29 -0700631 class EnabledState extends State {
632 @Override
633 public void enter() {
634 sendNsdStateChangeBroadcast(true);
Irfan Sheriff75006652012-04-17 23:15:29 -0700635 }
636
637 @Override
638 public void exit() {
Luke Huang05298582021-06-13 16:52:05 +0000639 // TODO: it is incorrect to stop the daemon without expunging all requests
640 // and sending error callbacks to clients.
Luke Huang92860f92021-06-23 06:29:30 +0000641 scheduleStop();
Irfan Sheriff75006652012-04-17 23:15:29 -0700642 }
643
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700644 private boolean requestLimitReached(ClientInfo clientInfo) {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900645 if (clientInfo.mClientRequests.size() >= ClientInfo.MAX_LIMIT) {
paulhub2225702021-11-17 09:35:33 +0800646 if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo);
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700647 return true;
648 }
649 return false;
650 }
651
Paul Hud44e1b72023-06-16 02:07:42 +0000652 private void storeLegacyRequestMap(int clientRequestId, int transactionId,
653 ClientInfo clientInfo, int what) {
654 clientInfo.mClientRequests.put(
655 clientRequestId, new LegacyClientRequest(transactionId, what));
656 mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
Luke Huang05298582021-06-13 16:52:05 +0000657 // Remove the cleanup event because here comes a new request.
658 cancelStop();
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700659 }
660
Paul Hud44e1b72023-06-16 02:07:42 +0000661 private void storeAdvertiserRequestMap(int clientRequestId, int transactionId,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900662 ClientInfo clientInfo, @Nullable Network requestedNetwork) {
Paul Hud44e1b72023-06-16 02:07:42 +0000663 clientInfo.mClientRequests.put(clientRequestId,
664 new AdvertiserClientRequest(transactionId, requestedNetwork));
665 mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900666 updateMulticastLock();
Paul Hu23fa2022023-01-13 22:57:24 +0800667 }
668
Paul Hud44e1b72023-06-16 02:07:42 +0000669 private void removeRequestMap(
670 int clientRequestId, int transactionId, ClientInfo clientInfo) {
671 final ClientRequest existing = clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900672 if (existing == null) return;
Paul Hud44e1b72023-06-16 02:07:42 +0000673 clientInfo.mClientRequests.remove(clientRequestId);
674 mTransactionIdToClientInfoMap.remove(transactionId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900675
676 if (existing instanceof LegacyClientRequest) {
677 maybeScheduleStop();
678 } else {
679 maybeStopMonitoringSocketsIfNoActiveRequest();
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900680 updateMulticastLock();
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900681 }
682 }
683
Paul Hud44e1b72023-06-16 02:07:42 +0000684 private void storeDiscoveryManagerRequestMap(int clientRequestId, int transactionId,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900685 MdnsListener listener, ClientInfo clientInfo,
686 @Nullable Network requestedNetwork) {
Paul Hud44e1b72023-06-16 02:07:42 +0000687 clientInfo.mClientRequests.put(clientRequestId,
688 new DiscoveryManagerRequest(transactionId, listener, requestedNetwork));
689 mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900690 updateMulticastLock();
Paul Hu23fa2022023-01-13 22:57:24 +0800691 }
692
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900693 /**
694 * Truncate a service name to up to 63 UTF-8 bytes.
695 *
696 * See RFC6763 4.1.1: service instance names are UTF-8 and up to 63 bytes. Truncating
697 * names used in registerService follows historical behavior (see mdnsresponder
698 * handle_regservice_request).
699 */
700 @NonNull
701 private String truncateServiceName(@NonNull String originalName) {
Yuyang Huangde802c82023-05-02 17:14:22 +0900702 return MdnsUtils.truncateServiceName(originalName, MAX_LABEL_LENGTH);
Paul Hu23fa2022023-01-13 22:57:24 +0800703 }
704
Paul Hud44e1b72023-06-16 02:07:42 +0000705 private void stopDiscoveryManagerRequest(ClientRequest request, int clientRequestId,
706 int transactionId, ClientInfo clientInfo) {
Paul Hue4f5f252023-02-16 21:13:47 +0800707 clientInfo.unregisterMdnsListenerFromRequest(request);
Paul Hud44e1b72023-06-16 02:07:42 +0000708 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hue4f5f252023-02-16 21:13:47 +0800709 }
710
Irfan Sheriff75006652012-04-17 23:15:29 -0700711 @Override
712 public boolean processMessage(Message msg) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900713 final ClientInfo clientInfo;
Paul Hud44e1b72023-06-16 02:07:42 +0000714 final int transactionId;
715 final int clientRequestId = msg.arg2;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900716 final ListenerArgs args;
Irfan Sheriff75006652012-04-17 23:15:29 -0700717 switch (msg.what) {
Paul Hu75069ed2023-01-14 00:31:09 +0800718 case NsdManager.DISCOVER_SERVICES: {
paulhub2225702021-11-17 09:35:33 +0800719 if (DBG) Log.d(TAG, "Discover services");
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900720 args = (ListenerArgs) msg.obj;
721 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000722 // If the binder death notification for a INsdManagerCallback was received
723 // before any calls are received by NsdService, the clientInfo would be
724 // cleared and cause NPE. Add a null check here to prevent this corner case.
725 if (clientInfo == null) {
726 Log.e(TAG, "Unknown connector in discovery");
727 break;
728 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700729
730 if (requestLimitReached(clientInfo)) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900731 clientInfo.onDiscoverServicesFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000732 clientRequestId, NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriff75006652012-04-17 23:15:29 -0700733 break;
734 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700735
Paul Hu23fa2022023-01-13 22:57:24 +0800736 final NsdServiceInfo info = args.serviceInfo;
Paul Hud44e1b72023-06-16 02:07:42 +0000737 transactionId = getUniqueId();
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900738 final Pair<String, String> typeAndSubtype =
739 parseTypeAndSubtype(info.getServiceType());
740 final String serviceType = typeAndSubtype == null
741 ? null : typeAndSubtype.first;
Paul Hu2e0a88c2023-03-09 16:05:01 +0800742 if (clientInfo.mUseJavaBackend
743 || mDeps.isMdnsDiscoveryManagerEnabled(mContext)
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900744 || useDiscoveryManagerForType(serviceType)) {
Paul Hu23fa2022023-01-13 22:57:24 +0800745 if (serviceType == null) {
Paul Hud44e1b72023-06-16 02:07:42 +0000746 clientInfo.onDiscoverServicesFailed(clientRequestId,
Paul Hu23fa2022023-01-13 22:57:24 +0800747 NsdManager.FAILURE_INTERNAL_ERROR);
748 break;
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700749 }
Paul Hu23fa2022023-01-13 22:57:24 +0800750
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900751 final String listenServiceType = serviceType + ".local";
Paul Hu23fa2022023-01-13 22:57:24 +0800752 maybeStartMonitoringSockets();
Paul Hud44e1b72023-06-16 02:07:42 +0000753 final MdnsListener listener = new DiscoveryListener(clientRequestId,
754 transactionId, info, listenServiceType);
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900755 final MdnsSearchOptions.Builder optionsBuilder =
756 MdnsSearchOptions.newBuilder()
757 .setNetwork(info.getNetwork())
Yuyang Huangff963222023-06-01 18:42:42 +0900758 .setRemoveExpiredService(true)
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900759 .setIsPassiveMode(true);
760 if (typeAndSubtype.second != null) {
761 // The parsing ensures subtype starts with an underscore.
762 // MdnsSearchOptions expects the underscore to not be present.
763 optionsBuilder.addSubtype(typeAndSubtype.second.substring(1));
764 }
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900765 mMdnsDiscoveryManager.registerListener(
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900766 listenServiceType, listener, optionsBuilder.build());
Paul Hud44e1b72023-06-16 02:07:42 +0000767 storeDiscoveryManagerRequestMap(clientRequestId, transactionId,
768 listener, clientInfo, info.getNetwork());
769 clientInfo.onDiscoverServicesStarted(clientRequestId, info);
770 clientInfo.log("Register a DiscoveryListener " + transactionId
Paul Hub2e67d32023-04-18 05:50:14 +0000771 + " for service type:" + listenServiceType);
Irfan Sheriff75006652012-04-17 23:15:29 -0700772 } else {
Paul Hu23fa2022023-01-13 22:57:24 +0800773 maybeStartDaemon();
Paul Hud44e1b72023-06-16 02:07:42 +0000774 if (discoverServices(transactionId, info)) {
Paul Hu23fa2022023-01-13 22:57:24 +0800775 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +0000776 Log.d(TAG, "Discover " + msg.arg2 + " " + transactionId
Paul Hu23fa2022023-01-13 22:57:24 +0800777 + info.getServiceType());
778 }
Paul Hud44e1b72023-06-16 02:07:42 +0000779 storeLegacyRequestMap(
780 clientRequestId, transactionId, clientInfo, msg.what);
781 clientInfo.onDiscoverServicesStarted(clientRequestId, info);
Paul Hu23fa2022023-01-13 22:57:24 +0800782 } else {
Paul Hud44e1b72023-06-16 02:07:42 +0000783 stopServiceDiscovery(transactionId);
784 clientInfo.onDiscoverServicesFailed(clientRequestId,
Paul Hu23fa2022023-01-13 22:57:24 +0800785 NsdManager.FAILURE_INTERNAL_ERROR);
786 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700787 }
788 break;
Paul Hu75069ed2023-01-14 00:31:09 +0800789 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900790 case NsdManager.STOP_DISCOVERY: {
paulhub2225702021-11-17 09:35:33 +0800791 if (DBG) Log.d(TAG, "Stop service discovery");
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900792 args = (ListenerArgs) msg.obj;
793 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000794 // If the binder death notification for a INsdManagerCallback was received
795 // before any calls are received by NsdService, the clientInfo would be
796 // cleared and cause NPE. Add a null check here to prevent this corner case.
797 if (clientInfo == null) {
798 Log.e(TAG, "Unknown connector in stop discovery");
799 break;
800 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700801
Paul Hud44e1b72023-06-16 02:07:42 +0000802 final ClientRequest request =
803 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900804 if (request == null) {
805 Log.e(TAG, "Unknown client request in STOP_DISCOVERY");
Irfan Sheriff75006652012-04-17 23:15:29 -0700806 break;
807 }
Paul Hud44e1b72023-06-16 02:07:42 +0000808 transactionId = request.mTransactionId;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900809 // Note isMdnsDiscoveryManagerEnabled may have changed to false at this
810 // point, so this needs to check the type of the original request to
811 // unregister instead of looking at the flag value.
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900812 if (request instanceof DiscoveryManagerRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +0000813 stopDiscoveryManagerRequest(
814 request, clientRequestId, transactionId, clientInfo);
815 clientInfo.onStopDiscoverySucceeded(clientRequestId);
816 clientInfo.log("Unregister the DiscoveryListener " + transactionId);
Irfan Sheriff75006652012-04-17 23:15:29 -0700817 } else {
Paul Hud44e1b72023-06-16 02:07:42 +0000818 removeRequestMap(clientRequestId, transactionId, clientInfo);
819 if (stopServiceDiscovery(transactionId)) {
820 clientInfo.onStopDiscoverySucceeded(clientRequestId);
Paul Hu23fa2022023-01-13 22:57:24 +0800821 } else {
822 clientInfo.onStopDiscoveryFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000823 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Paul Hu23fa2022023-01-13 22:57:24 +0800824 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700825 }
826 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900827 }
828 case NsdManager.REGISTER_SERVICE: {
paulhub2225702021-11-17 09:35:33 +0800829 if (DBG) Log.d(TAG, "Register service");
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900830 args = (ListenerArgs) msg.obj;
831 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000832 // If the binder death notification for a INsdManagerCallback was received
833 // before any calls are received by NsdService, the clientInfo would be
834 // cleared and cause NPE. Add a null check here to prevent this corner case.
835 if (clientInfo == null) {
836 Log.e(TAG, "Unknown connector in registration");
837 break;
838 }
839
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700840 if (requestLimitReached(clientInfo)) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900841 clientInfo.onRegisterServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000842 clientRequestId, NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700843 break;
Irfan Sheriff75006652012-04-17 23:15:29 -0700844 }
845
Paul Hud44e1b72023-06-16 02:07:42 +0000846 transactionId = getUniqueId();
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900847 final NsdServiceInfo serviceInfo = args.serviceInfo;
848 final String serviceType = serviceInfo.getServiceType();
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900849 final Pair<String, String> typeSubtype = parseTypeAndSubtype(serviceType);
850 final String registerServiceType = typeSubtype == null
851 ? null : typeSubtype.first;
Paul Hu2e0a88c2023-03-09 16:05:01 +0800852 if (clientInfo.mUseJavaBackend
853 || mDeps.isMdnsAdvertiserEnabled(mContext)
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900854 || useAdvertiserForType(registerServiceType)) {
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900855 if (registerServiceType == null) {
856 Log.e(TAG, "Invalid service type: " + serviceType);
Paul Hud44e1b72023-06-16 02:07:42 +0000857 clientInfo.onRegisterServiceFailed(clientRequestId,
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900858 NsdManager.FAILURE_INTERNAL_ERROR);
859 break;
860 }
861 serviceInfo.setServiceType(registerServiceType);
862 serviceInfo.setServiceName(truncateServiceName(
863 serviceInfo.getServiceName()));
864
865 maybeStartMonitoringSockets();
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900866 // TODO: pass in the subtype as well. Including the subtype in the
867 // service type would generate service instance names like
868 // Name._subtype._sub._type._tcp, which is incorrect
869 // (it should be Name._type._tcp).
Paul Hud44e1b72023-06-16 02:07:42 +0000870 mAdvertiser.addService(transactionId, serviceInfo, typeSubtype.second);
871 storeAdvertiserRequestMap(clientRequestId, transactionId, clientInfo,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900872 serviceInfo.getNetwork());
Irfan Sheriff75006652012-04-17 23:15:29 -0700873 } else {
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900874 maybeStartDaemon();
Paul Hud44e1b72023-06-16 02:07:42 +0000875 if (registerService(transactionId, serviceInfo)) {
876 if (DBG) {
877 Log.d(TAG, "Register " + clientRequestId
878 + " " + transactionId);
879 }
880 storeLegacyRequestMap(
881 clientRequestId, transactionId, clientInfo, msg.what);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900882 // Return success after mDns reports success
883 } else {
Paul Hud44e1b72023-06-16 02:07:42 +0000884 unregisterService(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900885 clientInfo.onRegisterServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000886 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900887 }
888
Irfan Sheriff75006652012-04-17 23:15:29 -0700889 }
890 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900891 }
892 case NsdManager.UNREGISTER_SERVICE: {
paulhub2225702021-11-17 09:35:33 +0800893 if (DBG) Log.d(TAG, "unregister service");
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900894 args = (ListenerArgs) msg.obj;
895 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000896 // If the binder death notification for a INsdManagerCallback was received
897 // before any calls are received by NsdService, the clientInfo would be
898 // cleared and cause NPE. Add a null check here to prevent this corner case.
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900899 if (clientInfo == null) {
paulhub2225702021-11-17 09:35:33 +0800900 Log.e(TAG, "Unknown connector in unregistration");
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700901 break;
Irfan Sheriff75006652012-04-17 23:15:29 -0700902 }
Paul Hud44e1b72023-06-16 02:07:42 +0000903 final ClientRequest request =
904 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900905 if (request == null) {
906 Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE");
907 break;
908 }
Paul Hud44e1b72023-06-16 02:07:42 +0000909 transactionId = request.mTransactionId;
910 removeRequestMap(clientRequestId, transactionId, clientInfo);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900911
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900912 // Note isMdnsAdvertiserEnabled may have changed to false at this point,
913 // so this needs to check the type of the original request to unregister
914 // instead of looking at the flag value.
915 if (request instanceof AdvertiserClientRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +0000916 mAdvertiser.removeService(transactionId);
917 clientInfo.onUnregisterServiceSucceeded(clientRequestId);
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700918 } else {
Paul Hud44e1b72023-06-16 02:07:42 +0000919 if (unregisterService(transactionId)) {
920 clientInfo.onUnregisterServiceSucceeded(clientRequestId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900921 } else {
922 clientInfo.onUnregisterServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000923 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900924 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700925 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700926 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900927 }
Paul Hu75069ed2023-01-14 00:31:09 +0800928 case NsdManager.RESOLVE_SERVICE: {
paulhub2225702021-11-17 09:35:33 +0800929 if (DBG) Log.d(TAG, "Resolve service");
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900930 args = (ListenerArgs) msg.obj;
931 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000932 // If the binder death notification for a INsdManagerCallback was received
933 // before any calls are received by NsdService, the clientInfo would be
934 // cleared and cause NPE. Add a null check here to prevent this corner case.
935 if (clientInfo == null) {
936 Log.e(TAG, "Unknown connector in resolution");
937 break;
938 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700939
Paul Hu75069ed2023-01-14 00:31:09 +0800940 final NsdServiceInfo info = args.serviceInfo;
Paul Hud44e1b72023-06-16 02:07:42 +0000941 transactionId = getUniqueId();
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900942 final Pair<String, String> typeSubtype =
943 parseTypeAndSubtype(info.getServiceType());
944 final String serviceType = typeSubtype == null
945 ? null : typeSubtype.first;
Paul Hu2e0a88c2023-03-09 16:05:01 +0800946 if (clientInfo.mUseJavaBackend
947 || mDeps.isMdnsDiscoveryManagerEnabled(mContext)
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900948 || useDiscoveryManagerForType(serviceType)) {
Paul Hu75069ed2023-01-14 00:31:09 +0800949 if (serviceType == null) {
Paul Hud44e1b72023-06-16 02:07:42 +0000950 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu75069ed2023-01-14 00:31:09 +0800951 NsdManager.FAILURE_INTERNAL_ERROR);
952 break;
953 }
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900954 final String resolveServiceType = serviceType + ".local";
Paul Hu75069ed2023-01-14 00:31:09 +0800955
956 maybeStartMonitoringSockets();
Paul Hud44e1b72023-06-16 02:07:42 +0000957 final MdnsListener listener = new ResolutionListener(clientRequestId,
958 transactionId, info, resolveServiceType);
Paul Hu75069ed2023-01-14 00:31:09 +0800959 final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
960 .setNetwork(info.getNetwork())
961 .setIsPassiveMode(true)
Remi NGUYEN VANbb62b1d2023-02-27 12:18:27 +0900962 .setResolveInstanceName(info.getServiceName())
Yuyang Huangff963222023-06-01 18:42:42 +0900963 .setRemoveExpiredService(true)
Paul Hu75069ed2023-01-14 00:31:09 +0800964 .build();
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900965 mMdnsDiscoveryManager.registerListener(
966 resolveServiceType, listener, options);
Paul Hud44e1b72023-06-16 02:07:42 +0000967 storeDiscoveryManagerRequestMap(clientRequestId, transactionId,
968 listener, clientInfo, info.getNetwork());
969 clientInfo.log("Register a ResolutionListener " + transactionId
Paul Hub2e67d32023-04-18 05:50:14 +0000970 + " for service type:" + resolveServiceType);
Irfan Sheriff75006652012-04-17 23:15:29 -0700971 } else {
Paul Hu75069ed2023-01-14 00:31:09 +0800972 if (clientInfo.mResolvedService != null) {
973 clientInfo.onResolveServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000974 clientRequestId, NsdManager.FAILURE_ALREADY_ACTIVE);
Paul Hu75069ed2023-01-14 00:31:09 +0800975 break;
976 }
977
978 maybeStartDaemon();
Paul Hud44e1b72023-06-16 02:07:42 +0000979 if (resolveService(transactionId, info)) {
Paul Hu75069ed2023-01-14 00:31:09 +0800980 clientInfo.mResolvedService = new NsdServiceInfo();
Paul Hud44e1b72023-06-16 02:07:42 +0000981 storeLegacyRequestMap(
982 clientRequestId, transactionId, clientInfo, msg.what);
Paul Hu75069ed2023-01-14 00:31:09 +0800983 } else {
984 clientInfo.onResolveServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000985 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Paul Hu75069ed2023-01-14 00:31:09 +0800986 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700987 }
988 break;
Paul Hu75069ed2023-01-14 00:31:09 +0800989 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900990 case NsdManager.STOP_RESOLUTION: {
Paul Hub58deb72022-12-26 09:24:42 +0000991 if (DBG) Log.d(TAG, "Stop service resolution");
992 args = (ListenerArgs) msg.obj;
993 clientInfo = mClients.get(args.connector);
994 // If the binder death notification for a INsdManagerCallback was received
995 // before any calls are received by NsdService, the clientInfo would be
996 // cleared and cause NPE. Add a null check here to prevent this corner case.
997 if (clientInfo == null) {
998 Log.e(TAG, "Unknown connector in stop resolution");
999 break;
1000 }
1001
Paul Hud44e1b72023-06-16 02:07:42 +00001002 final ClientRequest request =
1003 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001004 if (request == null) {
1005 Log.e(TAG, "Unknown client request in STOP_RESOLUTION");
1006 break;
1007 }
Paul Hud44e1b72023-06-16 02:07:42 +00001008 transactionId = request.mTransactionId;
Paul Hue4f5f252023-02-16 21:13:47 +08001009 // Note isMdnsDiscoveryManagerEnabled may have changed to false at this
1010 // point, so this needs to check the type of the original request to
1011 // unregister instead of looking at the flag value.
1012 if (request instanceof DiscoveryManagerRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +00001013 stopDiscoveryManagerRequest(
1014 request, clientRequestId, transactionId, clientInfo);
1015 clientInfo.onStopResolutionSucceeded(clientRequestId);
1016 clientInfo.log("Unregister the ResolutionListener " + transactionId);
Paul Hub58deb72022-12-26 09:24:42 +00001017 } else {
Paul Hud44e1b72023-06-16 02:07:42 +00001018 removeRequestMap(clientRequestId, transactionId, clientInfo);
1019 if (stopResolveService(transactionId)) {
1020 clientInfo.onStopResolutionSucceeded(clientRequestId);
Paul Hue4f5f252023-02-16 21:13:47 +08001021 } else {
1022 clientInfo.onStopResolutionFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001023 clientRequestId, NsdManager.FAILURE_OPERATION_NOT_RUNNING);
Paul Hue4f5f252023-02-16 21:13:47 +08001024 }
1025 clientInfo.mResolvedService = null;
Paul Hub58deb72022-12-26 09:24:42 +00001026 }
Paul Hub58deb72022-12-26 09:24:42 +00001027 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001028 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001029 case NsdManager.REGISTER_SERVICE_CALLBACK: {
Paul Hu18aeccc2022-12-27 08:48:48 +00001030 if (DBG) Log.d(TAG, "Register a service callback");
1031 args = (ListenerArgs) msg.obj;
1032 clientInfo = mClients.get(args.connector);
1033 // If the binder death notification for a INsdManagerCallback was received
1034 // before any calls are received by NsdService, the clientInfo would be
1035 // cleared and cause NPE. Add a null check here to prevent this corner case.
1036 if (clientInfo == null) {
1037 Log.e(TAG, "Unknown connector in callback registration");
1038 break;
1039 }
1040
Paul Hu30bd70d2023-02-07 13:20:56 +00001041 final NsdServiceInfo info = args.serviceInfo;
Paul Hud44e1b72023-06-16 02:07:42 +00001042 transactionId = getUniqueId();
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001043 final Pair<String, String> typeAndSubtype =
1044 parseTypeAndSubtype(info.getServiceType());
1045 final String serviceType = typeAndSubtype == null
1046 ? null : typeAndSubtype.first;
Paul Hu30bd70d2023-02-07 13:20:56 +00001047 if (serviceType == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00001048 clientInfo.onServiceInfoCallbackRegistrationFailed(clientRequestId,
Paul Hu30bd70d2023-02-07 13:20:56 +00001049 NsdManager.FAILURE_BAD_PARAMETERS);
Paul Hu18aeccc2022-12-27 08:48:48 +00001050 break;
1051 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001052 final String resolveServiceType = serviceType + ".local";
Paul Hu18aeccc2022-12-27 08:48:48 +00001053
Paul Hu30bd70d2023-02-07 13:20:56 +00001054 maybeStartMonitoringSockets();
Paul Hud44e1b72023-06-16 02:07:42 +00001055 final MdnsListener listener = new ServiceInfoListener(clientRequestId,
1056 transactionId, info, resolveServiceType);
Paul Hu30bd70d2023-02-07 13:20:56 +00001057 final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
1058 .setNetwork(info.getNetwork())
1059 .setIsPassiveMode(true)
1060 .setResolveInstanceName(info.getServiceName())
Yuyang Huangff963222023-06-01 18:42:42 +09001061 .setRemoveExpiredService(true)
Paul Hu30bd70d2023-02-07 13:20:56 +00001062 .build();
1063 mMdnsDiscoveryManager.registerListener(
1064 resolveServiceType, listener, options);
Paul Hud44e1b72023-06-16 02:07:42 +00001065 storeDiscoveryManagerRequestMap(clientRequestId, transactionId, listener,
1066 clientInfo, info.getNetwork());
1067 clientInfo.log("Register a ServiceInfoListener " + transactionId
Paul Hub2e67d32023-04-18 05:50:14 +00001068 + " for service type:" + resolveServiceType);
Paul Hu18aeccc2022-12-27 08:48:48 +00001069 break;
Paul Hu30bd70d2023-02-07 13:20:56 +00001070 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001071 case NsdManager.UNREGISTER_SERVICE_CALLBACK: {
Paul Hu18aeccc2022-12-27 08:48:48 +00001072 if (DBG) Log.d(TAG, "Unregister a service callback");
1073 args = (ListenerArgs) msg.obj;
1074 clientInfo = mClients.get(args.connector);
1075 // If the binder death notification for a INsdManagerCallback was received
1076 // before any calls are received by NsdService, the clientInfo would be
1077 // cleared and cause NPE. Add a null check here to prevent this corner case.
1078 if (clientInfo == null) {
1079 Log.e(TAG, "Unknown connector in callback unregistration");
1080 break;
1081 }
1082
Paul Hud44e1b72023-06-16 02:07:42 +00001083 final ClientRequest request =
1084 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001085 if (request == null) {
Paul Hu30bd70d2023-02-07 13:20:56 +00001086 Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE_CALLBACK");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001087 break;
1088 }
Paul Hud44e1b72023-06-16 02:07:42 +00001089 transactionId = request.mTransactionId;
Paul Hu30bd70d2023-02-07 13:20:56 +00001090 if (request instanceof DiscoveryManagerRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +00001091 stopDiscoveryManagerRequest(
1092 request, clientRequestId, transactionId, clientInfo);
1093 clientInfo.onServiceInfoCallbackUnregistered(clientRequestId);
1094 clientInfo.log("Unregister the ServiceInfoListener " + transactionId);
Paul Hu18aeccc2022-12-27 08:48:48 +00001095 } else {
Paul Hu30bd70d2023-02-07 13:20:56 +00001096 loge("Unregister failed with non-DiscoveryManagerRequest.");
Paul Hu18aeccc2022-12-27 08:48:48 +00001097 }
Paul Hu18aeccc2022-12-27 08:48:48 +00001098 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001099 }
paulhu2b9ed952022-02-10 21:58:32 +08001100 case MDNS_SERVICE_EVENT:
1101 if (!handleMDnsServiceEvent(msg.arg1, msg.arg2, msg.obj)) {
Hugo Benichif0c84092017-04-05 14:43:29 +09001102 return NOT_HANDLED;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001103 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001104 break;
Paul Hu019621e2023-01-13 23:26:49 +08001105 case MDNS_DISCOVERY_MANAGER_EVENT:
1106 if (!handleMdnsDiscoveryManagerEvent(msg.arg1, msg.arg2, msg.obj)) {
1107 return NOT_HANDLED;
1108 }
1109 break;
Irfan Sheriff75006652012-04-17 23:15:29 -07001110 default:
Hugo Benichif0c84092017-04-05 14:43:29 +09001111 return NOT_HANDLED;
Irfan Sheriff75006652012-04-17 23:15:29 -07001112 }
Hugo Benichif0c84092017-04-05 14:43:29 +09001113 return HANDLED;
Irfan Sheriff75006652012-04-17 23:15:29 -07001114 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001115
Paul Hud44e1b72023-06-16 02:07:42 +00001116 private boolean handleMDnsServiceEvent(int code, int transactionId, Object obj) {
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001117 NsdServiceInfo servInfo;
Paul Hud44e1b72023-06-16 02:07:42 +00001118 ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001119 if (clientInfo == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00001120 Log.e(TAG, String.format(
1121 "transactionId %d for %d has no client mapping", transactionId, code));
Hugo Benichif0c84092017-04-05 14:43:29 +09001122 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001123 }
1124
1125 /* This goes in response as msg.arg2 */
Paul Hud44e1b72023-06-16 02:07:42 +00001126 int clientRequestId = clientInfo.getClientRequestId(transactionId);
1127 if (clientRequestId < 0) {
Vinit Deshapnde930a8512013-06-25 19:45:03 -07001128 // This can happen because of race conditions. For example,
1129 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
1130 // and we may get in this situation.
Paul Hud44e1b72023-06-16 02:07:42 +00001131 Log.d(TAG, String.format("%d for transactionId %d that is no longer active",
1132 code, transactionId));
Hugo Benichif0c84092017-04-05 14:43:29 +09001133 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001134 }
Hugo Benichi32be63d2017-04-05 14:06:11 +09001135 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00001136 Log.d(TAG, String.format(
1137 "MDns service event code:%d transactionId=%d", code, transactionId));
Hugo Benichi32be63d2017-04-05 14:06:11 +09001138 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001139 switch (code) {
paulhu2b9ed952022-02-10 21:58:32 +08001140 case IMDnsEventListener.SERVICE_FOUND: {
1141 final DiscoveryInfo info = (DiscoveryInfo) obj;
1142 final String name = info.serviceName;
1143 final String type = info.registrationType;
1144 servInfo = new NsdServiceInfo(name, type);
1145 final int foundNetId = info.netId;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001146 if (foundNetId == 0L) {
1147 // Ignore services that do not have a Network: they are not usable
1148 // by apps, as they would need privileged permissions to use
1149 // interfaces that do not have an associated Network.
1150 break;
1151 }
Remi NGUYEN VAN643edb62023-01-23 19:14:57 +09001152 if (foundNetId == INetd.DUMMY_NET_ID) {
1153 // Ignore services on the dummy0 interface: they are only seen when
1154 // discovering locally advertised services, and are not reachable
1155 // through that interface.
1156 break;
1157 }
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001158 setServiceNetworkForCallback(servInfo, info.netId, info.interfaceIdx);
Paul Hud44e1b72023-06-16 02:07:42 +00001159 clientInfo.onServiceFound(clientRequestId, servInfo);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001160 break;
paulhu2b9ed952022-02-10 21:58:32 +08001161 }
1162 case IMDnsEventListener.SERVICE_LOST: {
1163 final DiscoveryInfo info = (DiscoveryInfo) obj;
1164 final String name = info.serviceName;
1165 final String type = info.registrationType;
1166 final int lostNetId = info.netId;
1167 servInfo = new NsdServiceInfo(name, type);
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001168 // The network could be set to null (netId 0) if it was torn down when the
1169 // service is lost
1170 // TODO: avoid returning null in that case, possibly by remembering
1171 // found services on the same interface index and their network at the time
1172 setServiceNetworkForCallback(servInfo, lostNetId, info.interfaceIdx);
Paul Hud44e1b72023-06-16 02:07:42 +00001173 clientInfo.onServiceLost(clientRequestId, servInfo);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001174 break;
paulhu2b9ed952022-02-10 21:58:32 +08001175 }
1176 case IMDnsEventListener.SERVICE_DISCOVERY_FAILED:
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001177 clientInfo.onDiscoverServicesFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001178 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001179 break;
paulhu2b9ed952022-02-10 21:58:32 +08001180 case IMDnsEventListener.SERVICE_REGISTERED: {
1181 final RegistrationInfo info = (RegistrationInfo) obj;
1182 final String name = info.serviceName;
1183 servInfo = new NsdServiceInfo(name, null /* serviceType */);
Paul Hud44e1b72023-06-16 02:07:42 +00001184 clientInfo.onRegisterServiceSucceeded(clientRequestId, servInfo);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001185 break;
paulhu2b9ed952022-02-10 21:58:32 +08001186 }
1187 case IMDnsEventListener.SERVICE_REGISTRATION_FAILED:
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001188 clientInfo.onRegisterServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001189 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001190 break;
paulhu2b9ed952022-02-10 21:58:32 +08001191 case IMDnsEventListener.SERVICE_RESOLVED: {
1192 final ResolutionInfo info = (ResolutionInfo) obj;
Sreeram Ramachandrana53dd7f2014-09-03 15:45:59 -07001193 int index = 0;
paulhu2b9ed952022-02-10 21:58:32 +08001194 final String fullName = info.serviceFullName;
1195 while (index < fullName.length() && fullName.charAt(index) != '.') {
1196 if (fullName.charAt(index) == '\\') {
Sreeram Ramachandrana53dd7f2014-09-03 15:45:59 -07001197 ++index;
1198 }
1199 ++index;
1200 }
paulhu2b9ed952022-02-10 21:58:32 +08001201 if (index >= fullName.length()) {
1202 Log.e(TAG, "Invalid service found " + fullName);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001203 break;
1204 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001205
paulhube186602022-04-12 07:18:23 +00001206 String name = unescape(fullName.substring(0, index));
paulhu2b9ed952022-02-10 21:58:32 +08001207 String rest = fullName.substring(index);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001208 String type = rest.replace(".local.", "");
1209
Paul Hu30bd70d2023-02-07 13:20:56 +00001210 final NsdServiceInfo serviceInfo = clientInfo.mResolvedService;
Paul Hu18aeccc2022-12-27 08:48:48 +00001211 serviceInfo.setServiceName(name);
1212 serviceInfo.setServiceType(type);
1213 serviceInfo.setPort(info.port);
1214 serviceInfo.setTxtRecords(info.txtRecord);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001215 // Network will be added after SERVICE_GET_ADDR_SUCCESS
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001216
Paul Hud44e1b72023-06-16 02:07:42 +00001217 stopResolveService(transactionId);
1218 removeRequestMap(clientRequestId, transactionId, clientInfo);
Vinit Deshapnde4429e872013-11-12 15:36:37 -08001219
Paul Hud44e1b72023-06-16 02:07:42 +00001220 final int transactionId2 = getUniqueId();
1221 if (getAddrInfo(transactionId2, info.hostname, info.interfaceIdx)) {
1222 storeLegacyRequestMap(clientRequestId, transactionId2, clientInfo,
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001223 NsdManager.RESOLVE_SERVICE);
Vinit Deshapnde4429e872013-11-12 15:36:37 -08001224 } else {
Paul Hu30bd70d2023-02-07 13:20:56 +00001225 clientInfo.onResolveServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001226 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Paul Hu30bd70d2023-02-07 13:20:56 +00001227 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001228 }
1229 break;
paulhu2b9ed952022-02-10 21:58:32 +08001230 }
1231 case IMDnsEventListener.SERVICE_RESOLUTION_FAILED:
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001232 /* NNN resolveId errorCode */
Paul Hud44e1b72023-06-16 02:07:42 +00001233 stopResolveService(transactionId);
1234 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hu30bd70d2023-02-07 13:20:56 +00001235 clientInfo.onResolveServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001236 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Paul Hu30bd70d2023-02-07 13:20:56 +00001237 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001238 break;
paulhu2b9ed952022-02-10 21:58:32 +08001239 case IMDnsEventListener.SERVICE_GET_ADDR_FAILED:
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001240 /* NNN resolveId errorCode */
Paul Hud44e1b72023-06-16 02:07:42 +00001241 stopGetAddrInfo(transactionId);
1242 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hu30bd70d2023-02-07 13:20:56 +00001243 clientInfo.onResolveServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001244 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Paul Hu30bd70d2023-02-07 13:20:56 +00001245 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001246 break;
paulhu2b9ed952022-02-10 21:58:32 +08001247 case IMDnsEventListener.SERVICE_GET_ADDR_SUCCESS: {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001248 /* NNN resolveId hostname ttl addr interfaceIdx netId */
paulhu2b9ed952022-02-10 21:58:32 +08001249 final GetAddressInfo info = (GetAddressInfo) obj;
1250 final String address = info.address;
1251 final int netId = info.netId;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001252 InetAddress serviceHost = null;
1253 try {
paulhu2b9ed952022-02-10 21:58:32 +08001254 serviceHost = InetAddress.getByName(address);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001255 } catch (UnknownHostException e) {
1256 Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e);
1257 }
1258
1259 // If the resolved service is on an interface without a network, consider it
1260 // as a failure: it would not be usable by apps as they would need
1261 // privileged permissions.
Paul Hu30bd70d2023-02-07 13:20:56 +00001262 if (netId != NETID_UNSET && serviceHost != null) {
1263 clientInfo.mResolvedService.setHost(serviceHost);
1264 setServiceNetworkForCallback(clientInfo.mResolvedService,
1265 netId, info.interfaceIdx);
1266 clientInfo.onResolveServiceSucceeded(
Paul Hud44e1b72023-06-16 02:07:42 +00001267 clientRequestId, clientInfo.mResolvedService);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001268 } else {
Paul Hu30bd70d2023-02-07 13:20:56 +00001269 clientInfo.onResolveServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001270 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001271 }
Paul Hud44e1b72023-06-16 02:07:42 +00001272 stopGetAddrInfo(transactionId);
1273 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hu30bd70d2023-02-07 13:20:56 +00001274 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001275 break;
paulhu2b9ed952022-02-10 21:58:32 +08001276 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001277 default:
Hugo Benichif0c84092017-04-05 14:43:29 +09001278 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001279 }
Hugo Benichif0c84092017-04-05 14:43:29 +09001280 return true;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001281 }
Paul Hu019621e2023-01-13 23:26:49 +08001282
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001283 @Nullable
1284 private NsdServiceInfo buildNsdServiceInfoFromMdnsEvent(
1285 final MdnsEvent event, int code) {
Paul Hu019621e2023-01-13 23:26:49 +08001286 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001287 final String[] typeArray = serviceInfo.getServiceType();
1288 final String joinedType;
1289 if (typeArray.length == 0
1290 || !typeArray[typeArray.length - 1].equals(LOCAL_DOMAIN_NAME)) {
1291 Log.wtf(TAG, "MdnsServiceInfo type does not end in .local: "
1292 + Arrays.toString(typeArray));
1293 return null;
1294 } else {
1295 joinedType = TextUtils.join(".",
1296 Arrays.copyOfRange(typeArray, 0, typeArray.length - 1));
1297 }
1298 final String serviceType;
1299 switch (code) {
1300 case NsdManager.SERVICE_FOUND:
1301 case NsdManager.SERVICE_LOST:
1302 // For consistency with historical behavior, discovered service types have
1303 // a dot at the end.
1304 serviceType = joinedType + ".";
1305 break;
1306 case RESOLVE_SERVICE_SUCCEEDED:
1307 // For consistency with historical behavior, resolved service types have
1308 // a dot at the beginning.
1309 serviceType = "." + joinedType;
1310 break;
1311 default:
1312 serviceType = joinedType;
1313 break;
1314 }
Paul Hu019621e2023-01-13 23:26:49 +08001315 final String serviceName = serviceInfo.getServiceInstanceName();
1316 final NsdServiceInfo servInfo = new NsdServiceInfo(serviceName, serviceType);
1317 final Network network = serviceInfo.getNetwork();
Yuyang Huang3bee9d42023-04-04 13:00:54 +09001318 // In MdnsDiscoveryManagerEvent, the Network can be null which means it is a
1319 // network for Tethering interface. In other words, the network == null means the
1320 // network has netId = INetd.LOCAL_NET_ID.
Paul Hu019621e2023-01-13 23:26:49 +08001321 setServiceNetworkForCallback(
1322 servInfo,
Yuyang Huang3bee9d42023-04-04 13:00:54 +09001323 network == null ? INetd.LOCAL_NET_ID : network.netId,
Paul Hu019621e2023-01-13 23:26:49 +08001324 serviceInfo.getInterfaceIndex());
1325 return servInfo;
1326 }
1327
1328 private boolean handleMdnsDiscoveryManagerEvent(
1329 int transactionId, int code, Object obj) {
Paul Hud44e1b72023-06-16 02:07:42 +00001330 final ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Paul Hu019621e2023-01-13 23:26:49 +08001331 if (clientInfo == null) {
1332 Log.e(TAG, String.format(
1333 "id %d for %d has no client mapping", transactionId, code));
1334 return false;
1335 }
1336
1337 final MdnsEvent event = (MdnsEvent) obj;
Paul Hud44e1b72023-06-16 02:07:42 +00001338 final int clientRequestId = event.mClientRequestId;
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001339 final NsdServiceInfo info = buildNsdServiceInfoFromMdnsEvent(event, code);
1340 // Errors are already logged if null
1341 if (info == null) return false;
Paul Hu83ec7f42023-06-07 18:04:09 +08001342 mServiceLogs.log(String.format(
1343 "MdnsDiscoveryManager event code=%s transactionId=%d",
1344 NsdManager.nameOf(code), transactionId));
Paul Hu019621e2023-01-13 23:26:49 +08001345 switch (code) {
1346 case NsdManager.SERVICE_FOUND:
Paul Hud44e1b72023-06-16 02:07:42 +00001347 clientInfo.onServiceFound(clientRequestId, info);
Paul Hu319751a2023-01-13 23:56:34 +08001348 break;
1349 case NsdManager.SERVICE_LOST:
Paul Hud44e1b72023-06-16 02:07:42 +00001350 clientInfo.onServiceLost(clientRequestId, info);
Paul Hu019621e2023-01-13 23:26:49 +08001351 break;
Paul Hu75069ed2023-01-14 00:31:09 +08001352 case NsdManager.RESOLVE_SERVICE_SUCCEEDED: {
Paul Hud44e1b72023-06-16 02:07:42 +00001353 final ClientRequest request =
1354 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001355 if (request == null) {
1356 Log.e(TAG, "Unknown client request in RESOLVE_SERVICE_SUCCEEDED");
1357 break;
1358 }
Paul Hu75069ed2023-01-14 00:31:09 +08001359 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
Paul Hu75069ed2023-01-14 00:31:09 +08001360 info.setPort(serviceInfo.getPort());
1361
1362 Map<String, String> attrs = serviceInfo.getAttributes();
1363 for (Map.Entry<String, String> kv : attrs.entrySet()) {
1364 final String key = kv.getKey();
1365 try {
1366 info.setAttribute(key, serviceInfo.getAttributeAsBytes(key));
1367 } catch (IllegalArgumentException e) {
1368 Log.e(TAG, "Invalid attribute", e);
1369 }
1370 }
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001371 final List<InetAddress> addresses = getInetAddresses(serviceInfo);
Paul Hu2b865912023-03-06 14:27:53 +08001372 if (addresses.size() != 0) {
1373 info.setHostAddresses(addresses);
Paul Hud44e1b72023-06-16 02:07:42 +00001374 clientInfo.onResolveServiceSucceeded(clientRequestId, info);
Paul Hu2b865912023-03-06 14:27:53 +08001375 } else {
1376 // No address. Notify resolution failure.
Paul Hu75069ed2023-01-14 00:31:09 +08001377 clientInfo.onResolveServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001378 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Paul Hu75069ed2023-01-14 00:31:09 +08001379 }
1380
1381 // Unregister the listener immediately like IMDnsEventListener design
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001382 if (!(request instanceof DiscoveryManagerRequest)) {
1383 Log.wtf(TAG, "non-DiscoveryManager request in DiscoveryManager event");
1384 break;
1385 }
Paul Hud44e1b72023-06-16 02:07:42 +00001386 stopDiscoveryManagerRequest(
1387 request, clientRequestId, transactionId, clientInfo);
Paul Hu75069ed2023-01-14 00:31:09 +08001388 break;
1389 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001390 case NsdManager.SERVICE_UPDATED: {
1391 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
1392 info.setPort(serviceInfo.getPort());
1393
1394 Map<String, String> attrs = serviceInfo.getAttributes();
1395 for (Map.Entry<String, String> kv : attrs.entrySet()) {
1396 final String key = kv.getKey();
1397 try {
1398 info.setAttribute(key, serviceInfo.getAttributeAsBytes(key));
1399 } catch (IllegalArgumentException e) {
1400 Log.e(TAG, "Invalid attribute", e);
1401 }
1402 }
1403
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001404 final List<InetAddress> addresses = getInetAddresses(serviceInfo);
Paul Hu30bd70d2023-02-07 13:20:56 +00001405 info.setHostAddresses(addresses);
Paul Hud44e1b72023-06-16 02:07:42 +00001406 clientInfo.onServiceUpdated(clientRequestId, info);
Paul Hu30bd70d2023-02-07 13:20:56 +00001407 break;
1408 }
1409 case NsdManager.SERVICE_UPDATED_LOST:
Paul Hud44e1b72023-06-16 02:07:42 +00001410 clientInfo.onServiceUpdatedLost(clientRequestId);
Paul Hu30bd70d2023-02-07 13:20:56 +00001411 break;
Paul Hu019621e2023-01-13 23:26:49 +08001412 default:
1413 return false;
1414 }
1415 return true;
1416 }
Irfan Sheriff75006652012-04-17 23:15:29 -07001417 }
1418 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001419
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001420 @NonNull
1421 private static List<InetAddress> getInetAddresses(@NonNull MdnsServiceInfo serviceInfo) {
1422 final List<String> v4Addrs = serviceInfo.getIpv4Addresses();
1423 final List<String> v6Addrs = serviceInfo.getIpv6Addresses();
1424 final List<InetAddress> addresses = new ArrayList<>(v4Addrs.size() + v6Addrs.size());
1425 for (String ipv4Address : v4Addrs) {
1426 try {
1427 addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
1428 } catch (IllegalArgumentException e) {
1429 Log.wtf(TAG, "Invalid ipv4 address", e);
1430 }
1431 }
1432 for (String ipv6Address : v6Addrs) {
1433 try {
Yuyang Huanga6a6ff92023-04-24 13:33:34 +09001434 final Inet6Address addr = (Inet6Address) InetAddresses.parseNumericAddress(
1435 ipv6Address);
1436 addresses.add(InetAddressUtils.withScopeId(addr, serviceInfo.getInterfaceIndex()));
1437 } catch (IllegalArgumentException e) {
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001438 Log.wtf(TAG, "Invalid ipv6 address", e);
1439 }
1440 }
1441 return addresses;
1442 }
1443
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001444 private static void setServiceNetworkForCallback(NsdServiceInfo info, int netId, int ifaceIdx) {
1445 switch (netId) {
1446 case NETID_UNSET:
1447 info.setNetwork(null);
1448 break;
1449 case INetd.LOCAL_NET_ID:
1450 // Special case for LOCAL_NET_ID: Networks on netId 99 are not generally
1451 // visible / usable for apps, so do not return it. Store the interface
1452 // index instead, so at least if the client tries to resolve the service
1453 // with that NsdServiceInfo, it will be done on the same interface.
1454 // If they recreate the NsdServiceInfo themselves, resolution would be
1455 // done on all interfaces as before T, which should also work.
1456 info.setNetwork(null);
1457 info.setInterfaceIndex(ifaceIdx);
1458 break;
1459 default:
1460 info.setNetwork(new Network(netId));
1461 }
1462 }
1463
paulhube186602022-04-12 07:18:23 +00001464 // The full service name is escaped from standard DNS rules on mdnsresponder, making it suitable
1465 // for passing to standard system DNS APIs such as res_query() . Thus, make the service name
1466 // unescape for getting right service address. See "Notes on DNS Name Escaping" on
1467 // external/mdnsresponder/mDNSShared/dns_sd.h for more details.
1468 private String unescape(String s) {
1469 StringBuilder sb = new StringBuilder(s.length());
1470 for (int i = 0; i < s.length(); ++i) {
1471 char c = s.charAt(i);
1472 if (c == '\\') {
1473 if (++i >= s.length()) {
1474 Log.e(TAG, "Unexpected end of escape sequence in: " + s);
1475 break;
1476 }
1477 c = s.charAt(i);
1478 if (c != '.' && c != '\\') {
1479 if (i + 2 >= s.length()) {
1480 Log.e(TAG, "Unexpected end of escape sequence in: " + s);
1481 break;
1482 }
1483 c = (char) ((c - '0') * 100 + (s.charAt(i + 1) - '0') * 10
1484 + (s.charAt(i + 2) - '0'));
1485 i += 2;
1486 }
1487 }
1488 sb.append(c);
1489 }
1490 return sb.toString();
1491 }
1492
Paul Hu7445e3d2023-03-03 15:14:00 +08001493 /**
1494 * Check the given service type is valid and construct it to a service type
1495 * which can use for discovery / resolution service.
1496 *
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001497 * <p>The valid service type should be 2 labels, or 3 labels if the query is for a
Paul Hu7445e3d2023-03-03 15:14:00 +08001498 * subtype (see RFC6763 7.1). Each label is up to 63 characters and must start with an
1499 * underscore; they are alphanumerical characters or dashes or underscore, except the
1500 * last one that is just alphanumerical. The last label must be _tcp or _udp.
1501 *
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001502 * <p>The subtype may also be specified with a comma after the service type, for example
1503 * _type._tcp,_subtype.
1504 *
Paul Hu7445e3d2023-03-03 15:14:00 +08001505 * @param serviceType the request service type for discovery / resolution service
1506 * @return constructed service type or null if the given service type is invalid.
1507 */
1508 @Nullable
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001509 public static Pair<String, String> parseTypeAndSubtype(String serviceType) {
Paul Hu7445e3d2023-03-03 15:14:00 +08001510 if (TextUtils.isEmpty(serviceType)) return null;
1511
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001512 final String typeOrSubtypePattern = "_[a-zA-Z0-9-_]{1,61}[a-zA-Z0-9]";
Paul Hu7445e3d2023-03-03 15:14:00 +08001513 final Pattern serviceTypePattern = Pattern.compile(
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001514 // Optional leading subtype (_subtype._type._tcp)
1515 // (?: xxx) is a non-capturing parenthesis, don't capture the dot
1516 "^(?:(" + typeOrSubtypePattern + ")\\.)?"
1517 // Actual type (_type._tcp.local)
1518 + "(" + typeOrSubtypePattern + "\\._(?:tcp|udp))"
Paul Hu7445e3d2023-03-03 15:14:00 +08001519 // Drop '.' at the end of service type that is compatible with old backend.
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001520 // e.g. allow "_type._tcp.local."
1521 + "\\.?"
1522 // Optional subtype after comma, for "_type._tcp,_subtype" format
1523 + "(?:,(" + typeOrSubtypePattern + "))?"
1524 + "$");
Paul Hu7445e3d2023-03-03 15:14:00 +08001525 final Matcher matcher = serviceTypePattern.matcher(serviceType);
1526 if (!matcher.matches()) return null;
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001527 // Use the subtype either at the beginning or after the comma
1528 final String subtype = matcher.group(1) != null ? matcher.group(1) : matcher.group(3);
1529 return new Pair<>(matcher.group(2), subtype);
Paul Hu7445e3d2023-03-03 15:14:00 +08001530 }
1531
Hugo Benichi803a2f02017-04-24 11:35:06 +09001532 @VisibleForTesting
paulhu2b9ed952022-02-10 21:58:32 +08001533 NsdService(Context ctx, Handler handler, long cleanupDelayMs) {
Paul Hu4bd98ef2023-01-12 13:42:07 +08001534 this(ctx, handler, cleanupDelayMs, new Dependencies());
1535 }
1536
1537 @VisibleForTesting
1538 NsdService(Context ctx, Handler handler, long cleanupDelayMs, Dependencies deps) {
Luke Huang05298582021-06-13 16:52:05 +00001539 mCleanupDelayMs = cleanupDelayMs;
Hugo Benichi803a2f02017-04-24 11:35:06 +09001540 mContext = ctx;
Hugo Benichi803a2f02017-04-24 11:35:06 +09001541 mNsdStateMachine = new NsdStateMachine(TAG, handler);
Irfan Sheriff75006652012-04-17 23:15:29 -07001542 mNsdStateMachine.start();
paulhu2b9ed952022-02-10 21:58:32 +08001543 mMDnsManager = ctx.getSystemService(MDnsManager.class);
1544 mMDnsEventCallback = new MDnsEventCallback(mNsdStateMachine);
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001545 mDeps = deps;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001546
Paul Hu14667de2023-04-17 22:42:47 +08001547 mMdnsSocketProvider = deps.makeMdnsSocketProvider(ctx, handler.getLooper(),
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001548 LOGGER.forSubComponent("MdnsSocketProvider"), new SocketRequestMonitor());
Yuyang Huang700778b2023-03-08 16:17:05 +09001549 // Netlink monitor starts on boot, and intentionally never stopped, to ensure that all
1550 // address events are received.
1551 handler.post(mMdnsSocketProvider::startNetLinkMonitor);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001552
1553 // NsdService is started after ActivityManager (startOtherServices in SystemServer, vs.
1554 // startBootstrapServices).
1555 mRunningAppActiveImportanceCutoff = mDeps.getDeviceConfigInt(
1556 MDNS_CONFIG_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF,
1557 DEFAULT_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF);
1558 final ActivityManager am = ctx.getSystemService(ActivityManager.class);
1559 am.addOnUidImportanceListener(new UidImportanceListener(handler),
1560 mRunningAppActiveImportanceCutoff);
1561
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001562 mMdnsSocketClient =
1563 new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider);
Paul Hu14667de2023-04-17 22:42:47 +08001564 mMdnsDiscoveryManager = deps.makeMdnsDiscoveryManager(new ExecutorProvider(),
Yuyang Huang243d1a52023-05-23 17:26:52 +09001565 mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"));
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001566 handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
1567 mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider,
Paul Hu14667de2023-04-17 22:42:47 +08001568 new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"));
Paul Hu4bd98ef2023-01-12 13:42:07 +08001569 }
1570
1571 /**
1572 * Dependencies of NsdService, for injection in tests.
1573 */
1574 @VisibleForTesting
1575 public static class Dependencies {
1576 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001577 * Check whether the MdnsDiscoveryManager feature is enabled.
Paul Hu4bd98ef2023-01-12 13:42:07 +08001578 *
1579 * @param context The global context information about an app environment.
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001580 * @return true if the MdnsDiscoveryManager feature is enabled.
Paul Hu4bd98ef2023-01-12 13:42:07 +08001581 */
1582 public boolean isMdnsDiscoveryManagerEnabled(Context context) {
Motomu Utsumi278db582023-04-21 12:35:22 +09001583 return isAtLeastU() || DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_TETHERING,
1584 MDNS_DISCOVERY_MANAGER_VERSION, DeviceConfigUtils.TETHERING_MODULE_NAME,
Remi NGUYEN VANbeb03f12023-03-08 19:03:27 +09001585 false /* defaultEnabled */);
Paul Hu4bd98ef2023-01-12 13:42:07 +08001586 }
1587
1588 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001589 * Check whether the MdnsAdvertiser feature is enabled.
1590 *
1591 * @param context The global context information about an app environment.
1592 * @return true if the MdnsAdvertiser feature is enabled.
1593 */
1594 public boolean isMdnsAdvertiserEnabled(Context context) {
Motomu Utsumi278db582023-04-21 12:35:22 +09001595 return isAtLeastU() || DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_TETHERING,
1596 MDNS_ADVERTISER_VERSION, DeviceConfigUtils.TETHERING_MODULE_NAME,
1597 false /* defaultEnabled */);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001598 }
1599
1600 /**
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001601 * Get the type allowlist flag value.
1602 * @see #MDNS_TYPE_ALLOWLIST_FLAGS
1603 */
1604 @Nullable
1605 public String getTypeAllowlistFlags() {
1606 return DeviceConfigUtils.getDeviceConfigProperty(NAMESPACE_TETHERING,
1607 MDNS_TYPE_ALLOWLIST_FLAGS, null);
1608 }
1609
1610 /**
1611 * @see DeviceConfigUtils#isFeatureEnabled(Context, String, String, String, boolean)
1612 */
1613 public boolean isFeatureEnabled(Context context, String feature) {
1614 return DeviceConfigUtils.isFeatureEnabled(context, NAMESPACE_TETHERING,
1615 feature, DeviceConfigUtils.TETHERING_MODULE_NAME, false /* defaultEnabled */);
1616 }
1617
1618 /**
Paul Hu4bd98ef2023-01-12 13:42:07 +08001619 * @see MdnsDiscoveryManager
1620 */
1621 public MdnsDiscoveryManager makeMdnsDiscoveryManager(
Paul Hu14667de2023-04-17 22:42:47 +08001622 @NonNull ExecutorProvider executorProvider,
Yuyang Huang243d1a52023-05-23 17:26:52 +09001623 @NonNull MdnsMultinetworkSocketClient socketClient, @NonNull SharedLog sharedLog) {
1624 return new MdnsDiscoveryManager(executorProvider, socketClient, sharedLog);
Paul Hu4bd98ef2023-01-12 13:42:07 +08001625 }
1626
1627 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001628 * @see MdnsAdvertiser
1629 */
1630 public MdnsAdvertiser makeMdnsAdvertiser(
1631 @NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
Paul Hu14667de2023-04-17 22:42:47 +08001632 @NonNull MdnsAdvertiser.AdvertiserCallback cb, @NonNull SharedLog sharedLog) {
1633 return new MdnsAdvertiser(looper, socketProvider, cb, sharedLog);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001634 }
1635
1636 /**
Paul Hu4bd98ef2023-01-12 13:42:07 +08001637 * @see MdnsSocketProvider
1638 */
Paul Hu14667de2023-04-17 22:42:47 +08001639 public MdnsSocketProvider makeMdnsSocketProvider(@NonNull Context context,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001640 @NonNull Looper looper, @NonNull SharedLog sharedLog,
1641 @NonNull MdnsSocketProvider.SocketRequestMonitor socketCreationCallback) {
1642 return new MdnsSocketProvider(context, looper, sharedLog, socketCreationCallback);
1643 }
1644
1645 /**
1646 * @see DeviceConfig#getInt(String, String, int)
1647 */
1648 public int getDeviceConfigInt(@NonNull String config, int defaultValue) {
1649 return DeviceConfig.getInt(NAMESPACE_TETHERING, config, defaultValue);
1650 }
1651
1652 /**
1653 * @see Binder#getCallingUid()
1654 */
1655 public int getCallingUid() {
1656 return Binder.getCallingUid();
Paul Hu4bd98ef2023-01-12 13:42:07 +08001657 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001658 }
1659
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001660 /**
1661 * Return whether a type is allowlisted to use the Java backend.
1662 * @param type The service type
1663 * @param flagPrefix One of {@link #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX} or
1664 * {@link #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX}.
1665 */
1666 private boolean isTypeAllowlistedForJavaBackend(@Nullable String type,
1667 @NonNull String flagPrefix) {
1668 if (type == null) return false;
1669 final String typesConfig = mDeps.getTypeAllowlistFlags();
1670 if (TextUtils.isEmpty(typesConfig)) return false;
1671
1672 final String mappingPrefix = type + ":";
1673 String mappedFlag = null;
1674 for (String mapping : TextUtils.split(typesConfig, ",")) {
1675 if (mapping.startsWith(mappingPrefix)) {
1676 mappedFlag = mapping.substring(mappingPrefix.length());
1677 break;
1678 }
1679 }
1680
1681 if (mappedFlag == null) return false;
1682
1683 return mDeps.isFeatureEnabled(mContext,
1684 flagPrefix + mappedFlag + MDNS_ALLOWLIST_FLAG_SUFFIX);
1685 }
1686
1687 private boolean useDiscoveryManagerForType(@Nullable String type) {
1688 return isTypeAllowlistedForJavaBackend(type, MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX);
1689 }
1690
1691 private boolean useAdvertiserForType(@Nullable String type) {
1692 return isTypeAllowlistedForJavaBackend(type, MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX);
1693 }
1694
paulhu1b35e822022-04-08 14:48:41 +08001695 public static NsdService create(Context context) {
Hugo Benichi803a2f02017-04-24 11:35:06 +09001696 HandlerThread thread = new HandlerThread(TAG);
1697 thread.start();
1698 Handler handler = new Handler(thread.getLooper());
paulhu2b9ed952022-02-10 21:58:32 +08001699 NsdService service = new NsdService(context, handler, CLEANUP_DELAY_MS);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001700 return service;
1701 }
1702
paulhu2b9ed952022-02-10 21:58:32 +08001703 private static class MDnsEventCallback extends IMDnsEventListener.Stub {
1704 private final StateMachine mStateMachine;
1705
1706 MDnsEventCallback(StateMachine sm) {
1707 mStateMachine = sm;
1708 }
1709
1710 @Override
1711 public void onServiceRegistrationStatus(final RegistrationInfo status) {
1712 mStateMachine.sendMessage(
1713 MDNS_SERVICE_EVENT, status.result, status.id, status);
1714 }
1715
1716 @Override
1717 public void onServiceDiscoveryStatus(final DiscoveryInfo status) {
1718 mStateMachine.sendMessage(
1719 MDNS_SERVICE_EVENT, status.result, status.id, status);
1720 }
1721
1722 @Override
1723 public void onServiceResolutionStatus(final ResolutionInfo status) {
1724 mStateMachine.sendMessage(
1725 MDNS_SERVICE_EVENT, status.result, status.id, status);
1726 }
1727
1728 @Override
1729 public void onGettingServiceAddressStatus(final GetAddressInfo status) {
1730 mStateMachine.sendMessage(
1731 MDNS_SERVICE_EVENT, status.result, status.id, status);
1732 }
1733
1734 @Override
1735 public int getInterfaceVersion() throws RemoteException {
1736 return this.VERSION;
1737 }
1738
1739 @Override
1740 public String getInterfaceHash() throws RemoteException {
1741 return this.HASH;
1742 }
1743 }
1744
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001745 private class AdvertiserCallback implements MdnsAdvertiser.AdvertiserCallback {
1746 @Override
Paul Hud44e1b72023-06-16 02:07:42 +00001747 public void onRegisterServiceSucceeded(int transactionId, NsdServiceInfo registeredInfo) {
1748 mServiceLogs.log("onRegisterServiceSucceeded: transactionId " + transactionId);
1749 final ClientInfo clientInfo = getClientInfoOrLog(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001750 if (clientInfo == null) return;
1751
Paul Hud44e1b72023-06-16 02:07:42 +00001752 final int clientRequestId = getClientRequestIdOrLog(clientInfo, transactionId);
1753 if (clientRequestId < 0) return;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001754
1755 // onRegisterServiceSucceeded only has the service name in its info. This aligns with
1756 // historical behavior.
1757 final NsdServiceInfo cbInfo = new NsdServiceInfo(registeredInfo.getServiceName(), null);
Paul Hud44e1b72023-06-16 02:07:42 +00001758 clientInfo.onRegisterServiceSucceeded(clientRequestId, cbInfo);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001759 }
1760
1761 @Override
Paul Hud44e1b72023-06-16 02:07:42 +00001762 public void onRegisterServiceFailed(int transactionId, int errorCode) {
1763 final ClientInfo clientInfo = getClientInfoOrLog(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001764 if (clientInfo == null) return;
1765
Paul Hud44e1b72023-06-16 02:07:42 +00001766 final int clientRequestId = getClientRequestIdOrLog(clientInfo, transactionId);
1767 if (clientRequestId < 0) return;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001768
Paul Hud44e1b72023-06-16 02:07:42 +00001769 clientInfo.onRegisterServiceFailed(clientRequestId, errorCode);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001770 }
1771
Paul Hud44e1b72023-06-16 02:07:42 +00001772 private ClientInfo getClientInfoOrLog(int transactionId) {
1773 final ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001774 if (clientInfo == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00001775 Log.e(TAG, String.format("Callback for service %d has no client", transactionId));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001776 }
1777 return clientInfo;
1778 }
1779
Paul Hud44e1b72023-06-16 02:07:42 +00001780 private int getClientRequestIdOrLog(@NonNull ClientInfo info, int transactionId) {
1781 final int clientRequestId = info.getClientRequestId(transactionId);
1782 if (clientRequestId < 0) {
1783 Log.e(TAG, String.format(
1784 "Client request ID not found for service %d", transactionId));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001785 }
Paul Hud44e1b72023-06-16 02:07:42 +00001786 return clientRequestId;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001787 }
1788 }
1789
Paul Hu2e0a88c2023-03-09 16:05:01 +08001790 private static class ConnectorArgs {
1791 @NonNull public final NsdServiceConnector connector;
1792 @NonNull public final INsdManagerCallback callback;
1793 public final boolean useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00001794 public final int uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08001795
1796 ConnectorArgs(@NonNull NsdServiceConnector connector, @NonNull INsdManagerCallback callback,
Paul Hub2e67d32023-04-18 05:50:14 +00001797 boolean useJavaBackend, int uid) {
Paul Hu2e0a88c2023-03-09 16:05:01 +08001798 this.connector = connector;
1799 this.callback = callback;
1800 this.useJavaBackend = useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00001801 this.uid = uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08001802 }
1803 }
1804
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001805 @Override
Paul Hu2e0a88c2023-03-09 16:05:01 +08001806 public INsdServiceConnector connect(INsdManagerCallback cb, boolean useJavaBackend) {
Hugo Benichi803a2f02017-04-24 11:35:06 +09001807 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
Paul Hu2e0a88c2023-03-09 16:05:01 +08001808 if (DBG) Log.d(TAG, "New client connect. useJavaBackend=" + useJavaBackend);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001809 final INsdServiceConnector connector = new NsdServiceConnector();
Paul Hub2e67d32023-04-18 05:50:14 +00001810 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.REGISTER_CLIENT,
1811 new ConnectorArgs((NsdServiceConnector) connector, cb, useJavaBackend,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001812 mDeps.getCallingUid())));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001813 return connector;
Irfan Sheriff75006652012-04-17 23:15:29 -07001814 }
1815
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001816 private static class ListenerArgs {
1817 public final NsdServiceConnector connector;
1818 public final NsdServiceInfo serviceInfo;
1819 ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) {
1820 this.connector = connector;
1821 this.serviceInfo = serviceInfo;
1822 }
1823 }
1824
1825 private class NsdServiceConnector extends INsdServiceConnector.Stub
1826 implements IBinder.DeathRecipient {
1827 @Override
1828 public void registerService(int listenerKey, NsdServiceInfo serviceInfo) {
1829 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1830 NsdManager.REGISTER_SERVICE, 0, listenerKey,
1831 new ListenerArgs(this, serviceInfo)));
1832 }
1833
1834 @Override
1835 public void unregisterService(int listenerKey) {
1836 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1837 NsdManager.UNREGISTER_SERVICE, 0, listenerKey,
1838 new ListenerArgs(this, null)));
1839 }
1840
1841 @Override
1842 public void discoverServices(int listenerKey, NsdServiceInfo serviceInfo) {
1843 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1844 NsdManager.DISCOVER_SERVICES, 0, listenerKey,
1845 new ListenerArgs(this, serviceInfo)));
1846 }
1847
1848 @Override
1849 public void stopDiscovery(int listenerKey) {
1850 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1851 NsdManager.STOP_DISCOVERY, 0, listenerKey, new ListenerArgs(this, null)));
1852 }
1853
1854 @Override
1855 public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) {
1856 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1857 NsdManager.RESOLVE_SERVICE, 0, listenerKey,
1858 new ListenerArgs(this, serviceInfo)));
1859 }
1860
1861 @Override
Paul Hub58deb72022-12-26 09:24:42 +00001862 public void stopResolution(int listenerKey) {
1863 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1864 NsdManager.STOP_RESOLUTION, 0, listenerKey, new ListenerArgs(this, null)));
1865 }
1866
1867 @Override
Paul Hu18aeccc2022-12-27 08:48:48 +00001868 public void registerServiceInfoCallback(int listenerKey, NsdServiceInfo serviceInfo) {
1869 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1870 NsdManager.REGISTER_SERVICE_CALLBACK, 0, listenerKey,
1871 new ListenerArgs(this, serviceInfo)));
1872 }
1873
1874 @Override
1875 public void unregisterServiceInfoCallback(int listenerKey) {
1876 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1877 NsdManager.UNREGISTER_SERVICE_CALLBACK, 0, listenerKey,
1878 new ListenerArgs(this, null)));
1879 }
1880
1881 @Override
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001882 public void startDaemon() {
1883 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
1884 NsdManager.DAEMON_STARTUP, new ListenerArgs(this, null)));
1885 }
1886
1887 @Override
1888 public void binderDied() {
1889 mNsdStateMachine.sendMessage(
1890 mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this));
1891 }
Irfan Sheriff75006652012-04-17 23:15:29 -07001892 }
1893
Hugo Benichi912db992017-04-24 16:41:03 +09001894 private void sendNsdStateChangeBroadcast(boolean isEnabled) {
Irfan Sheriff52fc83a2012-04-19 10:26:34 -07001895 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff75006652012-04-17 23:15:29 -07001896 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Hugo Benichi912db992017-04-24 16:41:03 +09001897 int nsdState = isEnabled ? NsdManager.NSD_STATE_ENABLED : NsdManager.NSD_STATE_DISABLED;
1898 intent.putExtra(NsdManager.EXTRA_NSD_STATE, nsdState);
Dianne Hackborn692107e2012-08-29 18:32:08 -07001899 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff75006652012-04-17 23:15:29 -07001900 }
1901
Irfan Sheriffe8de2462012-04-11 14:52:19 -07001902 private int getUniqueId() {
1903 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
1904 return mUniqueId;
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001905 }
1906
Paul Hud44e1b72023-06-16 02:07:42 +00001907 private boolean registerService(int transactionId, NsdServiceInfo service) {
Hugo Benichi6d706442017-04-24 16:19:58 +09001908 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00001909 Log.d(TAG, "registerService: " + transactionId + " " + service);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001910 }
Hugo Benichi6d706442017-04-24 16:19:58 +09001911 String name = service.getServiceName();
1912 String type = service.getServiceType();
1913 int port = service.getPort();
1914 byte[] textRecord = service.getTxtRecord();
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001915 final int registerInterface = getNetworkInterfaceIndex(service);
1916 if (service.getNetwork() != null && registerInterface == IFACE_IDX_ANY) {
Paul Hu360a8e92022-04-26 11:14:14 +08001917 Log.e(TAG, "Interface to register service on not found");
1918 return false;
1919 }
Paul Hud44e1b72023-06-16 02:07:42 +00001920 return mMDnsManager.registerService(
1921 transactionId, name, type, port, textRecord, registerInterface);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001922 }
1923
Paul Hud44e1b72023-06-16 02:07:42 +00001924 private boolean unregisterService(int transactionId) {
1925 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001926 }
1927
Paul Hud44e1b72023-06-16 02:07:42 +00001928 private boolean discoverServices(int transactionId, NsdServiceInfo serviceInfo) {
paulhu2b9ed952022-02-10 21:58:32 +08001929 final String type = serviceInfo.getServiceType();
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001930 final int discoverInterface = getNetworkInterfaceIndex(serviceInfo);
1931 if (serviceInfo.getNetwork() != null && discoverInterface == IFACE_IDX_ANY) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001932 Log.e(TAG, "Interface to discover service on not found");
1933 return false;
1934 }
Paul Hud44e1b72023-06-16 02:07:42 +00001935 return mMDnsManager.discover(transactionId, type, discoverInterface);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001936 }
1937
Paul Hud44e1b72023-06-16 02:07:42 +00001938 private boolean stopServiceDiscovery(int transactionId) {
1939 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001940 }
1941
Paul Hud44e1b72023-06-16 02:07:42 +00001942 private boolean resolveService(int transactionId, NsdServiceInfo service) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001943 final String name = service.getServiceName();
1944 final String type = service.getServiceType();
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001945 final int resolveInterface = getNetworkInterfaceIndex(service);
1946 if (service.getNetwork() != null && resolveInterface == IFACE_IDX_ANY) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001947 Log.e(TAG, "Interface to resolve service on not found");
1948 return false;
1949 }
Paul Hud44e1b72023-06-16 02:07:42 +00001950 return mMDnsManager.resolve(transactionId, name, type, "local.", resolveInterface);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001951 }
1952
1953 /**
1954 * Guess the interface to use to resolve or discover a service on a specific network.
1955 *
1956 * This is an imperfect guess, as for example the network may be gone or not yet fully
1957 * registered. This is fine as failing is correct if the network is gone, and a client
1958 * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also
1959 * this is to support the legacy mdnsresponder implementation, which historically resolved
1960 * services on an unspecified network.
1961 */
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001962 private int getNetworkInterfaceIndex(NsdServiceInfo serviceInfo) {
1963 final Network network = serviceInfo.getNetwork();
1964 if (network == null) {
1965 // Fallback to getInterfaceIndex if present (typically if the NsdServiceInfo was
1966 // provided by NsdService from discovery results, and the service was found on an
1967 // interface that has no app-usable Network).
1968 if (serviceInfo.getInterfaceIndex() != 0) {
1969 return serviceInfo.getInterfaceIndex();
1970 }
1971 return IFACE_IDX_ANY;
1972 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001973
1974 final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
1975 if (cm == null) {
1976 Log.wtf(TAG, "No ConnectivityManager for resolveService");
1977 return IFACE_IDX_ANY;
1978 }
1979 final LinkProperties lp = cm.getLinkProperties(network);
1980 if (lp == null) return IFACE_IDX_ANY;
1981
1982 // Only resolve on non-stacked interfaces
1983 final NetworkInterface iface;
1984 try {
1985 iface = NetworkInterface.getByName(lp.getInterfaceName());
1986 } catch (SocketException e) {
1987 Log.e(TAG, "Error querying interface", e);
1988 return IFACE_IDX_ANY;
1989 }
1990
1991 if (iface == null) {
1992 Log.e(TAG, "Interface not found: " + lp.getInterfaceName());
1993 return IFACE_IDX_ANY;
1994 }
1995
1996 return iface.getIndex();
Irfan Sheriffe8de2462012-04-11 14:52:19 -07001997 }
1998
Paul Hud44e1b72023-06-16 02:07:42 +00001999 private boolean stopResolveService(int transactionId) {
2000 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002001 }
2002
Paul Hud44e1b72023-06-16 02:07:42 +00002003 private boolean getAddrInfo(int transactionId, String hostname, int interfaceIdx) {
2004 return mMDnsManager.getServiceAddress(transactionId, hostname, interfaceIdx);
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002005 }
2006
Paul Hud44e1b72023-06-16 02:07:42 +00002007 private boolean stopGetAddrInfo(int transactionId) {
2008 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002009 }
2010
2011 @Override
Paul Hub2e67d32023-04-18 05:50:14 +00002012 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
2013 if (!PermissionUtils.checkDumpPermission(mContext, TAG, writer)) return;
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002014
Paul Hub2e67d32023-04-18 05:50:14 +00002015 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
2016 // Dump state machine logs
Irfan Sheriff75006652012-04-17 23:15:29 -07002017 mNsdStateMachine.dump(fd, pw, args);
Paul Hub2e67d32023-04-18 05:50:14 +00002018
2019 // Dump service and clients logs
2020 pw.println();
Paul Hu14667de2023-04-17 22:42:47 +08002021 pw.println("Logs:");
Paul Hub2e67d32023-04-18 05:50:14 +00002022 pw.increaseIndent();
2023 mServiceLogs.reverseDump(pw);
2024 pw.decreaseIndent();
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002025 }
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002026
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002027 private abstract static class ClientRequest {
Paul Hud44e1b72023-06-16 02:07:42 +00002028 private final int mTransactionId;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002029
Paul Hud44e1b72023-06-16 02:07:42 +00002030 private ClientRequest(int transactionId) {
2031 mTransactionId = transactionId;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002032 }
2033 }
2034
2035 private static class LegacyClientRequest extends ClientRequest {
2036 private final int mRequestCode;
2037
Paul Hud44e1b72023-06-16 02:07:42 +00002038 private LegacyClientRequest(int transactionId, int requestCode) {
2039 super(transactionId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002040 mRequestCode = requestCode;
2041 }
2042 }
2043
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002044 private abstract static class JavaBackendClientRequest extends ClientRequest {
2045 @Nullable
2046 private final Network mRequestedNetwork;
2047
Paul Hud44e1b72023-06-16 02:07:42 +00002048 private JavaBackendClientRequest(int transactionId, @Nullable Network requestedNetwork) {
2049 super(transactionId);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002050 mRequestedNetwork = requestedNetwork;
2051 }
2052
2053 @Nullable
2054 public Network getRequestedNetwork() {
2055 return mRequestedNetwork;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002056 }
2057 }
2058
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002059 private static class AdvertiserClientRequest extends JavaBackendClientRequest {
Paul Hud44e1b72023-06-16 02:07:42 +00002060 private AdvertiserClientRequest(int transactionId, @Nullable Network requestedNetwork) {
2061 super(transactionId, requestedNetwork);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002062 }
2063 }
2064
2065 private static class DiscoveryManagerRequest extends JavaBackendClientRequest {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002066 @NonNull
2067 private final MdnsListener mListener;
2068
Paul Hud44e1b72023-06-16 02:07:42 +00002069 private DiscoveryManagerRequest(int transactionId, @NonNull MdnsListener listener,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002070 @Nullable Network requestedNetwork) {
Paul Hud44e1b72023-06-16 02:07:42 +00002071 super(transactionId, requestedNetwork);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002072 mListener = listener;
2073 }
2074 }
2075
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002076 /* Information tracked per client */
2077 private class ClientInfo {
2078
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07002079 private static final int MAX_LIMIT = 10;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002080 private final INsdManagerCallback mCb;
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002081 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07002082 private NsdServiceInfo mResolvedService;
2083
Paul Hud44e1b72023-06-16 02:07:42 +00002084 /* A map from client request ID (listenerKey) to the request */
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002085 private final SparseArray<ClientRequest> mClientRequests = new SparseArray<>();
Paul Hu23fa2022023-01-13 22:57:24 +08002086
Luke Huangf7277ed2021-07-12 21:15:10 +08002087 // The target SDK of this client < Build.VERSION_CODES.S
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002088 private boolean mIsPreSClient = false;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002089 private final int mUid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002090 // The flag of using java backend if the client's target SDK >= U
2091 private final boolean mUseJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002092 // Store client logs
2093 private final SharedLog mClientLogs;
Paul Hucdef3532023-06-18 14:47:35 +00002094 // Report the nsd metrics data
2095 private final NetworkNsdReportedMetrics mMetrics;
Luke Huangf7277ed2021-07-12 21:15:10 +08002096
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002097 private ClientInfo(INsdManagerCallback cb, int uid, boolean useJavaBackend,
Paul Hucdef3532023-06-18 14:47:35 +00002098 SharedLog sharedLog, NetworkNsdReportedMetrics metrics) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002099 mCb = cb;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002100 mUid = uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002101 mUseJavaBackend = useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002102 mClientLogs = sharedLog;
2103 mClientLogs.log("New client. useJavaBackend=" + useJavaBackend);
Paul Hucdef3532023-06-18 14:47:35 +00002104 mMetrics = metrics;
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002105 }
Irfan Sheriff75006652012-04-17 23:15:29 -07002106
2107 @Override
2108 public String toString() {
Jeff Sharkey63465382020-10-17 21:20:13 -06002109 StringBuilder sb = new StringBuilder();
Irfan Sheriff75006652012-04-17 23:15:29 -07002110 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002111 sb.append("mIsLegacy ").append(mIsPreSClient).append("\n");
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002112 sb.append("mUseJavaBackend ").append(mUseJavaBackend).append("\n");
2113 sb.append("mUid ").append(mUid).append("\n");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002114 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002115 int clientRequestId = mClientRequests.keyAt(i);
2116 sb.append("clientRequestId ")
2117 .append(clientRequestId)
2118 .append(" transactionId ").append(mClientRequests.valueAt(i).mTransactionId)
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002119 .append(" type ").append(
2120 mClientRequests.valueAt(i).getClass().getSimpleName())
2121 .append("\n");
Irfan Sheriff75006652012-04-17 23:15:29 -07002122 }
2123 return sb.toString();
2124 }
Dave Plattfeff2af2014-03-07 14:48:22 -08002125
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002126 private boolean isPreSClient() {
2127 return mIsPreSClient;
Luke Huangf7277ed2021-07-12 21:15:10 +08002128 }
2129
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002130 private void setPreSClient() {
2131 mIsPreSClient = true;
Luke Huangf7277ed2021-07-12 21:15:10 +08002132 }
2133
Paul Hue4f5f252023-02-16 21:13:47 +08002134 private void unregisterMdnsListenerFromRequest(ClientRequest request) {
2135 final MdnsListener listener =
2136 ((DiscoveryManagerRequest) request).mListener;
2137 mMdnsDiscoveryManager.unregisterListener(
2138 listener.getListenedServiceType(), listener);
2139 }
2140
Dave Plattfeff2af2014-03-07 14:48:22 -08002141 // Remove any pending requests from the global map when we get rid of a client,
2142 // and send cancellations to the daemon.
2143 private void expungeAllRequests() {
Paul Hub2e67d32023-04-18 05:50:14 +00002144 mClientLogs.log("Client unregistered. expungeAllRequests!");
Hugo Benichid2552ae2017-04-11 14:42:47 +09002145 // TODO: to keep handler responsive, do not clean all requests for that client at once.
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002146 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002147 final int clientRequestId = mClientRequests.keyAt(i);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002148 final ClientRequest request = mClientRequests.valueAt(i);
Paul Hud44e1b72023-06-16 02:07:42 +00002149 final int transactionId = request.mTransactionId;
2150 mTransactionIdToClientInfoMap.remove(transactionId);
paulhub2225702021-11-17 09:35:33 +08002151 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00002152 Log.d(TAG, "Terminating clientRequestId " + clientRequestId
2153 + " transactionId " + transactionId
2154 + " type " + mClientRequests.get(clientRequestId));
paulhub2225702021-11-17 09:35:33 +08002155 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002156
2157 if (request instanceof DiscoveryManagerRequest) {
Paul Hue4f5f252023-02-16 21:13:47 +08002158 unregisterMdnsListenerFromRequest(request);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002159 continue;
2160 }
2161
2162 if (request instanceof AdvertiserClientRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +00002163 mAdvertiser.removeService(transactionId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002164 continue;
2165 }
2166
2167 if (!(request instanceof LegacyClientRequest)) {
2168 throw new IllegalStateException("Unknown request type: " + request.getClass());
2169 }
2170
2171 switch (((LegacyClientRequest) request).mRequestCode) {
Dave Plattfeff2af2014-03-07 14:48:22 -08002172 case NsdManager.DISCOVER_SERVICES:
Paul Hud44e1b72023-06-16 02:07:42 +00002173 stopServiceDiscovery(transactionId);
Dave Plattfeff2af2014-03-07 14:48:22 -08002174 break;
2175 case NsdManager.RESOLVE_SERVICE:
Paul Hud44e1b72023-06-16 02:07:42 +00002176 stopResolveService(transactionId);
Dave Plattfeff2af2014-03-07 14:48:22 -08002177 break;
2178 case NsdManager.REGISTER_SERVICE:
Paul Hud44e1b72023-06-16 02:07:42 +00002179 unregisterService(transactionId);
Dave Plattfeff2af2014-03-07 14:48:22 -08002180 break;
2181 default:
2182 break;
2183 }
2184 }
Dave Plattfeff2af2014-03-07 14:48:22 -08002185 mClientRequests.clear();
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002186 updateMulticastLock();
2187 }
2188
2189 /**
2190 * Returns true if this client has any Java backend request that requests one of the given
2191 * networks.
2192 */
2193 boolean hasAnyJavaBackendRequestForNetworks(@NonNull ArraySet<Network> networks) {
2194 for (int i = 0; i < mClientRequests.size(); i++) {
2195 final ClientRequest req = mClientRequests.valueAt(i);
2196 if (!(req instanceof JavaBackendClientRequest)) {
2197 continue;
2198 }
2199 final Network reqNetwork = ((JavaBackendClientRequest) mClientRequests.valueAt(i))
2200 .getRequestedNetwork();
2201 if (MdnsUtils.isAnyNetworkMatched(reqNetwork, networks)) {
2202 return true;
2203 }
2204 }
2205 return false;
Dave Plattfeff2af2014-03-07 14:48:22 -08002206 }
2207
Paul Hud44e1b72023-06-16 02:07:42 +00002208 // mClientRequests is a sparse array of client request id -> ClientRequest. For a given
2209 // transaction id, return the corresponding client request id.
2210 private int getClientRequestId(final int transactionId) {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002211 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002212 if (mClientRequests.valueAt(i).mTransactionId == transactionId) {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002213 return mClientRequests.keyAt(i);
2214 }
Christopher Lane74411222014-04-25 18:39:07 -07002215 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002216 return -1;
Christopher Lane74411222014-04-25 18:39:07 -07002217 }
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002218
Paul Hub2e67d32023-04-18 05:50:14 +00002219 private void log(String message) {
2220 mClientLogs.log(message);
2221 }
2222
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002223 void onDiscoverServicesStarted(int listenerKey, NsdServiceInfo info) {
2224 try {
2225 mCb.onDiscoverServicesStarted(listenerKey, info);
2226 } catch (RemoteException e) {
2227 Log.e(TAG, "Error calling onDiscoverServicesStarted", e);
2228 }
2229 }
2230
2231 void onDiscoverServicesFailed(int listenerKey, int error) {
2232 try {
2233 mCb.onDiscoverServicesFailed(listenerKey, error);
2234 } catch (RemoteException e) {
2235 Log.e(TAG, "Error calling onDiscoverServicesFailed", e);
2236 }
2237 }
2238
2239 void onServiceFound(int listenerKey, NsdServiceInfo info) {
2240 try {
2241 mCb.onServiceFound(listenerKey, info);
2242 } catch (RemoteException e) {
2243 Log.e(TAG, "Error calling onServiceFound(", e);
2244 }
2245 }
2246
2247 void onServiceLost(int listenerKey, NsdServiceInfo info) {
2248 try {
2249 mCb.onServiceLost(listenerKey, info);
2250 } catch (RemoteException e) {
2251 Log.e(TAG, "Error calling onServiceLost(", e);
2252 }
2253 }
2254
2255 void onStopDiscoveryFailed(int listenerKey, int error) {
2256 try {
2257 mCb.onStopDiscoveryFailed(listenerKey, error);
2258 } catch (RemoteException e) {
2259 Log.e(TAG, "Error calling onStopDiscoveryFailed", e);
2260 }
2261 }
2262
2263 void onStopDiscoverySucceeded(int listenerKey) {
2264 try {
2265 mCb.onStopDiscoverySucceeded(listenerKey);
2266 } catch (RemoteException e) {
2267 Log.e(TAG, "Error calling onStopDiscoverySucceeded", e);
2268 }
2269 }
2270
2271 void onRegisterServiceFailed(int listenerKey, int error) {
2272 try {
2273 mCb.onRegisterServiceFailed(listenerKey, error);
2274 } catch (RemoteException e) {
2275 Log.e(TAG, "Error calling onRegisterServiceFailed", e);
2276 }
2277 }
2278
2279 void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info) {
2280 try {
2281 mCb.onRegisterServiceSucceeded(listenerKey, info);
2282 } catch (RemoteException e) {
2283 Log.e(TAG, "Error calling onRegisterServiceSucceeded", e);
2284 }
2285 }
2286
2287 void onUnregisterServiceFailed(int listenerKey, int error) {
2288 try {
2289 mCb.onUnregisterServiceFailed(listenerKey, error);
2290 } catch (RemoteException e) {
2291 Log.e(TAG, "Error calling onUnregisterServiceFailed", e);
2292 }
2293 }
2294
2295 void onUnregisterServiceSucceeded(int listenerKey) {
2296 try {
2297 mCb.onUnregisterServiceSucceeded(listenerKey);
2298 } catch (RemoteException e) {
2299 Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e);
2300 }
2301 }
2302
2303 void onResolveServiceFailed(int listenerKey, int error) {
2304 try {
2305 mCb.onResolveServiceFailed(listenerKey, error);
2306 } catch (RemoteException e) {
2307 Log.e(TAG, "Error calling onResolveServiceFailed", e);
2308 }
2309 }
2310
2311 void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info) {
2312 try {
2313 mCb.onResolveServiceSucceeded(listenerKey, info);
2314 } catch (RemoteException e) {
2315 Log.e(TAG, "Error calling onResolveServiceSucceeded", e);
2316 }
2317 }
Paul Hub58deb72022-12-26 09:24:42 +00002318
2319 void onStopResolutionFailed(int listenerKey, int error) {
2320 try {
2321 mCb.onStopResolutionFailed(listenerKey, error);
2322 } catch (RemoteException e) {
2323 Log.e(TAG, "Error calling onStopResolutionFailed", e);
2324 }
2325 }
2326
2327 void onStopResolutionSucceeded(int listenerKey) {
2328 try {
2329 mCb.onStopResolutionSucceeded(listenerKey);
2330 } catch (RemoteException e) {
2331 Log.e(TAG, "Error calling onStopResolutionSucceeded", e);
2332 }
2333 }
Paul Hu18aeccc2022-12-27 08:48:48 +00002334
2335 void onServiceInfoCallbackRegistrationFailed(int listenerKey, int error) {
2336 try {
2337 mCb.onServiceInfoCallbackRegistrationFailed(listenerKey, error);
2338 } catch (RemoteException e) {
2339 Log.e(TAG, "Error calling onServiceInfoCallbackRegistrationFailed", e);
2340 }
2341 }
2342
2343 void onServiceUpdated(int listenerKey, NsdServiceInfo info) {
2344 try {
2345 mCb.onServiceUpdated(listenerKey, info);
2346 } catch (RemoteException e) {
2347 Log.e(TAG, "Error calling onServiceUpdated", e);
2348 }
2349 }
2350
2351 void onServiceUpdatedLost(int listenerKey) {
2352 try {
2353 mCb.onServiceUpdatedLost(listenerKey);
2354 } catch (RemoteException e) {
2355 Log.e(TAG, "Error calling onServiceUpdatedLost", e);
2356 }
2357 }
2358
2359 void onServiceInfoCallbackUnregistered(int listenerKey) {
2360 try {
2361 mCb.onServiceInfoCallbackUnregistered(listenerKey);
2362 } catch (RemoteException e) {
2363 Log.e(TAG, "Error calling onServiceInfoCallbackUnregistered", e);
2364 }
2365 }
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002366 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002367}