blob: edd481860fd854a3b7c741ee94b9cd8ae0476375 [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
Yuyang Huangd5896e72023-11-28 13:23:59 +090019import static android.Manifest.permission.DEVICE_POWER;
Yuyang Huang33fa4d22023-02-14 22:59:37 +090020import static android.Manifest.permission.NETWORK_SETTINGS;
Yuyang Huang8e6fbc82023-08-07 17:46:19 +090021import static android.Manifest.permission.NETWORK_STACK;
paulhu2b9ed952022-02-10 21:58:32 +080022import static android.net.ConnectivityManager.NETID_UNSET;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090023import static android.net.NetworkCapabilities.TRANSPORT_VPN;
24import static android.net.NetworkCapabilities.TRANSPORT_WIFI;
Yuyang Huang8e6fbc82023-08-07 17:46:19 +090025import static android.net.NetworkStack.PERMISSION_MAINLINE_NETWORK_STACK;
Paul Hu019621e2023-01-13 23:26:49 +080026import static android.net.nsd.NsdManager.MDNS_DISCOVERY_MANAGER_EVENT;
paulhu2b9ed952022-02-10 21:58:32 +080027import static android.net.nsd.NsdManager.MDNS_SERVICE_EVENT;
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +090028import static android.net.nsd.NsdManager.RESOLVE_SERVICE_SUCCEEDED;
Remi NGUYEN VAN629234c2024-02-08 18:27:45 +090029import static android.net.nsd.NsdManager.SUBTYPE_LABEL_REGEX;
Yuyang Huang86d083f2023-12-12 19:56:41 +090030import static android.net.nsd.NsdManager.TYPE_REGEX;
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +090031import static android.provider.DeviceConfig.NAMESPACE_TETHERING;
Motomu Utsumied4e7ec2023-09-13 14:58:32 +090032
Remi NGUYEN VANbeb03f12023-03-08 19:03:27 +090033import static com.android.modules.utils.build.SdkLevel.isAtLeastU;
Yuyang Huang8e6fbc82023-08-07 17:46:19 +090034import static com.android.networkstack.apishim.ConstantsShim.REGISTER_NSD_OFFLOAD_ENGINE;
Paul Hu043bcd42023-07-14 16:38:25 +080035import static com.android.server.connectivity.mdns.MdnsAdvertiser.AdvertiserMetrics;
36import static com.android.server.connectivity.mdns.MdnsConstants.NO_PACKET;
Yuyang Huangde802c82023-05-02 17:14:22 +090037import static com.android.server.connectivity.mdns.MdnsRecord.MAX_LABEL_LENGTH;
Paul Hu11a883d2023-12-14 07:36:44 +000038import static com.android.server.connectivity.mdns.MdnsSearchOptions.AGGRESSIVE_QUERY_MODE;
Paul Hu05086bd2024-01-26 03:48:51 +000039import static com.android.server.connectivity.mdns.MdnsSearchOptions.PASSIVE_QUERY_MODE;
Paul Hucdef3532023-06-18 14:47:35 +000040import static com.android.server.connectivity.mdns.util.MdnsUtils.Clock;
Remi NGUYEN VANbeb03f12023-03-08 19:03:27 +090041
Paul Hu23fa2022023-01-13 22:57:24 +080042import android.annotation.NonNull;
Paul Hu4bd98ef2023-01-12 13:42:07 +080043import android.annotation.Nullable;
Yuyang Huangfc831702023-08-21 17:48:48 +090044import android.annotation.RequiresApi;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090045import android.app.ActivityManager;
paulhua262cc12019-08-12 16:25:11 +080046import android.content.Context;
Irfan Sheriff75006652012-04-17 23:15:29 -070047import android.content.Intent;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +090048import android.net.ConnectivityManager;
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +090049import android.net.INetd;
Paul Hu75069ed2023-01-14 00:31:09 +080050import android.net.InetAddresses;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +090051import android.net.LinkProperties;
52import android.net.Network;
paulhu2b9ed952022-02-10 21:58:32 +080053import android.net.mdns.aidl.DiscoveryInfo;
54import android.net.mdns.aidl.GetAddressInfo;
55import android.net.mdns.aidl.IMDnsEventListener;
56import android.net.mdns.aidl.RegistrationInfo;
57import android.net.mdns.aidl.ResolutionInfo;
Yuyang Huang86d083f2023-12-12 19:56:41 +090058import android.net.nsd.AdvertisingRequest;
Kangping Dong1f1a3792023-12-10 22:05:04 +080059import android.net.nsd.DiscoveryRequest;
Irfan Sheriff77ec5582012-03-22 17:01:39 -070060import android.net.nsd.INsdManager;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +090061import android.net.nsd.INsdManagerCallback;
62import android.net.nsd.INsdServiceConnector;
Yuyang Huang33fa4d22023-02-14 22:59:37 +090063import android.net.nsd.IOffloadEngine;
paulhu2b9ed952022-02-10 21:58:32 +080064import android.net.nsd.MDnsManager;
Irfan Sheriff77ec5582012-03-22 17:01:39 -070065import android.net.nsd.NsdManager;
paulhua262cc12019-08-12 16:25:11 +080066import android.net.nsd.NsdServiceInfo;
Yuyang Huang33fa4d22023-02-14 22:59:37 +090067import android.net.nsd.OffloadEngine;
68import android.net.nsd.OffloadServiceInfo;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090069import android.net.wifi.WifiManager;
Paul Hub2e67d32023-04-18 05:50:14 +000070import android.os.Binder;
Yuyang Huangfc831702023-08-21 17:48:48 +090071import android.os.Build;
Hugo Benichi803a2f02017-04-24 11:35:06 +090072import android.os.Handler;
paulhua262cc12019-08-12 16:25:11 +080073import android.os.HandlerThread;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +090074import android.os.IBinder;
Paul Hu4bd98ef2023-01-12 13:42:07 +080075import android.os.Looper;
Irfan Sheriff77ec5582012-03-22 17:01:39 -070076import android.os.Message;
Yuyang Huang33fa4d22023-02-14 22:59:37 +090077import android.os.RemoteCallbackList;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +090078import android.os.RemoteException;
Dianne Hackborn692107e2012-08-29 18:32:08 -070079import android.os.UserHandle;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090080import android.provider.DeviceConfig;
Paul Hu23fa2022023-01-13 22:57:24 +080081import android.text.TextUtils;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090082import android.util.ArraySet;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +090083import android.util.Log;
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +090084import android.util.Pair;
Irfan Sheriffe4c42f42012-05-03 16:44:27 -070085import android.util.SparseArray;
Irfan Sheriff77ec5582012-03-22 17:01:39 -070086
paulhua262cc12019-08-12 16:25:11 +080087import com.android.internal.annotations.VisibleForTesting;
Paul Hub2e67d32023-04-18 05:50:14 +000088import com.android.internal.util.IndentingPrintWriter;
paulhua262cc12019-08-12 16:25:11 +080089import com.android.internal.util.State;
90import com.android.internal.util.StateMachine;
Paul Hucdef3532023-06-18 14:47:35 +000091import com.android.metrics.NetworkNsdReportedMetrics;
Yuyang Huang8e6fbc82023-08-07 17:46:19 +090092import com.android.modules.utils.build.SdkLevel;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +090093import com.android.net.module.util.CollectionUtils;
Paul Hu4bd98ef2023-01-12 13:42:07 +080094import com.android.net.module.util.DeviceConfigUtils;
Yuyang Huanga6a6ff92023-04-24 13:33:34 +090095import com.android.net.module.util.InetAddressUtils;
paulhu3ffffe72021-09-16 10:15:22 +080096import com.android.net.module.util.PermissionUtils;
Paul Hub2e67d32023-04-18 05:50:14 +000097import com.android.net.module.util.SharedLog;
Paul Hu4bd98ef2023-01-12 13:42:07 +080098import com.android.server.connectivity.mdns.ExecutorProvider;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +090099import com.android.server.connectivity.mdns.MdnsAdvertiser;
Yuyang Huange5cba9c2023-11-02 18:05:47 +0900100import com.android.server.connectivity.mdns.MdnsAdvertisingOptions;
Paul Hu4bd98ef2023-01-12 13:42:07 +0800101import com.android.server.connectivity.mdns.MdnsDiscoveryManager;
Yuyang Huangb96a0712023-09-07 15:13:15 +0900102import com.android.server.connectivity.mdns.MdnsFeatureFlags;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900103import com.android.server.connectivity.mdns.MdnsInterfaceSocket;
Paul Hu4bd98ef2023-01-12 13:42:07 +0800104import com.android.server.connectivity.mdns.MdnsMultinetworkSocketClient;
Paul Hu23fa2022023-01-13 22:57:24 +0800105import com.android.server.connectivity.mdns.MdnsSearchOptions;
106import com.android.server.connectivity.mdns.MdnsServiceBrowserListener;
107import com.android.server.connectivity.mdns.MdnsServiceInfo;
Paul Hu4bd98ef2023-01-12 13:42:07 +0800108import com.android.server.connectivity.mdns.MdnsSocketProvider;
Yuyang Huangde802c82023-05-02 17:14:22 +0900109import com.android.server.connectivity.mdns.util.MdnsUtils;
paulhua262cc12019-08-12 16:25:11 +0800110
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700111import java.io.FileDescriptor;
112import java.io.PrintWriter;
Yuyang Huangaa0e9602023-03-17 12:43:09 +0900113import java.net.Inet6Address;
Irfan Sheriffe8de2462012-04-11 14:52:19 -0700114import java.net.InetAddress;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +0900115import java.net.NetworkInterface;
116import java.net.SocketException;
117import java.net.UnknownHostException;
Paul Hu2b865912023-03-06 14:27:53 +0800118import java.util.ArrayList;
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +0900119import java.util.Arrays;
Kangping Dong5af24b62023-12-10 21:41:16 +0800120import java.util.Collection;
Yuyang Huang170d42f2023-12-09 15:26:16 +0900121import java.util.Collections;
Irfan Sheriffe8de2462012-04-11 14:52:19 -0700122import java.util.HashMap;
Kangping Dong5af24b62023-12-10 21:41:16 +0800123import java.util.LinkedHashMap;
Paul Hu23fa2022023-01-13 22:57:24 +0800124import java.util.List;
Paul Hu75069ed2023-01-14 00:31:09 +0800125import java.util.Map;
Yuyang Huang33fa4d22023-02-14 22:59:37 +0900126import java.util.Objects;
Paul Hu812e9212023-06-20 06:24:53 +0000127import java.util.Set;
Paul Hu23fa2022023-01-13 22:57:24 +0800128import java.util.regex.Matcher;
129import java.util.regex.Pattern;
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700130
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700131/**
132 * Network Service Discovery Service handles remote service discovery operation requests by
133 * implementing the INsdManager interface.
134 *
135 * @hide
136 */
Yuyang Huangfc831702023-08-21 17:48:48 +0900137@RequiresApi(Build.VERSION_CODES.TIRAMISU)
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700138public class NsdService extends INsdManager.Stub {
139 private static final String TAG = "NsdService";
140 private static final String MDNS_TAG = "mDnsConnector";
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900141 /**
142 * Enable discovery using the Java DiscoveryManager, instead of the legacy mdnsresponder
143 * implementation.
144 */
Paul Hu4bd98ef2023-01-12 13:42:07 +0800145 private static final String MDNS_DISCOVERY_MANAGER_VERSION = "mdns_discovery_manager_version";
Paul Hu23fa2022023-01-13 22:57:24 +0800146 private static final String LOCAL_DOMAIN_NAME = "local";
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700147
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900148 /**
149 * Enable advertising using the Java MdnsAdvertiser, instead of the legacy mdnsresponder
150 * implementation.
151 */
152 private static final String MDNS_ADVERTISER_VERSION = "mdns_advertiser_version";
153
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900154 /**
155 * Comma-separated list of type:flag mappings indicating the flags to use to allowlist
156 * discovery/advertising using MdnsDiscoveryManager / MdnsAdvertiser for a given type.
157 *
158 * For example _mytype._tcp.local and _othertype._tcp.local would be configured with:
159 * _mytype._tcp:mytype,_othertype._tcp.local:othertype
160 *
161 * In which case the flags:
162 * "mdns_discovery_manager_allowlist_mytype_version",
163 * "mdns_advertiser_allowlist_mytype_version",
164 * "mdns_discovery_manager_allowlist_othertype_version",
165 * "mdns_advertiser_allowlist_othertype_version"
166 * would be used to toggle MdnsDiscoveryManager / MdnsAdvertiser for each type. The flags will
167 * be read with
Motomu Utsumi624aeb42023-08-15 15:52:27 +0900168 * {@link DeviceConfigUtils#isTetheringFeatureEnabled}
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900169 *
170 * @see #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX
171 * @see #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX
172 * @see #MDNS_ALLOWLIST_FLAG_SUFFIX
173 */
174 private static final String MDNS_TYPE_ALLOWLIST_FLAGS = "mdns_type_allowlist_flags";
175
176 private static final String MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX =
177 "mdns_discovery_manager_allowlist_";
178 private static final String MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX =
179 "mdns_advertiser_allowlist_";
180 private static final String MDNS_ALLOWLIST_FLAG_SUFFIX = "_version";
181
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +0900182 private static final String FORCE_ENABLE_FLAG_FOR_TEST_PREFIX = "test_";
Kangping Dong5af24b62023-12-10 21:41:16 +0800183
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900184 @VisibleForTesting
185 static final String MDNS_CONFIG_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF =
186 "mdns_config_running_app_active_importance_cutoff";
187 @VisibleForTesting
188 static final int DEFAULT_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF =
189 ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;
190 private final int mRunningAppActiveImportanceCutoff;
191
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900192 public static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
Luke Huang92860f92021-06-23 06:29:30 +0000193 private static final long CLEANUP_DELAY_MS = 10000;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +0900194 private static final int IFACE_IDX_ANY = 0;
Paul Hu812e9212023-06-20 06:24:53 +0000195 private static final int MAX_SERVICES_COUNT_METRIC_PER_CLIENT = 100;
196 @VisibleForTesting
197 static final int NO_TRANSACTION = -1;
Paul Hubad6fe92023-07-24 21:25:22 +0800198 private static final int NO_SENT_QUERY_COUNT = 0;
199 private static final int DISCOVERY_QUERY_SENT_CALLBACK = 1000;
Kangping Dong5af24b62023-12-10 21:41:16 +0800200 private static final int MAX_SUBTYPE_COUNT = 100;
Paul Hu14667de2023-04-17 22:42:47 +0800201 private static final SharedLog LOGGER = new SharedLog("serviceDiscovery");
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700202
Hugo Benichi32be63d2017-04-05 14:06:11 +0900203 private final Context mContext;
Hugo Benichi32be63d2017-04-05 14:06:11 +0900204 private final NsdStateMachine mNsdStateMachine;
Ken Chen80c9f6f2023-11-15 18:24:54 +0800205 // It can be null on V+ device since mdns native service provided by netd is removed.
206 private final @Nullable MDnsManager mMDnsManager;
paulhu2b9ed952022-02-10 21:58:32 +0800207 private final MDnsEventCallback mMDnsEventCallback;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900208 @NonNull
209 private final Dependencies mDeps;
210 @NonNull
Paul Hu4bd98ef2023-01-12 13:42:07 +0800211 private final MdnsMultinetworkSocketClient mMdnsSocketClient;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900212 @NonNull
Paul Hu4bd98ef2023-01-12 13:42:07 +0800213 private final MdnsDiscoveryManager mMdnsDiscoveryManager;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900214 @NonNull
Paul Hu4bd98ef2023-01-12 13:42:07 +0800215 private final MdnsSocketProvider mMdnsSocketProvider;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900216 @NonNull
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900217 private final MdnsAdvertiser mAdvertiser;
Paul Hu777ed052023-06-19 13:35:15 +0000218 @NonNull
219 private final Clock mClock;
Paul Hu14667de2023-04-17 22:42:47 +0800220 private final SharedLog mServiceLogs = LOGGER.forSubComponent(TAG);
Paul Hu23fa2022023-01-13 22:57:24 +0800221 // WARNING : Accessing these values in any thread is not safe, it must only be changed in the
paulhu2b9ed952022-02-10 21:58:32 +0800222 // state machine thread. If change this outside state machine, it will need to introduce
223 // synchronization.
224 private boolean mIsDaemonStarted = false;
Paul Hu23fa2022023-01-13 22:57:24 +0800225 private boolean mIsMonitoringSocketsStarted = false;
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700226
227 /**
228 * Clients receiving asynchronous messages
229 */
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900230 private final HashMap<NsdServiceConnector, ClientInfo> mClients = new HashMap<>();
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700231
Paul Hud44e1b72023-06-16 02:07:42 +0000232 /* A map from transaction(unique) id to client info */
233 private final SparseArray<ClientInfo> mTransactionIdToClientInfoMap = new SparseArray<>();
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700234
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900235 // Note this is not final to avoid depending on the Wi-Fi service starting before NsdService
236 @Nullable
237 private WifiManager.MulticastLock mHeldMulticastLock;
238 // Fulfilled network requests that require the Wi-Fi lock: key is the obtained Network
239 // (non-null), value is the requested Network (nullable)
240 @NonNull
241 private final ArraySet<Network> mWifiLockRequiredNetworks = new ArraySet<>();
242 @NonNull
243 private final ArraySet<Integer> mRunningAppActiveUids = new ArraySet<>();
244
Luke Huang05298582021-06-13 16:52:05 +0000245 private final long mCleanupDelayMs;
Irfan Sheriff77ec5582012-03-22 17:01:39 -0700246
Hugo Benichi32be63d2017-04-05 14:06:11 +0900247 private static final int INVALID_ID = 0;
Irfan Sheriffe8de2462012-04-11 14:52:19 -0700248 private int mUniqueId = 1;
Luke Huangf7277ed2021-07-12 21:15:10 +0800249 // The count of the connected legacy clients.
250 private int mLegacyClientCount = 0;
Paul Hub2e67d32023-04-18 05:50:14 +0000251 // The number of client that ever connected.
252 private int mClientNumberId = 1;
Irfan Sheriffe8de2462012-04-11 14:52:19 -0700253
Yuyang Huang33fa4d22023-02-14 22:59:37 +0900254 private final RemoteCallbackList<IOffloadEngine> mOffloadEngines =
255 new RemoteCallbackList<>();
Paul Hu11a883d2023-12-14 07:36:44 +0000256 @NonNull
257 private final MdnsFeatureFlags mMdnsFeatureFlags;
Yuyang Huang33fa4d22023-02-14 22:59:37 +0900258
259 private static class OffloadEngineInfo {
260 @NonNull final String mInterfaceName;
261 final long mOffloadCapabilities;
262 final long mOffloadType;
263 @NonNull final IOffloadEngine mOffloadEngine;
264
265 OffloadEngineInfo(@NonNull IOffloadEngine offloadEngine,
266 @NonNull String interfaceName, long capabilities, long offloadType) {
267 this.mOffloadEngine = offloadEngine;
268 this.mInterfaceName = interfaceName;
269 this.mOffloadCapabilities = capabilities;
270 this.mOffloadType = offloadType;
271 }
272 }
273
Paul Hu812e9212023-06-20 06:24:53 +0000274 @VisibleForTesting
275 static class MdnsListener implements MdnsServiceBrowserListener {
Paul Hud44e1b72023-06-16 02:07:42 +0000276 protected final int mClientRequestId;
Paul Hu23fa2022023-01-13 22:57:24 +0800277 protected final int mTransactionId;
278 @NonNull
Paul Hu23fa2022023-01-13 22:57:24 +0800279 protected final String mListenedServiceType;
280
Kangping Dong97b2adc2024-01-11 16:00:37 +0800281 MdnsListener(int clientRequestId, int transactionId, @NonNull String listenedServiceType) {
Paul Hud44e1b72023-06-16 02:07:42 +0000282 mClientRequestId = clientRequestId;
Paul Hu23fa2022023-01-13 22:57:24 +0800283 mTransactionId = transactionId;
Paul Hu23fa2022023-01-13 22:57:24 +0800284 mListenedServiceType = listenedServiceType;
285 }
286
287 @NonNull
288 public String getListenedServiceType() {
289 return mListenedServiceType;
290 }
291
292 @Override
Paul Hua6bc4632023-06-26 01:18:29 +0000293 public void onServiceFound(@NonNull MdnsServiceInfo serviceInfo,
294 boolean isServiceFromCache) { }
Paul Hu23fa2022023-01-13 22:57:24 +0800295
296 @Override
297 public void onServiceUpdated(@NonNull MdnsServiceInfo serviceInfo) { }
298
299 @Override
300 public void onServiceRemoved(@NonNull MdnsServiceInfo serviceInfo) { }
301
302 @Override
Paul Hua6bc4632023-06-26 01:18:29 +0000303 public void onServiceNameDiscovered(@NonNull MdnsServiceInfo serviceInfo,
304 boolean isServiceFromCache) { }
Paul Hu23fa2022023-01-13 22:57:24 +0800305
306 @Override
307 public void onServiceNameRemoved(@NonNull MdnsServiceInfo serviceInfo) { }
308
309 @Override
310 public void onSearchStoppedWithError(int error) { }
311
312 @Override
313 public void onSearchFailedToStart() { }
314
315 @Override
Paul Hubad6fe92023-07-24 21:25:22 +0800316 public void onDiscoveryQuerySent(@NonNull List<String> subtypes,
317 int sentQueryTransactionId) { }
Paul Hu23fa2022023-01-13 22:57:24 +0800318
319 @Override
320 public void onFailedToParseMdnsResponse(int receivedPacketNumber, int errorCode) { }
321 }
322
323 private class DiscoveryListener extends MdnsListener {
324
Paul Hud44e1b72023-06-16 02:07:42 +0000325 DiscoveryListener(int clientRequestId, int transactionId,
Kangping Dong97b2adc2024-01-11 16:00:37 +0800326 @NonNull String listenServiceType) {
327 super(clientRequestId, transactionId, listenServiceType);
Paul Hu23fa2022023-01-13 22:57:24 +0800328 }
329
330 @Override
Paul Hua6bc4632023-06-26 01:18:29 +0000331 public void onServiceNameDiscovered(@NonNull MdnsServiceInfo serviceInfo,
332 boolean isServiceFromCache) {
Paul Hu019621e2023-01-13 23:26:49 +0800333 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
334 NsdManager.SERVICE_FOUND,
Paul Hua6bc4632023-06-26 01:18:29 +0000335 new MdnsEvent(mClientRequestId, serviceInfo, isServiceFromCache));
Paul Hu23fa2022023-01-13 22:57:24 +0800336 }
337
338 @Override
339 public void onServiceNameRemoved(@NonNull MdnsServiceInfo serviceInfo) {
Paul Hu319751a2023-01-13 23:56:34 +0800340 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
341 NsdManager.SERVICE_LOST,
Paul Hud44e1b72023-06-16 02:07:42 +0000342 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu23fa2022023-01-13 22:57:24 +0800343 }
Paul Hubad6fe92023-07-24 21:25:22 +0800344
345 @Override
346 public void onDiscoveryQuerySent(@NonNull List<String> subtypes,
347 int sentQueryTransactionId) {
348 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
349 DISCOVERY_QUERY_SENT_CALLBACK, new MdnsEvent(mClientRequestId));
350 }
Paul Hu23fa2022023-01-13 22:57:24 +0800351 }
352
Paul Hu75069ed2023-01-14 00:31:09 +0800353 private class ResolutionListener extends MdnsListener {
354
Paul Hud44e1b72023-06-16 02:07:42 +0000355 ResolutionListener(int clientRequestId, int transactionId,
Kangping Dong97b2adc2024-01-11 16:00:37 +0800356 @NonNull String listenServiceType) {
357 super(clientRequestId, transactionId, listenServiceType);
Paul Hu75069ed2023-01-14 00:31:09 +0800358 }
359
360 @Override
Paul Hua6bc4632023-06-26 01:18:29 +0000361 public void onServiceFound(MdnsServiceInfo serviceInfo, boolean isServiceFromCache) {
Paul Hu75069ed2023-01-14 00:31:09 +0800362 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
363 NsdManager.RESOLVE_SERVICE_SUCCEEDED,
Paul Hua6bc4632023-06-26 01:18:29 +0000364 new MdnsEvent(mClientRequestId, serviceInfo, isServiceFromCache));
Paul Hu75069ed2023-01-14 00:31:09 +0800365 }
Paul Hubad6fe92023-07-24 21:25:22 +0800366
367 @Override
368 public void onDiscoveryQuerySent(@NonNull List<String> subtypes,
369 int sentQueryTransactionId) {
370 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
371 DISCOVERY_QUERY_SENT_CALLBACK, new MdnsEvent(mClientRequestId));
372 }
Paul Hu75069ed2023-01-14 00:31:09 +0800373 }
374
Paul Hu30bd70d2023-02-07 13:20:56 +0000375 private class ServiceInfoListener extends MdnsListener {
376
Paul Hud44e1b72023-06-16 02:07:42 +0000377 ServiceInfoListener(int clientRequestId, int transactionId,
Kangping Dong97b2adc2024-01-11 16:00:37 +0800378 @NonNull String listenServiceType) {
379 super(clientRequestId, transactionId, listenServiceType);
Paul Hu30bd70d2023-02-07 13:20:56 +0000380 }
381
382 @Override
Paul Hua6bc4632023-06-26 01:18:29 +0000383 public void onServiceFound(@NonNull MdnsServiceInfo serviceInfo,
384 boolean isServiceFromCache) {
Paul Hu30bd70d2023-02-07 13:20:56 +0000385 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
386 NsdManager.SERVICE_UPDATED,
Paul Hua6bc4632023-06-26 01:18:29 +0000387 new MdnsEvent(mClientRequestId, serviceInfo, isServiceFromCache));
Paul Hu30bd70d2023-02-07 13:20:56 +0000388 }
389
390 @Override
391 public void onServiceUpdated(@NonNull MdnsServiceInfo serviceInfo) {
392 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
393 NsdManager.SERVICE_UPDATED,
Paul Hud44e1b72023-06-16 02:07:42 +0000394 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu30bd70d2023-02-07 13:20:56 +0000395 }
396
397 @Override
398 public void onServiceRemoved(@NonNull MdnsServiceInfo serviceInfo) {
399 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
400 NsdManager.SERVICE_UPDATED_LOST,
Paul Hud44e1b72023-06-16 02:07:42 +0000401 new MdnsEvent(mClientRequestId, serviceInfo));
Paul Hu30bd70d2023-02-07 13:20:56 +0000402 }
Paul Hubad6fe92023-07-24 21:25:22 +0800403
404 @Override
405 public void onDiscoveryQuerySent(@NonNull List<String> subtypes,
406 int sentQueryTransactionId) {
407 mNsdStateMachine.sendMessage(MDNS_DISCOVERY_MANAGER_EVENT, mTransactionId,
408 DISCOVERY_QUERY_SENT_CALLBACK, new MdnsEvent(mClientRequestId));
409 }
Paul Hu30bd70d2023-02-07 13:20:56 +0000410 }
411
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900412 private class SocketRequestMonitor implements MdnsSocketProvider.SocketRequestMonitor {
413 @Override
414 public void onSocketRequestFulfilled(@Nullable Network socketNetwork,
415 @NonNull MdnsInterfaceSocket socket, @NonNull int[] transports) {
416 // The network may be null for Wi-Fi SoftAp interfaces (tethering), but there is no APF
417 // filtering on such interfaces, so taking the multicast lock is not necessary to
418 // disable APF filtering of multicast.
419 if (socketNetwork == null
420 || !CollectionUtils.contains(transports, TRANSPORT_WIFI)
421 || CollectionUtils.contains(transports, TRANSPORT_VPN)) {
422 return;
423 }
424
425 if (mWifiLockRequiredNetworks.add(socketNetwork)) {
426 updateMulticastLock();
427 }
428 }
429
430 @Override
431 public void onSocketDestroyed(@Nullable Network socketNetwork,
432 @NonNull MdnsInterfaceSocket socket) {
433 if (mWifiLockRequiredNetworks.remove(socketNetwork)) {
434 updateMulticastLock();
435 }
436 }
437 }
438
439 private class UidImportanceListener implements ActivityManager.OnUidImportanceListener {
440 private final Handler mHandler;
441
442 private UidImportanceListener(Handler handler) {
443 mHandler = handler;
444 }
445
446 @Override
447 public void onUidImportance(int uid, int importance) {
448 mHandler.post(() -> handleUidImportanceChanged(uid, importance));
449 }
450 }
451
452 private void handleUidImportanceChanged(int uid, int importance) {
453 // Lower importance values are more "important"
454 final boolean modified = importance <= mRunningAppActiveImportanceCutoff
455 ? mRunningAppActiveUids.add(uid)
456 : mRunningAppActiveUids.remove(uid);
457 if (modified) {
458 updateMulticastLock();
459 }
460 }
461
462 /**
463 * Take or release the lock based on updated internal state.
464 *
465 * This determines whether the lock needs to be held based on
466 * {@link #mWifiLockRequiredNetworks}, {@link #mRunningAppActiveUids} and
467 * {@link ClientInfo#mClientRequests}, so it must be called after any of the these have been
468 * updated.
469 */
470 private void updateMulticastLock() {
471 final int needsLockUid = getMulticastLockNeededUid();
472 if (needsLockUid >= 0 && mHeldMulticastLock == null) {
473 final WifiManager wm = mContext.getSystemService(WifiManager.class);
474 if (wm == null) {
475 Log.wtf(TAG, "Got a TRANSPORT_WIFI network without WifiManager");
476 return;
477 }
478 mHeldMulticastLock = wm.createMulticastLock(TAG);
479 mHeldMulticastLock.acquire();
480 mServiceLogs.log("Taking multicast lock for uid " + needsLockUid);
481 } else if (needsLockUid < 0 && mHeldMulticastLock != null) {
482 mHeldMulticastLock.release();
483 mHeldMulticastLock = null;
484 mServiceLogs.log("Released multicast lock");
485 }
486 }
487
488 /**
489 * @return The UID of an app requiring the multicast lock, or -1 if none.
490 */
491 private int getMulticastLockNeededUid() {
492 if (mWifiLockRequiredNetworks.size() == 0) {
493 // Return early if NSD is not active, or not on any relevant network
494 return -1;
495 }
Paul Hud44e1b72023-06-16 02:07:42 +0000496 for (int i = 0; i < mTransactionIdToClientInfoMap.size(); i++) {
497 final ClientInfo clientInfo = mTransactionIdToClientInfoMap.valueAt(i);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900498 if (!mRunningAppActiveUids.contains(clientInfo.mUid)) {
499 // Ignore non-active UIDs
500 continue;
501 }
502
503 if (clientInfo.hasAnyJavaBackendRequestForNetworks(mWifiLockRequiredNetworks)) {
504 return clientInfo.mUid;
505 }
506 }
507 return -1;
508 }
509
Paul Hu019621e2023-01-13 23:26:49 +0800510 /**
511 * Data class of mdns service callback information.
512 */
513 private static class MdnsEvent {
Paul Hud44e1b72023-06-16 02:07:42 +0000514 final int mClientRequestId;
Paul Hubad6fe92023-07-24 21:25:22 +0800515 @Nullable
Paul Hu019621e2023-01-13 23:26:49 +0800516 final MdnsServiceInfo mMdnsServiceInfo;
Paul Hua6bc4632023-06-26 01:18:29 +0000517 final boolean mIsServiceFromCache;
Paul Hu019621e2023-01-13 23:26:49 +0800518
Paul Hubad6fe92023-07-24 21:25:22 +0800519 MdnsEvent(int clientRequestId) {
520 this(clientRequestId, null /* mdnsServiceInfo */, false /* isServiceFromCache */);
521 }
522
523 MdnsEvent(int clientRequestId, @Nullable MdnsServiceInfo mdnsServiceInfo) {
Paul Hua6bc4632023-06-26 01:18:29 +0000524 this(clientRequestId, mdnsServiceInfo, false /* isServiceFromCache */);
525 }
526
Paul Hubad6fe92023-07-24 21:25:22 +0800527 MdnsEvent(int clientRequestId, @Nullable MdnsServiceInfo mdnsServiceInfo,
Paul Hua6bc4632023-06-26 01:18:29 +0000528 boolean isServiceFromCache) {
Paul Hud44e1b72023-06-16 02:07:42 +0000529 mClientRequestId = clientRequestId;
Paul Hu019621e2023-01-13 23:26:49 +0800530 mMdnsServiceInfo = mdnsServiceInfo;
Paul Hua6bc4632023-06-26 01:18:29 +0000531 mIsServiceFromCache = isServiceFromCache;
Paul Hu019621e2023-01-13 23:26:49 +0800532 }
533 }
534
Paul Hu77c11182023-10-23 16:17:32 +0800535 // TODO: Use a Handler instead of a StateMachine since there are no state changes.
Irfan Sheriff75006652012-04-17 23:15:29 -0700536 private class NsdStateMachine extends StateMachine {
537
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700538 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff75006652012-04-17 23:15:29 -0700539
540 @Override
Wink Saville358f5d42012-05-29 12:40:46 -0700541 protected String getWhatToString(int what) {
Hugo Benichi32be63d2017-04-05 14:06:11 +0900542 return NsdManager.nameOf(what);
Irfan Sheriff75006652012-04-17 23:15:29 -0700543 }
544
Luke Huang92860f92021-06-23 06:29:30 +0000545 private void maybeStartDaemon() {
Paul Hu4a87ed42024-01-10 08:58:30 +0000546 if (mIsDaemonStarted) {
547 if (DBG) Log.d(TAG, "Daemon is already started.");
Ken Chen80c9f6f2023-11-15 18:24:54 +0800548 return;
549 }
550
Paul Hu4a87ed42024-01-10 08:58:30 +0000551 if (mMDnsManager == null) {
552 Log.wtf(TAG, "maybeStartDaemon: mMDnsManager is null");
paulhu2b9ed952022-02-10 21:58:32 +0800553 return;
554 }
555 mMDnsManager.registerEventListener(mMDnsEventCallback);
556 mMDnsManager.startDaemon();
557 mIsDaemonStarted = true;
Luke Huang05298582021-06-13 16:52:05 +0000558 maybeScheduleStop();
Paul Hub2e67d32023-04-18 05:50:14 +0000559 mServiceLogs.log("Start mdns_responder daemon");
Luke Huang05298582021-06-13 16:52:05 +0000560 }
561
paulhu2b9ed952022-02-10 21:58:32 +0800562 private void maybeStopDaemon() {
Paul Hu4a87ed42024-01-10 08:58:30 +0000563 if (!mIsDaemonStarted) {
564 if (DBG) Log.d(TAG, "Daemon has not been started.");
Ken Chen80c9f6f2023-11-15 18:24:54 +0800565 return;
566 }
567
Paul Hu4a87ed42024-01-10 08:58:30 +0000568 if (mMDnsManager == null) {
569 Log.wtf(TAG, "maybeStopDaemon: mMDnsManager is null");
paulhu2b9ed952022-02-10 21:58:32 +0800570 return;
571 }
572 mMDnsManager.unregisterEventListener(mMDnsEventCallback);
573 mMDnsManager.stopDaemon();
574 mIsDaemonStarted = false;
Paul Hub2e67d32023-04-18 05:50:14 +0000575 mServiceLogs.log("Stop mdns_responder daemon");
paulhu2b9ed952022-02-10 21:58:32 +0800576 }
577
Luke Huang92860f92021-06-23 06:29:30 +0000578 private boolean isAnyRequestActive() {
Paul Hud44e1b72023-06-16 02:07:42 +0000579 return mTransactionIdToClientInfoMap.size() != 0;
Luke Huang92860f92021-06-23 06:29:30 +0000580 }
581
582 private void scheduleStop() {
583 sendMessageDelayed(NsdManager.DAEMON_CLEANUP, mCleanupDelayMs);
584 }
585 private void maybeScheduleStop() {
Luke Huangf7277ed2021-07-12 21:15:10 +0800586 // The native daemon should stay alive and can't be cleanup
587 // if any legacy client connected.
588 if (!isAnyRequestActive() && mLegacyClientCount == 0) {
Luke Huang92860f92021-06-23 06:29:30 +0000589 scheduleStop();
Luke Huang05298582021-06-13 16:52:05 +0000590 }
591 }
592
Luke Huang92860f92021-06-23 06:29:30 +0000593 private void cancelStop() {
Luke Huang05298582021-06-13 16:52:05 +0000594 this.removeMessages(NsdManager.DAEMON_CLEANUP);
595 }
596
Paul Hu23fa2022023-01-13 22:57:24 +0800597 private void maybeStartMonitoringSockets() {
598 if (mIsMonitoringSocketsStarted) {
599 if (DBG) Log.d(TAG, "Socket monitoring is already started.");
600 return;
601 }
602
603 mMdnsSocketProvider.startMonitoringSockets();
604 mIsMonitoringSocketsStarted = true;
605 }
606
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900607 private void maybeStopMonitoringSocketsIfNoActiveRequest() {
608 if (!mIsMonitoringSocketsStarted) return;
609 if (isAnyRequestActive()) return;
610
Paul Hu58f20602023-02-18 11:41:07 +0800611 mMdnsSocketProvider.requestStopWhenInactive();
Paul Hu23fa2022023-01-13 22:57:24 +0800612 mIsMonitoringSocketsStarted = false;
613 }
614
Hugo Benichi803a2f02017-04-24 11:35:06 +0900615 NsdStateMachine(String name, Handler handler) {
616 super(name, handler);
Paul Hu77c11182023-10-23 16:17:32 +0800617 addState(mEnabledState);
paulhu5568f452021-11-30 13:31:29 +0800618 State initialState = mEnabledState;
Hugo Benichi912db992017-04-24 16:41:03 +0900619 setInitialState(initialState);
Wink Saville358f5d42012-05-29 12:40:46 -0700620 setLogRecSize(25);
Irfan Sheriff75006652012-04-17 23:15:29 -0700621 }
622
Irfan Sheriff75006652012-04-17 23:15:29 -0700623 class EnabledState extends State {
624 @Override
625 public void enter() {
626 sendNsdStateChangeBroadcast(true);
Irfan Sheriff75006652012-04-17 23:15:29 -0700627 }
628
629 @Override
630 public void exit() {
Luke Huang05298582021-06-13 16:52:05 +0000631 // TODO: it is incorrect to stop the daemon without expunging all requests
632 // and sending error callbacks to clients.
Luke Huang92860f92021-06-23 06:29:30 +0000633 scheduleStop();
Irfan Sheriff75006652012-04-17 23:15:29 -0700634 }
635
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700636 private boolean requestLimitReached(ClientInfo clientInfo) {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900637 if (clientInfo.mClientRequests.size() >= ClientInfo.MAX_LIMIT) {
paulhub2225702021-11-17 09:35:33 +0800638 if (DBG) Log.d(TAG, "Exceeded max outstanding requests " + clientInfo);
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700639 return true;
640 }
641 return false;
642 }
643
Paul Hu508a0122023-09-11 15:31:33 +0800644 private ClientRequest storeLegacyRequestMap(int clientRequestId, int transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +0000645 ClientInfo clientInfo, int what, long startTimeMs) {
Paul Hu508a0122023-09-11 15:31:33 +0800646 final LegacyClientRequest request =
647 new LegacyClientRequest(transactionId, what, startTimeMs);
648 clientInfo.mClientRequests.put(clientRequestId, request);
Paul Hud44e1b72023-06-16 02:07:42 +0000649 mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
Luke Huang05298582021-06-13 16:52:05 +0000650 // Remove the cleanup event because here comes a new request.
651 cancelStop();
Paul Hu508a0122023-09-11 15:31:33 +0800652 return request;
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700653 }
654
Paul Hud44e1b72023-06-16 02:07:42 +0000655 private void storeAdvertiserRequestMap(int clientRequestId, int transactionId,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900656 ClientInfo clientInfo, @Nullable Network requestedNetwork) {
Paul Hu777ed052023-06-19 13:35:15 +0000657 clientInfo.mClientRequests.put(clientRequestId, new AdvertiserClientRequest(
Paul Hu812e9212023-06-20 06:24:53 +0000658 transactionId, requestedNetwork, mClock.elapsedRealtime()));
Paul Hud44e1b72023-06-16 02:07:42 +0000659 mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900660 updateMulticastLock();
Paul Hu23fa2022023-01-13 22:57:24 +0800661 }
662
Paul Hud44e1b72023-06-16 02:07:42 +0000663 private void removeRequestMap(
664 int clientRequestId, int transactionId, ClientInfo clientInfo) {
665 final ClientRequest existing = clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900666 if (existing == null) return;
Paul Hud44e1b72023-06-16 02:07:42 +0000667 clientInfo.mClientRequests.remove(clientRequestId);
668 mTransactionIdToClientInfoMap.remove(transactionId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900669
670 if (existing instanceof LegacyClientRequest) {
671 maybeScheduleStop();
672 } else {
673 maybeStopMonitoringSocketsIfNoActiveRequest();
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900674 updateMulticastLock();
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900675 }
676 }
677
Paul Hu508a0122023-09-11 15:31:33 +0800678 private ClientRequest storeDiscoveryManagerRequestMap(int clientRequestId,
679 int transactionId, MdnsListener listener, ClientInfo clientInfo,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900680 @Nullable Network requestedNetwork) {
Paul Hu508a0122023-09-11 15:31:33 +0800681 final DiscoveryManagerRequest request = new DiscoveryManagerRequest(transactionId,
682 listener, requestedNetwork, mClock.elapsedRealtime());
683 clientInfo.mClientRequests.put(clientRequestId, request);
Paul Hud44e1b72023-06-16 02:07:42 +0000684 mTransactionIdToClientInfoMap.put(transactionId, clientInfo);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900685 updateMulticastLock();
Paul Hu508a0122023-09-11 15:31:33 +0800686 return request;
Paul Hu23fa2022023-01-13 22:57:24 +0800687 }
688
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900689 /**
690 * Truncate a service name to up to 63 UTF-8 bytes.
691 *
692 * See RFC6763 4.1.1: service instance names are UTF-8 and up to 63 bytes. Truncating
693 * names used in registerService follows historical behavior (see mdnsresponder
694 * handle_regservice_request).
695 */
696 @NonNull
697 private String truncateServiceName(@NonNull String originalName) {
Yuyang Huangde802c82023-05-02 17:14:22 +0900698 return MdnsUtils.truncateServiceName(originalName, MAX_LABEL_LENGTH);
Paul Hu23fa2022023-01-13 22:57:24 +0800699 }
700
Paul Hud44e1b72023-06-16 02:07:42 +0000701 private void stopDiscoveryManagerRequest(ClientRequest request, int clientRequestId,
702 int transactionId, ClientInfo clientInfo) {
Paul Hue4f5f252023-02-16 21:13:47 +0800703 clientInfo.unregisterMdnsListenerFromRequest(request);
Paul Hud44e1b72023-06-16 02:07:42 +0000704 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hue4f5f252023-02-16 21:13:47 +0800705 }
706
Paul Hu77c11182023-10-23 16:17:32 +0800707 private ClientInfo getClientInfoForReply(Message msg) {
708 final ListenerArgs args = (ListenerArgs) msg.obj;
709 return mClients.get(args.connector);
710 }
711
Kangping Dong5af24b62023-12-10 21:41:16 +0800712 /**
713 * Returns {@code false} if {@code subtypes} exceeds the maximum number limit or
714 * contains invalid subtype label.
715 */
716 private boolean checkSubtypeLabels(Set<String> subtypes) {
717 if (subtypes.size() > MAX_SUBTYPE_COUNT) {
718 mServiceLogs.e(
719 "Too many subtypes: " + subtypes.size() + " (max = "
720 + MAX_SUBTYPE_COUNT + ")");
721 return false;
722 }
723
724 for (String subtype : subtypes) {
725 if (!checkSubtypeLabel(subtype)) {
726 mServiceLogs.e("Subtype " + subtype + " is invalid");
727 return false;
728 }
729 }
730 return true;
731 }
732
733 private Set<String> dedupSubtypeLabels(Collection<String> subtypes) {
734 final Map<String, String> subtypeMap = new LinkedHashMap<>(subtypes.size());
735 for (String subtype : subtypes) {
736 subtypeMap.put(MdnsUtils.toDnsLowerCase(subtype), subtype);
737 }
738 return new ArraySet<>(subtypeMap.values());
739 }
740
Irfan Sheriff75006652012-04-17 23:15:29 -0700741 @Override
742 public boolean processMessage(Message msg) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900743 final ClientInfo clientInfo;
Paul Hud44e1b72023-06-16 02:07:42 +0000744 final int transactionId;
745 final int clientRequestId = msg.arg2;
Yuyang Huang33fa4d22023-02-14 22:59:37 +0900746 final OffloadEngineInfo offloadEngineInfo;
Irfan Sheriff75006652012-04-17 23:15:29 -0700747 switch (msg.what) {
Paul Hu75069ed2023-01-14 00:31:09 +0800748 case NsdManager.DISCOVER_SERVICES: {
paulhub2225702021-11-17 09:35:33 +0800749 if (DBG) Log.d(TAG, "Discover services");
Kangping Dong1f1a3792023-12-10 22:05:04 +0800750 final DiscoveryArgs discoveryArgs = (DiscoveryArgs) msg.obj;
751 clientInfo = mClients.get(discoveryArgs.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000752 // If the binder death notification for a INsdManagerCallback was received
753 // before any calls are received by NsdService, the clientInfo would be
754 // cleared and cause NPE. Add a null check here to prevent this corner case.
755 if (clientInfo == null) {
756 Log.e(TAG, "Unknown connector in discovery");
757 break;
758 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700759
760 if (requestLimitReached(clientInfo)) {
Paul Hu508a0122023-09-11 15:31:33 +0800761 clientInfo.onDiscoverServicesFailedImmediately(clientRequestId,
762 NsdManager.FAILURE_MAX_LIMIT, true /* isLegacy */);
Irfan Sheriff75006652012-04-17 23:15:29 -0700763 break;
764 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700765
Kangping Dong1f1a3792023-12-10 22:05:04 +0800766 final DiscoveryRequest discoveryRequest = discoveryArgs.discoveryRequest;
Paul Hud44e1b72023-06-16 02:07:42 +0000767 transactionId = getUniqueId();
Yuyang Huang170d42f2023-12-09 15:26:16 +0900768 final Pair<String, List<String>> typeAndSubtype =
Kangping Dong1f1a3792023-12-10 22:05:04 +0800769 parseTypeAndSubtype(discoveryRequest.getServiceType());
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900770 final String serviceType = typeAndSubtype == null
771 ? null : typeAndSubtype.first;
Paul Hu2e0a88c2023-03-09 16:05:01 +0800772 if (clientInfo.mUseJavaBackend
773 || mDeps.isMdnsDiscoveryManagerEnabled(mContext)
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900774 || useDiscoveryManagerForType(serviceType)) {
Yuyang Huang170d42f2023-12-09 15:26:16 +0900775 if (serviceType == null || typeAndSubtype.second.size() > 1) {
Paul Hu508a0122023-09-11 15:31:33 +0800776 clientInfo.onDiscoverServicesFailedImmediately(clientRequestId,
777 NsdManager.FAILURE_INTERNAL_ERROR, false /* isLegacy */);
Paul Hu23fa2022023-01-13 22:57:24 +0800778 break;
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700779 }
Paul Hu23fa2022023-01-13 22:57:24 +0800780
Kangping Dong1f1a3792023-12-10 22:05:04 +0800781 String subtype = discoveryRequest.getSubtype();
782 if (subtype == null && !typeAndSubtype.second.isEmpty()) {
783 subtype = typeAndSubtype.second.get(0);
784 }
785
786 if (subtype != null && !checkSubtypeLabel(subtype)) {
787 clientInfo.onDiscoverServicesFailedImmediately(clientRequestId,
788 NsdManager.FAILURE_BAD_PARAMETERS, false /* isLegacy */);
789 break;
790 }
791
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900792 final String listenServiceType = serviceType + ".local";
Paul Hu23fa2022023-01-13 22:57:24 +0800793 maybeStartMonitoringSockets();
Paul Hud44e1b72023-06-16 02:07:42 +0000794 final MdnsListener listener = new DiscoveryListener(clientRequestId,
Kangping Dong97b2adc2024-01-11 16:00:37 +0800795 transactionId, listenServiceType);
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900796 final MdnsSearchOptions.Builder optionsBuilder =
797 MdnsSearchOptions.newBuilder()
Kangping Dong1f1a3792023-12-10 22:05:04 +0800798 .setNetwork(discoveryRequest.getNetwork())
Yuyang Huangff963222023-06-01 18:42:42 +0900799 .setRemoveExpiredService(true)
Paul Hu11a883d2023-12-14 07:36:44 +0000800 .setQueryMode(
801 mMdnsFeatureFlags.isAggressiveQueryModeEnabled()
802 ? AGGRESSIVE_QUERY_MODE
803 : PASSIVE_QUERY_MODE);
Kangping Dong1f1a3792023-12-10 22:05:04 +0800804 if (subtype != null) {
805 // checkSubtypeLabels() ensures that subtypes start with '_' but
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900806 // MdnsSearchOptions expects the underscore to not be present.
Kangping Dong1f1a3792023-12-10 22:05:04 +0800807 optionsBuilder.addSubtype(subtype.substring(1));
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900808 }
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900809 mMdnsDiscoveryManager.registerListener(
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900810 listenServiceType, listener, optionsBuilder.build());
Paul Hu508a0122023-09-11 15:31:33 +0800811 final ClientRequest request = storeDiscoveryManagerRequestMap(
812 clientRequestId, transactionId, listener, clientInfo,
Kangping Dong1f1a3792023-12-10 22:05:04 +0800813 discoveryRequest.getNetwork());
814 clientInfo.onDiscoverServicesStarted(
815 clientRequestId, discoveryRequest, request);
Paul Hud44e1b72023-06-16 02:07:42 +0000816 clientInfo.log("Register a DiscoveryListener " + transactionId
Paul Hub2e67d32023-04-18 05:50:14 +0000817 + " for service type:" + listenServiceType);
Irfan Sheriff75006652012-04-17 23:15:29 -0700818 } else {
Paul Hu23fa2022023-01-13 22:57:24 +0800819 maybeStartDaemon();
Kangping Dong1f1a3792023-12-10 22:05:04 +0800820 if (discoverServices(transactionId, discoveryRequest)) {
Paul Hu23fa2022023-01-13 22:57:24 +0800821 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +0000822 Log.d(TAG, "Discover " + msg.arg2 + " " + transactionId
Kangping Dong1f1a3792023-12-10 22:05:04 +0800823 + discoveryRequest.getServiceType());
Paul Hu23fa2022023-01-13 22:57:24 +0800824 }
Paul Hu508a0122023-09-11 15:31:33 +0800825 final ClientRequest request = storeLegacyRequestMap(clientRequestId,
826 transactionId, clientInfo, msg.what,
827 mClock.elapsedRealtime());
Paul Hu812e9212023-06-20 06:24:53 +0000828 clientInfo.onDiscoverServicesStarted(
Kangping Dong1f1a3792023-12-10 22:05:04 +0800829 clientRequestId, discoveryRequest, request);
Paul Hu23fa2022023-01-13 22:57:24 +0800830 } else {
Paul Hud44e1b72023-06-16 02:07:42 +0000831 stopServiceDiscovery(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +0800832 clientInfo.onDiscoverServicesFailedImmediately(clientRequestId,
833 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */);
Paul Hu23fa2022023-01-13 22:57:24 +0800834 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700835 }
836 break;
Paul Hu75069ed2023-01-14 00:31:09 +0800837 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900838 case NsdManager.STOP_DISCOVERY: {
paulhub2225702021-11-17 09:35:33 +0800839 if (DBG) Log.d(TAG, "Stop service discovery");
Yuyang Huang86d083f2023-12-12 19:56:41 +0900840 final ListenerArgs args = (ListenerArgs) msg.obj;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900841 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000842 // If the binder death notification for a INsdManagerCallback was received
843 // before any calls are received by NsdService, the clientInfo would be
844 // cleared and cause NPE. Add a null check here to prevent this corner case.
845 if (clientInfo == null) {
846 Log.e(TAG, "Unknown connector in stop discovery");
847 break;
848 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700849
Paul Hud44e1b72023-06-16 02:07:42 +0000850 final ClientRequest request =
851 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900852 if (request == null) {
853 Log.e(TAG, "Unknown client request in STOP_DISCOVERY");
Irfan Sheriff75006652012-04-17 23:15:29 -0700854 break;
855 }
Paul Hud44e1b72023-06-16 02:07:42 +0000856 transactionId = request.mTransactionId;
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900857 // Note isMdnsDiscoveryManagerEnabled may have changed to false at this
858 // point, so this needs to check the type of the original request to
859 // unregister instead of looking at the flag value.
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900860 if (request instanceof DiscoveryManagerRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +0000861 stopDiscoveryManagerRequest(
862 request, clientRequestId, transactionId, clientInfo);
Paul Hu812e9212023-06-20 06:24:53 +0000863 clientInfo.onStopDiscoverySucceeded(clientRequestId, request);
Paul Hud44e1b72023-06-16 02:07:42 +0000864 clientInfo.log("Unregister the DiscoveryListener " + transactionId);
Irfan Sheriff75006652012-04-17 23:15:29 -0700865 } else {
Paul Hud44e1b72023-06-16 02:07:42 +0000866 removeRequestMap(clientRequestId, transactionId, clientInfo);
867 if (stopServiceDiscovery(transactionId)) {
Paul Hu812e9212023-06-20 06:24:53 +0000868 clientInfo.onStopDiscoverySucceeded(clientRequestId, request);
Paul Hu23fa2022023-01-13 22:57:24 +0800869 } else {
870 clientInfo.onStopDiscoveryFailed(
Paul Hud44e1b72023-06-16 02:07:42 +0000871 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Paul Hu23fa2022023-01-13 22:57:24 +0800872 }
Irfan Sheriff75006652012-04-17 23:15:29 -0700873 }
874 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900875 }
876 case NsdManager.REGISTER_SERVICE: {
paulhub2225702021-11-17 09:35:33 +0800877 if (DBG) Log.d(TAG, "Register service");
Yuyang Huang86d083f2023-12-12 19:56:41 +0900878 final AdvertisingArgs args = (AdvertisingArgs) msg.obj;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900879 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000880 // If the binder death notification for a INsdManagerCallback was received
881 // before any calls are received by NsdService, the clientInfo would be
882 // cleared and cause NPE. Add a null check here to prevent this corner case.
883 if (clientInfo == null) {
884 Log.e(TAG, "Unknown connector in registration");
885 break;
886 }
887
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700888 if (requestLimitReached(clientInfo)) {
Paul Hu508a0122023-09-11 15:31:33 +0800889 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
890 NsdManager.FAILURE_MAX_LIMIT, true /* isLegacy */);
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700891 break;
Irfan Sheriff75006652012-04-17 23:15:29 -0700892 }
Yuyang Huang86d083f2023-12-12 19:56:41 +0900893 final AdvertisingRequest advertisingRequest = args.advertisingRequest;
894 if (advertisingRequest == null) {
895 Log.e(TAG, "Unknown advertisingRequest in registration");
896 break;
897 }
898 final NsdServiceInfo serviceInfo = advertisingRequest.getServiceInfo();
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900899 final String serviceType = serviceInfo.getServiceType();
Yuyang Huang170d42f2023-12-09 15:26:16 +0900900 final Pair<String, List<String>> typeSubtype = parseTypeAndSubtype(
901 serviceType);
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +0900902 final String registerServiceType = typeSubtype == null
903 ? null : typeSubtype.first;
Handa Wang096e32e2024-01-14 08:21:28 +0000904 final String hostname = serviceInfo.getHostname();
905 // Keep compatible with the legacy behavior: It's allowed to set host
906 // addresses for a service registration although the host addresses
907 // won't be registered. To register the addresses for a host, the
908 // hostname must be specified.
909 if (hostname == null) {
910 serviceInfo.setHostAddresses(Collections.emptyList());
911 }
Paul Hu2e0a88c2023-03-09 16:05:01 +0800912 if (clientInfo.mUseJavaBackend
913 || mDeps.isMdnsAdvertiserEnabled(mContext)
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900914 || useAdvertiserForType(registerServiceType)) {
Handa Wang096e32e2024-01-14 08:21:28 +0000915 if (serviceType != null && registerServiceType == null) {
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900916 Log.e(TAG, "Invalid service type: " + serviceType);
Paul Hu508a0122023-09-11 15:31:33 +0800917 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
918 NsdManager.FAILURE_INTERNAL_ERROR, false /* isLegacy */);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900919 break;
920 }
Yuyang Huang86d083f2023-12-12 19:56:41 +0900921 boolean isUpdateOnly = (advertisingRequest.getAdvertisingConfig()
922 & AdvertisingRequest.NSD_ADVERTISING_UPDATE_ONLY) > 0;
923 // If it is an update request, then reuse the old transactionId
924 if (isUpdateOnly) {
925 final ClientRequest existingClientRequest =
926 clientInfo.mClientRequests.get(clientRequestId);
927 if (existingClientRequest == null) {
928 Log.e(TAG, "Invalid update on requestId: " + clientRequestId);
929 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
930 NsdManager.FAILURE_INTERNAL_ERROR,
931 false /* isLegacy */);
932 break;
933 }
934 transactionId = existingClientRequest.mTransactionId;
935 } else {
936 transactionId = getUniqueId();
937 }
Handa Wang096e32e2024-01-14 08:21:28 +0000938
939 if (registerServiceType != null) {
940 serviceInfo.setServiceType(registerServiceType);
941 serviceInfo.setServiceName(
942 truncateServiceName(serviceInfo.getServiceName()));
943 }
944
945 if (!checkHostname(hostname)) {
946 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
947 NsdManager.FAILURE_BAD_PARAMETERS, false /* isLegacy */);
948 break;
949 }
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900950
Kangping Dong5af24b62023-12-10 21:41:16 +0800951 Set<String> subtypes = new ArraySet<>(serviceInfo.getSubtypes());
Handa Wang096e32e2024-01-14 08:21:28 +0000952 if (typeSubtype != null && typeSubtype.second != null) {
953 for (String subType : typeSubtype.second) {
954 if (!TextUtils.isEmpty(subType)) {
955 subtypes.add(subType);
956 }
Yuyang Huang170d42f2023-12-09 15:26:16 +0900957 }
Kangping Dong5af24b62023-12-10 21:41:16 +0800958 }
Kangping Dong5af24b62023-12-10 21:41:16 +0800959 subtypes = dedupSubtypeLabels(subtypes);
960
961 if (!checkSubtypeLabels(subtypes)) {
962 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
963 NsdManager.FAILURE_BAD_PARAMETERS, false /* isLegacy */);
964 break;
965 }
966
967 serviceInfo.setSubtypes(subtypes);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900968 maybeStartMonitoringSockets();
Yuyang Huang86d083f2023-12-12 19:56:41 +0900969 final MdnsAdvertisingOptions mdnsAdvertisingOptions =
970 MdnsAdvertisingOptions.newBuilder().setIsOnlyUpdate(
971 isUpdateOnly).build();
Yuyang Huange5cba9c2023-11-02 18:05:47 +0900972 mAdvertiser.addOrUpdateService(transactionId, serviceInfo,
Handa Wang096e32e2024-01-14 08:21:28 +0000973 mdnsAdvertisingOptions, clientInfo.mUid);
Paul Hud44e1b72023-06-16 02:07:42 +0000974 storeAdvertiserRequestMap(clientRequestId, transactionId, clientInfo,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900975 serviceInfo.getNetwork());
Irfan Sheriff75006652012-04-17 23:15:29 -0700976 } else {
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900977 maybeStartDaemon();
Yuyang Huang86d083f2023-12-12 19:56:41 +0900978 transactionId = getUniqueId();
Paul Hud44e1b72023-06-16 02:07:42 +0000979 if (registerService(transactionId, serviceInfo)) {
980 if (DBG) {
981 Log.d(TAG, "Register " + clientRequestId
982 + " " + transactionId);
983 }
Paul Hua6bc4632023-06-26 01:18:29 +0000984 storeLegacyRequestMap(clientRequestId, transactionId, clientInfo,
985 msg.what, mClock.elapsedRealtime());
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900986 // Return success after mDns reports success
987 } else {
Paul Hud44e1b72023-06-16 02:07:42 +0000988 unregisterService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +0800989 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
990 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900991 }
992
Irfan Sheriff75006652012-04-17 23:15:29 -0700993 }
994 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900995 }
996 case NsdManager.UNREGISTER_SERVICE: {
paulhub2225702021-11-17 09:35:33 +0800997 if (DBG) Log.d(TAG, "unregister service");
Yuyang Huang86d083f2023-12-12 19:56:41 +0900998 final ListenerArgs args = (ListenerArgs) msg.obj;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900999 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +00001000 // If the binder death notification for a INsdManagerCallback was received
1001 // before any calls are received by NsdService, the clientInfo would be
1002 // cleared and cause NPE. Add a null check here to prevent this corner case.
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001003 if (clientInfo == null) {
paulhub2225702021-11-17 09:35:33 +08001004 Log.e(TAG, "Unknown connector in unregistration");
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001005 break;
Irfan Sheriff75006652012-04-17 23:15:29 -07001006 }
Paul Hud44e1b72023-06-16 02:07:42 +00001007 final ClientRequest request =
1008 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001009 if (request == null) {
1010 Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE");
1011 break;
1012 }
Paul Hud44e1b72023-06-16 02:07:42 +00001013 transactionId = request.mTransactionId;
1014 removeRequestMap(clientRequestId, transactionId, clientInfo);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001015
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001016 // Note isMdnsAdvertiserEnabled may have changed to false at this point,
1017 // so this needs to check the type of the original request to unregister
1018 // instead of looking at the flag value.
1019 if (request instanceof AdvertiserClientRequest) {
Paul Hu043bcd42023-07-14 16:38:25 +08001020 final AdvertiserMetrics metrics =
1021 mAdvertiser.getAdvertiserMetrics(transactionId);
Paul Hud44e1b72023-06-16 02:07:42 +00001022 mAdvertiser.removeService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08001023 clientInfo.onUnregisterServiceSucceeded(
1024 clientRequestId, request, metrics);
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001025 } else {
Paul Hud44e1b72023-06-16 02:07:42 +00001026 if (unregisterService(transactionId)) {
Paul Hu508a0122023-09-11 15:31:33 +08001027 clientInfo.onUnregisterServiceSucceeded(clientRequestId, request,
Paul Hu043bcd42023-07-14 16:38:25 +08001028 new AdvertiserMetrics(NO_PACKET /* repliedRequestsCount */,
1029 NO_PACKET /* sentPacketCount */,
1030 0 /* conflictDuringProbingCount */,
1031 0 /* conflictAfterProbingCount */));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001032 } else {
1033 clientInfo.onUnregisterServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001034 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001035 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001036 }
Irfan Sheriff75006652012-04-17 23:15:29 -07001037 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001038 }
Paul Hu75069ed2023-01-14 00:31:09 +08001039 case NsdManager.RESOLVE_SERVICE: {
paulhub2225702021-11-17 09:35:33 +08001040 if (DBG) Log.d(TAG, "Resolve service");
Yuyang Huang86d083f2023-12-12 19:56:41 +09001041 final ListenerArgs args = (ListenerArgs) msg.obj;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001042 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +00001043 // If the binder death notification for a INsdManagerCallback was received
1044 // before any calls are received by NsdService, the clientInfo would be
1045 // cleared and cause NPE. Add a null check here to prevent this corner case.
1046 if (clientInfo == null) {
1047 Log.e(TAG, "Unknown connector in resolution");
1048 break;
1049 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001050
Paul Hu75069ed2023-01-14 00:31:09 +08001051 final NsdServiceInfo info = args.serviceInfo;
Paul Hud44e1b72023-06-16 02:07:42 +00001052 transactionId = getUniqueId();
Yuyang Huang170d42f2023-12-09 15:26:16 +09001053 final Pair<String, List<String>> typeSubtype =
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001054 parseTypeAndSubtype(info.getServiceType());
1055 final String serviceType = typeSubtype == null
1056 ? null : typeSubtype.first;
Paul Hu2e0a88c2023-03-09 16:05:01 +08001057 if (clientInfo.mUseJavaBackend
1058 || mDeps.isMdnsDiscoveryManagerEnabled(mContext)
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001059 || useDiscoveryManagerForType(serviceType)) {
Paul Hu75069ed2023-01-14 00:31:09 +08001060 if (serviceType == null) {
Paul Hu508a0122023-09-11 15:31:33 +08001061 clientInfo.onResolveServiceFailedImmediately(clientRequestId,
1062 NsdManager.FAILURE_INTERNAL_ERROR, false /* isLegacy */);
Paul Hu75069ed2023-01-14 00:31:09 +08001063 break;
1064 }
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001065 final String resolveServiceType = serviceType + ".local";
Paul Hu75069ed2023-01-14 00:31:09 +08001066
1067 maybeStartMonitoringSockets();
Paul Hud44e1b72023-06-16 02:07:42 +00001068 final MdnsListener listener = new ResolutionListener(clientRequestId,
Kangping Dong97b2adc2024-01-11 16:00:37 +08001069 transactionId, resolveServiceType);
Paul Hu75069ed2023-01-14 00:31:09 +08001070 final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
1071 .setNetwork(info.getNetwork())
Paul Hu11a883d2023-12-14 07:36:44 +00001072 .setQueryMode(mMdnsFeatureFlags.isAggressiveQueryModeEnabled()
1073 ? AGGRESSIVE_QUERY_MODE
1074 : PASSIVE_QUERY_MODE)
Remi NGUYEN VANbb62b1d2023-02-27 12:18:27 +09001075 .setResolveInstanceName(info.getServiceName())
Yuyang Huangff963222023-06-01 18:42:42 +09001076 .setRemoveExpiredService(true)
Paul Hu75069ed2023-01-14 00:31:09 +08001077 .build();
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001078 mMdnsDiscoveryManager.registerListener(
1079 resolveServiceType, listener, options);
Paul Hud44e1b72023-06-16 02:07:42 +00001080 storeDiscoveryManagerRequestMap(clientRequestId, transactionId,
1081 listener, clientInfo, info.getNetwork());
1082 clientInfo.log("Register a ResolutionListener " + transactionId
Paul Hub2e67d32023-04-18 05:50:14 +00001083 + " for service type:" + resolveServiceType);
Irfan Sheriff75006652012-04-17 23:15:29 -07001084 } else {
Paul Hu75069ed2023-01-14 00:31:09 +08001085 if (clientInfo.mResolvedService != null) {
Paul Hu508a0122023-09-11 15:31:33 +08001086 clientInfo.onResolveServiceFailedImmediately(clientRequestId,
1087 NsdManager.FAILURE_ALREADY_ACTIVE, true /* isLegacy */);
Paul Hu75069ed2023-01-14 00:31:09 +08001088 break;
1089 }
1090
1091 maybeStartDaemon();
Paul Hud44e1b72023-06-16 02:07:42 +00001092 if (resolveService(transactionId, info)) {
Paul Hu75069ed2023-01-14 00:31:09 +08001093 clientInfo.mResolvedService = new NsdServiceInfo();
Paul Hua6bc4632023-06-26 01:18:29 +00001094 storeLegacyRequestMap(clientRequestId, transactionId, clientInfo,
1095 msg.what, mClock.elapsedRealtime());
Paul Hu75069ed2023-01-14 00:31:09 +08001096 } else {
Paul Hu508a0122023-09-11 15:31:33 +08001097 clientInfo.onResolveServiceFailedImmediately(clientRequestId,
1098 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */);
Paul Hu75069ed2023-01-14 00:31:09 +08001099 }
Irfan Sheriff75006652012-04-17 23:15:29 -07001100 }
1101 break;
Paul Hu75069ed2023-01-14 00:31:09 +08001102 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001103 case NsdManager.STOP_RESOLUTION: {
Paul Hub58deb72022-12-26 09:24:42 +00001104 if (DBG) Log.d(TAG, "Stop service resolution");
Yuyang Huang86d083f2023-12-12 19:56:41 +09001105 final ListenerArgs args = (ListenerArgs) msg.obj;
Paul Hub58deb72022-12-26 09:24:42 +00001106 clientInfo = mClients.get(args.connector);
1107 // If the binder death notification for a INsdManagerCallback was received
1108 // before any calls are received by NsdService, the clientInfo would be
1109 // cleared and cause NPE. Add a null check here to prevent this corner case.
1110 if (clientInfo == null) {
1111 Log.e(TAG, "Unknown connector in stop resolution");
1112 break;
1113 }
1114
Paul Hud44e1b72023-06-16 02:07:42 +00001115 final ClientRequest request =
1116 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001117 if (request == null) {
1118 Log.e(TAG, "Unknown client request in STOP_RESOLUTION");
1119 break;
1120 }
Paul Hud44e1b72023-06-16 02:07:42 +00001121 transactionId = request.mTransactionId;
Paul Hue4f5f252023-02-16 21:13:47 +08001122 // Note isMdnsDiscoveryManagerEnabled may have changed to false at this
1123 // point, so this needs to check the type of the original request to
1124 // unregister instead of looking at the flag value.
1125 if (request instanceof DiscoveryManagerRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +00001126 stopDiscoveryManagerRequest(
1127 request, clientRequestId, transactionId, clientInfo);
Paul Hu60149052023-07-31 14:26:08 +08001128 clientInfo.onStopResolutionSucceeded(clientRequestId, request);
Paul Hud44e1b72023-06-16 02:07:42 +00001129 clientInfo.log("Unregister the ResolutionListener " + transactionId);
Paul Hub58deb72022-12-26 09:24:42 +00001130 } else {
Paul Hud44e1b72023-06-16 02:07:42 +00001131 removeRequestMap(clientRequestId, transactionId, clientInfo);
1132 if (stopResolveService(transactionId)) {
Paul Hu60149052023-07-31 14:26:08 +08001133 clientInfo.onStopResolutionSucceeded(clientRequestId, request);
Paul Hue4f5f252023-02-16 21:13:47 +08001134 } else {
1135 clientInfo.onStopResolutionFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001136 clientRequestId, NsdManager.FAILURE_OPERATION_NOT_RUNNING);
Paul Hue4f5f252023-02-16 21:13:47 +08001137 }
1138 clientInfo.mResolvedService = null;
Paul Hub58deb72022-12-26 09:24:42 +00001139 }
Paul Hub58deb72022-12-26 09:24:42 +00001140 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001141 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001142 case NsdManager.REGISTER_SERVICE_CALLBACK: {
Paul Hu18aeccc2022-12-27 08:48:48 +00001143 if (DBG) Log.d(TAG, "Register a service callback");
Yuyang Huang86d083f2023-12-12 19:56:41 +09001144 final ListenerArgs args = (ListenerArgs) msg.obj;
Paul Hu18aeccc2022-12-27 08:48:48 +00001145 clientInfo = mClients.get(args.connector);
1146 // If the binder death notification for a INsdManagerCallback was received
1147 // before any calls are received by NsdService, the clientInfo would be
1148 // cleared and cause NPE. Add a null check here to prevent this corner case.
1149 if (clientInfo == null) {
1150 Log.e(TAG, "Unknown connector in callback registration");
1151 break;
1152 }
1153
Paul Hu30bd70d2023-02-07 13:20:56 +00001154 final NsdServiceInfo info = args.serviceInfo;
Paul Hud44e1b72023-06-16 02:07:42 +00001155 transactionId = getUniqueId();
Yuyang Huang170d42f2023-12-09 15:26:16 +09001156 final Pair<String, List<String>> typeAndSubtype =
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001157 parseTypeAndSubtype(info.getServiceType());
1158 final String serviceType = typeAndSubtype == null
1159 ? null : typeAndSubtype.first;
Paul Hu30bd70d2023-02-07 13:20:56 +00001160 if (serviceType == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00001161 clientInfo.onServiceInfoCallbackRegistrationFailed(clientRequestId,
Paul Hu30bd70d2023-02-07 13:20:56 +00001162 NsdManager.FAILURE_BAD_PARAMETERS);
Paul Hu18aeccc2022-12-27 08:48:48 +00001163 break;
1164 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001165 final String resolveServiceType = serviceType + ".local";
Paul Hu18aeccc2022-12-27 08:48:48 +00001166
Paul Hu30bd70d2023-02-07 13:20:56 +00001167 maybeStartMonitoringSockets();
Paul Hud44e1b72023-06-16 02:07:42 +00001168 final MdnsListener listener = new ServiceInfoListener(clientRequestId,
Kangping Dong97b2adc2024-01-11 16:00:37 +08001169 transactionId, resolveServiceType);
Paul Hu30bd70d2023-02-07 13:20:56 +00001170 final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
1171 .setNetwork(info.getNetwork())
Paul Hu11a883d2023-12-14 07:36:44 +00001172 .setQueryMode(mMdnsFeatureFlags.isAggressiveQueryModeEnabled()
1173 ? AGGRESSIVE_QUERY_MODE
1174 : PASSIVE_QUERY_MODE)
Paul Hu30bd70d2023-02-07 13:20:56 +00001175 .setResolveInstanceName(info.getServiceName())
Yuyang Huangff963222023-06-01 18:42:42 +09001176 .setRemoveExpiredService(true)
Paul Hu30bd70d2023-02-07 13:20:56 +00001177 .build();
1178 mMdnsDiscoveryManager.registerListener(
1179 resolveServiceType, listener, options);
Paul Hud44e1b72023-06-16 02:07:42 +00001180 storeDiscoveryManagerRequestMap(clientRequestId, transactionId, listener,
1181 clientInfo, info.getNetwork());
Paul Huddce5912023-08-01 10:26:49 +08001182 clientInfo.onServiceInfoCallbackRegistered(transactionId);
Paul Hud44e1b72023-06-16 02:07:42 +00001183 clientInfo.log("Register a ServiceInfoListener " + transactionId
Paul Hub2e67d32023-04-18 05:50:14 +00001184 + " for service type:" + resolveServiceType);
Paul Hu18aeccc2022-12-27 08:48:48 +00001185 break;
Paul Hu30bd70d2023-02-07 13:20:56 +00001186 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001187 case NsdManager.UNREGISTER_SERVICE_CALLBACK: {
Paul Hu18aeccc2022-12-27 08:48:48 +00001188 if (DBG) Log.d(TAG, "Unregister a service callback");
Yuyang Huang86d083f2023-12-12 19:56:41 +09001189 final ListenerArgs args = (ListenerArgs) msg.obj;
Paul Hu18aeccc2022-12-27 08:48:48 +00001190 clientInfo = mClients.get(args.connector);
1191 // If the binder death notification for a INsdManagerCallback was received
1192 // before any calls are received by NsdService, the clientInfo would be
1193 // cleared and cause NPE. Add a null check here to prevent this corner case.
1194 if (clientInfo == null) {
1195 Log.e(TAG, "Unknown connector in callback unregistration");
1196 break;
1197 }
1198
Paul Hud44e1b72023-06-16 02:07:42 +00001199 final ClientRequest request =
1200 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001201 if (request == null) {
Paul Hu30bd70d2023-02-07 13:20:56 +00001202 Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE_CALLBACK");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001203 break;
1204 }
Paul Hud44e1b72023-06-16 02:07:42 +00001205 transactionId = request.mTransactionId;
Paul Hu30bd70d2023-02-07 13:20:56 +00001206 if (request instanceof DiscoveryManagerRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +00001207 stopDiscoveryManagerRequest(
1208 request, clientRequestId, transactionId, clientInfo);
Paul Huddce5912023-08-01 10:26:49 +08001209 clientInfo.onServiceInfoCallbackUnregistered(clientRequestId, request);
Paul Hud44e1b72023-06-16 02:07:42 +00001210 clientInfo.log("Unregister the ServiceInfoListener " + transactionId);
Paul Hu18aeccc2022-12-27 08:48:48 +00001211 } else {
Paul Hu30bd70d2023-02-07 13:20:56 +00001212 loge("Unregister failed with non-DiscoveryManagerRequest.");
Paul Hu18aeccc2022-12-27 08:48:48 +00001213 }
Paul Hu18aeccc2022-12-27 08:48:48 +00001214 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001215 }
paulhu2b9ed952022-02-10 21:58:32 +08001216 case MDNS_SERVICE_EVENT:
1217 if (!handleMDnsServiceEvent(msg.arg1, msg.arg2, msg.obj)) {
Hugo Benichif0c84092017-04-05 14:43:29 +09001218 return NOT_HANDLED;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001219 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001220 break;
Paul Hu019621e2023-01-13 23:26:49 +08001221 case MDNS_DISCOVERY_MANAGER_EVENT:
1222 if (!handleMdnsDiscoveryManagerEvent(msg.arg1, msg.arg2, msg.obj)) {
1223 return NOT_HANDLED;
1224 }
1225 break;
Yuyang Huang33fa4d22023-02-14 22:59:37 +09001226 case NsdManager.REGISTER_OFFLOAD_ENGINE:
1227 offloadEngineInfo = (OffloadEngineInfo) msg.obj;
1228 // TODO: Limits the number of registrations created by a given class.
1229 mOffloadEngines.register(offloadEngineInfo.mOffloadEngine,
1230 offloadEngineInfo);
Yuyang Huangc275a9e2023-08-25 18:03:22 +09001231 sendAllOffloadServiceInfos(offloadEngineInfo);
Yuyang Huang33fa4d22023-02-14 22:59:37 +09001232 break;
1233 case NsdManager.UNREGISTER_OFFLOAD_ENGINE:
1234 mOffloadEngines.unregister((IOffloadEngine) msg.obj);
1235 break;
Paul Hu77c11182023-10-23 16:17:32 +08001236 case NsdManager.REGISTER_CLIENT:
1237 final ConnectorArgs arg = (ConnectorArgs) msg.obj;
1238 final INsdManagerCallback cb = arg.callback;
1239 try {
1240 cb.asBinder().linkToDeath(arg.connector, 0);
1241 final String tag = "Client" + arg.uid + "-" + mClientNumberId++;
1242 final NetworkNsdReportedMetrics metrics =
1243 mDeps.makeNetworkNsdReportedMetrics(
1244 (int) mClock.elapsedRealtime());
1245 clientInfo = new ClientInfo(cb, arg.uid, arg.useJavaBackend,
1246 mServiceLogs.forSubComponent(tag), metrics);
1247 mClients.put(arg.connector, clientInfo);
1248 } catch (RemoteException e) {
1249 Log.w(TAG, "Client request id " + clientRequestId
1250 + " has already died");
1251 }
1252 break;
1253 case NsdManager.UNREGISTER_CLIENT:
1254 final NsdServiceConnector connector = (NsdServiceConnector) msg.obj;
1255 clientInfo = mClients.remove(connector);
1256 if (clientInfo != null) {
1257 clientInfo.expungeAllRequests();
1258 if (clientInfo.isPreSClient()) {
1259 mLegacyClientCount -= 1;
1260 }
1261 }
1262 maybeStopMonitoringSocketsIfNoActiveRequest();
1263 maybeScheduleStop();
1264 break;
1265 case NsdManager.DAEMON_CLEANUP:
1266 maybeStopDaemon();
1267 break;
1268 // This event should be only sent by the legacy (target SDK < S) clients.
1269 // Mark the sending client as legacy.
1270 case NsdManager.DAEMON_STARTUP:
1271 clientInfo = getClientInfoForReply(msg);
1272 if (clientInfo != null) {
1273 cancelStop();
1274 clientInfo.setPreSClient();
1275 mLegacyClientCount += 1;
1276 maybeStartDaemon();
1277 }
1278 break;
Irfan Sheriff75006652012-04-17 23:15:29 -07001279 default:
Paul Hu77c11182023-10-23 16:17:32 +08001280 Log.wtf(TAG, "Unhandled " + msg);
Hugo Benichif0c84092017-04-05 14:43:29 +09001281 return NOT_HANDLED;
Irfan Sheriff75006652012-04-17 23:15:29 -07001282 }
Hugo Benichif0c84092017-04-05 14:43:29 +09001283 return HANDLED;
Irfan Sheriff75006652012-04-17 23:15:29 -07001284 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001285
Paul Hud44e1b72023-06-16 02:07:42 +00001286 private boolean handleMDnsServiceEvent(int code, int transactionId, Object obj) {
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001287 NsdServiceInfo servInfo;
Paul Hud44e1b72023-06-16 02:07:42 +00001288 ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001289 if (clientInfo == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00001290 Log.e(TAG, String.format(
1291 "transactionId %d for %d has no client mapping", transactionId, code));
Hugo Benichif0c84092017-04-05 14:43:29 +09001292 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001293 }
1294
1295 /* This goes in response as msg.arg2 */
Paul Hud44e1b72023-06-16 02:07:42 +00001296 int clientRequestId = clientInfo.getClientRequestId(transactionId);
1297 if (clientRequestId < 0) {
Vinit Deshapnde930a8512013-06-25 19:45:03 -07001298 // This can happen because of race conditions. For example,
1299 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
1300 // and we may get in this situation.
Paul Hud44e1b72023-06-16 02:07:42 +00001301 Log.d(TAG, String.format("%d for transactionId %d that is no longer active",
1302 code, transactionId));
Hugo Benichif0c84092017-04-05 14:43:29 +09001303 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001304 }
Paul Hu812e9212023-06-20 06:24:53 +00001305 final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
1306 if (request == null) {
1307 Log.e(TAG, "Unknown client request. clientRequestId=" + clientRequestId);
1308 return false;
1309 }
Hugo Benichi32be63d2017-04-05 14:06:11 +09001310 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00001311 Log.d(TAG, String.format(
1312 "MDns service event code:%d transactionId=%d", code, transactionId));
Hugo Benichi32be63d2017-04-05 14:06:11 +09001313 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001314 switch (code) {
paulhu2b9ed952022-02-10 21:58:32 +08001315 case IMDnsEventListener.SERVICE_FOUND: {
1316 final DiscoveryInfo info = (DiscoveryInfo) obj;
1317 final String name = info.serviceName;
1318 final String type = info.registrationType;
1319 servInfo = new NsdServiceInfo(name, type);
1320 final int foundNetId = info.netId;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001321 if (foundNetId == 0L) {
1322 // Ignore services that do not have a Network: they are not usable
1323 // by apps, as they would need privileged permissions to use
1324 // interfaces that do not have an associated Network.
1325 break;
1326 }
Remi NGUYEN VAN643edb62023-01-23 19:14:57 +09001327 if (foundNetId == INetd.DUMMY_NET_ID) {
1328 // Ignore services on the dummy0 interface: they are only seen when
1329 // discovering locally advertised services, and are not reachable
1330 // through that interface.
1331 break;
1332 }
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001333 setServiceNetworkForCallback(servInfo, info.netId, info.interfaceIdx);
Paul Hu812e9212023-06-20 06:24:53 +00001334
1335 clientInfo.onServiceFound(clientRequestId, servInfo, request);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001336 break;
paulhu2b9ed952022-02-10 21:58:32 +08001337 }
1338 case IMDnsEventListener.SERVICE_LOST: {
1339 final DiscoveryInfo info = (DiscoveryInfo) obj;
1340 final String name = info.serviceName;
1341 final String type = info.registrationType;
1342 final int lostNetId = info.netId;
1343 servInfo = new NsdServiceInfo(name, type);
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001344 // The network could be set to null (netId 0) if it was torn down when the
1345 // service is lost
1346 // TODO: avoid returning null in that case, possibly by remembering
1347 // found services on the same interface index and their network at the time
1348 setServiceNetworkForCallback(servInfo, lostNetId, info.interfaceIdx);
Paul Hu812e9212023-06-20 06:24:53 +00001349 clientInfo.onServiceLost(clientRequestId, servInfo, request);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001350 break;
paulhu2b9ed952022-02-10 21:58:32 +08001351 }
1352 case IMDnsEventListener.SERVICE_DISCOVERY_FAILED:
Paul Hu812e9212023-06-20 06:24:53 +00001353 clientInfo.onDiscoverServicesFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001354 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1355 transactionId,
Paul Hu812e9212023-06-20 06:24:53 +00001356 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001357 break;
paulhu2b9ed952022-02-10 21:58:32 +08001358 case IMDnsEventListener.SERVICE_REGISTERED: {
1359 final RegistrationInfo info = (RegistrationInfo) obj;
1360 final String name = info.serviceName;
1361 servInfo = new NsdServiceInfo(name, null /* serviceType */);
Paul Hu508a0122023-09-11 15:31:33 +08001362 clientInfo.onRegisterServiceSucceeded(clientRequestId, servInfo, request);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001363 break;
paulhu2b9ed952022-02-10 21:58:32 +08001364 }
1365 case IMDnsEventListener.SERVICE_REGISTRATION_FAILED:
Paul Hu777ed052023-06-19 13:35:15 +00001366 clientInfo.onRegisterServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001367 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1368 transactionId,
Paul Hu812e9212023-06-20 06:24:53 +00001369 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001370 break;
paulhu2b9ed952022-02-10 21:58:32 +08001371 case IMDnsEventListener.SERVICE_RESOLVED: {
1372 final ResolutionInfo info = (ResolutionInfo) obj;
Sreeram Ramachandrana53dd7f2014-09-03 15:45:59 -07001373 int index = 0;
paulhu2b9ed952022-02-10 21:58:32 +08001374 final String fullName = info.serviceFullName;
1375 while (index < fullName.length() && fullName.charAt(index) != '.') {
1376 if (fullName.charAt(index) == '\\') {
Sreeram Ramachandrana53dd7f2014-09-03 15:45:59 -07001377 ++index;
1378 }
1379 ++index;
1380 }
paulhu2b9ed952022-02-10 21:58:32 +08001381 if (index >= fullName.length()) {
1382 Log.e(TAG, "Invalid service found " + fullName);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001383 break;
1384 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001385
paulhube186602022-04-12 07:18:23 +00001386 String name = unescape(fullName.substring(0, index));
paulhu2b9ed952022-02-10 21:58:32 +08001387 String rest = fullName.substring(index);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001388 String type = rest.replace(".local.", "");
1389
Paul Hu30bd70d2023-02-07 13:20:56 +00001390 final NsdServiceInfo serviceInfo = clientInfo.mResolvedService;
Paul Hu18aeccc2022-12-27 08:48:48 +00001391 serviceInfo.setServiceName(name);
1392 serviceInfo.setServiceType(type);
1393 serviceInfo.setPort(info.port);
1394 serviceInfo.setTxtRecords(info.txtRecord);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001395 // Network will be added after SERVICE_GET_ADDR_SUCCESS
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001396
Paul Hud44e1b72023-06-16 02:07:42 +00001397 stopResolveService(transactionId);
1398 removeRequestMap(clientRequestId, transactionId, clientInfo);
Vinit Deshapnde4429e872013-11-12 15:36:37 -08001399
Paul Hud44e1b72023-06-16 02:07:42 +00001400 final int transactionId2 = getUniqueId();
1401 if (getAddrInfo(transactionId2, info.hostname, info.interfaceIdx)) {
1402 storeLegacyRequestMap(clientRequestId, transactionId2, clientInfo,
Paul Hua6bc4632023-06-26 01:18:29 +00001403 NsdManager.RESOLVE_SERVICE, request.mStartTimeMs);
Vinit Deshapnde4429e872013-11-12 15:36:37 -08001404 } else {
Paul Hua6bc4632023-06-26 01:18:29 +00001405 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001406 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1407 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001408 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hu30bd70d2023-02-07 13:20:56 +00001409 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001410 }
1411 break;
paulhu2b9ed952022-02-10 21:58:32 +08001412 }
1413 case IMDnsEventListener.SERVICE_RESOLUTION_FAILED:
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001414 /* NNN resolveId errorCode */
Paul Hud44e1b72023-06-16 02:07:42 +00001415 stopResolveService(transactionId);
1416 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hua6bc4632023-06-26 01:18:29 +00001417 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001418 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1419 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001420 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hu30bd70d2023-02-07 13:20:56 +00001421 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001422 break;
paulhu2b9ed952022-02-10 21:58:32 +08001423 case IMDnsEventListener.SERVICE_GET_ADDR_FAILED:
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001424 /* NNN resolveId errorCode */
Paul Hud44e1b72023-06-16 02:07:42 +00001425 stopGetAddrInfo(transactionId);
1426 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hua6bc4632023-06-26 01:18:29 +00001427 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001428 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1429 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001430 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hu30bd70d2023-02-07 13:20:56 +00001431 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001432 break;
paulhu2b9ed952022-02-10 21:58:32 +08001433 case IMDnsEventListener.SERVICE_GET_ADDR_SUCCESS: {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001434 /* NNN resolveId hostname ttl addr interfaceIdx netId */
paulhu2b9ed952022-02-10 21:58:32 +08001435 final GetAddressInfo info = (GetAddressInfo) obj;
1436 final String address = info.address;
1437 final int netId = info.netId;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001438 InetAddress serviceHost = null;
1439 try {
paulhu2b9ed952022-02-10 21:58:32 +08001440 serviceHost = InetAddress.getByName(address);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001441 } catch (UnknownHostException e) {
1442 Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e);
1443 }
1444
1445 // If the resolved service is on an interface without a network, consider it
1446 // as a failure: it would not be usable by apps as they would need
1447 // privileged permissions.
Paul Hu30bd70d2023-02-07 13:20:56 +00001448 if (netId != NETID_UNSET && serviceHost != null) {
1449 clientInfo.mResolvedService.setHost(serviceHost);
1450 setServiceNetworkForCallback(clientInfo.mResolvedService,
1451 netId, info.interfaceIdx);
1452 clientInfo.onResolveServiceSucceeded(
Paul Hua6bc4632023-06-26 01:18:29 +00001453 clientRequestId, clientInfo.mResolvedService, request);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001454 } else {
Paul Hua6bc4632023-06-26 01:18:29 +00001455 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001456 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1457 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001458 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001459 }
Paul Hud44e1b72023-06-16 02:07:42 +00001460 stopGetAddrInfo(transactionId);
1461 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hu30bd70d2023-02-07 13:20:56 +00001462 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001463 break;
paulhu2b9ed952022-02-10 21:58:32 +08001464 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001465 default:
Hugo Benichif0c84092017-04-05 14:43:29 +09001466 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001467 }
Hugo Benichif0c84092017-04-05 14:43:29 +09001468 return true;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001469 }
Paul Hu019621e2023-01-13 23:26:49 +08001470
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001471 @Nullable
1472 private NsdServiceInfo buildNsdServiceInfoFromMdnsEvent(
1473 final MdnsEvent event, int code) {
Paul Hu019621e2023-01-13 23:26:49 +08001474 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001475 final String[] typeArray = serviceInfo.getServiceType();
1476 final String joinedType;
1477 if (typeArray.length == 0
1478 || !typeArray[typeArray.length - 1].equals(LOCAL_DOMAIN_NAME)) {
1479 Log.wtf(TAG, "MdnsServiceInfo type does not end in .local: "
1480 + Arrays.toString(typeArray));
1481 return null;
1482 } else {
1483 joinedType = TextUtils.join(".",
1484 Arrays.copyOfRange(typeArray, 0, typeArray.length - 1));
1485 }
1486 final String serviceType;
1487 switch (code) {
1488 case NsdManager.SERVICE_FOUND:
1489 case NsdManager.SERVICE_LOST:
1490 // For consistency with historical behavior, discovered service types have
1491 // a dot at the end.
1492 serviceType = joinedType + ".";
1493 break;
1494 case RESOLVE_SERVICE_SUCCEEDED:
1495 // For consistency with historical behavior, resolved service types have
1496 // a dot at the beginning.
1497 serviceType = "." + joinedType;
1498 break;
1499 default:
1500 serviceType = joinedType;
1501 break;
1502 }
Paul Hu019621e2023-01-13 23:26:49 +08001503 final String serviceName = serviceInfo.getServiceInstanceName();
1504 final NsdServiceInfo servInfo = new NsdServiceInfo(serviceName, serviceType);
1505 final Network network = serviceInfo.getNetwork();
Yuyang Huang3bee9d42023-04-04 13:00:54 +09001506 // In MdnsDiscoveryManagerEvent, the Network can be null which means it is a
1507 // network for Tethering interface. In other words, the network == null means the
1508 // network has netId = INetd.LOCAL_NET_ID.
Paul Hu019621e2023-01-13 23:26:49 +08001509 setServiceNetworkForCallback(
1510 servInfo,
Yuyang Huang3bee9d42023-04-04 13:00:54 +09001511 network == null ? INetd.LOCAL_NET_ID : network.netId,
Paul Hu019621e2023-01-13 23:26:49 +08001512 serviceInfo.getInterfaceIndex());
Kangping Dong5af24b62023-12-10 21:41:16 +08001513 servInfo.setSubtypes(dedupSubtypeLabels(serviceInfo.getSubtypes()));
Paul Hu019621e2023-01-13 23:26:49 +08001514 return servInfo;
1515 }
1516
1517 private boolean handleMdnsDiscoveryManagerEvent(
1518 int transactionId, int code, Object obj) {
Paul Hud44e1b72023-06-16 02:07:42 +00001519 final ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Paul Hu019621e2023-01-13 23:26:49 +08001520 if (clientInfo == null) {
1521 Log.e(TAG, String.format(
1522 "id %d for %d has no client mapping", transactionId, code));
1523 return false;
1524 }
1525
1526 final MdnsEvent event = (MdnsEvent) obj;
Paul Hud44e1b72023-06-16 02:07:42 +00001527 final int clientRequestId = event.mClientRequestId;
Paul Hubad6fe92023-07-24 21:25:22 +08001528 final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
1529 if (request == null) {
1530 Log.e(TAG, "Unknown client request. clientRequestId=" + clientRequestId);
1531 return false;
1532 }
1533
1534 // Deal with the discovery sent callback
1535 if (code == DISCOVERY_QUERY_SENT_CALLBACK) {
1536 request.onQuerySent();
1537 return true;
1538 }
1539
1540 // Deal with other callbacks.
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001541 final NsdServiceInfo info = buildNsdServiceInfoFromMdnsEvent(event, code);
1542 // Errors are already logged if null
1543 if (info == null) return false;
Paul Hu83ec7f42023-06-07 18:04:09 +08001544 mServiceLogs.log(String.format(
1545 "MdnsDiscoveryManager event code=%s transactionId=%d",
1546 NsdManager.nameOf(code), transactionId));
Paul Hu019621e2023-01-13 23:26:49 +08001547 switch (code) {
1548 case NsdManager.SERVICE_FOUND:
Paul Hu812e9212023-06-20 06:24:53 +00001549 clientInfo.onServiceFound(clientRequestId, info, request);
Paul Hu319751a2023-01-13 23:56:34 +08001550 break;
1551 case NsdManager.SERVICE_LOST:
Paul Hu812e9212023-06-20 06:24:53 +00001552 clientInfo.onServiceLost(clientRequestId, info, request);
Paul Hu019621e2023-01-13 23:26:49 +08001553 break;
Paul Hu75069ed2023-01-14 00:31:09 +08001554 case NsdManager.RESOLVE_SERVICE_SUCCEEDED: {
1555 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
Paul Hu75069ed2023-01-14 00:31:09 +08001556 info.setPort(serviceInfo.getPort());
1557
1558 Map<String, String> attrs = serviceInfo.getAttributes();
1559 for (Map.Entry<String, String> kv : attrs.entrySet()) {
1560 final String key = kv.getKey();
1561 try {
1562 info.setAttribute(key, serviceInfo.getAttributeAsBytes(key));
1563 } catch (IllegalArgumentException e) {
1564 Log.e(TAG, "Invalid attribute", e);
1565 }
1566 }
Handa Wang096e32e2024-01-14 08:21:28 +00001567 info.setHostname(getHostname(serviceInfo));
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001568 final List<InetAddress> addresses = getInetAddresses(serviceInfo);
Paul Hu2b865912023-03-06 14:27:53 +08001569 if (addresses.size() != 0) {
1570 info.setHostAddresses(addresses);
Paul Hua6bc4632023-06-26 01:18:29 +00001571 request.setServiceFromCache(event.mIsServiceFromCache);
1572 clientInfo.onResolveServiceSucceeded(clientRequestId, info, request);
Paul Hu2b865912023-03-06 14:27:53 +08001573 } else {
1574 // No address. Notify resolution failure.
Paul Hua6bc4632023-06-26 01:18:29 +00001575 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001576 NsdManager.FAILURE_INTERNAL_ERROR, false /* isLegacy */,
1577 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001578 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hu75069ed2023-01-14 00:31:09 +08001579 }
1580
1581 // Unregister the listener immediately like IMDnsEventListener design
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001582 if (!(request instanceof DiscoveryManagerRequest)) {
1583 Log.wtf(TAG, "non-DiscoveryManager request in DiscoveryManager event");
1584 break;
1585 }
Paul Hud44e1b72023-06-16 02:07:42 +00001586 stopDiscoveryManagerRequest(
1587 request, clientRequestId, transactionId, clientInfo);
Paul Hu75069ed2023-01-14 00:31:09 +08001588 break;
1589 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001590 case NsdManager.SERVICE_UPDATED: {
1591 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
1592 info.setPort(serviceInfo.getPort());
1593
1594 Map<String, String> attrs = serviceInfo.getAttributes();
1595 for (Map.Entry<String, String> kv : attrs.entrySet()) {
1596 final String key = kv.getKey();
1597 try {
1598 info.setAttribute(key, serviceInfo.getAttributeAsBytes(key));
1599 } catch (IllegalArgumentException e) {
1600 Log.e(TAG, "Invalid attribute", e);
1601 }
1602 }
1603
Handa Wang096e32e2024-01-14 08:21:28 +00001604 info.setHostname(getHostname(serviceInfo));
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001605 final List<InetAddress> addresses = getInetAddresses(serviceInfo);
Paul Hu30bd70d2023-02-07 13:20:56 +00001606 info.setHostAddresses(addresses);
Paul Huddce5912023-08-01 10:26:49 +08001607 clientInfo.onServiceUpdated(clientRequestId, info, request);
1608 // Set the ServiceFromCache flag only if the service is actually being
1609 // retrieved from the cache. This flag should not be overridden by later
1610 // service updates, which may not be cached.
1611 if (event.mIsServiceFromCache) {
1612 request.setServiceFromCache(true);
1613 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001614 break;
1615 }
1616 case NsdManager.SERVICE_UPDATED_LOST:
Paul Huddce5912023-08-01 10:26:49 +08001617 clientInfo.onServiceUpdatedLost(clientRequestId, request);
Paul Hu30bd70d2023-02-07 13:20:56 +00001618 break;
Paul Hu019621e2023-01-13 23:26:49 +08001619 default:
1620 return false;
1621 }
1622 return true;
1623 }
Irfan Sheriff75006652012-04-17 23:15:29 -07001624 }
1625 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001626
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001627 @NonNull
1628 private static List<InetAddress> getInetAddresses(@NonNull MdnsServiceInfo serviceInfo) {
1629 final List<String> v4Addrs = serviceInfo.getIpv4Addresses();
1630 final List<String> v6Addrs = serviceInfo.getIpv6Addresses();
1631 final List<InetAddress> addresses = new ArrayList<>(v4Addrs.size() + v6Addrs.size());
1632 for (String ipv4Address : v4Addrs) {
1633 try {
1634 addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
1635 } catch (IllegalArgumentException e) {
1636 Log.wtf(TAG, "Invalid ipv4 address", e);
1637 }
1638 }
1639 for (String ipv6Address : v6Addrs) {
1640 try {
Yuyang Huanga6a6ff92023-04-24 13:33:34 +09001641 final Inet6Address addr = (Inet6Address) InetAddresses.parseNumericAddress(
1642 ipv6Address);
1643 addresses.add(InetAddressUtils.withScopeId(addr, serviceInfo.getInterfaceIndex()));
1644 } catch (IllegalArgumentException e) {
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001645 Log.wtf(TAG, "Invalid ipv6 address", e);
1646 }
1647 }
1648 return addresses;
1649 }
1650
Handa Wang096e32e2024-01-14 08:21:28 +00001651 @NonNull
1652 private static String getHostname(@NonNull MdnsServiceInfo serviceInfo) {
1653 String[] hostname = serviceInfo.getHostName();
1654 // Strip the "local" top-level domain.
1655 if (hostname.length >= 2 && hostname[hostname.length - 1].equals("local")) {
1656 hostname = Arrays.copyOf(hostname, hostname.length - 1);
1657 }
1658 return String.join(".", hostname);
1659 }
1660
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001661 private static void setServiceNetworkForCallback(NsdServiceInfo info, int netId, int ifaceIdx) {
1662 switch (netId) {
1663 case NETID_UNSET:
1664 info.setNetwork(null);
1665 break;
1666 case INetd.LOCAL_NET_ID:
1667 // Special case for LOCAL_NET_ID: Networks on netId 99 are not generally
1668 // visible / usable for apps, so do not return it. Store the interface
1669 // index instead, so at least if the client tries to resolve the service
1670 // with that NsdServiceInfo, it will be done on the same interface.
1671 // If they recreate the NsdServiceInfo themselves, resolution would be
1672 // done on all interfaces as before T, which should also work.
1673 info.setNetwork(null);
1674 info.setInterfaceIndex(ifaceIdx);
1675 break;
1676 default:
1677 info.setNetwork(new Network(netId));
1678 }
1679 }
1680
paulhube186602022-04-12 07:18:23 +00001681 // The full service name is escaped from standard DNS rules on mdnsresponder, making it suitable
1682 // for passing to standard system DNS APIs such as res_query() . Thus, make the service name
1683 // unescape for getting right service address. See "Notes on DNS Name Escaping" on
1684 // external/mdnsresponder/mDNSShared/dns_sd.h for more details.
1685 private String unescape(String s) {
1686 StringBuilder sb = new StringBuilder(s.length());
1687 for (int i = 0; i < s.length(); ++i) {
1688 char c = s.charAt(i);
1689 if (c == '\\') {
1690 if (++i >= s.length()) {
1691 Log.e(TAG, "Unexpected end of escape sequence in: " + s);
1692 break;
1693 }
1694 c = s.charAt(i);
1695 if (c != '.' && c != '\\') {
1696 if (i + 2 >= s.length()) {
1697 Log.e(TAG, "Unexpected end of escape sequence in: " + s);
1698 break;
1699 }
1700 c = (char) ((c - '0') * 100 + (s.charAt(i + 1) - '0') * 10
1701 + (s.charAt(i + 2) - '0'));
1702 i += 2;
1703 }
1704 }
1705 sb.append(c);
1706 }
1707 return sb.toString();
1708 }
1709
Paul Hu7445e3d2023-03-03 15:14:00 +08001710 /**
1711 * Check the given service type is valid and construct it to a service type
1712 * which can use for discovery / resolution service.
1713 *
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001714 * <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 +08001715 * subtype (see RFC6763 7.1). Each label is up to 63 characters and must start with an
1716 * underscore; they are alphanumerical characters or dashes or underscore, except the
1717 * last one that is just alphanumerical. The last label must be _tcp or _udp.
1718 *
Yuyang Huang170d42f2023-12-09 15:26:16 +09001719 * <p>The subtypes may also be specified with a comma after the service type, for example
1720 * _type._tcp,_subtype1,_subtype2
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001721 *
Paul Hu7445e3d2023-03-03 15:14:00 +08001722 * @param serviceType the request service type for discovery / resolution service
1723 * @return constructed service type or null if the given service type is invalid.
1724 */
1725 @Nullable
Yuyang Huang170d42f2023-12-09 15:26:16 +09001726 public static Pair<String, List<String>> parseTypeAndSubtype(String serviceType) {
Paul Hu7445e3d2023-03-03 15:14:00 +08001727 if (TextUtils.isEmpty(serviceType)) return null;
Yuyang Huang86d083f2023-12-12 19:56:41 +09001728 final Pattern serviceTypePattern = Pattern.compile(TYPE_REGEX);
Paul Hu7445e3d2023-03-03 15:14:00 +08001729 final Matcher matcher = serviceTypePattern.matcher(serviceType);
1730 if (!matcher.matches()) return null;
Yuyang Huang170d42f2023-12-09 15:26:16 +09001731 final String queryType = matcher.group(2);
1732 // Use the subtype at the beginning
1733 if (matcher.group(1) != null) {
1734 return new Pair<>(queryType, List.of(matcher.group(1)));
1735 }
1736 // Use the subtypes at the end
1737 final String subTypesStr = matcher.group(3);
1738 if (subTypesStr != null && !subTypesStr.isEmpty()) {
1739 final String[] subTypes = subTypesStr.substring(1).split(",");
1740 return new Pair<>(queryType, List.of(subTypes));
1741 }
1742
1743 return new Pair<>(queryType, Collections.emptyList());
Paul Hu7445e3d2023-03-03 15:14:00 +08001744 }
1745
Handa Wang096e32e2024-01-14 08:21:28 +00001746 /**
1747 * Checks if the hostname is valid.
1748 *
1749 * <p>For now NsdService only allows single-label hostnames conforming to RFC 1035. In other
1750 * words, the hostname should be at most 63 characters long and it only contains letters, digits
1751 * and hyphens.
1752 */
1753 public static boolean checkHostname(@Nullable String hostname) {
1754 if (hostname == null) {
1755 return true;
1756 }
1757 String HOSTNAME_REGEX = "^[a-zA-Z]([a-zA-Z0-9-_]{0,61}[a-zA-Z0-9])?$";
1758 return Pattern.compile(HOSTNAME_REGEX).matcher(hostname).matches();
1759 }
1760
Kangping Dong5af24b62023-12-10 21:41:16 +08001761 /** Returns {@code true} if {@code subtype} is a valid DNS-SD subtype label. */
1762 private static boolean checkSubtypeLabel(String subtype) {
Remi NGUYEN VAN629234c2024-02-08 18:27:45 +09001763 return Pattern.compile("^" + SUBTYPE_LABEL_REGEX + "$").matcher(subtype).matches();
Kangping Dong5af24b62023-12-10 21:41:16 +08001764 }
1765
Hugo Benichi803a2f02017-04-24 11:35:06 +09001766 @VisibleForTesting
paulhu2b9ed952022-02-10 21:58:32 +08001767 NsdService(Context ctx, Handler handler, long cleanupDelayMs) {
Paul Hu4bd98ef2023-01-12 13:42:07 +08001768 this(ctx, handler, cleanupDelayMs, new Dependencies());
1769 }
1770
1771 @VisibleForTesting
1772 NsdService(Context ctx, Handler handler, long cleanupDelayMs, Dependencies deps) {
Luke Huang05298582021-06-13 16:52:05 +00001773 mCleanupDelayMs = cleanupDelayMs;
Hugo Benichi803a2f02017-04-24 11:35:06 +09001774 mContext = ctx;
Hugo Benichi803a2f02017-04-24 11:35:06 +09001775 mNsdStateMachine = new NsdStateMachine(TAG, handler);
Irfan Sheriff75006652012-04-17 23:15:29 -07001776 mNsdStateMachine.start();
Ken Chen80c9f6f2023-11-15 18:24:54 +08001777 // It can fail on V+ device since mdns native service provided by netd is removed.
1778 mMDnsManager = SdkLevel.isAtLeastV() ? null : ctx.getSystemService(MDnsManager.class);
paulhu2b9ed952022-02-10 21:58:32 +08001779 mMDnsEventCallback = new MDnsEventCallback(mNsdStateMachine);
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001780 mDeps = deps;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001781
Paul Hu14667de2023-04-17 22:42:47 +08001782 mMdnsSocketProvider = deps.makeMdnsSocketProvider(ctx, handler.getLooper(),
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001783 LOGGER.forSubComponent("MdnsSocketProvider"), new SocketRequestMonitor());
Yuyang Huang700778b2023-03-08 16:17:05 +09001784 // Netlink monitor starts on boot, and intentionally never stopped, to ensure that all
Yuyang Huangfca402a2023-05-24 14:45:59 +09001785 // address events are received. When the netlink monitor starts, any IP addresses already
1786 // on the interfaces will not be seen. In practice, the network will not connect at boot
1787 // time As a result, all the netlink message should be observed if the netlink monitor
1788 // starts here.
Yuyang Huang700778b2023-03-08 16:17:05 +09001789 handler.post(mMdnsSocketProvider::startNetLinkMonitor);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001790
1791 // NsdService is started after ActivityManager (startOtherServices in SystemServer, vs.
1792 // startBootstrapServices).
1793 mRunningAppActiveImportanceCutoff = mDeps.getDeviceConfigInt(
1794 MDNS_CONFIG_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF,
1795 DEFAULT_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF);
1796 final ActivityManager am = ctx.getSystemService(ActivityManager.class);
1797 am.addOnUidImportanceListener(new UidImportanceListener(handler),
1798 mRunningAppActiveImportanceCutoff);
1799
Paul Hu11a883d2023-12-14 07:36:44 +00001800 mMdnsFeatureFlags = new MdnsFeatureFlags.Builder()
Paul Huf3fe3332023-10-16 17:13:25 +08001801 .setIsMdnsOffloadFeatureEnabled(mDeps.isTetheringFeatureNotChickenedOut(
1802 mContext, MdnsFeatureFlags.NSD_FORCE_DISABLE_MDNS_OFFLOAD))
1803 .setIncludeInetAddressRecordsInProbing(mDeps.isFeatureEnabled(
1804 mContext, MdnsFeatureFlags.INCLUDE_INET_ADDRESS_RECORDS_IN_PROBING))
Paul Hu596a5002023-10-18 17:07:31 +08001805 .setIsExpiredServicesRemovalEnabled(mDeps.isFeatureEnabled(
1806 mContext, MdnsFeatureFlags.NSD_EXPIRED_SERVICES_REMOVAL))
Paul Hufd357ef2023-11-01 16:32:45 +08001807 .setIsLabelCountLimitEnabled(mDeps.isTetheringFeatureNotChickenedOut(
1808 mContext, MdnsFeatureFlags.NSD_LIMIT_LABEL_COUNT))
Paul Hu01f243f2023-11-22 17:26:36 +08001809 .setIsKnownAnswerSuppressionEnabled(mDeps.isFeatureEnabled(
1810 mContext, MdnsFeatureFlags.NSD_KNOWN_ANSWER_SUPPRESSION))
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +09001811 .setIsUnicastReplyEnabled(mDeps.isFeatureEnabled(
1812 mContext, MdnsFeatureFlags.NSD_UNICAST_REPLY_ENABLED))
Paul Hu11a883d2023-12-14 07:36:44 +00001813 .setIsAggressiveQueryModeEnabled(mDeps.isFeatureEnabled(
1814 mContext, MdnsFeatureFlags.NSD_AGGRESSIVE_QUERY_MODE))
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +09001815 .setOverrideProvider(flag -> mDeps.isFeatureEnabled(
1816 mContext, FORCE_ENABLE_FLAG_FOR_TEST_PREFIX + flag))
Paul Huf3fe3332023-10-16 17:13:25 +08001817 .build();
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001818 mMdnsSocketClient =
Yuyang Huang7ddf2932023-08-01 18:16:30 +09001819 new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider,
Paul Hu11a883d2023-12-14 07:36:44 +00001820 LOGGER.forSubComponent("MdnsMultinetworkSocketClient"), mMdnsFeatureFlags);
Paul Hu14667de2023-04-17 22:42:47 +08001821 mMdnsDiscoveryManager = deps.makeMdnsDiscoveryManager(new ExecutorProvider(),
Paul Hu11a883d2023-12-14 07:36:44 +00001822 mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"),
1823 mMdnsFeatureFlags);
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001824 handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
1825 mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider,
Paul Hu11a883d2023-12-14 07:36:44 +00001826 new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"),
1827 mMdnsFeatureFlags, mContext);
Paul Hu777ed052023-06-19 13:35:15 +00001828 mClock = deps.makeClock();
Paul Hu4bd98ef2023-01-12 13:42:07 +08001829 }
1830
1831 /**
1832 * Dependencies of NsdService, for injection in tests.
1833 */
1834 @VisibleForTesting
1835 public static class Dependencies {
1836 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001837 * Check whether the MdnsDiscoveryManager feature is enabled.
Paul Hu4bd98ef2023-01-12 13:42:07 +08001838 *
1839 * @param context The global context information about an app environment.
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001840 * @return true if the MdnsDiscoveryManager feature is enabled.
Paul Hu4bd98ef2023-01-12 13:42:07 +08001841 */
1842 public boolean isMdnsDiscoveryManagerEnabled(Context context) {
Motomu Utsumi624aeb42023-08-15 15:52:27 +09001843 return isAtLeastU() || DeviceConfigUtils.isTetheringFeatureEnabled(context,
Motomu Utsumi3e0be392023-08-15 16:32:44 +09001844 MDNS_DISCOVERY_MANAGER_VERSION);
Paul Hu4bd98ef2023-01-12 13:42:07 +08001845 }
1846
1847 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001848 * Check whether the MdnsAdvertiser feature is enabled.
1849 *
1850 * @param context The global context information about an app environment.
1851 * @return true if the MdnsAdvertiser feature is enabled.
1852 */
1853 public boolean isMdnsAdvertiserEnabled(Context context) {
Motomu Utsumi624aeb42023-08-15 15:52:27 +09001854 return isAtLeastU() || DeviceConfigUtils.isTetheringFeatureEnabled(context,
Motomu Utsumi3e0be392023-08-15 16:32:44 +09001855 MDNS_ADVERTISER_VERSION);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001856 }
1857
1858 /**
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001859 * Get the type allowlist flag value.
1860 * @see #MDNS_TYPE_ALLOWLIST_FLAGS
1861 */
1862 @Nullable
1863 public String getTypeAllowlistFlags() {
1864 return DeviceConfigUtils.getDeviceConfigProperty(NAMESPACE_TETHERING,
1865 MDNS_TYPE_ALLOWLIST_FLAGS, null);
1866 }
1867
1868 /**
Motomu Utsumi624aeb42023-08-15 15:52:27 +09001869 * @see DeviceConfigUtils#isTetheringFeatureEnabled
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001870 */
1871 public boolean isFeatureEnabled(Context context, String feature) {
Motomu Utsumi3e0be392023-08-15 16:32:44 +09001872 return DeviceConfigUtils.isTetheringFeatureEnabled(context, feature);
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001873 }
1874
1875 /**
Yuyang Huangb96a0712023-09-07 15:13:15 +09001876 * @see DeviceConfigUtils#isTetheringFeatureNotChickenedOut
1877 */
Motomu Utsumied4e7ec2023-09-13 14:58:32 +09001878 public boolean isTetheringFeatureNotChickenedOut(Context context, String feature) {
1879 return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, feature);
Yuyang Huangb96a0712023-09-07 15:13:15 +09001880 }
1881
1882 /**
Paul Huf3fe3332023-10-16 17:13:25 +08001883 * @see DeviceConfigUtils#isTrunkStableFeatureEnabled
1884 */
1885 public boolean isTrunkStableFeatureEnabled(String feature) {
1886 return DeviceConfigUtils.isTrunkStableFeatureEnabled(feature);
1887 }
1888
1889 /**
Paul Hu4bd98ef2023-01-12 13:42:07 +08001890 * @see MdnsDiscoveryManager
1891 */
1892 public MdnsDiscoveryManager makeMdnsDiscoveryManager(
Paul Hu14667de2023-04-17 22:42:47 +08001893 @NonNull ExecutorProvider executorProvider,
Paul Huf3fe3332023-10-16 17:13:25 +08001894 @NonNull MdnsMultinetworkSocketClient socketClient, @NonNull SharedLog sharedLog,
1895 @NonNull MdnsFeatureFlags featureFlags) {
1896 return new MdnsDiscoveryManager(
1897 executorProvider, socketClient, sharedLog, featureFlags);
Paul Hu4bd98ef2023-01-12 13:42:07 +08001898 }
1899
1900 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001901 * @see MdnsAdvertiser
1902 */
1903 public MdnsAdvertiser makeMdnsAdvertiser(
1904 @NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
Yuyang Huangb96a0712023-09-07 15:13:15 +09001905 @NonNull MdnsAdvertiser.AdvertiserCallback cb, @NonNull SharedLog sharedLog,
Remi NGUYEN VAN5c9d6cb2024-01-23 17:14:55 +09001906 MdnsFeatureFlags featureFlags, Context context) {
1907 return new MdnsAdvertiser(looper, socketProvider, cb, sharedLog, featureFlags, context);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001908 }
1909
1910 /**
Paul Hu4bd98ef2023-01-12 13:42:07 +08001911 * @see MdnsSocketProvider
1912 */
Paul Hu14667de2023-04-17 22:42:47 +08001913 public MdnsSocketProvider makeMdnsSocketProvider(@NonNull Context context,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001914 @NonNull Looper looper, @NonNull SharedLog sharedLog,
1915 @NonNull MdnsSocketProvider.SocketRequestMonitor socketCreationCallback) {
1916 return new MdnsSocketProvider(context, looper, sharedLog, socketCreationCallback);
1917 }
1918
1919 /**
1920 * @see DeviceConfig#getInt(String, String, int)
1921 */
1922 public int getDeviceConfigInt(@NonNull String config, int defaultValue) {
1923 return DeviceConfig.getInt(NAMESPACE_TETHERING, config, defaultValue);
1924 }
1925
1926 /**
1927 * @see Binder#getCallingUid()
1928 */
1929 public int getCallingUid() {
1930 return Binder.getCallingUid();
Paul Hu4bd98ef2023-01-12 13:42:07 +08001931 }
Paul Hu777ed052023-06-19 13:35:15 +00001932
1933 /**
1934 * @see NetworkNsdReportedMetrics
1935 */
Paul Hu508a0122023-09-11 15:31:33 +08001936 public NetworkNsdReportedMetrics makeNetworkNsdReportedMetrics(int clientId) {
1937 return new NetworkNsdReportedMetrics(clientId);
Paul Hu777ed052023-06-19 13:35:15 +00001938 }
1939
1940 /**
1941 * @see MdnsUtils.Clock
1942 */
1943 public Clock makeClock() {
1944 return new Clock();
1945 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001946 }
1947
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001948 /**
1949 * Return whether a type is allowlisted to use the Java backend.
1950 * @param type The service type
1951 * @param flagPrefix One of {@link #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX} or
1952 * {@link #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX}.
1953 */
1954 private boolean isTypeAllowlistedForJavaBackend(@Nullable String type,
1955 @NonNull String flagPrefix) {
1956 if (type == null) return false;
1957 final String typesConfig = mDeps.getTypeAllowlistFlags();
1958 if (TextUtils.isEmpty(typesConfig)) return false;
1959
1960 final String mappingPrefix = type + ":";
1961 String mappedFlag = null;
1962 for (String mapping : TextUtils.split(typesConfig, ",")) {
1963 if (mapping.startsWith(mappingPrefix)) {
1964 mappedFlag = mapping.substring(mappingPrefix.length());
1965 break;
1966 }
1967 }
1968
1969 if (mappedFlag == null) return false;
1970
1971 return mDeps.isFeatureEnabled(mContext,
1972 flagPrefix + mappedFlag + MDNS_ALLOWLIST_FLAG_SUFFIX);
1973 }
1974
1975 private boolean useDiscoveryManagerForType(@Nullable String type) {
1976 return isTypeAllowlistedForJavaBackend(type, MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX);
1977 }
1978
1979 private boolean useAdvertiserForType(@Nullable String type) {
1980 return isTypeAllowlistedForJavaBackend(type, MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX);
1981 }
1982
paulhu1b35e822022-04-08 14:48:41 +08001983 public static NsdService create(Context context) {
Hugo Benichi803a2f02017-04-24 11:35:06 +09001984 HandlerThread thread = new HandlerThread(TAG);
1985 thread.start();
1986 Handler handler = new Handler(thread.getLooper());
paulhu2b9ed952022-02-10 21:58:32 +08001987 NsdService service = new NsdService(context, handler, CLEANUP_DELAY_MS);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001988 return service;
1989 }
1990
paulhu2b9ed952022-02-10 21:58:32 +08001991 private static class MDnsEventCallback extends IMDnsEventListener.Stub {
1992 private final StateMachine mStateMachine;
1993
1994 MDnsEventCallback(StateMachine sm) {
1995 mStateMachine = sm;
1996 }
1997
1998 @Override
1999 public void onServiceRegistrationStatus(final RegistrationInfo status) {
2000 mStateMachine.sendMessage(
2001 MDNS_SERVICE_EVENT, status.result, status.id, status);
2002 }
2003
2004 @Override
2005 public void onServiceDiscoveryStatus(final DiscoveryInfo status) {
2006 mStateMachine.sendMessage(
2007 MDNS_SERVICE_EVENT, status.result, status.id, status);
2008 }
2009
2010 @Override
2011 public void onServiceResolutionStatus(final ResolutionInfo status) {
2012 mStateMachine.sendMessage(
2013 MDNS_SERVICE_EVENT, status.result, status.id, status);
2014 }
2015
2016 @Override
2017 public void onGettingServiceAddressStatus(final GetAddressInfo status) {
2018 mStateMachine.sendMessage(
2019 MDNS_SERVICE_EVENT, status.result, status.id, status);
2020 }
2021
2022 @Override
2023 public int getInterfaceVersion() throws RemoteException {
2024 return this.VERSION;
2025 }
2026
2027 @Override
2028 public String getInterfaceHash() throws RemoteException {
2029 return this.HASH;
2030 }
2031 }
2032
Yuyang Huangc275a9e2023-08-25 18:03:22 +09002033 private void sendAllOffloadServiceInfos(@NonNull OffloadEngineInfo offloadEngineInfo) {
2034 final String targetInterface = offloadEngineInfo.mInterfaceName;
2035 final IOffloadEngine offloadEngine = offloadEngineInfo.mOffloadEngine;
2036 final List<MdnsAdvertiser.OffloadServiceInfoWrapper> offloadWrappers =
2037 mAdvertiser.getAllInterfaceOffloadServiceInfos(targetInterface);
2038 for (MdnsAdvertiser.OffloadServiceInfoWrapper wrapper : offloadWrappers) {
2039 try {
2040 offloadEngine.onOffloadServiceUpdated(wrapper.mOffloadServiceInfo);
2041 } catch (RemoteException e) {
2042 // Can happen in regular cases, do not log a stacktrace
2043 Log.i(TAG, "Failed to send offload callback, remote died: " + e.getMessage());
2044 }
2045 }
2046 }
2047
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002048 private void sendOffloadServiceInfosUpdate(@NonNull String targetInterfaceName,
2049 @NonNull OffloadServiceInfo offloadServiceInfo, boolean isRemove) {
2050 final int count = mOffloadEngines.beginBroadcast();
2051 try {
2052 for (int i = 0; i < count; i++) {
2053 final OffloadEngineInfo offloadEngineInfo =
2054 (OffloadEngineInfo) mOffloadEngines.getBroadcastCookie(i);
2055 final String interfaceName = offloadEngineInfo.mInterfaceName;
2056 if (!targetInterfaceName.equals(interfaceName)
2057 || ((offloadEngineInfo.mOffloadType
2058 & offloadServiceInfo.getOffloadType()) == 0)) {
2059 continue;
2060 }
2061 try {
2062 if (isRemove) {
2063 mOffloadEngines.getBroadcastItem(i).onOffloadServiceRemoved(
2064 offloadServiceInfo);
2065 } else {
2066 mOffloadEngines.getBroadcastItem(i).onOffloadServiceUpdated(
2067 offloadServiceInfo);
2068 }
2069 } catch (RemoteException e) {
2070 // Can happen in regular cases, do not log a stacktrace
Yuyang Huangc275a9e2023-08-25 18:03:22 +09002071 Log.i(TAG, "Failed to send offload callback, remote died: " + e.getMessage());
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002072 }
2073 }
2074 } finally {
2075 mOffloadEngines.finishBroadcast();
2076 }
2077 }
2078
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002079 private class AdvertiserCallback implements MdnsAdvertiser.AdvertiserCallback {
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002080 // TODO: add a callback to notify when a service is being added on each interface (as soon
2081 // as probing starts), and call mOffloadCallbacks. This callback is for
2082 // OFFLOAD_CAPABILITY_FILTER_REPLIES offload type.
2083
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002084 @Override
Paul Hud44e1b72023-06-16 02:07:42 +00002085 public void onRegisterServiceSucceeded(int transactionId, NsdServiceInfo registeredInfo) {
2086 mServiceLogs.log("onRegisterServiceSucceeded: transactionId " + transactionId);
2087 final ClientInfo clientInfo = getClientInfoOrLog(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002088 if (clientInfo == null) return;
2089
Paul Hud44e1b72023-06-16 02:07:42 +00002090 final int clientRequestId = getClientRequestIdOrLog(clientInfo, transactionId);
2091 if (clientRequestId < 0) return;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002092
Handa Wang096e32e2024-01-14 08:21:28 +00002093 // onRegisterServiceSucceeded only has the service name and hostname in its info. This
2094 // aligns with historical behavior.
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002095 final NsdServiceInfo cbInfo = new NsdServiceInfo(registeredInfo.getServiceName(), null);
Handa Wang096e32e2024-01-14 08:21:28 +00002096 cbInfo.setHostname(registeredInfo.getHostname());
Paul Hu777ed052023-06-19 13:35:15 +00002097 final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
Paul Hu508a0122023-09-11 15:31:33 +08002098 clientInfo.onRegisterServiceSucceeded(clientRequestId, cbInfo, request);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002099 }
2100
2101 @Override
Paul Hud44e1b72023-06-16 02:07:42 +00002102 public void onRegisterServiceFailed(int transactionId, int errorCode) {
2103 final ClientInfo clientInfo = getClientInfoOrLog(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002104 if (clientInfo == null) return;
2105
Paul Hud44e1b72023-06-16 02:07:42 +00002106 final int clientRequestId = getClientRequestIdOrLog(clientInfo, transactionId);
2107 if (clientRequestId < 0) return;
Paul Hu777ed052023-06-19 13:35:15 +00002108 final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
Paul Hu508a0122023-09-11 15:31:33 +08002109 clientInfo.onRegisterServiceFailed(clientRequestId, errorCode, false /* isLegacy */,
2110 transactionId, request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002111 }
2112
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002113 @Override
2114 public void onOffloadStartOrUpdate(@NonNull String interfaceName,
2115 @NonNull OffloadServiceInfo offloadServiceInfo) {
2116 sendOffloadServiceInfosUpdate(interfaceName, offloadServiceInfo, false /* isRemove */);
2117 }
2118
2119 @Override
2120 public void onOffloadStop(@NonNull String interfaceName,
2121 @NonNull OffloadServiceInfo offloadServiceInfo) {
2122 sendOffloadServiceInfosUpdate(interfaceName, offloadServiceInfo, true /* isRemove */);
2123 }
2124
Paul Hud44e1b72023-06-16 02:07:42 +00002125 private ClientInfo getClientInfoOrLog(int transactionId) {
2126 final ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002127 if (clientInfo == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00002128 Log.e(TAG, String.format("Callback for service %d has no client", transactionId));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002129 }
2130 return clientInfo;
2131 }
2132
Paul Hud44e1b72023-06-16 02:07:42 +00002133 private int getClientRequestIdOrLog(@NonNull ClientInfo info, int transactionId) {
2134 final int clientRequestId = info.getClientRequestId(transactionId);
2135 if (clientRequestId < 0) {
2136 Log.e(TAG, String.format(
2137 "Client request ID not found for service %d", transactionId));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002138 }
Paul Hud44e1b72023-06-16 02:07:42 +00002139 return clientRequestId;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002140 }
2141 }
2142
Paul Hu2e0a88c2023-03-09 16:05:01 +08002143 private static class ConnectorArgs {
2144 @NonNull public final NsdServiceConnector connector;
2145 @NonNull public final INsdManagerCallback callback;
2146 public final boolean useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002147 public final int uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002148
2149 ConnectorArgs(@NonNull NsdServiceConnector connector, @NonNull INsdManagerCallback callback,
Paul Hub2e67d32023-04-18 05:50:14 +00002150 boolean useJavaBackend, int uid) {
Paul Hu2e0a88c2023-03-09 16:05:01 +08002151 this.connector = connector;
2152 this.callback = callback;
2153 this.useJavaBackend = useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002154 this.uid = uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002155 }
2156 }
2157
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002158 @Override
Paul Hu2e0a88c2023-03-09 16:05:01 +08002159 public INsdServiceConnector connect(INsdManagerCallback cb, boolean useJavaBackend) {
Hugo Benichi803a2f02017-04-24 11:35:06 +09002160 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
Paul Hu101dbf52023-08-09 16:05:20 +08002161 final int uid = mDeps.getCallingUid();
2162 if (cb == null) {
2163 throw new IllegalArgumentException("Unknown client callback from uid=" + uid);
2164 }
Paul Hu2e0a88c2023-03-09 16:05:01 +08002165 if (DBG) Log.d(TAG, "New client connect. useJavaBackend=" + useJavaBackend);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002166 final INsdServiceConnector connector = new NsdServiceConnector();
Paul Hub2e67d32023-04-18 05:50:14 +00002167 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.REGISTER_CLIENT,
Paul Hu101dbf52023-08-09 16:05:20 +08002168 new ConnectorArgs((NsdServiceConnector) connector, cb, useJavaBackend, uid)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002169 return connector;
Irfan Sheriff75006652012-04-17 23:15:29 -07002170 }
2171
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002172 private static class ListenerArgs {
2173 public final NsdServiceConnector connector;
2174 public final NsdServiceInfo serviceInfo;
2175 ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) {
2176 this.connector = connector;
2177 this.serviceInfo = serviceInfo;
2178 }
2179 }
2180
Yuyang Huang86d083f2023-12-12 19:56:41 +09002181 private static class AdvertisingArgs {
2182 public final NsdServiceConnector connector;
2183 public final AdvertisingRequest advertisingRequest;
2184
2185 AdvertisingArgs(NsdServiceConnector connector, AdvertisingRequest advertisingRequest) {
2186 this.connector = connector;
2187 this.advertisingRequest = advertisingRequest;
2188 }
2189 }
2190
Kangping Dong1f1a3792023-12-10 22:05:04 +08002191 private static final class DiscoveryArgs {
2192 public final NsdServiceConnector connector;
2193 public final DiscoveryRequest discoveryRequest;
2194 DiscoveryArgs(NsdServiceConnector connector, DiscoveryRequest discoveryRequest) {
2195 this.connector = connector;
2196 this.discoveryRequest = discoveryRequest;
2197 }
2198 }
2199
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002200 private class NsdServiceConnector extends INsdServiceConnector.Stub
2201 implements IBinder.DeathRecipient {
Yuyang Huang86d083f2023-12-12 19:56:41 +09002202
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002203 @Override
Yuyang Huang86d083f2023-12-12 19:56:41 +09002204 public void registerService(int listenerKey, AdvertisingRequest advertisingRequest)
2205 throws RemoteException {
Handa Wang096e32e2024-01-14 08:21:28 +00002206 NsdManager.checkServiceInfoForRegistration(advertisingRequest.getServiceInfo());
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002207 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2208 NsdManager.REGISTER_SERVICE, 0, listenerKey,
Yuyang Huang86d083f2023-12-12 19:56:41 +09002209 new AdvertisingArgs(this, advertisingRequest)
2210 ));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002211 }
2212
2213 @Override
2214 public void unregisterService(int listenerKey) {
2215 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2216 NsdManager.UNREGISTER_SERVICE, 0, listenerKey,
Yuyang Huang86d083f2023-12-12 19:56:41 +09002217 new ListenerArgs(this, (NsdServiceInfo) null)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002218 }
2219
2220 @Override
Kangping Dong1f1a3792023-12-10 22:05:04 +08002221 public void discoverServices(int listenerKey, DiscoveryRequest discoveryRequest) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002222 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2223 NsdManager.DISCOVER_SERVICES, 0, listenerKey,
Kangping Dong1f1a3792023-12-10 22:05:04 +08002224 new DiscoveryArgs(this, discoveryRequest)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002225 }
2226
2227 @Override
2228 public void stopDiscovery(int listenerKey) {
Yuyang Huang86d083f2023-12-12 19:56:41 +09002229 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.STOP_DISCOVERY,
2230 0, listenerKey, new ListenerArgs(this, (NsdServiceInfo) null)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002231 }
2232
2233 @Override
2234 public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) {
2235 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2236 NsdManager.RESOLVE_SERVICE, 0, listenerKey,
2237 new ListenerArgs(this, serviceInfo)));
2238 }
2239
2240 @Override
Paul Hub58deb72022-12-26 09:24:42 +00002241 public void stopResolution(int listenerKey) {
Yuyang Huang86d083f2023-12-12 19:56:41 +09002242 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.STOP_RESOLUTION,
2243 0, listenerKey, new ListenerArgs(this, (NsdServiceInfo) null)));
Paul Hub58deb72022-12-26 09:24:42 +00002244 }
2245
2246 @Override
Paul Hu18aeccc2022-12-27 08:48:48 +00002247 public void registerServiceInfoCallback(int listenerKey, NsdServiceInfo serviceInfo) {
2248 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2249 NsdManager.REGISTER_SERVICE_CALLBACK, 0, listenerKey,
2250 new ListenerArgs(this, serviceInfo)));
2251 }
2252
2253 @Override
2254 public void unregisterServiceInfoCallback(int listenerKey) {
2255 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2256 NsdManager.UNREGISTER_SERVICE_CALLBACK, 0, listenerKey,
Yuyang Huang86d083f2023-12-12 19:56:41 +09002257 new ListenerArgs(this, (NsdServiceInfo) null)));
Paul Hu18aeccc2022-12-27 08:48:48 +00002258 }
2259
2260 @Override
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002261 public void startDaemon() {
Yuyang Huang86d083f2023-12-12 19:56:41 +09002262 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.DAEMON_STARTUP,
2263 new ListenerArgs(this, (NsdServiceInfo) null)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002264 }
2265
2266 @Override
2267 public void binderDied() {
2268 mNsdStateMachine.sendMessage(
2269 mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this));
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002270
2271 }
2272
2273 @Override
2274 public void registerOffloadEngine(String ifaceName, IOffloadEngine cb,
2275 @OffloadEngine.OffloadCapability long offloadCapabilities,
2276 @OffloadEngine.OffloadType long offloadTypes) {
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002277 checkOffloadEnginePermission(mContext);
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002278 Objects.requireNonNull(ifaceName);
2279 Objects.requireNonNull(cb);
2280 mNsdStateMachine.sendMessage(
2281 mNsdStateMachine.obtainMessage(NsdManager.REGISTER_OFFLOAD_ENGINE,
2282 new OffloadEngineInfo(cb, ifaceName, offloadCapabilities,
2283 offloadTypes)));
2284 }
2285
2286 @Override
2287 public void unregisterOffloadEngine(IOffloadEngine cb) {
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002288 checkOffloadEnginePermission(mContext);
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002289 Objects.requireNonNull(cb);
2290 mNsdStateMachine.sendMessage(
2291 mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_OFFLOAD_ENGINE, cb));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002292 }
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002293
2294 private static void checkOffloadEnginePermission(Context context) {
2295 if (!SdkLevel.isAtLeastT()) {
2296 throw new SecurityException("API is not available in before API level 33");
2297 }
Yuyang Huangd5896e72023-11-28 13:23:59 +09002298
Ken Chena7bae552023-12-27 11:40:57 +08002299 final ArrayList<String> permissionsList = new ArrayList<>(Arrays.asList(NETWORK_STACK,
2300 PERMISSION_MAINLINE_NETWORK_STACK, NETWORK_SETTINGS));
2301
2302 if (SdkLevel.isAtLeastV()) {
2303 // REGISTER_NSD_OFFLOAD_ENGINE was only added to the SDK in V.
2304 permissionsList.add(REGISTER_NSD_OFFLOAD_ENGINE);
2305 } else if (SdkLevel.isAtLeastU()) {
2306 // REGISTER_NSD_OFFLOAD_ENGINE cannot be backport to U. In U, check the DEVICE_POWER
2307 // permission instead.
2308 permissionsList.add(DEVICE_POWER);
Yuyang Huangd5896e72023-11-28 13:23:59 +09002309 }
2310
Junyu Lai71b51532024-02-01 10:39:01 +08002311 if (PermissionUtils.hasAnyPermissionOf(context,
Ken Chena7bae552023-12-27 11:40:57 +08002312 permissionsList.toArray(new String[0]))) {
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002313 return;
2314 }
2315 throw new SecurityException("Requires one of the following permissions: "
Ken Chena7bae552023-12-27 11:40:57 +08002316 + String.join(", ", permissionsList) + ".");
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002317 }
Irfan Sheriff75006652012-04-17 23:15:29 -07002318 }
2319
Hugo Benichi912db992017-04-24 16:41:03 +09002320 private void sendNsdStateChangeBroadcast(boolean isEnabled) {
Irfan Sheriff52fc83a2012-04-19 10:26:34 -07002321 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff75006652012-04-17 23:15:29 -07002322 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Hugo Benichi912db992017-04-24 16:41:03 +09002323 int nsdState = isEnabled ? NsdManager.NSD_STATE_ENABLED : NsdManager.NSD_STATE_DISABLED;
2324 intent.putExtra(NsdManager.EXTRA_NSD_STATE, nsdState);
Dianne Hackborn692107e2012-08-29 18:32:08 -07002325 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff75006652012-04-17 23:15:29 -07002326 }
2327
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002328 private int getUniqueId() {
2329 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
2330 return mUniqueId;
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002331 }
2332
Paul Hud44e1b72023-06-16 02:07:42 +00002333 private boolean registerService(int transactionId, NsdServiceInfo service) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002334 if (mMDnsManager == null) {
2335 Log.wtf(TAG, "registerService: mMDnsManager is null");
2336 return false;
2337 }
2338
Hugo Benichi6d706442017-04-24 16:19:58 +09002339 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00002340 Log.d(TAG, "registerService: " + transactionId + " " + service);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002341 }
Hugo Benichi6d706442017-04-24 16:19:58 +09002342 String name = service.getServiceName();
2343 String type = service.getServiceType();
2344 int port = service.getPort();
2345 byte[] textRecord = service.getTxtRecord();
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09002346 final int registerInterface = getNetworkInterfaceIndex(service);
2347 if (service.getNetwork() != null && registerInterface == IFACE_IDX_ANY) {
Paul Hu360a8e92022-04-26 11:14:14 +08002348 Log.e(TAG, "Interface to register service on not found");
2349 return false;
2350 }
Paul Hud44e1b72023-06-16 02:07:42 +00002351 return mMDnsManager.registerService(
2352 transactionId, name, type, port, textRecord, registerInterface);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002353 }
2354
Paul Hud44e1b72023-06-16 02:07:42 +00002355 private boolean unregisterService(int transactionId) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002356 if (mMDnsManager == null) {
2357 Log.wtf(TAG, "unregisterService: mMDnsManager is null");
2358 return false;
2359 }
Paul Hud44e1b72023-06-16 02:07:42 +00002360 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002361 }
2362
Kangping Dong1f1a3792023-12-10 22:05:04 +08002363 private boolean discoverServices(int transactionId, DiscoveryRequest discoveryRequest) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002364 if (mMDnsManager == null) {
2365 Log.wtf(TAG, "discoverServices: mMDnsManager is null");
2366 return false;
2367 }
2368
Kangping Dong1f1a3792023-12-10 22:05:04 +08002369 final String type = discoveryRequest.getServiceType();
2370 final int discoverInterface = getNetworkInterfaceIndex(discoveryRequest);
2371 if (discoveryRequest.getNetwork() != null && discoverInterface == IFACE_IDX_ANY) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002372 Log.e(TAG, "Interface to discover service on not found");
2373 return false;
2374 }
Paul Hud44e1b72023-06-16 02:07:42 +00002375 return mMDnsManager.discover(transactionId, type, discoverInterface);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002376 }
2377
Paul Hud44e1b72023-06-16 02:07:42 +00002378 private boolean stopServiceDiscovery(int transactionId) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002379 if (mMDnsManager == null) {
2380 Log.wtf(TAG, "stopServiceDiscovery: mMDnsManager is null");
2381 return false;
2382 }
Paul Hud44e1b72023-06-16 02:07:42 +00002383 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002384 }
2385
Paul Hud44e1b72023-06-16 02:07:42 +00002386 private boolean resolveService(int transactionId, NsdServiceInfo service) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002387 if (mMDnsManager == null) {
2388 Log.wtf(TAG, "resolveService: mMDnsManager is null");
2389 return false;
2390 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002391 final String name = service.getServiceName();
2392 final String type = service.getServiceType();
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09002393 final int resolveInterface = getNetworkInterfaceIndex(service);
2394 if (service.getNetwork() != null && resolveInterface == IFACE_IDX_ANY) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002395 Log.e(TAG, "Interface to resolve service on not found");
2396 return false;
2397 }
Paul Hud44e1b72023-06-16 02:07:42 +00002398 return mMDnsManager.resolve(transactionId, name, type, "local.", resolveInterface);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002399 }
2400
2401 /**
2402 * Guess the interface to use to resolve or discover a service on a specific network.
2403 *
2404 * This is an imperfect guess, as for example the network may be gone or not yet fully
2405 * registered. This is fine as failing is correct if the network is gone, and a client
2406 * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also
2407 * this is to support the legacy mdnsresponder implementation, which historically resolved
2408 * services on an unspecified network.
2409 */
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09002410 private int getNetworkInterfaceIndex(NsdServiceInfo serviceInfo) {
2411 final Network network = serviceInfo.getNetwork();
2412 if (network == null) {
2413 // Fallback to getInterfaceIndex if present (typically if the NsdServiceInfo was
2414 // provided by NsdService from discovery results, and the service was found on an
2415 // interface that has no app-usable Network).
2416 if (serviceInfo.getInterfaceIndex() != 0) {
2417 return serviceInfo.getInterfaceIndex();
2418 }
2419 return IFACE_IDX_ANY;
2420 }
Kangping Dong1f1a3792023-12-10 22:05:04 +08002421 return getNetworkInterfaceIndex(network);
2422 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002423
Kangping Dong1f1a3792023-12-10 22:05:04 +08002424 /**
2425 * Returns the interface to use to discover a service on a specific network, or {@link
2426 * IFACE_IDX_ANY} if no network is specified.
2427 */
2428 private int getNetworkInterfaceIndex(DiscoveryRequest discoveryRequest) {
2429 final Network network = discoveryRequest.getNetwork();
2430 if (network == null) {
2431 return IFACE_IDX_ANY;
2432 }
2433 return getNetworkInterfaceIndex(network);
2434 }
2435
2436 /**
2437 * Returns the interface of a specific network, or {@link IFACE_IDX_ANY} if no interface is
2438 * associated with {@code network}.
2439 */
2440 private int getNetworkInterfaceIndex(@NonNull Network network) {
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002441 String interfaceName = getNetworkInterfaceName(network);
2442 if (interfaceName == null) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002443 return IFACE_IDX_ANY;
2444 }
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002445 return getNetworkInterfaceIndexByName(interfaceName);
2446 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002447
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002448 private String getNetworkInterfaceName(@Nullable Network network) {
2449 if (network == null) {
2450 return null;
2451 }
2452 final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
2453 if (cm == null) {
2454 Log.wtf(TAG, "No ConnectivityManager");
2455 return null;
2456 }
2457 final LinkProperties lp = cm.getLinkProperties(network);
2458 if (lp == null) {
2459 return null;
2460 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002461 // Only resolve on non-stacked interfaces
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002462 return lp.getInterfaceName();
2463 }
2464
2465 private int getNetworkInterfaceIndexByName(final String ifaceName) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002466 final NetworkInterface iface;
2467 try {
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002468 iface = NetworkInterface.getByName(ifaceName);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002469 } catch (SocketException e) {
2470 Log.e(TAG, "Error querying interface", e);
2471 return IFACE_IDX_ANY;
2472 }
2473
2474 if (iface == null) {
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002475 Log.e(TAG, "Interface not found: " + ifaceName);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002476 return IFACE_IDX_ANY;
2477 }
2478
2479 return iface.getIndex();
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002480 }
2481
Paul Hud44e1b72023-06-16 02:07:42 +00002482 private boolean stopResolveService(int transactionId) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002483 if (mMDnsManager == null) {
2484 Log.wtf(TAG, "stopResolveService: mMDnsManager is null");
2485 return false;
2486 }
Paul Hud44e1b72023-06-16 02:07:42 +00002487 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002488 }
2489
Paul Hud44e1b72023-06-16 02:07:42 +00002490 private boolean getAddrInfo(int transactionId, String hostname, int interfaceIdx) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002491 if (mMDnsManager == null) {
2492 Log.wtf(TAG, "getAddrInfo: mMDnsManager is null");
2493 return false;
2494 }
Paul Hud44e1b72023-06-16 02:07:42 +00002495 return mMDnsManager.getServiceAddress(transactionId, hostname, interfaceIdx);
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002496 }
2497
Paul Hud44e1b72023-06-16 02:07:42 +00002498 private boolean stopGetAddrInfo(int transactionId) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002499 if (mMDnsManager == null) {
2500 Log.wtf(TAG, "stopGetAddrInfo: mMDnsManager is null");
2501 return false;
2502 }
Paul Hud44e1b72023-06-16 02:07:42 +00002503 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002504 }
2505
2506 @Override
Paul Hub2e67d32023-04-18 05:50:14 +00002507 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
Junyu Lai71b51532024-02-01 10:39:01 +08002508 if (!PermissionUtils.hasDumpPermission(mContext, TAG, writer)) return;
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002509
Paul Hub2e67d32023-04-18 05:50:14 +00002510 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
2511 // Dump state machine logs
Irfan Sheriff75006652012-04-17 23:15:29 -07002512 mNsdStateMachine.dump(fd, pw, args);
Paul Hub2e67d32023-04-18 05:50:14 +00002513
2514 // Dump service and clients logs
2515 pw.println();
Paul Hu14667de2023-04-17 22:42:47 +08002516 pw.println("Logs:");
Paul Hub2e67d32023-04-18 05:50:14 +00002517 pw.increaseIndent();
2518 mServiceLogs.reverseDump(pw);
2519 pw.decreaseIndent();
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002520 }
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002521
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002522 private abstract static class ClientRequest {
Paul Hud44e1b72023-06-16 02:07:42 +00002523 private final int mTransactionId;
Paul Hu777ed052023-06-19 13:35:15 +00002524 private final long mStartTimeMs;
Paul Hu812e9212023-06-20 06:24:53 +00002525 private int mFoundServiceCount = 0;
2526 private int mLostServiceCount = 0;
2527 private final Set<String> mServices = new ArraySet<>();
Paul Hua6bc4632023-06-26 01:18:29 +00002528 private boolean mIsServiceFromCache = false;
Paul Hubad6fe92023-07-24 21:25:22 +08002529 private int mSentQueryCount = NO_SENT_QUERY_COUNT;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002530
Paul Hu812e9212023-06-20 06:24:53 +00002531 private ClientRequest(int transactionId, long startTimeMs) {
Paul Hud44e1b72023-06-16 02:07:42 +00002532 mTransactionId = transactionId;
Paul Hu777ed052023-06-19 13:35:15 +00002533 mStartTimeMs = startTimeMs;
2534 }
2535
Paul Hu812e9212023-06-20 06:24:53 +00002536 public long calculateRequestDurationMs(long stopTimeMs) {
Paul Hu777ed052023-06-19 13:35:15 +00002537 return stopTimeMs - mStartTimeMs;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002538 }
Paul Hu812e9212023-06-20 06:24:53 +00002539
2540 public void onServiceFound(String serviceName) {
2541 mFoundServiceCount++;
2542 if (mServices.size() <= MAX_SERVICES_COUNT_METRIC_PER_CLIENT) {
2543 mServices.add(serviceName);
2544 }
2545 }
2546
2547 public void onServiceLost() {
2548 mLostServiceCount++;
2549 }
2550
2551 public int getFoundServiceCount() {
2552 return mFoundServiceCount;
2553 }
2554
2555 public int getLostServiceCount() {
2556 return mLostServiceCount;
2557 }
2558
2559 public int getServicesCount() {
2560 return mServices.size();
2561 }
Paul Hua6bc4632023-06-26 01:18:29 +00002562
2563 public void setServiceFromCache(boolean isServiceFromCache) {
2564 mIsServiceFromCache = isServiceFromCache;
2565 }
2566
2567 public boolean isServiceFromCache() {
2568 return mIsServiceFromCache;
2569 }
Paul Hubad6fe92023-07-24 21:25:22 +08002570
2571 public void onQuerySent() {
2572 mSentQueryCount++;
2573 }
2574
2575 public int getSentQueryCount() {
2576 return mSentQueryCount;
2577 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002578 }
2579
2580 private static class LegacyClientRequest extends ClientRequest {
2581 private final int mRequestCode;
2582
Paul Hu812e9212023-06-20 06:24:53 +00002583 private LegacyClientRequest(int transactionId, int requestCode, long startTimeMs) {
2584 super(transactionId, startTimeMs);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002585 mRequestCode = requestCode;
2586 }
2587 }
2588
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002589 private abstract static class JavaBackendClientRequest extends ClientRequest {
2590 @Nullable
2591 private final Network mRequestedNetwork;
2592
Paul Hu777ed052023-06-19 13:35:15 +00002593 private JavaBackendClientRequest(int transactionId, @Nullable Network requestedNetwork,
Paul Hu812e9212023-06-20 06:24:53 +00002594 long startTimeMs) {
2595 super(transactionId, startTimeMs);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002596 mRequestedNetwork = requestedNetwork;
2597 }
2598
2599 @Nullable
2600 public Network getRequestedNetwork() {
2601 return mRequestedNetwork;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002602 }
2603 }
2604
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002605 private static class AdvertiserClientRequest extends JavaBackendClientRequest {
Paul Hu777ed052023-06-19 13:35:15 +00002606 private AdvertiserClientRequest(int transactionId, @Nullable Network requestedNetwork,
Paul Hu812e9212023-06-20 06:24:53 +00002607 long startTimeMs) {
2608 super(transactionId, requestedNetwork, startTimeMs);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002609 }
2610 }
2611
2612 private static class DiscoveryManagerRequest extends JavaBackendClientRequest {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002613 @NonNull
2614 private final MdnsListener mListener;
2615
Paul Hud44e1b72023-06-16 02:07:42 +00002616 private DiscoveryManagerRequest(int transactionId, @NonNull MdnsListener listener,
Paul Hu812e9212023-06-20 06:24:53 +00002617 @Nullable Network requestedNetwork, long startTimeMs) {
2618 super(transactionId, requestedNetwork, startTimeMs);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002619 mListener = listener;
2620 }
2621 }
2622
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002623 /* Information tracked per client */
2624 private class ClientInfo {
2625
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07002626 private static final int MAX_LIMIT = 10;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002627 private final INsdManagerCallback mCb;
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002628 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07002629 private NsdServiceInfo mResolvedService;
2630
Paul Hud44e1b72023-06-16 02:07:42 +00002631 /* A map from client request ID (listenerKey) to the request */
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002632 private final SparseArray<ClientRequest> mClientRequests = new SparseArray<>();
Paul Hu23fa2022023-01-13 22:57:24 +08002633
Luke Huangf7277ed2021-07-12 21:15:10 +08002634 // The target SDK of this client < Build.VERSION_CODES.S
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002635 private boolean mIsPreSClient = false;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002636 private final int mUid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002637 // The flag of using java backend if the client's target SDK >= U
2638 private final boolean mUseJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002639 // Store client logs
2640 private final SharedLog mClientLogs;
Paul Hucdef3532023-06-18 14:47:35 +00002641 // Report the nsd metrics data
2642 private final NetworkNsdReportedMetrics mMetrics;
Luke Huangf7277ed2021-07-12 21:15:10 +08002643
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002644 private ClientInfo(INsdManagerCallback cb, int uid, boolean useJavaBackend,
Paul Hucdef3532023-06-18 14:47:35 +00002645 SharedLog sharedLog, NetworkNsdReportedMetrics metrics) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002646 mCb = cb;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002647 mUid = uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002648 mUseJavaBackend = useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002649 mClientLogs = sharedLog;
2650 mClientLogs.log("New client. useJavaBackend=" + useJavaBackend);
Paul Hucdef3532023-06-18 14:47:35 +00002651 mMetrics = metrics;
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002652 }
Irfan Sheriff75006652012-04-17 23:15:29 -07002653
2654 @Override
2655 public String toString() {
Jeff Sharkey63465382020-10-17 21:20:13 -06002656 StringBuilder sb = new StringBuilder();
Irfan Sheriff75006652012-04-17 23:15:29 -07002657 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002658 sb.append("mIsLegacy ").append(mIsPreSClient).append("\n");
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002659 sb.append("mUseJavaBackend ").append(mUseJavaBackend).append("\n");
2660 sb.append("mUid ").append(mUid).append("\n");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002661 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002662 int clientRequestId = mClientRequests.keyAt(i);
2663 sb.append("clientRequestId ")
2664 .append(clientRequestId)
2665 .append(" transactionId ").append(mClientRequests.valueAt(i).mTransactionId)
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002666 .append(" type ").append(
2667 mClientRequests.valueAt(i).getClass().getSimpleName())
2668 .append("\n");
Irfan Sheriff75006652012-04-17 23:15:29 -07002669 }
2670 return sb.toString();
2671 }
Dave Plattfeff2af2014-03-07 14:48:22 -08002672
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002673 private boolean isPreSClient() {
2674 return mIsPreSClient;
Luke Huangf7277ed2021-07-12 21:15:10 +08002675 }
2676
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002677 private void setPreSClient() {
2678 mIsPreSClient = true;
Luke Huangf7277ed2021-07-12 21:15:10 +08002679 }
2680
Paul Hu812e9212023-06-20 06:24:53 +00002681 private MdnsListener unregisterMdnsListenerFromRequest(ClientRequest request) {
Paul Hue4f5f252023-02-16 21:13:47 +08002682 final MdnsListener listener =
2683 ((DiscoveryManagerRequest) request).mListener;
2684 mMdnsDiscoveryManager.unregisterListener(
2685 listener.getListenedServiceType(), listener);
Paul Hu812e9212023-06-20 06:24:53 +00002686 return listener;
Paul Hue4f5f252023-02-16 21:13:47 +08002687 }
2688
Dave Plattfeff2af2014-03-07 14:48:22 -08002689 // Remove any pending requests from the global map when we get rid of a client,
2690 // and send cancellations to the daemon.
2691 private void expungeAllRequests() {
Paul Hub2e67d32023-04-18 05:50:14 +00002692 mClientLogs.log("Client unregistered. expungeAllRequests!");
Hugo Benichid2552ae2017-04-11 14:42:47 +09002693 // TODO: to keep handler responsive, do not clean all requests for that client at once.
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002694 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002695 final int clientRequestId = mClientRequests.keyAt(i);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002696 final ClientRequest request = mClientRequests.valueAt(i);
Paul Hud44e1b72023-06-16 02:07:42 +00002697 final int transactionId = request.mTransactionId;
2698 mTransactionIdToClientInfoMap.remove(transactionId);
paulhub2225702021-11-17 09:35:33 +08002699 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00002700 Log.d(TAG, "Terminating clientRequestId " + clientRequestId
2701 + " transactionId " + transactionId
2702 + " type " + mClientRequests.get(clientRequestId));
paulhub2225702021-11-17 09:35:33 +08002703 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002704
2705 if (request instanceof DiscoveryManagerRequest) {
Paul Hu812e9212023-06-20 06:24:53 +00002706 final MdnsListener listener = unregisterMdnsListenerFromRequest(request);
2707 if (listener instanceof DiscoveryListener) {
Paul Hu508a0122023-09-11 15:31:33 +08002708 mMetrics.reportServiceDiscoveryStop(false /* isLegacy */, transactionId,
Paul Hu812e9212023-06-20 06:24:53 +00002709 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2710 request.getFoundServiceCount(),
2711 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002712 request.getServicesCount(),
2713 request.getSentQueryCount());
Paul Hu60149052023-07-31 14:26:08 +08002714 } else if (listener instanceof ResolutionListener) {
Paul Hu508a0122023-09-11 15:31:33 +08002715 mMetrics.reportServiceResolutionStop(false /* isLegacy */, transactionId,
Paul Hu60149052023-07-31 14:26:08 +08002716 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Huddce5912023-08-01 10:26:49 +08002717 } else if (listener instanceof ServiceInfoListener) {
2718 mMetrics.reportServiceInfoCallbackUnregistered(transactionId,
2719 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2720 request.getFoundServiceCount(),
2721 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002722 request.isServiceFromCache(),
2723 request.getSentQueryCount());
Paul Hu812e9212023-06-20 06:24:53 +00002724 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002725 continue;
2726 }
2727
2728 if (request instanceof AdvertiserClientRequest) {
Paul Hu043bcd42023-07-14 16:38:25 +08002729 final AdvertiserMetrics metrics =
2730 mAdvertiser.getAdvertiserMetrics(transactionId);
Paul Hud44e1b72023-06-16 02:07:42 +00002731 mAdvertiser.removeService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08002732 mMetrics.reportServiceUnregistration(false /* isLegacy */, transactionId,
Paul Hu043bcd42023-07-14 16:38:25 +08002733 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2734 metrics.mRepliedRequestsCount, metrics.mSentPacketCount,
2735 metrics.mConflictDuringProbingCount,
2736 metrics.mConflictAfterProbingCount);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002737 continue;
2738 }
2739
2740 if (!(request instanceof LegacyClientRequest)) {
2741 throw new IllegalStateException("Unknown request type: " + request.getClass());
2742 }
2743
2744 switch (((LegacyClientRequest) request).mRequestCode) {
Dave Plattfeff2af2014-03-07 14:48:22 -08002745 case NsdManager.DISCOVER_SERVICES:
Paul Hud44e1b72023-06-16 02:07:42 +00002746 stopServiceDiscovery(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08002747 mMetrics.reportServiceDiscoveryStop(true /* isLegacy */, transactionId,
Paul Hu812e9212023-06-20 06:24:53 +00002748 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2749 request.getFoundServiceCount(),
2750 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002751 request.getServicesCount(),
2752 NO_SENT_QUERY_COUNT);
Dave Plattfeff2af2014-03-07 14:48:22 -08002753 break;
2754 case NsdManager.RESOLVE_SERVICE:
Paul Hud44e1b72023-06-16 02:07:42 +00002755 stopResolveService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08002756 mMetrics.reportServiceResolutionStop(true /* isLegacy */, transactionId,
Paul Hu60149052023-07-31 14:26:08 +08002757 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Dave Plattfeff2af2014-03-07 14:48:22 -08002758 break;
2759 case NsdManager.REGISTER_SERVICE:
Paul Hud44e1b72023-06-16 02:07:42 +00002760 unregisterService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08002761 mMetrics.reportServiceUnregistration(true /* isLegacy */, transactionId,
Paul Hu043bcd42023-07-14 16:38:25 +08002762 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2763 NO_PACKET /* repliedRequestsCount */,
2764 NO_PACKET /* sentPacketCount */,
2765 0 /* conflictDuringProbingCount */,
2766 0 /* conflictAfterProbingCount */);
Dave Plattfeff2af2014-03-07 14:48:22 -08002767 break;
2768 default:
2769 break;
2770 }
2771 }
Dave Plattfeff2af2014-03-07 14:48:22 -08002772 mClientRequests.clear();
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002773 updateMulticastLock();
2774 }
2775
2776 /**
2777 * Returns true if this client has any Java backend request that requests one of the given
2778 * networks.
2779 */
2780 boolean hasAnyJavaBackendRequestForNetworks(@NonNull ArraySet<Network> networks) {
2781 for (int i = 0; i < mClientRequests.size(); i++) {
2782 final ClientRequest req = mClientRequests.valueAt(i);
2783 if (!(req instanceof JavaBackendClientRequest)) {
2784 continue;
2785 }
2786 final Network reqNetwork = ((JavaBackendClientRequest) mClientRequests.valueAt(i))
2787 .getRequestedNetwork();
2788 if (MdnsUtils.isAnyNetworkMatched(reqNetwork, networks)) {
2789 return true;
2790 }
2791 }
2792 return false;
Dave Plattfeff2af2014-03-07 14:48:22 -08002793 }
2794
Paul Hud44e1b72023-06-16 02:07:42 +00002795 // mClientRequests is a sparse array of client request id -> ClientRequest. For a given
2796 // transaction id, return the corresponding client request id.
2797 private int getClientRequestId(final int transactionId) {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002798 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002799 if (mClientRequests.valueAt(i).mTransactionId == transactionId) {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002800 return mClientRequests.keyAt(i);
2801 }
Christopher Lane74411222014-04-25 18:39:07 -07002802 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002803 return -1;
Christopher Lane74411222014-04-25 18:39:07 -07002804 }
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002805
Paul Hub2e67d32023-04-18 05:50:14 +00002806 private void log(String message) {
2807 mClientLogs.log(message);
2808 }
2809
Paul Hu508a0122023-09-11 15:31:33 +08002810 private static boolean isLegacyClientRequest(@NonNull ClientRequest request) {
2811 return !(request instanceof DiscoveryManagerRequest)
2812 && !(request instanceof AdvertiserClientRequest);
2813 }
2814
Kangping Dong1f1a3792023-12-10 22:05:04 +08002815 void onDiscoverServicesStarted(int listenerKey, DiscoveryRequest discoveryRequest,
Paul Hu508a0122023-09-11 15:31:33 +08002816 ClientRequest request) {
2817 mMetrics.reportServiceDiscoveryStarted(
2818 isLegacyClientRequest(request), request.mTransactionId);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002819 try {
Kangping Dong1f1a3792023-12-10 22:05:04 +08002820 mCb.onDiscoverServicesStarted(listenerKey, discoveryRequest);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002821 } catch (RemoteException e) {
2822 Log.e(TAG, "Error calling onDiscoverServicesStarted", e);
2823 }
2824 }
Paul Hu508a0122023-09-11 15:31:33 +08002825 void onDiscoverServicesFailedImmediately(int listenerKey, int error, boolean isLegacy) {
2826 onDiscoverServicesFailed(listenerKey, error, isLegacy, NO_TRANSACTION,
2827 0L /* durationMs */);
Paul Hu812e9212023-06-20 06:24:53 +00002828 }
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002829
Paul Hu508a0122023-09-11 15:31:33 +08002830 void onDiscoverServicesFailed(int listenerKey, int error, boolean isLegacy,
2831 int transactionId, long durationMs) {
2832 mMetrics.reportServiceDiscoveryFailed(isLegacy, transactionId, durationMs);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002833 try {
2834 mCb.onDiscoverServicesFailed(listenerKey, error);
2835 } catch (RemoteException e) {
2836 Log.e(TAG, "Error calling onDiscoverServicesFailed", e);
2837 }
2838 }
2839
Paul Hu812e9212023-06-20 06:24:53 +00002840 void onServiceFound(int listenerKey, NsdServiceInfo info, ClientRequest request) {
2841 request.onServiceFound(info.getServiceName());
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002842 try {
2843 mCb.onServiceFound(listenerKey, info);
2844 } catch (RemoteException e) {
2845 Log.e(TAG, "Error calling onServiceFound(", e);
2846 }
2847 }
2848
Paul Hu812e9212023-06-20 06:24:53 +00002849 void onServiceLost(int listenerKey, NsdServiceInfo info, ClientRequest request) {
2850 request.onServiceLost();
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002851 try {
2852 mCb.onServiceLost(listenerKey, info);
2853 } catch (RemoteException e) {
2854 Log.e(TAG, "Error calling onServiceLost(", e);
2855 }
2856 }
2857
2858 void onStopDiscoveryFailed(int listenerKey, int error) {
2859 try {
2860 mCb.onStopDiscoveryFailed(listenerKey, error);
2861 } catch (RemoteException e) {
2862 Log.e(TAG, "Error calling onStopDiscoveryFailed", e);
2863 }
2864 }
2865
Paul Hu812e9212023-06-20 06:24:53 +00002866 void onStopDiscoverySucceeded(int listenerKey, ClientRequest request) {
2867 mMetrics.reportServiceDiscoveryStop(
Paul Hu508a0122023-09-11 15:31:33 +08002868 isLegacyClientRequest(request),
Paul Hu812e9212023-06-20 06:24:53 +00002869 request.mTransactionId,
2870 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2871 request.getFoundServiceCount(),
2872 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002873 request.getServicesCount(),
2874 request.getSentQueryCount());
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002875 try {
2876 mCb.onStopDiscoverySucceeded(listenerKey);
2877 } catch (RemoteException e) {
2878 Log.e(TAG, "Error calling onStopDiscoverySucceeded", e);
2879 }
2880 }
2881
Paul Hu508a0122023-09-11 15:31:33 +08002882 void onRegisterServiceFailedImmediately(int listenerKey, int error, boolean isLegacy) {
2883 onRegisterServiceFailed(listenerKey, error, isLegacy, NO_TRANSACTION,
2884 0L /* durationMs */);
Paul Hu777ed052023-06-19 13:35:15 +00002885 }
2886
Paul Hu508a0122023-09-11 15:31:33 +08002887 void onRegisterServiceFailed(int listenerKey, int error, boolean isLegacy,
2888 int transactionId, long durationMs) {
2889 mMetrics.reportServiceRegistrationFailed(isLegacy, transactionId, durationMs);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002890 try {
2891 mCb.onRegisterServiceFailed(listenerKey, error);
2892 } catch (RemoteException e) {
2893 Log.e(TAG, "Error calling onRegisterServiceFailed", e);
2894 }
2895 }
2896
Paul Hu508a0122023-09-11 15:31:33 +08002897 void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info,
2898 ClientRequest request) {
2899 mMetrics.reportServiceRegistrationSucceeded(isLegacyClientRequest(request),
2900 request.mTransactionId,
2901 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002902 try {
2903 mCb.onRegisterServiceSucceeded(listenerKey, info);
2904 } catch (RemoteException e) {
2905 Log.e(TAG, "Error calling onRegisterServiceSucceeded", e);
2906 }
2907 }
2908
2909 void onUnregisterServiceFailed(int listenerKey, int error) {
2910 try {
2911 mCb.onUnregisterServiceFailed(listenerKey, error);
2912 } catch (RemoteException e) {
2913 Log.e(TAG, "Error calling onUnregisterServiceFailed", e);
2914 }
2915 }
2916
Paul Hu508a0122023-09-11 15:31:33 +08002917 void onUnregisterServiceSucceeded(int listenerKey, ClientRequest request,
Paul Hu043bcd42023-07-14 16:38:25 +08002918 AdvertiserMetrics metrics) {
Paul Hu508a0122023-09-11 15:31:33 +08002919 mMetrics.reportServiceUnregistration(isLegacyClientRequest(request),
2920 request.mTransactionId,
2921 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
Paul Hu043bcd42023-07-14 16:38:25 +08002922 metrics.mRepliedRequestsCount, metrics.mSentPacketCount,
2923 metrics.mConflictDuringProbingCount, metrics.mConflictAfterProbingCount);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002924 try {
2925 mCb.onUnregisterServiceSucceeded(listenerKey);
2926 } catch (RemoteException e) {
2927 Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e);
2928 }
2929 }
2930
Paul Hu508a0122023-09-11 15:31:33 +08002931 void onResolveServiceFailedImmediately(int listenerKey, int error, boolean isLegacy) {
2932 onResolveServiceFailed(listenerKey, error, isLegacy, NO_TRANSACTION,
2933 0L /* durationMs */);
Paul Hua6bc4632023-06-26 01:18:29 +00002934 }
2935
Paul Hu508a0122023-09-11 15:31:33 +08002936 void onResolveServiceFailed(int listenerKey, int error, boolean isLegacy,
2937 int transactionId, long durationMs) {
2938 mMetrics.reportServiceResolutionFailed(isLegacy, transactionId, durationMs);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002939 try {
2940 mCb.onResolveServiceFailed(listenerKey, error);
2941 } catch (RemoteException e) {
2942 Log.e(TAG, "Error calling onResolveServiceFailed", e);
2943 }
2944 }
2945
Paul Hua6bc4632023-06-26 01:18:29 +00002946 void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info,
2947 ClientRequest request) {
2948 mMetrics.reportServiceResolved(
Paul Hu508a0122023-09-11 15:31:33 +08002949 isLegacyClientRequest(request),
Paul Hua6bc4632023-06-26 01:18:29 +00002950 request.mTransactionId,
2951 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
Paul Hubad6fe92023-07-24 21:25:22 +08002952 request.isServiceFromCache(),
2953 request.getSentQueryCount());
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002954 try {
2955 mCb.onResolveServiceSucceeded(listenerKey, info);
2956 } catch (RemoteException e) {
2957 Log.e(TAG, "Error calling onResolveServiceSucceeded", e);
2958 }
2959 }
Paul Hub58deb72022-12-26 09:24:42 +00002960
2961 void onStopResolutionFailed(int listenerKey, int error) {
2962 try {
2963 mCb.onStopResolutionFailed(listenerKey, error);
2964 } catch (RemoteException e) {
2965 Log.e(TAG, "Error calling onStopResolutionFailed", e);
2966 }
2967 }
2968
Paul Hu60149052023-07-31 14:26:08 +08002969 void onStopResolutionSucceeded(int listenerKey, ClientRequest request) {
2970 mMetrics.reportServiceResolutionStop(
Paul Hu508a0122023-09-11 15:31:33 +08002971 isLegacyClientRequest(request),
Paul Hu60149052023-07-31 14:26:08 +08002972 request.mTransactionId,
2973 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hub58deb72022-12-26 09:24:42 +00002974 try {
2975 mCb.onStopResolutionSucceeded(listenerKey);
2976 } catch (RemoteException e) {
2977 Log.e(TAG, "Error calling onStopResolutionSucceeded", e);
2978 }
2979 }
Paul Hu18aeccc2022-12-27 08:48:48 +00002980
2981 void onServiceInfoCallbackRegistrationFailed(int listenerKey, int error) {
Paul Huddce5912023-08-01 10:26:49 +08002982 mMetrics.reportServiceInfoCallbackRegistrationFailed(NO_TRANSACTION);
Paul Hu18aeccc2022-12-27 08:48:48 +00002983 try {
2984 mCb.onServiceInfoCallbackRegistrationFailed(listenerKey, error);
2985 } catch (RemoteException e) {
2986 Log.e(TAG, "Error calling onServiceInfoCallbackRegistrationFailed", e);
2987 }
2988 }
2989
Paul Huddce5912023-08-01 10:26:49 +08002990 void onServiceInfoCallbackRegistered(int transactionId) {
2991 mMetrics.reportServiceInfoCallbackRegistered(transactionId);
2992 }
2993
2994 void onServiceUpdated(int listenerKey, NsdServiceInfo info, ClientRequest request) {
2995 request.onServiceFound(info.getServiceName());
Paul Hu18aeccc2022-12-27 08:48:48 +00002996 try {
2997 mCb.onServiceUpdated(listenerKey, info);
2998 } catch (RemoteException e) {
2999 Log.e(TAG, "Error calling onServiceUpdated", e);
3000 }
3001 }
3002
Paul Huddce5912023-08-01 10:26:49 +08003003 void onServiceUpdatedLost(int listenerKey, ClientRequest request) {
3004 request.onServiceLost();
Paul Hu18aeccc2022-12-27 08:48:48 +00003005 try {
3006 mCb.onServiceUpdatedLost(listenerKey);
3007 } catch (RemoteException e) {
3008 Log.e(TAG, "Error calling onServiceUpdatedLost", e);
3009 }
3010 }
3011
Paul Huddce5912023-08-01 10:26:49 +08003012 void onServiceInfoCallbackUnregistered(int listenerKey, ClientRequest request) {
3013 mMetrics.reportServiceInfoCallbackUnregistered(
3014 request.mTransactionId,
3015 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
3016 request.getFoundServiceCount(),
3017 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08003018 request.isServiceFromCache(),
3019 request.getSentQueryCount());
Paul Hu18aeccc2022-12-27 08:48:48 +00003020 try {
3021 mCb.onServiceInfoCallbackUnregistered(listenerKey);
3022 } catch (RemoteException e) {
3023 Log.e(TAG, "Error calling onServiceInfoCallbackUnregistered", e);
3024 }
3025 }
Irfan Sheriffe8de2462012-04-11 14:52:19 -07003026 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07003027}