blob: 77c1ddb1cf19f33d8294e9d9bc36acf980ea5087 [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;
Yuyang Huang86d083f2023-12-12 19:56:41 +090029import static android.net.nsd.NsdManager.TYPE_REGEX;
30import static android.net.nsd.NsdManager.TYPE_SUBTYPE_LABEL_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;
Paul Hu2e0a88c2023-03-09 16:05:01 +0800904 if (clientInfo.mUseJavaBackend
905 || mDeps.isMdnsAdvertiserEnabled(mContext)
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +0900906 || useAdvertiserForType(registerServiceType)) {
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900907 if (registerServiceType == null) {
908 Log.e(TAG, "Invalid service type: " + serviceType);
Paul Hu508a0122023-09-11 15:31:33 +0800909 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
910 NsdManager.FAILURE_INTERNAL_ERROR, false /* isLegacy */);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900911 break;
912 }
Yuyang Huang86d083f2023-12-12 19:56:41 +0900913 boolean isUpdateOnly = (advertisingRequest.getAdvertisingConfig()
914 & AdvertisingRequest.NSD_ADVERTISING_UPDATE_ONLY) > 0;
915 // If it is an update request, then reuse the old transactionId
916 if (isUpdateOnly) {
917 final ClientRequest existingClientRequest =
918 clientInfo.mClientRequests.get(clientRequestId);
919 if (existingClientRequest == null) {
920 Log.e(TAG, "Invalid update on requestId: " + clientRequestId);
921 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
922 NsdManager.FAILURE_INTERNAL_ERROR,
923 false /* isLegacy */);
924 break;
925 }
926 transactionId = existingClientRequest.mTransactionId;
927 } else {
928 transactionId = getUniqueId();
929 }
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900930 serviceInfo.setServiceType(registerServiceType);
931 serviceInfo.setServiceName(truncateServiceName(
932 serviceInfo.getServiceName()));
933
Kangping Dong5af24b62023-12-10 21:41:16 +0800934 Set<String> subtypes = new ArraySet<>(serviceInfo.getSubtypes());
Yuyang Huang170d42f2023-12-09 15:26:16 +0900935 for (String subType: typeSubtype.second) {
936 if (!TextUtils.isEmpty(subType)) {
937 subtypes.add(subType);
938 }
Kangping Dong5af24b62023-12-10 21:41:16 +0800939 }
Kangping Dong5af24b62023-12-10 21:41:16 +0800940 subtypes = dedupSubtypeLabels(subtypes);
941
942 if (!checkSubtypeLabels(subtypes)) {
943 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
944 NsdManager.FAILURE_BAD_PARAMETERS, false /* isLegacy */);
945 break;
946 }
947
948 serviceInfo.setSubtypes(subtypes);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900949 maybeStartMonitoringSockets();
Yuyang Huang86d083f2023-12-12 19:56:41 +0900950 final MdnsAdvertisingOptions mdnsAdvertisingOptions =
951 MdnsAdvertisingOptions.newBuilder().setIsOnlyUpdate(
952 isUpdateOnly).build();
Yuyang Huange5cba9c2023-11-02 18:05:47 +0900953 mAdvertiser.addOrUpdateService(transactionId, serviceInfo,
Yuyang Huang86d083f2023-12-12 19:56:41 +0900954 mdnsAdvertisingOptions);
Paul Hud44e1b72023-06-16 02:07:42 +0000955 storeAdvertiserRequestMap(clientRequestId, transactionId, clientInfo,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +0900956 serviceInfo.getNetwork());
Irfan Sheriff75006652012-04-17 23:15:29 -0700957 } else {
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900958 maybeStartDaemon();
Yuyang Huang86d083f2023-12-12 19:56:41 +0900959 transactionId = getUniqueId();
Paul Hud44e1b72023-06-16 02:07:42 +0000960 if (registerService(transactionId, serviceInfo)) {
961 if (DBG) {
962 Log.d(TAG, "Register " + clientRequestId
963 + " " + transactionId);
964 }
Paul Hua6bc4632023-06-26 01:18:29 +0000965 storeLegacyRequestMap(clientRequestId, transactionId, clientInfo,
966 msg.what, mClock.elapsedRealtime());
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900967 // Return success after mDns reports success
968 } else {
Paul Hud44e1b72023-06-16 02:07:42 +0000969 unregisterService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +0800970 clientInfo.onRegisterServiceFailedImmediately(clientRequestId,
971 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900972 }
973
Irfan Sheriff75006652012-04-17 23:15:29 -0700974 }
975 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900976 }
977 case NsdManager.UNREGISTER_SERVICE: {
paulhub2225702021-11-17 09:35:33 +0800978 if (DBG) Log.d(TAG, "unregister service");
Yuyang Huang86d083f2023-12-12 19:56:41 +0900979 final ListenerArgs args = (ListenerArgs) msg.obj;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900980 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +0000981 // If the binder death notification for a INsdManagerCallback was received
982 // before any calls are received by NsdService, the clientInfo would be
983 // cleared and cause NPE. Add a null check here to prevent this corner case.
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +0900984 if (clientInfo == null) {
paulhub2225702021-11-17 09:35:33 +0800985 Log.e(TAG, "Unknown connector in unregistration");
Irfan Sheriffe4c42f42012-05-03 16:44:27 -0700986 break;
Irfan Sheriff75006652012-04-17 23:15:29 -0700987 }
Paul Hud44e1b72023-06-16 02:07:42 +0000988 final ClientRequest request =
989 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +0900990 if (request == null) {
991 Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE");
992 break;
993 }
Paul Hud44e1b72023-06-16 02:07:42 +0000994 transactionId = request.mTransactionId;
995 removeRequestMap(clientRequestId, transactionId, clientInfo);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +0900996
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +0900997 // Note isMdnsAdvertiserEnabled may have changed to false at this point,
998 // so this needs to check the type of the original request to unregister
999 // instead of looking at the flag value.
1000 if (request instanceof AdvertiserClientRequest) {
Paul Hu043bcd42023-07-14 16:38:25 +08001001 final AdvertiserMetrics metrics =
1002 mAdvertiser.getAdvertiserMetrics(transactionId);
Paul Hud44e1b72023-06-16 02:07:42 +00001003 mAdvertiser.removeService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08001004 clientInfo.onUnregisterServiceSucceeded(
1005 clientRequestId, request, metrics);
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001006 } else {
Paul Hud44e1b72023-06-16 02:07:42 +00001007 if (unregisterService(transactionId)) {
Paul Hu508a0122023-09-11 15:31:33 +08001008 clientInfo.onUnregisterServiceSucceeded(clientRequestId, request,
Paul Hu043bcd42023-07-14 16:38:25 +08001009 new AdvertiserMetrics(NO_PACKET /* repliedRequestsCount */,
1010 NO_PACKET /* sentPacketCount */,
1011 0 /* conflictDuringProbingCount */,
1012 0 /* conflictAfterProbingCount */));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001013 } else {
1014 clientInfo.onUnregisterServiceFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001015 clientRequestId, NsdManager.FAILURE_INTERNAL_ERROR);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001016 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001017 }
Irfan Sheriff75006652012-04-17 23:15:29 -07001018 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001019 }
Paul Hu75069ed2023-01-14 00:31:09 +08001020 case NsdManager.RESOLVE_SERVICE: {
paulhub2225702021-11-17 09:35:33 +08001021 if (DBG) Log.d(TAG, "Resolve service");
Yuyang Huang86d083f2023-12-12 19:56:41 +09001022 final ListenerArgs args = (ListenerArgs) msg.obj;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09001023 clientInfo = mClients.get(args.connector);
Paul Hu116b4c02022-08-16 07:21:55 +00001024 // If the binder death notification for a INsdManagerCallback was received
1025 // before any calls are received by NsdService, the clientInfo would be
1026 // cleared and cause NPE. Add a null check here to prevent this corner case.
1027 if (clientInfo == null) {
1028 Log.e(TAG, "Unknown connector in resolution");
1029 break;
1030 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001031
Paul Hu75069ed2023-01-14 00:31:09 +08001032 final NsdServiceInfo info = args.serviceInfo;
Paul Hud44e1b72023-06-16 02:07:42 +00001033 transactionId = getUniqueId();
Yuyang Huang170d42f2023-12-09 15:26:16 +09001034 final Pair<String, List<String>> typeSubtype =
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001035 parseTypeAndSubtype(info.getServiceType());
1036 final String serviceType = typeSubtype == null
1037 ? null : typeSubtype.first;
Paul Hu2e0a88c2023-03-09 16:05:01 +08001038 if (clientInfo.mUseJavaBackend
1039 || mDeps.isMdnsDiscoveryManagerEnabled(mContext)
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001040 || useDiscoveryManagerForType(serviceType)) {
Paul Hu75069ed2023-01-14 00:31:09 +08001041 if (serviceType == null) {
Paul Hu508a0122023-09-11 15:31:33 +08001042 clientInfo.onResolveServiceFailedImmediately(clientRequestId,
1043 NsdManager.FAILURE_INTERNAL_ERROR, false /* isLegacy */);
Paul Hu75069ed2023-01-14 00:31:09 +08001044 break;
1045 }
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001046 final String resolveServiceType = serviceType + ".local";
Paul Hu75069ed2023-01-14 00:31:09 +08001047
1048 maybeStartMonitoringSockets();
Paul Hud44e1b72023-06-16 02:07:42 +00001049 final MdnsListener listener = new ResolutionListener(clientRequestId,
Kangping Dong97b2adc2024-01-11 16:00:37 +08001050 transactionId, resolveServiceType);
Paul Hu75069ed2023-01-14 00:31:09 +08001051 final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
1052 .setNetwork(info.getNetwork())
Paul Hu11a883d2023-12-14 07:36:44 +00001053 .setQueryMode(mMdnsFeatureFlags.isAggressiveQueryModeEnabled()
1054 ? AGGRESSIVE_QUERY_MODE
1055 : PASSIVE_QUERY_MODE)
Remi NGUYEN VANbb62b1d2023-02-27 12:18:27 +09001056 .setResolveInstanceName(info.getServiceName())
Yuyang Huangff963222023-06-01 18:42:42 +09001057 .setRemoveExpiredService(true)
Paul Hu75069ed2023-01-14 00:31:09 +08001058 .build();
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001059 mMdnsDiscoveryManager.registerListener(
1060 resolveServiceType, listener, options);
Paul Hud44e1b72023-06-16 02:07:42 +00001061 storeDiscoveryManagerRequestMap(clientRequestId, transactionId,
1062 listener, clientInfo, info.getNetwork());
1063 clientInfo.log("Register a ResolutionListener " + transactionId
Paul Hub2e67d32023-04-18 05:50:14 +00001064 + " for service type:" + resolveServiceType);
Irfan Sheriff75006652012-04-17 23:15:29 -07001065 } else {
Paul Hu75069ed2023-01-14 00:31:09 +08001066 if (clientInfo.mResolvedService != null) {
Paul Hu508a0122023-09-11 15:31:33 +08001067 clientInfo.onResolveServiceFailedImmediately(clientRequestId,
1068 NsdManager.FAILURE_ALREADY_ACTIVE, true /* isLegacy */);
Paul Hu75069ed2023-01-14 00:31:09 +08001069 break;
1070 }
1071
1072 maybeStartDaemon();
Paul Hud44e1b72023-06-16 02:07:42 +00001073 if (resolveService(transactionId, info)) {
Paul Hu75069ed2023-01-14 00:31:09 +08001074 clientInfo.mResolvedService = new NsdServiceInfo();
Paul Hua6bc4632023-06-26 01:18:29 +00001075 storeLegacyRequestMap(clientRequestId, transactionId, clientInfo,
1076 msg.what, mClock.elapsedRealtime());
Paul Hu75069ed2023-01-14 00:31:09 +08001077 } else {
Paul Hu508a0122023-09-11 15:31:33 +08001078 clientInfo.onResolveServiceFailedImmediately(clientRequestId,
1079 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */);
Paul Hu75069ed2023-01-14 00:31:09 +08001080 }
Irfan Sheriff75006652012-04-17 23:15:29 -07001081 }
1082 break;
Paul Hu75069ed2023-01-14 00:31:09 +08001083 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001084 case NsdManager.STOP_RESOLUTION: {
Paul Hub58deb72022-12-26 09:24:42 +00001085 if (DBG) Log.d(TAG, "Stop service resolution");
Yuyang Huang86d083f2023-12-12 19:56:41 +09001086 final ListenerArgs args = (ListenerArgs) msg.obj;
Paul Hub58deb72022-12-26 09:24:42 +00001087 clientInfo = mClients.get(args.connector);
1088 // If the binder death notification for a INsdManagerCallback was received
1089 // before any calls are received by NsdService, the clientInfo would be
1090 // cleared and cause NPE. Add a null check here to prevent this corner case.
1091 if (clientInfo == null) {
1092 Log.e(TAG, "Unknown connector in stop resolution");
1093 break;
1094 }
1095
Paul Hud44e1b72023-06-16 02:07:42 +00001096 final ClientRequest request =
1097 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001098 if (request == null) {
1099 Log.e(TAG, "Unknown client request in STOP_RESOLUTION");
1100 break;
1101 }
Paul Hud44e1b72023-06-16 02:07:42 +00001102 transactionId = request.mTransactionId;
Paul Hue4f5f252023-02-16 21:13:47 +08001103 // Note isMdnsDiscoveryManagerEnabled may have changed to false at this
1104 // point, so this needs to check the type of the original request to
1105 // unregister instead of looking at the flag value.
1106 if (request instanceof DiscoveryManagerRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +00001107 stopDiscoveryManagerRequest(
1108 request, clientRequestId, transactionId, clientInfo);
Paul Hu60149052023-07-31 14:26:08 +08001109 clientInfo.onStopResolutionSucceeded(clientRequestId, request);
Paul Hud44e1b72023-06-16 02:07:42 +00001110 clientInfo.log("Unregister the ResolutionListener " + transactionId);
Paul Hub58deb72022-12-26 09:24:42 +00001111 } else {
Paul Hud44e1b72023-06-16 02:07:42 +00001112 removeRequestMap(clientRequestId, transactionId, clientInfo);
1113 if (stopResolveService(transactionId)) {
Paul Hu60149052023-07-31 14:26:08 +08001114 clientInfo.onStopResolutionSucceeded(clientRequestId, request);
Paul Hue4f5f252023-02-16 21:13:47 +08001115 } else {
1116 clientInfo.onStopResolutionFailed(
Paul Hud44e1b72023-06-16 02:07:42 +00001117 clientRequestId, NsdManager.FAILURE_OPERATION_NOT_RUNNING);
Paul Hue4f5f252023-02-16 21:13:47 +08001118 }
1119 clientInfo.mResolvedService = null;
Paul Hub58deb72022-12-26 09:24:42 +00001120 }
Paul Hub58deb72022-12-26 09:24:42 +00001121 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001122 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001123 case NsdManager.REGISTER_SERVICE_CALLBACK: {
Paul Hu18aeccc2022-12-27 08:48:48 +00001124 if (DBG) Log.d(TAG, "Register a service callback");
Yuyang Huang86d083f2023-12-12 19:56:41 +09001125 final ListenerArgs args = (ListenerArgs) msg.obj;
Paul Hu18aeccc2022-12-27 08:48:48 +00001126 clientInfo = mClients.get(args.connector);
1127 // If the binder death notification for a INsdManagerCallback was received
1128 // before any calls are received by NsdService, the clientInfo would be
1129 // cleared and cause NPE. Add a null check here to prevent this corner case.
1130 if (clientInfo == null) {
1131 Log.e(TAG, "Unknown connector in callback registration");
1132 break;
1133 }
1134
Paul Hu30bd70d2023-02-07 13:20:56 +00001135 final NsdServiceInfo info = args.serviceInfo;
Paul Hud44e1b72023-06-16 02:07:42 +00001136 transactionId = getUniqueId();
Yuyang Huang170d42f2023-12-09 15:26:16 +09001137 final Pair<String, List<String>> typeAndSubtype =
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001138 parseTypeAndSubtype(info.getServiceType());
1139 final String serviceType = typeAndSubtype == null
1140 ? null : typeAndSubtype.first;
Paul Hu30bd70d2023-02-07 13:20:56 +00001141 if (serviceType == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00001142 clientInfo.onServiceInfoCallbackRegistrationFailed(clientRequestId,
Paul Hu30bd70d2023-02-07 13:20:56 +00001143 NsdManager.FAILURE_BAD_PARAMETERS);
Paul Hu18aeccc2022-12-27 08:48:48 +00001144 break;
1145 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001146 final String resolveServiceType = serviceType + ".local";
Paul Hu18aeccc2022-12-27 08:48:48 +00001147
Paul Hu30bd70d2023-02-07 13:20:56 +00001148 maybeStartMonitoringSockets();
Paul Hud44e1b72023-06-16 02:07:42 +00001149 final MdnsListener listener = new ServiceInfoListener(clientRequestId,
Kangping Dong97b2adc2024-01-11 16:00:37 +08001150 transactionId, resolveServiceType);
Paul Hu30bd70d2023-02-07 13:20:56 +00001151 final MdnsSearchOptions options = MdnsSearchOptions.newBuilder()
1152 .setNetwork(info.getNetwork())
Paul Hu11a883d2023-12-14 07:36:44 +00001153 .setQueryMode(mMdnsFeatureFlags.isAggressiveQueryModeEnabled()
1154 ? AGGRESSIVE_QUERY_MODE
1155 : PASSIVE_QUERY_MODE)
Paul Hu30bd70d2023-02-07 13:20:56 +00001156 .setResolveInstanceName(info.getServiceName())
Yuyang Huangff963222023-06-01 18:42:42 +09001157 .setRemoveExpiredService(true)
Paul Hu30bd70d2023-02-07 13:20:56 +00001158 .build();
1159 mMdnsDiscoveryManager.registerListener(
1160 resolveServiceType, listener, options);
Paul Hud44e1b72023-06-16 02:07:42 +00001161 storeDiscoveryManagerRequestMap(clientRequestId, transactionId, listener,
1162 clientInfo, info.getNetwork());
Paul Huddce5912023-08-01 10:26:49 +08001163 clientInfo.onServiceInfoCallbackRegistered(transactionId);
Paul Hud44e1b72023-06-16 02:07:42 +00001164 clientInfo.log("Register a ServiceInfoListener " + transactionId
Paul Hub2e67d32023-04-18 05:50:14 +00001165 + " for service type:" + resolveServiceType);
Paul Hu18aeccc2022-12-27 08:48:48 +00001166 break;
Paul Hu30bd70d2023-02-07 13:20:56 +00001167 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001168 case NsdManager.UNREGISTER_SERVICE_CALLBACK: {
Paul Hu18aeccc2022-12-27 08:48:48 +00001169 if (DBG) Log.d(TAG, "Unregister a service callback");
Yuyang Huang86d083f2023-12-12 19:56:41 +09001170 final ListenerArgs args = (ListenerArgs) msg.obj;
Paul Hu18aeccc2022-12-27 08:48:48 +00001171 clientInfo = mClients.get(args.connector);
1172 // If the binder death notification for a INsdManagerCallback was received
1173 // before any calls are received by NsdService, the clientInfo would be
1174 // cleared and cause NPE. Add a null check here to prevent this corner case.
1175 if (clientInfo == null) {
1176 Log.e(TAG, "Unknown connector in callback unregistration");
1177 break;
1178 }
1179
Paul Hud44e1b72023-06-16 02:07:42 +00001180 final ClientRequest request =
1181 clientInfo.mClientRequests.get(clientRequestId);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001182 if (request == null) {
Paul Hu30bd70d2023-02-07 13:20:56 +00001183 Log.e(TAG, "Unknown client request in UNREGISTER_SERVICE_CALLBACK");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001184 break;
1185 }
Paul Hud44e1b72023-06-16 02:07:42 +00001186 transactionId = request.mTransactionId;
Paul Hu30bd70d2023-02-07 13:20:56 +00001187 if (request instanceof DiscoveryManagerRequest) {
Paul Hud44e1b72023-06-16 02:07:42 +00001188 stopDiscoveryManagerRequest(
1189 request, clientRequestId, transactionId, clientInfo);
Paul Huddce5912023-08-01 10:26:49 +08001190 clientInfo.onServiceInfoCallbackUnregistered(clientRequestId, request);
Paul Hud44e1b72023-06-16 02:07:42 +00001191 clientInfo.log("Unregister the ServiceInfoListener " + transactionId);
Paul Hu18aeccc2022-12-27 08:48:48 +00001192 } else {
Paul Hu30bd70d2023-02-07 13:20:56 +00001193 loge("Unregister failed with non-DiscoveryManagerRequest.");
Paul Hu18aeccc2022-12-27 08:48:48 +00001194 }
Paul Hu18aeccc2022-12-27 08:48:48 +00001195 break;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001196 }
paulhu2b9ed952022-02-10 21:58:32 +08001197 case MDNS_SERVICE_EVENT:
1198 if (!handleMDnsServiceEvent(msg.arg1, msg.arg2, msg.obj)) {
Hugo Benichif0c84092017-04-05 14:43:29 +09001199 return NOT_HANDLED;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001200 }
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07001201 break;
Paul Hu019621e2023-01-13 23:26:49 +08001202 case MDNS_DISCOVERY_MANAGER_EVENT:
1203 if (!handleMdnsDiscoveryManagerEvent(msg.arg1, msg.arg2, msg.obj)) {
1204 return NOT_HANDLED;
1205 }
1206 break;
Yuyang Huang33fa4d22023-02-14 22:59:37 +09001207 case NsdManager.REGISTER_OFFLOAD_ENGINE:
1208 offloadEngineInfo = (OffloadEngineInfo) msg.obj;
1209 // TODO: Limits the number of registrations created by a given class.
1210 mOffloadEngines.register(offloadEngineInfo.mOffloadEngine,
1211 offloadEngineInfo);
Yuyang Huangc275a9e2023-08-25 18:03:22 +09001212 sendAllOffloadServiceInfos(offloadEngineInfo);
Yuyang Huang33fa4d22023-02-14 22:59:37 +09001213 break;
1214 case NsdManager.UNREGISTER_OFFLOAD_ENGINE:
1215 mOffloadEngines.unregister((IOffloadEngine) msg.obj);
1216 break;
Paul Hu77c11182023-10-23 16:17:32 +08001217 case NsdManager.REGISTER_CLIENT:
1218 final ConnectorArgs arg = (ConnectorArgs) msg.obj;
1219 final INsdManagerCallback cb = arg.callback;
1220 try {
1221 cb.asBinder().linkToDeath(arg.connector, 0);
1222 final String tag = "Client" + arg.uid + "-" + mClientNumberId++;
1223 final NetworkNsdReportedMetrics metrics =
1224 mDeps.makeNetworkNsdReportedMetrics(
1225 (int) mClock.elapsedRealtime());
1226 clientInfo = new ClientInfo(cb, arg.uid, arg.useJavaBackend,
1227 mServiceLogs.forSubComponent(tag), metrics);
1228 mClients.put(arg.connector, clientInfo);
1229 } catch (RemoteException e) {
1230 Log.w(TAG, "Client request id " + clientRequestId
1231 + " has already died");
1232 }
1233 break;
1234 case NsdManager.UNREGISTER_CLIENT:
1235 final NsdServiceConnector connector = (NsdServiceConnector) msg.obj;
1236 clientInfo = mClients.remove(connector);
1237 if (clientInfo != null) {
1238 clientInfo.expungeAllRequests();
1239 if (clientInfo.isPreSClient()) {
1240 mLegacyClientCount -= 1;
1241 }
1242 }
1243 maybeStopMonitoringSocketsIfNoActiveRequest();
1244 maybeScheduleStop();
1245 break;
1246 case NsdManager.DAEMON_CLEANUP:
1247 maybeStopDaemon();
1248 break;
1249 // This event should be only sent by the legacy (target SDK < S) clients.
1250 // Mark the sending client as legacy.
1251 case NsdManager.DAEMON_STARTUP:
1252 clientInfo = getClientInfoForReply(msg);
1253 if (clientInfo != null) {
1254 cancelStop();
1255 clientInfo.setPreSClient();
1256 mLegacyClientCount += 1;
1257 maybeStartDaemon();
1258 }
1259 break;
Irfan Sheriff75006652012-04-17 23:15:29 -07001260 default:
Paul Hu77c11182023-10-23 16:17:32 +08001261 Log.wtf(TAG, "Unhandled " + msg);
Hugo Benichif0c84092017-04-05 14:43:29 +09001262 return NOT_HANDLED;
Irfan Sheriff75006652012-04-17 23:15:29 -07001263 }
Hugo Benichif0c84092017-04-05 14:43:29 +09001264 return HANDLED;
Irfan Sheriff75006652012-04-17 23:15:29 -07001265 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001266
Paul Hud44e1b72023-06-16 02:07:42 +00001267 private boolean handleMDnsServiceEvent(int code, int transactionId, Object obj) {
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001268 NsdServiceInfo servInfo;
Paul Hud44e1b72023-06-16 02:07:42 +00001269 ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001270 if (clientInfo == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00001271 Log.e(TAG, String.format(
1272 "transactionId %d for %d has no client mapping", transactionId, code));
Hugo Benichif0c84092017-04-05 14:43:29 +09001273 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001274 }
1275
1276 /* This goes in response as msg.arg2 */
Paul Hud44e1b72023-06-16 02:07:42 +00001277 int clientRequestId = clientInfo.getClientRequestId(transactionId);
1278 if (clientRequestId < 0) {
Vinit Deshapnde930a8512013-06-25 19:45:03 -07001279 // This can happen because of race conditions. For example,
1280 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
1281 // and we may get in this situation.
Paul Hud44e1b72023-06-16 02:07:42 +00001282 Log.d(TAG, String.format("%d for transactionId %d that is no longer active",
1283 code, transactionId));
Hugo Benichif0c84092017-04-05 14:43:29 +09001284 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001285 }
Paul Hu812e9212023-06-20 06:24:53 +00001286 final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
1287 if (request == null) {
1288 Log.e(TAG, "Unknown client request. clientRequestId=" + clientRequestId);
1289 return false;
1290 }
Hugo Benichi32be63d2017-04-05 14:06:11 +09001291 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00001292 Log.d(TAG, String.format(
1293 "MDns service event code:%d transactionId=%d", code, transactionId));
Hugo Benichi32be63d2017-04-05 14:06:11 +09001294 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001295 switch (code) {
paulhu2b9ed952022-02-10 21:58:32 +08001296 case IMDnsEventListener.SERVICE_FOUND: {
1297 final DiscoveryInfo info = (DiscoveryInfo) obj;
1298 final String name = info.serviceName;
1299 final String type = info.registrationType;
1300 servInfo = new NsdServiceInfo(name, type);
1301 final int foundNetId = info.netId;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001302 if (foundNetId == 0L) {
1303 // Ignore services that do not have a Network: they are not usable
1304 // by apps, as they would need privileged permissions to use
1305 // interfaces that do not have an associated Network.
1306 break;
1307 }
Remi NGUYEN VAN643edb62023-01-23 19:14:57 +09001308 if (foundNetId == INetd.DUMMY_NET_ID) {
1309 // Ignore services on the dummy0 interface: they are only seen when
1310 // discovering locally advertised services, and are not reachable
1311 // through that interface.
1312 break;
1313 }
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001314 setServiceNetworkForCallback(servInfo, info.netId, info.interfaceIdx);
Paul Hu812e9212023-06-20 06:24:53 +00001315
1316 clientInfo.onServiceFound(clientRequestId, servInfo, request);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001317 break;
paulhu2b9ed952022-02-10 21:58:32 +08001318 }
1319 case IMDnsEventListener.SERVICE_LOST: {
1320 final DiscoveryInfo info = (DiscoveryInfo) obj;
1321 final String name = info.serviceName;
1322 final String type = info.registrationType;
1323 final int lostNetId = info.netId;
1324 servInfo = new NsdServiceInfo(name, type);
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001325 // The network could be set to null (netId 0) if it was torn down when the
1326 // service is lost
1327 // TODO: avoid returning null in that case, possibly by remembering
1328 // found services on the same interface index and their network at the time
1329 setServiceNetworkForCallback(servInfo, lostNetId, info.interfaceIdx);
Paul Hu812e9212023-06-20 06:24:53 +00001330 clientInfo.onServiceLost(clientRequestId, servInfo, request);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001331 break;
paulhu2b9ed952022-02-10 21:58:32 +08001332 }
1333 case IMDnsEventListener.SERVICE_DISCOVERY_FAILED:
Paul Hu812e9212023-06-20 06:24:53 +00001334 clientInfo.onDiscoverServicesFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001335 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1336 transactionId,
Paul Hu812e9212023-06-20 06:24:53 +00001337 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001338 break;
paulhu2b9ed952022-02-10 21:58:32 +08001339 case IMDnsEventListener.SERVICE_REGISTERED: {
1340 final RegistrationInfo info = (RegistrationInfo) obj;
1341 final String name = info.serviceName;
1342 servInfo = new NsdServiceInfo(name, null /* serviceType */);
Paul Hu508a0122023-09-11 15:31:33 +08001343 clientInfo.onRegisterServiceSucceeded(clientRequestId, servInfo, request);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001344 break;
paulhu2b9ed952022-02-10 21:58:32 +08001345 }
1346 case IMDnsEventListener.SERVICE_REGISTRATION_FAILED:
Paul Hu777ed052023-06-19 13:35:15 +00001347 clientInfo.onRegisterServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001348 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1349 transactionId,
Paul Hu812e9212023-06-20 06:24:53 +00001350 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001351 break;
paulhu2b9ed952022-02-10 21:58:32 +08001352 case IMDnsEventListener.SERVICE_RESOLVED: {
1353 final ResolutionInfo info = (ResolutionInfo) obj;
Sreeram Ramachandrana53dd7f2014-09-03 15:45:59 -07001354 int index = 0;
paulhu2b9ed952022-02-10 21:58:32 +08001355 final String fullName = info.serviceFullName;
1356 while (index < fullName.length() && fullName.charAt(index) != '.') {
1357 if (fullName.charAt(index) == '\\') {
Sreeram Ramachandrana53dd7f2014-09-03 15:45:59 -07001358 ++index;
1359 }
1360 ++index;
1361 }
paulhu2b9ed952022-02-10 21:58:32 +08001362 if (index >= fullName.length()) {
1363 Log.e(TAG, "Invalid service found " + fullName);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001364 break;
1365 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001366
paulhube186602022-04-12 07:18:23 +00001367 String name = unescape(fullName.substring(0, index));
paulhu2b9ed952022-02-10 21:58:32 +08001368 String rest = fullName.substring(index);
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001369 String type = rest.replace(".local.", "");
1370
Paul Hu30bd70d2023-02-07 13:20:56 +00001371 final NsdServiceInfo serviceInfo = clientInfo.mResolvedService;
Paul Hu18aeccc2022-12-27 08:48:48 +00001372 serviceInfo.setServiceName(name);
1373 serviceInfo.setServiceType(type);
1374 serviceInfo.setPort(info.port);
1375 serviceInfo.setTxtRecords(info.txtRecord);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001376 // Network will be added after SERVICE_GET_ADDR_SUCCESS
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001377
Paul Hud44e1b72023-06-16 02:07:42 +00001378 stopResolveService(transactionId);
1379 removeRequestMap(clientRequestId, transactionId, clientInfo);
Vinit Deshapnde4429e872013-11-12 15:36:37 -08001380
Paul Hud44e1b72023-06-16 02:07:42 +00001381 final int transactionId2 = getUniqueId();
1382 if (getAddrInfo(transactionId2, info.hostname, info.interfaceIdx)) {
1383 storeLegacyRequestMap(clientRequestId, transactionId2, clientInfo,
Paul Hua6bc4632023-06-26 01:18:29 +00001384 NsdManager.RESOLVE_SERVICE, request.mStartTimeMs);
Vinit Deshapnde4429e872013-11-12 15:36:37 -08001385 } else {
Paul Hua6bc4632023-06-26 01:18:29 +00001386 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001387 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1388 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001389 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hu30bd70d2023-02-07 13:20:56 +00001390 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001391 }
1392 break;
paulhu2b9ed952022-02-10 21:58:32 +08001393 }
1394 case IMDnsEventListener.SERVICE_RESOLUTION_FAILED:
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001395 /* NNN resolveId errorCode */
Paul Hud44e1b72023-06-16 02:07:42 +00001396 stopResolveService(transactionId);
1397 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hua6bc4632023-06-26 01:18:29 +00001398 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001399 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1400 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001401 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hu30bd70d2023-02-07 13:20:56 +00001402 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001403 break;
paulhu2b9ed952022-02-10 21:58:32 +08001404 case IMDnsEventListener.SERVICE_GET_ADDR_FAILED:
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001405 /* NNN resolveId errorCode */
Paul Hud44e1b72023-06-16 02:07:42 +00001406 stopGetAddrInfo(transactionId);
1407 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hua6bc4632023-06-26 01:18:29 +00001408 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001409 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1410 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001411 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hu30bd70d2023-02-07 13:20:56 +00001412 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001413 break;
paulhu2b9ed952022-02-10 21:58:32 +08001414 case IMDnsEventListener.SERVICE_GET_ADDR_SUCCESS: {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001415 /* NNN resolveId hostname ttl addr interfaceIdx netId */
paulhu2b9ed952022-02-10 21:58:32 +08001416 final GetAddressInfo info = (GetAddressInfo) obj;
1417 final String address = info.address;
1418 final int netId = info.netId;
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001419 InetAddress serviceHost = null;
1420 try {
paulhu2b9ed952022-02-10 21:58:32 +08001421 serviceHost = InetAddress.getByName(address);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001422 } catch (UnknownHostException e) {
1423 Log.wtf(TAG, "Invalid host in GET_ADDR_SUCCESS", e);
1424 }
1425
1426 // If the resolved service is on an interface without a network, consider it
1427 // as a failure: it would not be usable by apps as they would need
1428 // privileged permissions.
Paul Hu30bd70d2023-02-07 13:20:56 +00001429 if (netId != NETID_UNSET && serviceHost != null) {
1430 clientInfo.mResolvedService.setHost(serviceHost);
1431 setServiceNetworkForCallback(clientInfo.mResolvedService,
1432 netId, info.interfaceIdx);
1433 clientInfo.onResolveServiceSucceeded(
Paul Hua6bc4632023-06-26 01:18:29 +00001434 clientRequestId, clientInfo.mResolvedService, request);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09001435 } else {
Paul Hua6bc4632023-06-26 01:18:29 +00001436 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001437 NsdManager.FAILURE_INTERNAL_ERROR, true /* isLegacy */,
1438 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001439 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001440 }
Paul Hud44e1b72023-06-16 02:07:42 +00001441 stopGetAddrInfo(transactionId);
1442 removeRequestMap(clientRequestId, transactionId, clientInfo);
Paul Hu30bd70d2023-02-07 13:20:56 +00001443 clientInfo.mResolvedService = null;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001444 break;
paulhu2b9ed952022-02-10 21:58:32 +08001445 }
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001446 default:
Hugo Benichif0c84092017-04-05 14:43:29 +09001447 return false;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001448 }
Hugo Benichif0c84092017-04-05 14:43:29 +09001449 return true;
Vairavan Srinivasan6ce48182012-08-05 13:14:12 -07001450 }
Paul Hu019621e2023-01-13 23:26:49 +08001451
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001452 @Nullable
1453 private NsdServiceInfo buildNsdServiceInfoFromMdnsEvent(
1454 final MdnsEvent event, int code) {
Paul Hu019621e2023-01-13 23:26:49 +08001455 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001456 final String[] typeArray = serviceInfo.getServiceType();
1457 final String joinedType;
1458 if (typeArray.length == 0
1459 || !typeArray[typeArray.length - 1].equals(LOCAL_DOMAIN_NAME)) {
1460 Log.wtf(TAG, "MdnsServiceInfo type does not end in .local: "
1461 + Arrays.toString(typeArray));
1462 return null;
1463 } else {
1464 joinedType = TextUtils.join(".",
1465 Arrays.copyOfRange(typeArray, 0, typeArray.length - 1));
1466 }
1467 final String serviceType;
1468 switch (code) {
1469 case NsdManager.SERVICE_FOUND:
1470 case NsdManager.SERVICE_LOST:
1471 // For consistency with historical behavior, discovered service types have
1472 // a dot at the end.
1473 serviceType = joinedType + ".";
1474 break;
1475 case RESOLVE_SERVICE_SUCCEEDED:
1476 // For consistency with historical behavior, resolved service types have
1477 // a dot at the beginning.
1478 serviceType = "." + joinedType;
1479 break;
1480 default:
1481 serviceType = joinedType;
1482 break;
1483 }
Paul Hu019621e2023-01-13 23:26:49 +08001484 final String serviceName = serviceInfo.getServiceInstanceName();
1485 final NsdServiceInfo servInfo = new NsdServiceInfo(serviceName, serviceType);
1486 final Network network = serviceInfo.getNetwork();
Yuyang Huang3bee9d42023-04-04 13:00:54 +09001487 // In MdnsDiscoveryManagerEvent, the Network can be null which means it is a
1488 // network for Tethering interface. In other words, the network == null means the
1489 // network has netId = INetd.LOCAL_NET_ID.
Paul Hu019621e2023-01-13 23:26:49 +08001490 setServiceNetworkForCallback(
1491 servInfo,
Yuyang Huang3bee9d42023-04-04 13:00:54 +09001492 network == null ? INetd.LOCAL_NET_ID : network.netId,
Paul Hu019621e2023-01-13 23:26:49 +08001493 serviceInfo.getInterfaceIndex());
Kangping Dong5af24b62023-12-10 21:41:16 +08001494 servInfo.setSubtypes(dedupSubtypeLabels(serviceInfo.getSubtypes()));
Paul Hu019621e2023-01-13 23:26:49 +08001495 return servInfo;
1496 }
1497
1498 private boolean handleMdnsDiscoveryManagerEvent(
1499 int transactionId, int code, Object obj) {
Paul Hud44e1b72023-06-16 02:07:42 +00001500 final ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Paul Hu019621e2023-01-13 23:26:49 +08001501 if (clientInfo == null) {
1502 Log.e(TAG, String.format(
1503 "id %d for %d has no client mapping", transactionId, code));
1504 return false;
1505 }
1506
1507 final MdnsEvent event = (MdnsEvent) obj;
Paul Hud44e1b72023-06-16 02:07:42 +00001508 final int clientRequestId = event.mClientRequestId;
Paul Hubad6fe92023-07-24 21:25:22 +08001509 final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
1510 if (request == null) {
1511 Log.e(TAG, "Unknown client request. clientRequestId=" + clientRequestId);
1512 return false;
1513 }
1514
1515 // Deal with the discovery sent callback
1516 if (code == DISCOVERY_QUERY_SENT_CALLBACK) {
1517 request.onQuerySent();
1518 return true;
1519 }
1520
1521 // Deal with other callbacks.
Remi NGUYEN VAN2f82fcd2023-05-10 13:24:53 +09001522 final NsdServiceInfo info = buildNsdServiceInfoFromMdnsEvent(event, code);
1523 // Errors are already logged if null
1524 if (info == null) return false;
Paul Hu83ec7f42023-06-07 18:04:09 +08001525 mServiceLogs.log(String.format(
1526 "MdnsDiscoveryManager event code=%s transactionId=%d",
1527 NsdManager.nameOf(code), transactionId));
Paul Hu019621e2023-01-13 23:26:49 +08001528 switch (code) {
1529 case NsdManager.SERVICE_FOUND:
Paul Hu812e9212023-06-20 06:24:53 +00001530 clientInfo.onServiceFound(clientRequestId, info, request);
Paul Hu319751a2023-01-13 23:56:34 +08001531 break;
1532 case NsdManager.SERVICE_LOST:
Paul Hu812e9212023-06-20 06:24:53 +00001533 clientInfo.onServiceLost(clientRequestId, info, request);
Paul Hu019621e2023-01-13 23:26:49 +08001534 break;
Paul Hu75069ed2023-01-14 00:31:09 +08001535 case NsdManager.RESOLVE_SERVICE_SUCCEEDED: {
1536 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
Paul Hu75069ed2023-01-14 00:31:09 +08001537 info.setPort(serviceInfo.getPort());
1538
1539 Map<String, String> attrs = serviceInfo.getAttributes();
1540 for (Map.Entry<String, String> kv : attrs.entrySet()) {
1541 final String key = kv.getKey();
1542 try {
1543 info.setAttribute(key, serviceInfo.getAttributeAsBytes(key));
1544 } catch (IllegalArgumentException e) {
1545 Log.e(TAG, "Invalid attribute", e);
1546 }
1547 }
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001548 final List<InetAddress> addresses = getInetAddresses(serviceInfo);
Paul Hu2b865912023-03-06 14:27:53 +08001549 if (addresses.size() != 0) {
1550 info.setHostAddresses(addresses);
Paul Hua6bc4632023-06-26 01:18:29 +00001551 request.setServiceFromCache(event.mIsServiceFromCache);
1552 clientInfo.onResolveServiceSucceeded(clientRequestId, info, request);
Paul Hu2b865912023-03-06 14:27:53 +08001553 } else {
1554 // No address. Notify resolution failure.
Paul Hua6bc4632023-06-26 01:18:29 +00001555 clientInfo.onResolveServiceFailed(clientRequestId,
Paul Hu508a0122023-09-11 15:31:33 +08001556 NsdManager.FAILURE_INTERNAL_ERROR, false /* isLegacy */,
1557 transactionId,
Paul Hua6bc4632023-06-26 01:18:29 +00001558 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hu75069ed2023-01-14 00:31:09 +08001559 }
1560
1561 // Unregister the listener immediately like IMDnsEventListener design
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09001562 if (!(request instanceof DiscoveryManagerRequest)) {
1563 Log.wtf(TAG, "non-DiscoveryManager request in DiscoveryManager event");
1564 break;
1565 }
Paul Hud44e1b72023-06-16 02:07:42 +00001566 stopDiscoveryManagerRequest(
1567 request, clientRequestId, transactionId, clientInfo);
Paul Hu75069ed2023-01-14 00:31:09 +08001568 break;
1569 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001570 case NsdManager.SERVICE_UPDATED: {
1571 final MdnsServiceInfo serviceInfo = event.mMdnsServiceInfo;
1572 info.setPort(serviceInfo.getPort());
1573
1574 Map<String, String> attrs = serviceInfo.getAttributes();
1575 for (Map.Entry<String, String> kv : attrs.entrySet()) {
1576 final String key = kv.getKey();
1577 try {
1578 info.setAttribute(key, serviceInfo.getAttributeAsBytes(key));
1579 } catch (IllegalArgumentException e) {
1580 Log.e(TAG, "Invalid attribute", e);
1581 }
1582 }
1583
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001584 final List<InetAddress> addresses = getInetAddresses(serviceInfo);
Paul Hu30bd70d2023-02-07 13:20:56 +00001585 info.setHostAddresses(addresses);
Paul Huddce5912023-08-01 10:26:49 +08001586 clientInfo.onServiceUpdated(clientRequestId, info, request);
1587 // Set the ServiceFromCache flag only if the service is actually being
1588 // retrieved from the cache. This flag should not be overridden by later
1589 // service updates, which may not be cached.
1590 if (event.mIsServiceFromCache) {
1591 request.setServiceFromCache(true);
1592 }
Paul Hu30bd70d2023-02-07 13:20:56 +00001593 break;
1594 }
1595 case NsdManager.SERVICE_UPDATED_LOST:
Paul Huddce5912023-08-01 10:26:49 +08001596 clientInfo.onServiceUpdatedLost(clientRequestId, request);
Paul Hu30bd70d2023-02-07 13:20:56 +00001597 break;
Paul Hu019621e2023-01-13 23:26:49 +08001598 default:
1599 return false;
1600 }
1601 return true;
1602 }
Irfan Sheriff75006652012-04-17 23:15:29 -07001603 }
1604 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001605
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001606 @NonNull
1607 private static List<InetAddress> getInetAddresses(@NonNull MdnsServiceInfo serviceInfo) {
1608 final List<String> v4Addrs = serviceInfo.getIpv4Addresses();
1609 final List<String> v6Addrs = serviceInfo.getIpv6Addresses();
1610 final List<InetAddress> addresses = new ArrayList<>(v4Addrs.size() + v6Addrs.size());
1611 for (String ipv4Address : v4Addrs) {
1612 try {
1613 addresses.add(InetAddresses.parseNumericAddress(ipv4Address));
1614 } catch (IllegalArgumentException e) {
1615 Log.wtf(TAG, "Invalid ipv4 address", e);
1616 }
1617 }
1618 for (String ipv6Address : v6Addrs) {
1619 try {
Yuyang Huanga6a6ff92023-04-24 13:33:34 +09001620 final Inet6Address addr = (Inet6Address) InetAddresses.parseNumericAddress(
1621 ipv6Address);
1622 addresses.add(InetAddressUtils.withScopeId(addr, serviceInfo.getInterfaceIndex()));
1623 } catch (IllegalArgumentException e) {
Yuyang Huangaa0e9602023-03-17 12:43:09 +09001624 Log.wtf(TAG, "Invalid ipv6 address", e);
1625 }
1626 }
1627 return addresses;
1628 }
1629
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09001630 private static void setServiceNetworkForCallback(NsdServiceInfo info, int netId, int ifaceIdx) {
1631 switch (netId) {
1632 case NETID_UNSET:
1633 info.setNetwork(null);
1634 break;
1635 case INetd.LOCAL_NET_ID:
1636 // Special case for LOCAL_NET_ID: Networks on netId 99 are not generally
1637 // visible / usable for apps, so do not return it. Store the interface
1638 // index instead, so at least if the client tries to resolve the service
1639 // with that NsdServiceInfo, it will be done on the same interface.
1640 // If they recreate the NsdServiceInfo themselves, resolution would be
1641 // done on all interfaces as before T, which should also work.
1642 info.setNetwork(null);
1643 info.setInterfaceIndex(ifaceIdx);
1644 break;
1645 default:
1646 info.setNetwork(new Network(netId));
1647 }
1648 }
1649
paulhube186602022-04-12 07:18:23 +00001650 // The full service name is escaped from standard DNS rules on mdnsresponder, making it suitable
1651 // for passing to standard system DNS APIs such as res_query() . Thus, make the service name
1652 // unescape for getting right service address. See "Notes on DNS Name Escaping" on
1653 // external/mdnsresponder/mDNSShared/dns_sd.h for more details.
1654 private String unescape(String s) {
1655 StringBuilder sb = new StringBuilder(s.length());
1656 for (int i = 0; i < s.length(); ++i) {
1657 char c = s.charAt(i);
1658 if (c == '\\') {
1659 if (++i >= s.length()) {
1660 Log.e(TAG, "Unexpected end of escape sequence in: " + s);
1661 break;
1662 }
1663 c = s.charAt(i);
1664 if (c != '.' && c != '\\') {
1665 if (i + 2 >= s.length()) {
1666 Log.e(TAG, "Unexpected end of escape sequence in: " + s);
1667 break;
1668 }
1669 c = (char) ((c - '0') * 100 + (s.charAt(i + 1) - '0') * 10
1670 + (s.charAt(i + 2) - '0'));
1671 i += 2;
1672 }
1673 }
1674 sb.append(c);
1675 }
1676 return sb.toString();
1677 }
1678
Paul Hu7445e3d2023-03-03 15:14:00 +08001679 /**
1680 * Check the given service type is valid and construct it to a service type
1681 * which can use for discovery / resolution service.
1682 *
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001683 * <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 +08001684 * subtype (see RFC6763 7.1). Each label is up to 63 characters and must start with an
1685 * underscore; they are alphanumerical characters or dashes or underscore, except the
1686 * last one that is just alphanumerical. The last label must be _tcp or _udp.
1687 *
Yuyang Huang170d42f2023-12-09 15:26:16 +09001688 * <p>The subtypes may also be specified with a comma after the service type, for example
1689 * _type._tcp,_subtype1,_subtype2
Remi NGUYEN VANf2d06412023-05-11 19:18:44 +09001690 *
Paul Hu7445e3d2023-03-03 15:14:00 +08001691 * @param serviceType the request service type for discovery / resolution service
1692 * @return constructed service type or null if the given service type is invalid.
1693 */
1694 @Nullable
Yuyang Huang170d42f2023-12-09 15:26:16 +09001695 public static Pair<String, List<String>> parseTypeAndSubtype(String serviceType) {
Paul Hu7445e3d2023-03-03 15:14:00 +08001696 if (TextUtils.isEmpty(serviceType)) return null;
Yuyang Huang86d083f2023-12-12 19:56:41 +09001697 final Pattern serviceTypePattern = Pattern.compile(TYPE_REGEX);
Paul Hu7445e3d2023-03-03 15:14:00 +08001698 final Matcher matcher = serviceTypePattern.matcher(serviceType);
1699 if (!matcher.matches()) return null;
Yuyang Huang170d42f2023-12-09 15:26:16 +09001700 final String queryType = matcher.group(2);
1701 // Use the subtype at the beginning
1702 if (matcher.group(1) != null) {
1703 return new Pair<>(queryType, List.of(matcher.group(1)));
1704 }
1705 // Use the subtypes at the end
1706 final String subTypesStr = matcher.group(3);
1707 if (subTypesStr != null && !subTypesStr.isEmpty()) {
1708 final String[] subTypes = subTypesStr.substring(1).split(",");
1709 return new Pair<>(queryType, List.of(subTypes));
1710 }
1711
1712 return new Pair<>(queryType, Collections.emptyList());
Paul Hu7445e3d2023-03-03 15:14:00 +08001713 }
1714
Kangping Dong5af24b62023-12-10 21:41:16 +08001715 /** Returns {@code true} if {@code subtype} is a valid DNS-SD subtype label. */
1716 private static boolean checkSubtypeLabel(String subtype) {
1717 return Pattern.compile("^" + TYPE_SUBTYPE_LABEL_REGEX + "$").matcher(subtype).matches();
1718 }
1719
Hugo Benichi803a2f02017-04-24 11:35:06 +09001720 @VisibleForTesting
paulhu2b9ed952022-02-10 21:58:32 +08001721 NsdService(Context ctx, Handler handler, long cleanupDelayMs) {
Paul Hu4bd98ef2023-01-12 13:42:07 +08001722 this(ctx, handler, cleanupDelayMs, new Dependencies());
1723 }
1724
1725 @VisibleForTesting
1726 NsdService(Context ctx, Handler handler, long cleanupDelayMs, Dependencies deps) {
Luke Huang05298582021-06-13 16:52:05 +00001727 mCleanupDelayMs = cleanupDelayMs;
Hugo Benichi803a2f02017-04-24 11:35:06 +09001728 mContext = ctx;
Hugo Benichi803a2f02017-04-24 11:35:06 +09001729 mNsdStateMachine = new NsdStateMachine(TAG, handler);
Irfan Sheriff75006652012-04-17 23:15:29 -07001730 mNsdStateMachine.start();
Ken Chen80c9f6f2023-11-15 18:24:54 +08001731 // It can fail on V+ device since mdns native service provided by netd is removed.
1732 mMDnsManager = SdkLevel.isAtLeastV() ? null : ctx.getSystemService(MDnsManager.class);
paulhu2b9ed952022-02-10 21:58:32 +08001733 mMDnsEventCallback = new MDnsEventCallback(mNsdStateMachine);
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001734 mDeps = deps;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001735
Paul Hu14667de2023-04-17 22:42:47 +08001736 mMdnsSocketProvider = deps.makeMdnsSocketProvider(ctx, handler.getLooper(),
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001737 LOGGER.forSubComponent("MdnsSocketProvider"), new SocketRequestMonitor());
Yuyang Huang700778b2023-03-08 16:17:05 +09001738 // Netlink monitor starts on boot, and intentionally never stopped, to ensure that all
Yuyang Huangfca402a2023-05-24 14:45:59 +09001739 // address events are received. When the netlink monitor starts, any IP addresses already
1740 // on the interfaces will not be seen. In practice, the network will not connect at boot
1741 // time As a result, all the netlink message should be observed if the netlink monitor
1742 // starts here.
Yuyang Huang700778b2023-03-08 16:17:05 +09001743 handler.post(mMdnsSocketProvider::startNetLinkMonitor);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001744
1745 // NsdService is started after ActivityManager (startOtherServices in SystemServer, vs.
1746 // startBootstrapServices).
1747 mRunningAppActiveImportanceCutoff = mDeps.getDeviceConfigInt(
1748 MDNS_CONFIG_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF,
1749 DEFAULT_RUNNING_APP_ACTIVE_IMPORTANCE_CUTOFF);
1750 final ActivityManager am = ctx.getSystemService(ActivityManager.class);
1751 am.addOnUidImportanceListener(new UidImportanceListener(handler),
1752 mRunningAppActiveImportanceCutoff);
1753
Paul Hu11a883d2023-12-14 07:36:44 +00001754 mMdnsFeatureFlags = new MdnsFeatureFlags.Builder()
Paul Huf3fe3332023-10-16 17:13:25 +08001755 .setIsMdnsOffloadFeatureEnabled(mDeps.isTetheringFeatureNotChickenedOut(
1756 mContext, MdnsFeatureFlags.NSD_FORCE_DISABLE_MDNS_OFFLOAD))
1757 .setIncludeInetAddressRecordsInProbing(mDeps.isFeatureEnabled(
1758 mContext, MdnsFeatureFlags.INCLUDE_INET_ADDRESS_RECORDS_IN_PROBING))
Paul Hu596a5002023-10-18 17:07:31 +08001759 .setIsExpiredServicesRemovalEnabled(mDeps.isFeatureEnabled(
1760 mContext, MdnsFeatureFlags.NSD_EXPIRED_SERVICES_REMOVAL))
Paul Hufd357ef2023-11-01 16:32:45 +08001761 .setIsLabelCountLimitEnabled(mDeps.isTetheringFeatureNotChickenedOut(
1762 mContext, MdnsFeatureFlags.NSD_LIMIT_LABEL_COUNT))
Paul Hu01f243f2023-11-22 17:26:36 +08001763 .setIsKnownAnswerSuppressionEnabled(mDeps.isFeatureEnabled(
1764 mContext, MdnsFeatureFlags.NSD_KNOWN_ANSWER_SUPPRESSION))
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +09001765 .setIsUnicastReplyEnabled(mDeps.isFeatureEnabled(
1766 mContext, MdnsFeatureFlags.NSD_UNICAST_REPLY_ENABLED))
Paul Hu11a883d2023-12-14 07:36:44 +00001767 .setIsAggressiveQueryModeEnabled(mDeps.isFeatureEnabled(
1768 mContext, MdnsFeatureFlags.NSD_AGGRESSIVE_QUERY_MODE))
Remi NGUYEN VAN0ca094b2023-09-13 16:27:12 +09001769 .setOverrideProvider(flag -> mDeps.isFeatureEnabled(
1770 mContext, FORCE_ENABLE_FLAG_FOR_TEST_PREFIX + flag))
Paul Huf3fe3332023-10-16 17:13:25 +08001771 .build();
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001772 mMdnsSocketClient =
Yuyang Huang7ddf2932023-08-01 18:16:30 +09001773 new MdnsMultinetworkSocketClient(handler.getLooper(), mMdnsSocketProvider,
Paul Hu11a883d2023-12-14 07:36:44 +00001774 LOGGER.forSubComponent("MdnsMultinetworkSocketClient"), mMdnsFeatureFlags);
Paul Hu14667de2023-04-17 22:42:47 +08001775 mMdnsDiscoveryManager = deps.makeMdnsDiscoveryManager(new ExecutorProvider(),
Paul Hu11a883d2023-12-14 07:36:44 +00001776 mMdnsSocketClient, LOGGER.forSubComponent("MdnsDiscoveryManager"),
1777 mMdnsFeatureFlags);
Remi NGUYEN VANa8a777b2023-01-18 18:57:41 +09001778 handler.post(() -> mMdnsSocketClient.setCallback(mMdnsDiscoveryManager));
1779 mAdvertiser = deps.makeMdnsAdvertiser(handler.getLooper(), mMdnsSocketProvider,
Paul Hu11a883d2023-12-14 07:36:44 +00001780 new AdvertiserCallback(), LOGGER.forSubComponent("MdnsAdvertiser"),
1781 mMdnsFeatureFlags, mContext);
Paul Hu777ed052023-06-19 13:35:15 +00001782 mClock = deps.makeClock();
Paul Hu4bd98ef2023-01-12 13:42:07 +08001783 }
1784
1785 /**
1786 * Dependencies of NsdService, for injection in tests.
1787 */
1788 @VisibleForTesting
1789 public static class Dependencies {
1790 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001791 * Check whether the MdnsDiscoveryManager feature is enabled.
Paul Hu4bd98ef2023-01-12 13:42:07 +08001792 *
1793 * @param context The global context information about an app environment.
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001794 * @return true if the MdnsDiscoveryManager feature is enabled.
Paul Hu4bd98ef2023-01-12 13:42:07 +08001795 */
1796 public boolean isMdnsDiscoveryManagerEnabled(Context context) {
Motomu Utsumi624aeb42023-08-15 15:52:27 +09001797 return isAtLeastU() || DeviceConfigUtils.isTetheringFeatureEnabled(context,
Motomu Utsumi3e0be392023-08-15 16:32:44 +09001798 MDNS_DISCOVERY_MANAGER_VERSION);
Paul Hu4bd98ef2023-01-12 13:42:07 +08001799 }
1800
1801 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001802 * Check whether the MdnsAdvertiser feature is enabled.
1803 *
1804 * @param context The global context information about an app environment.
1805 * @return true if the MdnsAdvertiser feature is enabled.
1806 */
1807 public boolean isMdnsAdvertiserEnabled(Context context) {
Motomu Utsumi624aeb42023-08-15 15:52:27 +09001808 return isAtLeastU() || DeviceConfigUtils.isTetheringFeatureEnabled(context,
Motomu Utsumi3e0be392023-08-15 16:32:44 +09001809 MDNS_ADVERTISER_VERSION);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001810 }
1811
1812 /**
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001813 * Get the type allowlist flag value.
1814 * @see #MDNS_TYPE_ALLOWLIST_FLAGS
1815 */
1816 @Nullable
1817 public String getTypeAllowlistFlags() {
1818 return DeviceConfigUtils.getDeviceConfigProperty(NAMESPACE_TETHERING,
1819 MDNS_TYPE_ALLOWLIST_FLAGS, null);
1820 }
1821
1822 /**
Motomu Utsumi624aeb42023-08-15 15:52:27 +09001823 * @see DeviceConfigUtils#isTetheringFeatureEnabled
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001824 */
1825 public boolean isFeatureEnabled(Context context, String feature) {
Motomu Utsumi3e0be392023-08-15 16:32:44 +09001826 return DeviceConfigUtils.isTetheringFeatureEnabled(context, feature);
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001827 }
1828
1829 /**
Yuyang Huangb96a0712023-09-07 15:13:15 +09001830 * @see DeviceConfigUtils#isTetheringFeatureNotChickenedOut
1831 */
Motomu Utsumied4e7ec2023-09-13 14:58:32 +09001832 public boolean isTetheringFeatureNotChickenedOut(Context context, String feature) {
1833 return DeviceConfigUtils.isTetheringFeatureNotChickenedOut(context, feature);
Yuyang Huangb96a0712023-09-07 15:13:15 +09001834 }
1835
1836 /**
Paul Huf3fe3332023-10-16 17:13:25 +08001837 * @see DeviceConfigUtils#isTrunkStableFeatureEnabled
1838 */
1839 public boolean isTrunkStableFeatureEnabled(String feature) {
1840 return DeviceConfigUtils.isTrunkStableFeatureEnabled(feature);
1841 }
1842
1843 /**
Paul Hu4bd98ef2023-01-12 13:42:07 +08001844 * @see MdnsDiscoveryManager
1845 */
1846 public MdnsDiscoveryManager makeMdnsDiscoveryManager(
Paul Hu14667de2023-04-17 22:42:47 +08001847 @NonNull ExecutorProvider executorProvider,
Paul Huf3fe3332023-10-16 17:13:25 +08001848 @NonNull MdnsMultinetworkSocketClient socketClient, @NonNull SharedLog sharedLog,
1849 @NonNull MdnsFeatureFlags featureFlags) {
1850 return new MdnsDiscoveryManager(
1851 executorProvider, socketClient, sharedLog, featureFlags);
Paul Hu4bd98ef2023-01-12 13:42:07 +08001852 }
1853
1854 /**
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001855 * @see MdnsAdvertiser
1856 */
1857 public MdnsAdvertiser makeMdnsAdvertiser(
1858 @NonNull Looper looper, @NonNull MdnsSocketProvider socketProvider,
Yuyang Huangb96a0712023-09-07 15:13:15 +09001859 @NonNull MdnsAdvertiser.AdvertiserCallback cb, @NonNull SharedLog sharedLog,
Remi NGUYEN VAN5c9d6cb2024-01-23 17:14:55 +09001860 MdnsFeatureFlags featureFlags, Context context) {
1861 return new MdnsAdvertiser(looper, socketProvider, cb, sharedLog, featureFlags, context);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09001862 }
1863
1864 /**
Paul Hu4bd98ef2023-01-12 13:42:07 +08001865 * @see MdnsSocketProvider
1866 */
Paul Hu14667de2023-04-17 22:42:47 +08001867 public MdnsSocketProvider makeMdnsSocketProvider(@NonNull Context context,
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09001868 @NonNull Looper looper, @NonNull SharedLog sharedLog,
1869 @NonNull MdnsSocketProvider.SocketRequestMonitor socketCreationCallback) {
1870 return new MdnsSocketProvider(context, looper, sharedLog, socketCreationCallback);
1871 }
1872
1873 /**
1874 * @see DeviceConfig#getInt(String, String, int)
1875 */
1876 public int getDeviceConfigInt(@NonNull String config, int defaultValue) {
1877 return DeviceConfig.getInt(NAMESPACE_TETHERING, config, defaultValue);
1878 }
1879
1880 /**
1881 * @see Binder#getCallingUid()
1882 */
1883 public int getCallingUid() {
1884 return Binder.getCallingUid();
Paul Hu4bd98ef2023-01-12 13:42:07 +08001885 }
Paul Hu777ed052023-06-19 13:35:15 +00001886
1887 /**
1888 * @see NetworkNsdReportedMetrics
1889 */
Paul Hu508a0122023-09-11 15:31:33 +08001890 public NetworkNsdReportedMetrics makeNetworkNsdReportedMetrics(int clientId) {
1891 return new NetworkNsdReportedMetrics(clientId);
Paul Hu777ed052023-06-19 13:35:15 +00001892 }
1893
1894 /**
1895 * @see MdnsUtils.Clock
1896 */
1897 public Clock makeClock() {
1898 return new Clock();
1899 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001900 }
1901
Remi NGUYEN VAN151d0a52023-03-03 17:50:50 +09001902 /**
1903 * Return whether a type is allowlisted to use the Java backend.
1904 * @param type The service type
1905 * @param flagPrefix One of {@link #MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX} or
1906 * {@link #MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX}.
1907 */
1908 private boolean isTypeAllowlistedForJavaBackend(@Nullable String type,
1909 @NonNull String flagPrefix) {
1910 if (type == null) return false;
1911 final String typesConfig = mDeps.getTypeAllowlistFlags();
1912 if (TextUtils.isEmpty(typesConfig)) return false;
1913
1914 final String mappingPrefix = type + ":";
1915 String mappedFlag = null;
1916 for (String mapping : TextUtils.split(typesConfig, ",")) {
1917 if (mapping.startsWith(mappingPrefix)) {
1918 mappedFlag = mapping.substring(mappingPrefix.length());
1919 break;
1920 }
1921 }
1922
1923 if (mappedFlag == null) return false;
1924
1925 return mDeps.isFeatureEnabled(mContext,
1926 flagPrefix + mappedFlag + MDNS_ALLOWLIST_FLAG_SUFFIX);
1927 }
1928
1929 private boolean useDiscoveryManagerForType(@Nullable String type) {
1930 return isTypeAllowlistedForJavaBackend(type, MDNS_DISCOVERY_MANAGER_ALLOWLIST_FLAG_PREFIX);
1931 }
1932
1933 private boolean useAdvertiserForType(@Nullable String type) {
1934 return isTypeAllowlistedForJavaBackend(type, MDNS_ADVERTISER_ALLOWLIST_FLAG_PREFIX);
1935 }
1936
paulhu1b35e822022-04-08 14:48:41 +08001937 public static NsdService create(Context context) {
Hugo Benichi803a2f02017-04-24 11:35:06 +09001938 HandlerThread thread = new HandlerThread(TAG);
1939 thread.start();
1940 Handler handler = new Handler(thread.getLooper());
paulhu2b9ed952022-02-10 21:58:32 +08001941 NsdService service = new NsdService(context, handler, CLEANUP_DELAY_MS);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07001942 return service;
1943 }
1944
paulhu2b9ed952022-02-10 21:58:32 +08001945 private static class MDnsEventCallback extends IMDnsEventListener.Stub {
1946 private final StateMachine mStateMachine;
1947
1948 MDnsEventCallback(StateMachine sm) {
1949 mStateMachine = sm;
1950 }
1951
1952 @Override
1953 public void onServiceRegistrationStatus(final RegistrationInfo status) {
1954 mStateMachine.sendMessage(
1955 MDNS_SERVICE_EVENT, status.result, status.id, status);
1956 }
1957
1958 @Override
1959 public void onServiceDiscoveryStatus(final DiscoveryInfo status) {
1960 mStateMachine.sendMessage(
1961 MDNS_SERVICE_EVENT, status.result, status.id, status);
1962 }
1963
1964 @Override
1965 public void onServiceResolutionStatus(final ResolutionInfo status) {
1966 mStateMachine.sendMessage(
1967 MDNS_SERVICE_EVENT, status.result, status.id, status);
1968 }
1969
1970 @Override
1971 public void onGettingServiceAddressStatus(final GetAddressInfo status) {
1972 mStateMachine.sendMessage(
1973 MDNS_SERVICE_EVENT, status.result, status.id, status);
1974 }
1975
1976 @Override
1977 public int getInterfaceVersion() throws RemoteException {
1978 return this.VERSION;
1979 }
1980
1981 @Override
1982 public String getInterfaceHash() throws RemoteException {
1983 return this.HASH;
1984 }
1985 }
1986
Yuyang Huangc275a9e2023-08-25 18:03:22 +09001987 private void sendAllOffloadServiceInfos(@NonNull OffloadEngineInfo offloadEngineInfo) {
1988 final String targetInterface = offloadEngineInfo.mInterfaceName;
1989 final IOffloadEngine offloadEngine = offloadEngineInfo.mOffloadEngine;
1990 final List<MdnsAdvertiser.OffloadServiceInfoWrapper> offloadWrappers =
1991 mAdvertiser.getAllInterfaceOffloadServiceInfos(targetInterface);
1992 for (MdnsAdvertiser.OffloadServiceInfoWrapper wrapper : offloadWrappers) {
1993 try {
1994 offloadEngine.onOffloadServiceUpdated(wrapper.mOffloadServiceInfo);
1995 } catch (RemoteException e) {
1996 // Can happen in regular cases, do not log a stacktrace
1997 Log.i(TAG, "Failed to send offload callback, remote died: " + e.getMessage());
1998 }
1999 }
2000 }
2001
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002002 private void sendOffloadServiceInfosUpdate(@NonNull String targetInterfaceName,
2003 @NonNull OffloadServiceInfo offloadServiceInfo, boolean isRemove) {
2004 final int count = mOffloadEngines.beginBroadcast();
2005 try {
2006 for (int i = 0; i < count; i++) {
2007 final OffloadEngineInfo offloadEngineInfo =
2008 (OffloadEngineInfo) mOffloadEngines.getBroadcastCookie(i);
2009 final String interfaceName = offloadEngineInfo.mInterfaceName;
2010 if (!targetInterfaceName.equals(interfaceName)
2011 || ((offloadEngineInfo.mOffloadType
2012 & offloadServiceInfo.getOffloadType()) == 0)) {
2013 continue;
2014 }
2015 try {
2016 if (isRemove) {
2017 mOffloadEngines.getBroadcastItem(i).onOffloadServiceRemoved(
2018 offloadServiceInfo);
2019 } else {
2020 mOffloadEngines.getBroadcastItem(i).onOffloadServiceUpdated(
2021 offloadServiceInfo);
2022 }
2023 } catch (RemoteException e) {
2024 // Can happen in regular cases, do not log a stacktrace
Yuyang Huangc275a9e2023-08-25 18:03:22 +09002025 Log.i(TAG, "Failed to send offload callback, remote died: " + e.getMessage());
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002026 }
2027 }
2028 } finally {
2029 mOffloadEngines.finishBroadcast();
2030 }
2031 }
2032
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002033 private class AdvertiserCallback implements MdnsAdvertiser.AdvertiserCallback {
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002034 // TODO: add a callback to notify when a service is being added on each interface (as soon
2035 // as probing starts), and call mOffloadCallbacks. This callback is for
2036 // OFFLOAD_CAPABILITY_FILTER_REPLIES offload type.
2037
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002038 @Override
Paul Hud44e1b72023-06-16 02:07:42 +00002039 public void onRegisterServiceSucceeded(int transactionId, NsdServiceInfo registeredInfo) {
2040 mServiceLogs.log("onRegisterServiceSucceeded: transactionId " + transactionId);
2041 final ClientInfo clientInfo = getClientInfoOrLog(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002042 if (clientInfo == null) return;
2043
Paul Hud44e1b72023-06-16 02:07:42 +00002044 final int clientRequestId = getClientRequestIdOrLog(clientInfo, transactionId);
2045 if (clientRequestId < 0) return;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002046
2047 // onRegisterServiceSucceeded only has the service name in its info. This aligns with
2048 // historical behavior.
2049 final NsdServiceInfo cbInfo = new NsdServiceInfo(registeredInfo.getServiceName(), null);
Paul Hu777ed052023-06-19 13:35:15 +00002050 final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
Paul Hu508a0122023-09-11 15:31:33 +08002051 clientInfo.onRegisterServiceSucceeded(clientRequestId, cbInfo, request);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002052 }
2053
2054 @Override
Paul Hud44e1b72023-06-16 02:07:42 +00002055 public void onRegisterServiceFailed(int transactionId, int errorCode) {
2056 final ClientInfo clientInfo = getClientInfoOrLog(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002057 if (clientInfo == null) return;
2058
Paul Hud44e1b72023-06-16 02:07:42 +00002059 final int clientRequestId = getClientRequestIdOrLog(clientInfo, transactionId);
2060 if (clientRequestId < 0) return;
Paul Hu777ed052023-06-19 13:35:15 +00002061 final ClientRequest request = clientInfo.mClientRequests.get(clientRequestId);
Paul Hu508a0122023-09-11 15:31:33 +08002062 clientInfo.onRegisterServiceFailed(clientRequestId, errorCode, false /* isLegacy */,
2063 transactionId, request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002064 }
2065
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002066 @Override
2067 public void onOffloadStartOrUpdate(@NonNull String interfaceName,
2068 @NonNull OffloadServiceInfo offloadServiceInfo) {
2069 sendOffloadServiceInfosUpdate(interfaceName, offloadServiceInfo, false /* isRemove */);
2070 }
2071
2072 @Override
2073 public void onOffloadStop(@NonNull String interfaceName,
2074 @NonNull OffloadServiceInfo offloadServiceInfo) {
2075 sendOffloadServiceInfosUpdate(interfaceName, offloadServiceInfo, true /* isRemove */);
2076 }
2077
Paul Hud44e1b72023-06-16 02:07:42 +00002078 private ClientInfo getClientInfoOrLog(int transactionId) {
2079 final ClientInfo clientInfo = mTransactionIdToClientInfoMap.get(transactionId);
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002080 if (clientInfo == null) {
Paul Hud44e1b72023-06-16 02:07:42 +00002081 Log.e(TAG, String.format("Callback for service %d has no client", transactionId));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002082 }
2083 return clientInfo;
2084 }
2085
Paul Hud44e1b72023-06-16 02:07:42 +00002086 private int getClientRequestIdOrLog(@NonNull ClientInfo info, int transactionId) {
2087 final int clientRequestId = info.getClientRequestId(transactionId);
2088 if (clientRequestId < 0) {
2089 Log.e(TAG, String.format(
2090 "Client request ID not found for service %d", transactionId));
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002091 }
Paul Hud44e1b72023-06-16 02:07:42 +00002092 return clientRequestId;
Remi NGUYEN VAN5b9074c2023-01-18 15:58:03 +09002093 }
2094 }
2095
Paul Hu2e0a88c2023-03-09 16:05:01 +08002096 private static class ConnectorArgs {
2097 @NonNull public final NsdServiceConnector connector;
2098 @NonNull public final INsdManagerCallback callback;
2099 public final boolean useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002100 public final int uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002101
2102 ConnectorArgs(@NonNull NsdServiceConnector connector, @NonNull INsdManagerCallback callback,
Paul Hub2e67d32023-04-18 05:50:14 +00002103 boolean useJavaBackend, int uid) {
Paul Hu2e0a88c2023-03-09 16:05:01 +08002104 this.connector = connector;
2105 this.callback = callback;
2106 this.useJavaBackend = useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002107 this.uid = uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002108 }
2109 }
2110
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002111 @Override
Paul Hu2e0a88c2023-03-09 16:05:01 +08002112 public INsdServiceConnector connect(INsdManagerCallback cb, boolean useJavaBackend) {
Hugo Benichi803a2f02017-04-24 11:35:06 +09002113 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
Paul Hu101dbf52023-08-09 16:05:20 +08002114 final int uid = mDeps.getCallingUid();
2115 if (cb == null) {
2116 throw new IllegalArgumentException("Unknown client callback from uid=" + uid);
2117 }
Paul Hu2e0a88c2023-03-09 16:05:01 +08002118 if (DBG) Log.d(TAG, "New client connect. useJavaBackend=" + useJavaBackend);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002119 final INsdServiceConnector connector = new NsdServiceConnector();
Paul Hub2e67d32023-04-18 05:50:14 +00002120 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.REGISTER_CLIENT,
Paul Hu101dbf52023-08-09 16:05:20 +08002121 new ConnectorArgs((NsdServiceConnector) connector, cb, useJavaBackend, uid)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002122 return connector;
Irfan Sheriff75006652012-04-17 23:15:29 -07002123 }
2124
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002125 private static class ListenerArgs {
2126 public final NsdServiceConnector connector;
2127 public final NsdServiceInfo serviceInfo;
2128 ListenerArgs(NsdServiceConnector connector, NsdServiceInfo serviceInfo) {
2129 this.connector = connector;
2130 this.serviceInfo = serviceInfo;
2131 }
2132 }
2133
Yuyang Huang86d083f2023-12-12 19:56:41 +09002134 private static class AdvertisingArgs {
2135 public final NsdServiceConnector connector;
2136 public final AdvertisingRequest advertisingRequest;
2137
2138 AdvertisingArgs(NsdServiceConnector connector, AdvertisingRequest advertisingRequest) {
2139 this.connector = connector;
2140 this.advertisingRequest = advertisingRequest;
2141 }
2142 }
2143
Kangping Dong1f1a3792023-12-10 22:05:04 +08002144 private static final class DiscoveryArgs {
2145 public final NsdServiceConnector connector;
2146 public final DiscoveryRequest discoveryRequest;
2147 DiscoveryArgs(NsdServiceConnector connector, DiscoveryRequest discoveryRequest) {
2148 this.connector = connector;
2149 this.discoveryRequest = discoveryRequest;
2150 }
2151 }
2152
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002153 private class NsdServiceConnector extends INsdServiceConnector.Stub
2154 implements IBinder.DeathRecipient {
Yuyang Huang86d083f2023-12-12 19:56:41 +09002155
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002156 @Override
Yuyang Huang86d083f2023-12-12 19:56:41 +09002157 public void registerService(int listenerKey, AdvertisingRequest advertisingRequest)
2158 throws RemoteException {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002159 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2160 NsdManager.REGISTER_SERVICE, 0, listenerKey,
Yuyang Huang86d083f2023-12-12 19:56:41 +09002161 new AdvertisingArgs(this, advertisingRequest)
2162 ));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002163 }
2164
2165 @Override
2166 public void unregisterService(int listenerKey) {
2167 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2168 NsdManager.UNREGISTER_SERVICE, 0, listenerKey,
Yuyang Huang86d083f2023-12-12 19:56:41 +09002169 new ListenerArgs(this, (NsdServiceInfo) null)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002170 }
2171
2172 @Override
Kangping Dong1f1a3792023-12-10 22:05:04 +08002173 public void discoverServices(int listenerKey, DiscoveryRequest discoveryRequest) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002174 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2175 NsdManager.DISCOVER_SERVICES, 0, listenerKey,
Kangping Dong1f1a3792023-12-10 22:05:04 +08002176 new DiscoveryArgs(this, discoveryRequest)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002177 }
2178
2179 @Override
2180 public void stopDiscovery(int listenerKey) {
Yuyang Huang86d083f2023-12-12 19:56:41 +09002181 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.STOP_DISCOVERY,
2182 0, listenerKey, new ListenerArgs(this, (NsdServiceInfo) null)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002183 }
2184
2185 @Override
2186 public void resolveService(int listenerKey, NsdServiceInfo serviceInfo) {
2187 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2188 NsdManager.RESOLVE_SERVICE, 0, listenerKey,
2189 new ListenerArgs(this, serviceInfo)));
2190 }
2191
2192 @Override
Paul Hub58deb72022-12-26 09:24:42 +00002193 public void stopResolution(int listenerKey) {
Yuyang Huang86d083f2023-12-12 19:56:41 +09002194 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.STOP_RESOLUTION,
2195 0, listenerKey, new ListenerArgs(this, (NsdServiceInfo) null)));
Paul Hub58deb72022-12-26 09:24:42 +00002196 }
2197
2198 @Override
Paul Hu18aeccc2022-12-27 08:48:48 +00002199 public void registerServiceInfoCallback(int listenerKey, NsdServiceInfo serviceInfo) {
2200 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2201 NsdManager.REGISTER_SERVICE_CALLBACK, 0, listenerKey,
2202 new ListenerArgs(this, serviceInfo)));
2203 }
2204
2205 @Override
2206 public void unregisterServiceInfoCallback(int listenerKey) {
2207 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(
2208 NsdManager.UNREGISTER_SERVICE_CALLBACK, 0, listenerKey,
Yuyang Huang86d083f2023-12-12 19:56:41 +09002209 new ListenerArgs(this, (NsdServiceInfo) null)));
Paul Hu18aeccc2022-12-27 08:48:48 +00002210 }
2211
2212 @Override
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002213 public void startDaemon() {
Yuyang Huang86d083f2023-12-12 19:56:41 +09002214 mNsdStateMachine.sendMessage(mNsdStateMachine.obtainMessage(NsdManager.DAEMON_STARTUP,
2215 new ListenerArgs(this, (NsdServiceInfo) null)));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002216 }
2217
2218 @Override
2219 public void binderDied() {
2220 mNsdStateMachine.sendMessage(
2221 mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_CLIENT, this));
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002222
2223 }
2224
2225 @Override
2226 public void registerOffloadEngine(String ifaceName, IOffloadEngine cb,
2227 @OffloadEngine.OffloadCapability long offloadCapabilities,
2228 @OffloadEngine.OffloadType long offloadTypes) {
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002229 checkOffloadEnginePermission(mContext);
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002230 Objects.requireNonNull(ifaceName);
2231 Objects.requireNonNull(cb);
2232 mNsdStateMachine.sendMessage(
2233 mNsdStateMachine.obtainMessage(NsdManager.REGISTER_OFFLOAD_ENGINE,
2234 new OffloadEngineInfo(cb, ifaceName, offloadCapabilities,
2235 offloadTypes)));
2236 }
2237
2238 @Override
2239 public void unregisterOffloadEngine(IOffloadEngine cb) {
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002240 checkOffloadEnginePermission(mContext);
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002241 Objects.requireNonNull(cb);
2242 mNsdStateMachine.sendMessage(
2243 mNsdStateMachine.obtainMessage(NsdManager.UNREGISTER_OFFLOAD_ENGINE, cb));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002244 }
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002245
2246 private static void checkOffloadEnginePermission(Context context) {
2247 if (!SdkLevel.isAtLeastT()) {
2248 throw new SecurityException("API is not available in before API level 33");
2249 }
Yuyang Huangd5896e72023-11-28 13:23:59 +09002250
Ken Chena7bae552023-12-27 11:40:57 +08002251 final ArrayList<String> permissionsList = new ArrayList<>(Arrays.asList(NETWORK_STACK,
2252 PERMISSION_MAINLINE_NETWORK_STACK, NETWORK_SETTINGS));
2253
2254 if (SdkLevel.isAtLeastV()) {
2255 // REGISTER_NSD_OFFLOAD_ENGINE was only added to the SDK in V.
2256 permissionsList.add(REGISTER_NSD_OFFLOAD_ENGINE);
2257 } else if (SdkLevel.isAtLeastU()) {
2258 // REGISTER_NSD_OFFLOAD_ENGINE cannot be backport to U. In U, check the DEVICE_POWER
2259 // permission instead.
2260 permissionsList.add(DEVICE_POWER);
Yuyang Huangd5896e72023-11-28 13:23:59 +09002261 }
2262
Ken Chena7bae552023-12-27 11:40:57 +08002263 if (PermissionUtils.checkAnyPermissionOf(context,
2264 permissionsList.toArray(new String[0]))) {
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002265 return;
2266 }
2267 throw new SecurityException("Requires one of the following permissions: "
Ken Chena7bae552023-12-27 11:40:57 +08002268 + String.join(", ", permissionsList) + ".");
Yuyang Huang8e6fbc82023-08-07 17:46:19 +09002269 }
Irfan Sheriff75006652012-04-17 23:15:29 -07002270 }
2271
Hugo Benichi912db992017-04-24 16:41:03 +09002272 private void sendNsdStateChangeBroadcast(boolean isEnabled) {
Irfan Sheriff52fc83a2012-04-19 10:26:34 -07002273 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff75006652012-04-17 23:15:29 -07002274 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Hugo Benichi912db992017-04-24 16:41:03 +09002275 int nsdState = isEnabled ? NsdManager.NSD_STATE_ENABLED : NsdManager.NSD_STATE_DISABLED;
2276 intent.putExtra(NsdManager.EXTRA_NSD_STATE, nsdState);
Dianne Hackborn692107e2012-08-29 18:32:08 -07002277 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff75006652012-04-17 23:15:29 -07002278 }
2279
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002280 private int getUniqueId() {
2281 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
2282 return mUniqueId;
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002283 }
2284
Paul Hud44e1b72023-06-16 02:07:42 +00002285 private boolean registerService(int transactionId, NsdServiceInfo service) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002286 if (mMDnsManager == null) {
2287 Log.wtf(TAG, "registerService: mMDnsManager is null");
2288 return false;
2289 }
2290
Hugo Benichi6d706442017-04-24 16:19:58 +09002291 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00002292 Log.d(TAG, "registerService: " + transactionId + " " + service);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002293 }
Hugo Benichi6d706442017-04-24 16:19:58 +09002294 String name = service.getServiceName();
2295 String type = service.getServiceType();
2296 int port = service.getPort();
2297 byte[] textRecord = service.getTxtRecord();
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09002298 final int registerInterface = getNetworkInterfaceIndex(service);
2299 if (service.getNetwork() != null && registerInterface == IFACE_IDX_ANY) {
Paul Hu360a8e92022-04-26 11:14:14 +08002300 Log.e(TAG, "Interface to register service on not found");
2301 return false;
2302 }
Paul Hud44e1b72023-06-16 02:07:42 +00002303 return mMDnsManager.registerService(
2304 transactionId, name, type, port, textRecord, registerInterface);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002305 }
2306
Paul Hud44e1b72023-06-16 02:07:42 +00002307 private boolean unregisterService(int transactionId) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002308 if (mMDnsManager == null) {
2309 Log.wtf(TAG, "unregisterService: mMDnsManager is null");
2310 return false;
2311 }
Paul Hud44e1b72023-06-16 02:07:42 +00002312 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002313 }
2314
Kangping Dong1f1a3792023-12-10 22:05:04 +08002315 private boolean discoverServices(int transactionId, DiscoveryRequest discoveryRequest) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002316 if (mMDnsManager == null) {
2317 Log.wtf(TAG, "discoverServices: mMDnsManager is null");
2318 return false;
2319 }
2320
Kangping Dong1f1a3792023-12-10 22:05:04 +08002321 final String type = discoveryRequest.getServiceType();
2322 final int discoverInterface = getNetworkInterfaceIndex(discoveryRequest);
2323 if (discoveryRequest.getNetwork() != null && discoverInterface == IFACE_IDX_ANY) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002324 Log.e(TAG, "Interface to discover service on not found");
2325 return false;
2326 }
Paul Hud44e1b72023-06-16 02:07:42 +00002327 return mMDnsManager.discover(transactionId, type, discoverInterface);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002328 }
2329
Paul Hud44e1b72023-06-16 02:07:42 +00002330 private boolean stopServiceDiscovery(int transactionId) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002331 if (mMDnsManager == null) {
2332 Log.wtf(TAG, "stopServiceDiscovery: mMDnsManager is null");
2333 return false;
2334 }
Paul Hud44e1b72023-06-16 02:07:42 +00002335 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002336 }
2337
Paul Hud44e1b72023-06-16 02:07:42 +00002338 private boolean resolveService(int transactionId, NsdServiceInfo service) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002339 if (mMDnsManager == null) {
2340 Log.wtf(TAG, "resolveService: mMDnsManager is null");
2341 return false;
2342 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002343 final String name = service.getServiceName();
2344 final String type = service.getServiceType();
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09002345 final int resolveInterface = getNetworkInterfaceIndex(service);
2346 if (service.getNetwork() != null && resolveInterface == IFACE_IDX_ANY) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002347 Log.e(TAG, "Interface to resolve service on not found");
2348 return false;
2349 }
Paul Hud44e1b72023-06-16 02:07:42 +00002350 return mMDnsManager.resolve(transactionId, name, type, "local.", resolveInterface);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002351 }
2352
2353 /**
2354 * Guess the interface to use to resolve or discover a service on a specific network.
2355 *
2356 * This is an imperfect guess, as for example the network may be gone or not yet fully
2357 * registered. This is fine as failing is correct if the network is gone, and a client
2358 * attempting to resolve/discover on a network not yet setup would have a bad time anyway; also
2359 * this is to support the legacy mdnsresponder implementation, which historically resolved
2360 * services on an unspecified network.
2361 */
Remi NGUYEN VAN1a8ee102022-05-30 12:42:24 +09002362 private int getNetworkInterfaceIndex(NsdServiceInfo serviceInfo) {
2363 final Network network = serviceInfo.getNetwork();
2364 if (network == null) {
2365 // Fallback to getInterfaceIndex if present (typically if the NsdServiceInfo was
2366 // provided by NsdService from discovery results, and the service was found on an
2367 // interface that has no app-usable Network).
2368 if (serviceInfo.getInterfaceIndex() != 0) {
2369 return serviceInfo.getInterfaceIndex();
2370 }
2371 return IFACE_IDX_ANY;
2372 }
Kangping Dong1f1a3792023-12-10 22:05:04 +08002373 return getNetworkInterfaceIndex(network);
2374 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002375
Kangping Dong1f1a3792023-12-10 22:05:04 +08002376 /**
2377 * Returns the interface to use to discover a service on a specific network, or {@link
2378 * IFACE_IDX_ANY} if no network is specified.
2379 */
2380 private int getNetworkInterfaceIndex(DiscoveryRequest discoveryRequest) {
2381 final Network network = discoveryRequest.getNetwork();
2382 if (network == null) {
2383 return IFACE_IDX_ANY;
2384 }
2385 return getNetworkInterfaceIndex(network);
2386 }
2387
2388 /**
2389 * Returns the interface of a specific network, or {@link IFACE_IDX_ANY} if no interface is
2390 * associated with {@code network}.
2391 */
2392 private int getNetworkInterfaceIndex(@NonNull Network network) {
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002393 String interfaceName = getNetworkInterfaceName(network);
2394 if (interfaceName == null) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002395 return IFACE_IDX_ANY;
2396 }
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002397 return getNetworkInterfaceIndexByName(interfaceName);
2398 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002399
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002400 private String getNetworkInterfaceName(@Nullable Network network) {
2401 if (network == null) {
2402 return null;
2403 }
2404 final ConnectivityManager cm = mContext.getSystemService(ConnectivityManager.class);
2405 if (cm == null) {
2406 Log.wtf(TAG, "No ConnectivityManager");
2407 return null;
2408 }
2409 final LinkProperties lp = cm.getLinkProperties(network);
2410 if (lp == null) {
2411 return null;
2412 }
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002413 // Only resolve on non-stacked interfaces
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002414 return lp.getInterfaceName();
2415 }
2416
2417 private int getNetworkInterfaceIndexByName(final String ifaceName) {
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002418 final NetworkInterface iface;
2419 try {
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002420 iface = NetworkInterface.getByName(ifaceName);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002421 } catch (SocketException e) {
2422 Log.e(TAG, "Error querying interface", e);
2423 return IFACE_IDX_ANY;
2424 }
2425
2426 if (iface == null) {
Yuyang Huang33fa4d22023-02-14 22:59:37 +09002427 Log.e(TAG, "Interface not found: " + ifaceName);
Remi NGUYEN VAN23651302021-12-16 15:31:16 +09002428 return IFACE_IDX_ANY;
2429 }
2430
2431 return iface.getIndex();
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002432 }
2433
Paul Hud44e1b72023-06-16 02:07:42 +00002434 private boolean stopResolveService(int transactionId) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002435 if (mMDnsManager == null) {
2436 Log.wtf(TAG, "stopResolveService: mMDnsManager is null");
2437 return false;
2438 }
Paul Hud44e1b72023-06-16 02:07:42 +00002439 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002440 }
2441
Paul Hud44e1b72023-06-16 02:07:42 +00002442 private boolean getAddrInfo(int transactionId, String hostname, int interfaceIdx) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002443 if (mMDnsManager == null) {
2444 Log.wtf(TAG, "getAddrInfo: mMDnsManager is null");
2445 return false;
2446 }
Paul Hud44e1b72023-06-16 02:07:42 +00002447 return mMDnsManager.getServiceAddress(transactionId, hostname, interfaceIdx);
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002448 }
2449
Paul Hud44e1b72023-06-16 02:07:42 +00002450 private boolean stopGetAddrInfo(int transactionId) {
Ken Chen80c9f6f2023-11-15 18:24:54 +08002451 if (mMDnsManager == null) {
2452 Log.wtf(TAG, "stopGetAddrInfo: mMDnsManager is null");
2453 return false;
2454 }
Paul Hud44e1b72023-06-16 02:07:42 +00002455 return mMDnsManager.stopOperation(transactionId);
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002456 }
2457
2458 @Override
Paul Hub2e67d32023-04-18 05:50:14 +00002459 public void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
2460 if (!PermissionUtils.checkDumpPermission(mContext, TAG, writer)) return;
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002461
Paul Hub2e67d32023-04-18 05:50:14 +00002462 final IndentingPrintWriter pw = new IndentingPrintWriter(writer, " ");
2463 // Dump state machine logs
Irfan Sheriff75006652012-04-17 23:15:29 -07002464 mNsdStateMachine.dump(fd, pw, args);
Paul Hub2e67d32023-04-18 05:50:14 +00002465
2466 // Dump service and clients logs
2467 pw.println();
Paul Hu14667de2023-04-17 22:42:47 +08002468 pw.println("Logs:");
Paul Hub2e67d32023-04-18 05:50:14 +00002469 pw.increaseIndent();
2470 mServiceLogs.reverseDump(pw);
2471 pw.decreaseIndent();
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002472 }
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002473
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002474 private abstract static class ClientRequest {
Paul Hud44e1b72023-06-16 02:07:42 +00002475 private final int mTransactionId;
Paul Hu777ed052023-06-19 13:35:15 +00002476 private final long mStartTimeMs;
Paul Hu812e9212023-06-20 06:24:53 +00002477 private int mFoundServiceCount = 0;
2478 private int mLostServiceCount = 0;
2479 private final Set<String> mServices = new ArraySet<>();
Paul Hua6bc4632023-06-26 01:18:29 +00002480 private boolean mIsServiceFromCache = false;
Paul Hubad6fe92023-07-24 21:25:22 +08002481 private int mSentQueryCount = NO_SENT_QUERY_COUNT;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002482
Paul Hu812e9212023-06-20 06:24:53 +00002483 private ClientRequest(int transactionId, long startTimeMs) {
Paul Hud44e1b72023-06-16 02:07:42 +00002484 mTransactionId = transactionId;
Paul Hu777ed052023-06-19 13:35:15 +00002485 mStartTimeMs = startTimeMs;
2486 }
2487
Paul Hu812e9212023-06-20 06:24:53 +00002488 public long calculateRequestDurationMs(long stopTimeMs) {
Paul Hu777ed052023-06-19 13:35:15 +00002489 return stopTimeMs - mStartTimeMs;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002490 }
Paul Hu812e9212023-06-20 06:24:53 +00002491
2492 public void onServiceFound(String serviceName) {
2493 mFoundServiceCount++;
2494 if (mServices.size() <= MAX_SERVICES_COUNT_METRIC_PER_CLIENT) {
2495 mServices.add(serviceName);
2496 }
2497 }
2498
2499 public void onServiceLost() {
2500 mLostServiceCount++;
2501 }
2502
2503 public int getFoundServiceCount() {
2504 return mFoundServiceCount;
2505 }
2506
2507 public int getLostServiceCount() {
2508 return mLostServiceCount;
2509 }
2510
2511 public int getServicesCount() {
2512 return mServices.size();
2513 }
Paul Hua6bc4632023-06-26 01:18:29 +00002514
2515 public void setServiceFromCache(boolean isServiceFromCache) {
2516 mIsServiceFromCache = isServiceFromCache;
2517 }
2518
2519 public boolean isServiceFromCache() {
2520 return mIsServiceFromCache;
2521 }
Paul Hubad6fe92023-07-24 21:25:22 +08002522
2523 public void onQuerySent() {
2524 mSentQueryCount++;
2525 }
2526
2527 public int getSentQueryCount() {
2528 return mSentQueryCount;
2529 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002530 }
2531
2532 private static class LegacyClientRequest extends ClientRequest {
2533 private final int mRequestCode;
2534
Paul Hu812e9212023-06-20 06:24:53 +00002535 private LegacyClientRequest(int transactionId, int requestCode, long startTimeMs) {
2536 super(transactionId, startTimeMs);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002537 mRequestCode = requestCode;
2538 }
2539 }
2540
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002541 private abstract static class JavaBackendClientRequest extends ClientRequest {
2542 @Nullable
2543 private final Network mRequestedNetwork;
2544
Paul Hu777ed052023-06-19 13:35:15 +00002545 private JavaBackendClientRequest(int transactionId, @Nullable Network requestedNetwork,
Paul Hu812e9212023-06-20 06:24:53 +00002546 long startTimeMs) {
2547 super(transactionId, startTimeMs);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002548 mRequestedNetwork = requestedNetwork;
2549 }
2550
2551 @Nullable
2552 public Network getRequestedNetwork() {
2553 return mRequestedNetwork;
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002554 }
2555 }
2556
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002557 private static class AdvertiserClientRequest extends JavaBackendClientRequest {
Paul Hu777ed052023-06-19 13:35:15 +00002558 private AdvertiserClientRequest(int transactionId, @Nullable Network requestedNetwork,
Paul Hu812e9212023-06-20 06:24:53 +00002559 long startTimeMs) {
2560 super(transactionId, requestedNetwork, startTimeMs);
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002561 }
2562 }
2563
2564 private static class DiscoveryManagerRequest extends JavaBackendClientRequest {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002565 @NonNull
2566 private final MdnsListener mListener;
2567
Paul Hud44e1b72023-06-16 02:07:42 +00002568 private DiscoveryManagerRequest(int transactionId, @NonNull MdnsListener listener,
Paul Hu812e9212023-06-20 06:24:53 +00002569 @Nullable Network requestedNetwork, long startTimeMs) {
2570 super(transactionId, requestedNetwork, startTimeMs);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002571 mListener = listener;
2572 }
2573 }
2574
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002575 /* Information tracked per client */
2576 private class ClientInfo {
2577
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07002578 private static final int MAX_LIMIT = 10;
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002579 private final INsdManagerCallback mCb;
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002580 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriffe4c42f42012-05-03 16:44:27 -07002581 private NsdServiceInfo mResolvedService;
2582
Paul Hud44e1b72023-06-16 02:07:42 +00002583 /* A map from client request ID (listenerKey) to the request */
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002584 private final SparseArray<ClientRequest> mClientRequests = new SparseArray<>();
Paul Hu23fa2022023-01-13 22:57:24 +08002585
Luke Huangf7277ed2021-07-12 21:15:10 +08002586 // The target SDK of this client < Build.VERSION_CODES.S
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002587 private boolean mIsPreSClient = false;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002588 private final int mUid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002589 // The flag of using java backend if the client's target SDK >= U
2590 private final boolean mUseJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002591 // Store client logs
2592 private final SharedLog mClientLogs;
Paul Hucdef3532023-06-18 14:47:35 +00002593 // Report the nsd metrics data
2594 private final NetworkNsdReportedMetrics mMetrics;
Luke Huangf7277ed2021-07-12 21:15:10 +08002595
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002596 private ClientInfo(INsdManagerCallback cb, int uid, boolean useJavaBackend,
Paul Hucdef3532023-06-18 14:47:35 +00002597 SharedLog sharedLog, NetworkNsdReportedMetrics metrics) {
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002598 mCb = cb;
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002599 mUid = uid;
Paul Hu2e0a88c2023-03-09 16:05:01 +08002600 mUseJavaBackend = useJavaBackend;
Paul Hub2e67d32023-04-18 05:50:14 +00002601 mClientLogs = sharedLog;
2602 mClientLogs.log("New client. useJavaBackend=" + useJavaBackend);
Paul Hucdef3532023-06-18 14:47:35 +00002603 mMetrics = metrics;
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002604 }
Irfan Sheriff75006652012-04-17 23:15:29 -07002605
2606 @Override
2607 public String toString() {
Jeff Sharkey63465382020-10-17 21:20:13 -06002608 StringBuilder sb = new StringBuilder();
Irfan Sheriff75006652012-04-17 23:15:29 -07002609 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002610 sb.append("mIsLegacy ").append(mIsPreSClient).append("\n");
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002611 sb.append("mUseJavaBackend ").append(mUseJavaBackend).append("\n");
2612 sb.append("mUid ").append(mUid).append("\n");
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002613 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002614 int clientRequestId = mClientRequests.keyAt(i);
2615 sb.append("clientRequestId ")
2616 .append(clientRequestId)
2617 .append(" transactionId ").append(mClientRequests.valueAt(i).mTransactionId)
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002618 .append(" type ").append(
2619 mClientRequests.valueAt(i).getClass().getSimpleName())
2620 .append("\n");
Irfan Sheriff75006652012-04-17 23:15:29 -07002621 }
2622 return sb.toString();
2623 }
Dave Plattfeff2af2014-03-07 14:48:22 -08002624
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002625 private boolean isPreSClient() {
2626 return mIsPreSClient;
Luke Huangf7277ed2021-07-12 21:15:10 +08002627 }
2628
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002629 private void setPreSClient() {
2630 mIsPreSClient = true;
Luke Huangf7277ed2021-07-12 21:15:10 +08002631 }
2632
Paul Hu812e9212023-06-20 06:24:53 +00002633 private MdnsListener unregisterMdnsListenerFromRequest(ClientRequest request) {
Paul Hue4f5f252023-02-16 21:13:47 +08002634 final MdnsListener listener =
2635 ((DiscoveryManagerRequest) request).mListener;
2636 mMdnsDiscoveryManager.unregisterListener(
2637 listener.getListenedServiceType(), listener);
Paul Hu812e9212023-06-20 06:24:53 +00002638 return listener;
Paul Hue4f5f252023-02-16 21:13:47 +08002639 }
2640
Dave Plattfeff2af2014-03-07 14:48:22 -08002641 // Remove any pending requests from the global map when we get rid of a client,
2642 // and send cancellations to the daemon.
2643 private void expungeAllRequests() {
Paul Hub2e67d32023-04-18 05:50:14 +00002644 mClientLogs.log("Client unregistered. expungeAllRequests!");
Hugo Benichid2552ae2017-04-11 14:42:47 +09002645 // TODO: to keep handler responsive, do not clean all requests for that client at once.
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002646 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002647 final int clientRequestId = mClientRequests.keyAt(i);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002648 final ClientRequest request = mClientRequests.valueAt(i);
Paul Hud44e1b72023-06-16 02:07:42 +00002649 final int transactionId = request.mTransactionId;
2650 mTransactionIdToClientInfoMap.remove(transactionId);
paulhub2225702021-11-17 09:35:33 +08002651 if (DBG) {
Paul Hud44e1b72023-06-16 02:07:42 +00002652 Log.d(TAG, "Terminating clientRequestId " + clientRequestId
2653 + " transactionId " + transactionId
2654 + " type " + mClientRequests.get(clientRequestId));
paulhub2225702021-11-17 09:35:33 +08002655 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002656
2657 if (request instanceof DiscoveryManagerRequest) {
Paul Hu812e9212023-06-20 06:24:53 +00002658 final MdnsListener listener = unregisterMdnsListenerFromRequest(request);
2659 if (listener instanceof DiscoveryListener) {
Paul Hu508a0122023-09-11 15:31:33 +08002660 mMetrics.reportServiceDiscoveryStop(false /* isLegacy */, transactionId,
Paul Hu812e9212023-06-20 06:24:53 +00002661 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2662 request.getFoundServiceCount(),
2663 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002664 request.getServicesCount(),
2665 request.getSentQueryCount());
Paul Hu60149052023-07-31 14:26:08 +08002666 } else if (listener instanceof ResolutionListener) {
Paul Hu508a0122023-09-11 15:31:33 +08002667 mMetrics.reportServiceResolutionStop(false /* isLegacy */, transactionId,
Paul Hu60149052023-07-31 14:26:08 +08002668 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Huddce5912023-08-01 10:26:49 +08002669 } else if (listener instanceof ServiceInfoListener) {
2670 mMetrics.reportServiceInfoCallbackUnregistered(transactionId,
2671 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2672 request.getFoundServiceCount(),
2673 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002674 request.isServiceFromCache(),
2675 request.getSentQueryCount());
Paul Hu812e9212023-06-20 06:24:53 +00002676 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002677 continue;
2678 }
2679
2680 if (request instanceof AdvertiserClientRequest) {
Paul Hu043bcd42023-07-14 16:38:25 +08002681 final AdvertiserMetrics metrics =
2682 mAdvertiser.getAdvertiserMetrics(transactionId);
Paul Hud44e1b72023-06-16 02:07:42 +00002683 mAdvertiser.removeService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08002684 mMetrics.reportServiceUnregistration(false /* isLegacy */, transactionId,
Paul Hu043bcd42023-07-14 16:38:25 +08002685 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2686 metrics.mRepliedRequestsCount, metrics.mSentPacketCount,
2687 metrics.mConflictDuringProbingCount,
2688 metrics.mConflictAfterProbingCount);
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002689 continue;
2690 }
2691
2692 if (!(request instanceof LegacyClientRequest)) {
2693 throw new IllegalStateException("Unknown request type: " + request.getClass());
2694 }
2695
2696 switch (((LegacyClientRequest) request).mRequestCode) {
Dave Plattfeff2af2014-03-07 14:48:22 -08002697 case NsdManager.DISCOVER_SERVICES:
Paul Hud44e1b72023-06-16 02:07:42 +00002698 stopServiceDiscovery(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08002699 mMetrics.reportServiceDiscoveryStop(true /* isLegacy */, transactionId,
Paul Hu812e9212023-06-20 06:24:53 +00002700 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2701 request.getFoundServiceCount(),
2702 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002703 request.getServicesCount(),
2704 NO_SENT_QUERY_COUNT);
Dave Plattfeff2af2014-03-07 14:48:22 -08002705 break;
2706 case NsdManager.RESOLVE_SERVICE:
Paul Hud44e1b72023-06-16 02:07:42 +00002707 stopResolveService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08002708 mMetrics.reportServiceResolutionStop(true /* isLegacy */, transactionId,
Paul Hu60149052023-07-31 14:26:08 +08002709 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Dave Plattfeff2af2014-03-07 14:48:22 -08002710 break;
2711 case NsdManager.REGISTER_SERVICE:
Paul Hud44e1b72023-06-16 02:07:42 +00002712 unregisterService(transactionId);
Paul Hu508a0122023-09-11 15:31:33 +08002713 mMetrics.reportServiceUnregistration(true /* isLegacy */, transactionId,
Paul Hu043bcd42023-07-14 16:38:25 +08002714 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2715 NO_PACKET /* repliedRequestsCount */,
2716 NO_PACKET /* sentPacketCount */,
2717 0 /* conflictDuringProbingCount */,
2718 0 /* conflictAfterProbingCount */);
Dave Plattfeff2af2014-03-07 14:48:22 -08002719 break;
2720 default:
2721 break;
2722 }
2723 }
Dave Plattfeff2af2014-03-07 14:48:22 -08002724 mClientRequests.clear();
Remi NGUYEN VANa8efbe02023-05-26 11:43:20 +09002725 updateMulticastLock();
2726 }
2727
2728 /**
2729 * Returns true if this client has any Java backend request that requests one of the given
2730 * networks.
2731 */
2732 boolean hasAnyJavaBackendRequestForNetworks(@NonNull ArraySet<Network> networks) {
2733 for (int i = 0; i < mClientRequests.size(); i++) {
2734 final ClientRequest req = mClientRequests.valueAt(i);
2735 if (!(req instanceof JavaBackendClientRequest)) {
2736 continue;
2737 }
2738 final Network reqNetwork = ((JavaBackendClientRequest) mClientRequests.valueAt(i))
2739 .getRequestedNetwork();
2740 if (MdnsUtils.isAnyNetworkMatched(reqNetwork, networks)) {
2741 return true;
2742 }
2743 }
2744 return false;
Dave Plattfeff2af2014-03-07 14:48:22 -08002745 }
2746
Paul Hud44e1b72023-06-16 02:07:42 +00002747 // mClientRequests is a sparse array of client request id -> ClientRequest. For a given
2748 // transaction id, return the corresponding client request id.
2749 private int getClientRequestId(final int transactionId) {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002750 for (int i = 0; i < mClientRequests.size(); i++) {
Paul Hud44e1b72023-06-16 02:07:42 +00002751 if (mClientRequests.valueAt(i).mTransactionId == transactionId) {
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002752 return mClientRequests.keyAt(i);
2753 }
Christopher Lane74411222014-04-25 18:39:07 -07002754 }
Remi NGUYEN VAN8f453b92023-01-18 17:44:36 +09002755 return -1;
Christopher Lane74411222014-04-25 18:39:07 -07002756 }
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002757
Paul Hub2e67d32023-04-18 05:50:14 +00002758 private void log(String message) {
2759 mClientLogs.log(message);
2760 }
2761
Paul Hu508a0122023-09-11 15:31:33 +08002762 private static boolean isLegacyClientRequest(@NonNull ClientRequest request) {
2763 return !(request instanceof DiscoveryManagerRequest)
2764 && !(request instanceof AdvertiserClientRequest);
2765 }
2766
Kangping Dong1f1a3792023-12-10 22:05:04 +08002767 void onDiscoverServicesStarted(int listenerKey, DiscoveryRequest discoveryRequest,
Paul Hu508a0122023-09-11 15:31:33 +08002768 ClientRequest request) {
2769 mMetrics.reportServiceDiscoveryStarted(
2770 isLegacyClientRequest(request), request.mTransactionId);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002771 try {
Kangping Dong1f1a3792023-12-10 22:05:04 +08002772 mCb.onDiscoverServicesStarted(listenerKey, discoveryRequest);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002773 } catch (RemoteException e) {
2774 Log.e(TAG, "Error calling onDiscoverServicesStarted", e);
2775 }
2776 }
Paul Hu508a0122023-09-11 15:31:33 +08002777 void onDiscoverServicesFailedImmediately(int listenerKey, int error, boolean isLegacy) {
2778 onDiscoverServicesFailed(listenerKey, error, isLegacy, NO_TRANSACTION,
2779 0L /* durationMs */);
Paul Hu812e9212023-06-20 06:24:53 +00002780 }
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002781
Paul Hu508a0122023-09-11 15:31:33 +08002782 void onDiscoverServicesFailed(int listenerKey, int error, boolean isLegacy,
2783 int transactionId, long durationMs) {
2784 mMetrics.reportServiceDiscoveryFailed(isLegacy, transactionId, durationMs);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002785 try {
2786 mCb.onDiscoverServicesFailed(listenerKey, error);
2787 } catch (RemoteException e) {
2788 Log.e(TAG, "Error calling onDiscoverServicesFailed", e);
2789 }
2790 }
2791
Paul Hu812e9212023-06-20 06:24:53 +00002792 void onServiceFound(int listenerKey, NsdServiceInfo info, ClientRequest request) {
2793 request.onServiceFound(info.getServiceName());
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002794 try {
2795 mCb.onServiceFound(listenerKey, info);
2796 } catch (RemoteException e) {
2797 Log.e(TAG, "Error calling onServiceFound(", e);
2798 }
2799 }
2800
Paul Hu812e9212023-06-20 06:24:53 +00002801 void onServiceLost(int listenerKey, NsdServiceInfo info, ClientRequest request) {
2802 request.onServiceLost();
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002803 try {
2804 mCb.onServiceLost(listenerKey, info);
2805 } catch (RemoteException e) {
2806 Log.e(TAG, "Error calling onServiceLost(", e);
2807 }
2808 }
2809
2810 void onStopDiscoveryFailed(int listenerKey, int error) {
2811 try {
2812 mCb.onStopDiscoveryFailed(listenerKey, error);
2813 } catch (RemoteException e) {
2814 Log.e(TAG, "Error calling onStopDiscoveryFailed", e);
2815 }
2816 }
2817
Paul Hu812e9212023-06-20 06:24:53 +00002818 void onStopDiscoverySucceeded(int listenerKey, ClientRequest request) {
2819 mMetrics.reportServiceDiscoveryStop(
Paul Hu508a0122023-09-11 15:31:33 +08002820 isLegacyClientRequest(request),
Paul Hu812e9212023-06-20 06:24:53 +00002821 request.mTransactionId,
2822 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2823 request.getFoundServiceCount(),
2824 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002825 request.getServicesCount(),
2826 request.getSentQueryCount());
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002827 try {
2828 mCb.onStopDiscoverySucceeded(listenerKey);
2829 } catch (RemoteException e) {
2830 Log.e(TAG, "Error calling onStopDiscoverySucceeded", e);
2831 }
2832 }
2833
Paul Hu508a0122023-09-11 15:31:33 +08002834 void onRegisterServiceFailedImmediately(int listenerKey, int error, boolean isLegacy) {
2835 onRegisterServiceFailed(listenerKey, error, isLegacy, NO_TRANSACTION,
2836 0L /* durationMs */);
Paul Hu777ed052023-06-19 13:35:15 +00002837 }
2838
Paul Hu508a0122023-09-11 15:31:33 +08002839 void onRegisterServiceFailed(int listenerKey, int error, boolean isLegacy,
2840 int transactionId, long durationMs) {
2841 mMetrics.reportServiceRegistrationFailed(isLegacy, transactionId, durationMs);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002842 try {
2843 mCb.onRegisterServiceFailed(listenerKey, error);
2844 } catch (RemoteException e) {
2845 Log.e(TAG, "Error calling onRegisterServiceFailed", e);
2846 }
2847 }
2848
Paul Hu508a0122023-09-11 15:31:33 +08002849 void onRegisterServiceSucceeded(int listenerKey, NsdServiceInfo info,
2850 ClientRequest request) {
2851 mMetrics.reportServiceRegistrationSucceeded(isLegacyClientRequest(request),
2852 request.mTransactionId,
2853 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002854 try {
2855 mCb.onRegisterServiceSucceeded(listenerKey, info);
2856 } catch (RemoteException e) {
2857 Log.e(TAG, "Error calling onRegisterServiceSucceeded", e);
2858 }
2859 }
2860
2861 void onUnregisterServiceFailed(int listenerKey, int error) {
2862 try {
2863 mCb.onUnregisterServiceFailed(listenerKey, error);
2864 } catch (RemoteException e) {
2865 Log.e(TAG, "Error calling onUnregisterServiceFailed", e);
2866 }
2867 }
2868
Paul Hu508a0122023-09-11 15:31:33 +08002869 void onUnregisterServiceSucceeded(int listenerKey, ClientRequest request,
Paul Hu043bcd42023-07-14 16:38:25 +08002870 AdvertiserMetrics metrics) {
Paul Hu508a0122023-09-11 15:31:33 +08002871 mMetrics.reportServiceUnregistration(isLegacyClientRequest(request),
2872 request.mTransactionId,
2873 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
Paul Hu043bcd42023-07-14 16:38:25 +08002874 metrics.mRepliedRequestsCount, metrics.mSentPacketCount,
2875 metrics.mConflictDuringProbingCount, metrics.mConflictAfterProbingCount);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002876 try {
2877 mCb.onUnregisterServiceSucceeded(listenerKey);
2878 } catch (RemoteException e) {
2879 Log.e(TAG, "Error calling onUnregisterServiceSucceeded", e);
2880 }
2881 }
2882
Paul Hu508a0122023-09-11 15:31:33 +08002883 void onResolveServiceFailedImmediately(int listenerKey, int error, boolean isLegacy) {
2884 onResolveServiceFailed(listenerKey, error, isLegacy, NO_TRANSACTION,
2885 0L /* durationMs */);
Paul Hua6bc4632023-06-26 01:18:29 +00002886 }
2887
Paul Hu508a0122023-09-11 15:31:33 +08002888 void onResolveServiceFailed(int listenerKey, int error, boolean isLegacy,
2889 int transactionId, long durationMs) {
2890 mMetrics.reportServiceResolutionFailed(isLegacy, transactionId, durationMs);
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002891 try {
2892 mCb.onResolveServiceFailed(listenerKey, error);
2893 } catch (RemoteException e) {
2894 Log.e(TAG, "Error calling onResolveServiceFailed", e);
2895 }
2896 }
2897
Paul Hua6bc4632023-06-26 01:18:29 +00002898 void onResolveServiceSucceeded(int listenerKey, NsdServiceInfo info,
2899 ClientRequest request) {
2900 mMetrics.reportServiceResolved(
Paul Hu508a0122023-09-11 15:31:33 +08002901 isLegacyClientRequest(request),
Paul Hua6bc4632023-06-26 01:18:29 +00002902 request.mTransactionId,
2903 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
Paul Hubad6fe92023-07-24 21:25:22 +08002904 request.isServiceFromCache(),
2905 request.getSentQueryCount());
Remi NGUYEN VAN62eb76e2021-09-09 17:39:05 +09002906 try {
2907 mCb.onResolveServiceSucceeded(listenerKey, info);
2908 } catch (RemoteException e) {
2909 Log.e(TAG, "Error calling onResolveServiceSucceeded", e);
2910 }
2911 }
Paul Hub58deb72022-12-26 09:24:42 +00002912
2913 void onStopResolutionFailed(int listenerKey, int error) {
2914 try {
2915 mCb.onStopResolutionFailed(listenerKey, error);
2916 } catch (RemoteException e) {
2917 Log.e(TAG, "Error calling onStopResolutionFailed", e);
2918 }
2919 }
2920
Paul Hu60149052023-07-31 14:26:08 +08002921 void onStopResolutionSucceeded(int listenerKey, ClientRequest request) {
2922 mMetrics.reportServiceResolutionStop(
Paul Hu508a0122023-09-11 15:31:33 +08002923 isLegacyClientRequest(request),
Paul Hu60149052023-07-31 14:26:08 +08002924 request.mTransactionId,
2925 request.calculateRequestDurationMs(mClock.elapsedRealtime()));
Paul Hub58deb72022-12-26 09:24:42 +00002926 try {
2927 mCb.onStopResolutionSucceeded(listenerKey);
2928 } catch (RemoteException e) {
2929 Log.e(TAG, "Error calling onStopResolutionSucceeded", e);
2930 }
2931 }
Paul Hu18aeccc2022-12-27 08:48:48 +00002932
2933 void onServiceInfoCallbackRegistrationFailed(int listenerKey, int error) {
Paul Huddce5912023-08-01 10:26:49 +08002934 mMetrics.reportServiceInfoCallbackRegistrationFailed(NO_TRANSACTION);
Paul Hu18aeccc2022-12-27 08:48:48 +00002935 try {
2936 mCb.onServiceInfoCallbackRegistrationFailed(listenerKey, error);
2937 } catch (RemoteException e) {
2938 Log.e(TAG, "Error calling onServiceInfoCallbackRegistrationFailed", e);
2939 }
2940 }
2941
Paul Huddce5912023-08-01 10:26:49 +08002942 void onServiceInfoCallbackRegistered(int transactionId) {
2943 mMetrics.reportServiceInfoCallbackRegistered(transactionId);
2944 }
2945
2946 void onServiceUpdated(int listenerKey, NsdServiceInfo info, ClientRequest request) {
2947 request.onServiceFound(info.getServiceName());
Paul Hu18aeccc2022-12-27 08:48:48 +00002948 try {
2949 mCb.onServiceUpdated(listenerKey, info);
2950 } catch (RemoteException e) {
2951 Log.e(TAG, "Error calling onServiceUpdated", e);
2952 }
2953 }
2954
Paul Huddce5912023-08-01 10:26:49 +08002955 void onServiceUpdatedLost(int listenerKey, ClientRequest request) {
2956 request.onServiceLost();
Paul Hu18aeccc2022-12-27 08:48:48 +00002957 try {
2958 mCb.onServiceUpdatedLost(listenerKey);
2959 } catch (RemoteException e) {
2960 Log.e(TAG, "Error calling onServiceUpdatedLost", e);
2961 }
2962 }
2963
Paul Huddce5912023-08-01 10:26:49 +08002964 void onServiceInfoCallbackUnregistered(int listenerKey, ClientRequest request) {
2965 mMetrics.reportServiceInfoCallbackUnregistered(
2966 request.mTransactionId,
2967 request.calculateRequestDurationMs(mClock.elapsedRealtime()),
2968 request.getFoundServiceCount(),
2969 request.getLostServiceCount(),
Paul Hubad6fe92023-07-24 21:25:22 +08002970 request.isServiceFromCache(),
2971 request.getSentQueryCount());
Paul Hu18aeccc2022-12-27 08:48:48 +00002972 try {
2973 mCb.onServiceInfoCallbackUnregistered(listenerKey);
2974 } catch (RemoteException e) {
2975 Log.e(TAG, "Error calling onServiceInfoCallbackUnregistered", e);
2976 }
2977 }
Irfan Sheriffe8de2462012-04-11 14:52:19 -07002978 }
Irfan Sheriff77ec5582012-03-22 17:01:39 -07002979}