blob: b9b7bf73c1e63eb89a9594221293aeca02e3ba2c [file] [log] [blame]
Irfan Sheriff7d024d32012-03-22 17:01:39 -07001/*
2 * Copyright (C) 2010 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.server;
18
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070019import android.content.ContentResolver;
paulhu59148b72019-08-12 16:25:11 +080020import android.content.Context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070021import android.content.Intent;
Irfan Sheriff919aca52012-06-01 16:44:13 -070022import android.database.ContentObserver;
paulhu59148b72019-08-12 16:25:11 +080023import android.net.NetworkStack;
Hugo Benichi03f6e1d2017-05-25 13:49:32 +090024import android.net.Uri;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070025import android.net.nsd.DnsSdTxtRecord;
26import android.net.nsd.INsdManager;
27import android.net.nsd.NsdManager;
paulhu59148b72019-08-12 16:25:11 +080028import android.net.nsd.NsdServiceInfo;
Hugo Benichicbb13672017-04-24 11:35:06 +090029import android.os.Handler;
paulhu59148b72019-08-12 16:25:11 +080030import android.os.HandlerThread;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070031import android.os.Message;
32import android.os.Messenger;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070033import android.os.UserHandle;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070034import android.provider.Settings;
Philip P. Moltmann312c61e2016-03-16 10:15:39 -070035import android.util.Base64;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070036import android.util.Slog;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070037import android.util.SparseArray;
Hugo Benichi0f86b442017-04-11 14:42:47 +090038import android.util.SparseIntArray;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070039
paulhu59148b72019-08-12 16:25:11 +080040import com.android.internal.annotations.VisibleForTesting;
41import com.android.internal.util.AsyncChannel;
42import com.android.internal.util.DumpUtils;
43import com.android.internal.util.State;
44import com.android.internal.util.StateMachine;
45
Irfan Sheriff7d024d32012-03-22 17:01:39 -070046import java.io.FileDescriptor;
47import java.io.PrintWriter;
Irfan Sheriff817388e2012-04-11 14:52:19 -070048import java.net.InetAddress;
Hugo Benichi1fac3192017-04-24 16:19:58 +090049import java.util.Arrays;
Irfan Sheriff817388e2012-04-11 14:52:19 -070050import java.util.HashMap;
Irfan Sheriff817388e2012-04-11 14:52:19 -070051import java.util.concurrent.CountDownLatch;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070052
Irfan Sheriff7d024d32012-03-22 17:01:39 -070053/**
54 * Network Service Discovery Service handles remote service discovery operation requests by
55 * implementing the INsdManager interface.
56 *
57 * @hide
58 */
59public class NsdService extends INsdManager.Stub {
60 private static final String TAG = "NsdService";
61 private static final String MDNS_TAG = "mDnsConnector";
62
Hugo Benichi2183ba92017-04-05 14:06:11 +090063 private static final boolean DBG = true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070064
Hugo Benichi2183ba92017-04-05 14:06:11 +090065 private final Context mContext;
Hugo Benichicbb13672017-04-24 11:35:06 +090066 private final NsdSettings mNsdSettings;
Hugo Benichi2183ba92017-04-05 14:06:11 +090067 private final NsdStateMachine mNsdStateMachine;
Hugo Benichi1fac3192017-04-24 16:19:58 +090068 private final DaemonConnection mDaemon;
69 private final NativeCallbackReceiver mDaemonCallback;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070070
71 /**
72 * Clients receiving asynchronous messages
73 */
Hugo Benichi2183ba92017-04-05 14:06:11 +090074 private final HashMap<Messenger, ClientInfo> mClients = new HashMap<>();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070075
Irfan Sheriff22af38c2012-05-03 16:44:27 -070076 /* A map from unique id to client info */
Hugo Benichi2183ba92017-04-05 14:06:11 +090077 private final SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<>();
Irfan Sheriff22af38c2012-05-03 16:44:27 -070078
Hugo Benichi2183ba92017-04-05 14:06:11 +090079 private final AsyncChannel mReplyChannel = new AsyncChannel();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070080
Hugo Benichi2183ba92017-04-05 14:06:11 +090081 private static final int INVALID_ID = 0;
Irfan Sheriff817388e2012-04-11 14:52:19 -070082 private int mUniqueId = 1;
83
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070084 private class NsdStateMachine extends StateMachine {
85
Irfan Sheriff22af38c2012-05-03 16:44:27 -070086 private final DefaultState mDefaultState = new DefaultState();
87 private final DisabledState mDisabledState = new DisabledState();
88 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070089
90 @Override
Wink Savillebbf30dfd2012-05-29 12:40:46 -070091 protected String getWhatToString(int what) {
Hugo Benichi2183ba92017-04-05 14:06:11 +090092 return NsdManager.nameOf(what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070093 }
94
Irfan Sheriff919aca52012-06-01 16:44:13 -070095 /**
96 * Observes the NSD on/off setting, and takes action when changed.
97 */
98 private void registerForNsdSetting() {
Hugo Benichi03f6e1d2017-05-25 13:49:32 +090099 final ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
Irfan Sheriff919aca52012-06-01 16:44:13 -0700100 @Override
Hugo Benichi2183ba92017-04-05 14:06:11 +0900101 public void onChange(boolean selfChange) {
Hugo Benichi2d968b42017-04-24 16:41:03 +0900102 notifyEnabled(isNsdEnabled());
Hugo Benichi2183ba92017-04-05 14:06:11 +0900103 }
Irfan Sheriff919aca52012-06-01 16:44:13 -0700104 };
105
Hugo Benichi03f6e1d2017-05-25 13:49:32 +0900106 final Uri uri = Settings.Global.getUriFor(Settings.Global.NSD_ON);
107 mNsdSettings.registerContentObserver(uri, contentObserver);
Irfan Sheriff919aca52012-06-01 16:44:13 -0700108 }
109
Hugo Benichicbb13672017-04-24 11:35:06 +0900110 NsdStateMachine(String name, Handler handler) {
111 super(name, handler);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700112 addState(mDefaultState);
113 addState(mDisabledState, mDefaultState);
114 addState(mEnabledState, mDefaultState);
Hugo Benichi2d968b42017-04-24 16:41:03 +0900115 State initialState = isNsdEnabled() ? mEnabledState : mDisabledState;
116 setInitialState(initialState);
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700117 setLogRecSize(25);
Irfan Sheriff919aca52012-06-01 16:44:13 -0700118 registerForNsdSetting();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700119 }
120
121 class DefaultState extends State {
122 @Override
123 public boolean processMessage(Message msg) {
Dave Plattf31760c2014-03-07 14:48:22 -0800124 ClientInfo cInfo = null;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700125 switch (msg.what) {
126 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
127 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
128 AsyncChannel c = (AsyncChannel) msg.obj;
129 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
130 c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
Dave Plattf31760c2014-03-07 14:48:22 -0800131 cInfo = new ClientInfo(c, msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700132 mClients.put(msg.replyTo, cInfo);
133 } else {
134 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
135 }
136 break;
137 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Dave Plattf31760c2014-03-07 14:48:22 -0800138 switch (msg.arg1) {
139 case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
140 Slog.e(TAG, "Send failed, client connection lost");
141 break;
142 case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
143 if (DBG) Slog.d(TAG, "Client disconnected");
144 break;
145 default:
146 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
147 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700148 }
Dave Plattf31760c2014-03-07 14:48:22 -0800149 cInfo = mClients.get(msg.replyTo);
150 if (cInfo != null) {
151 cInfo.expungeAllRequests();
152 mClients.remove(msg.replyTo);
153 }
154 //Last client
155 if (mClients.size() == 0) {
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900156 mDaemon.stop();
Dave Plattf31760c2014-03-07 14:48:22 -0800157 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700158 break;
159 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
160 AsyncChannel ac = new AsyncChannel();
161 ac.connect(mContext, getHandler(), msg.replyTo);
162 break;
163 case NsdManager.DISCOVER_SERVICES:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700164 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
165 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700166 break;
167 case NsdManager.STOP_DISCOVERY:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700168 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
169 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700170 break;
171 case NsdManager.REGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700172 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
173 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700174 break;
175 case NsdManager.UNREGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700176 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
177 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700178 break;
179 case NsdManager.RESOLVE_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700180 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
181 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700182 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700183 case NsdManager.NATIVE_DAEMON_EVENT:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700184 default:
185 Slog.e(TAG, "Unhandled " + msg);
186 return NOT_HANDLED;
187 }
188 return HANDLED;
189 }
190 }
191
192 class DisabledState extends State {
193 @Override
194 public void enter() {
195 sendNsdStateChangeBroadcast(false);
196 }
197
198 @Override
199 public boolean processMessage(Message msg) {
200 switch (msg.what) {
201 case NsdManager.ENABLE:
202 transitionTo(mEnabledState);
203 break;
204 default:
205 return NOT_HANDLED;
206 }
207 return HANDLED;
208 }
209 }
210
211 class EnabledState extends State {
212 @Override
213 public void enter() {
214 sendNsdStateChangeBroadcast(true);
215 if (mClients.size() > 0) {
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900216 mDaemon.start();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700217 }
218 }
219
220 @Override
221 public void exit() {
222 if (mClients.size() > 0) {
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900223 mDaemon.stop();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700224 }
225 }
226
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700227 private boolean requestLimitReached(ClientInfo clientInfo) {
228 if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
229 if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
230 return true;
231 }
232 return false;
233 }
234
Dave Plattf31760c2014-03-07 14:48:22 -0800235 private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700236 clientInfo.mClientIds.put(clientId, globalId);
Dave Plattf31760c2014-03-07 14:48:22 -0800237 clientInfo.mClientRequests.put(clientId, what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700238 mIdToClientInfoMap.put(globalId, clientInfo);
239 }
240
241 private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
Hugo Benichi0f86b442017-04-11 14:42:47 +0900242 clientInfo.mClientIds.delete(clientId);
243 clientInfo.mClientRequests.delete(clientId);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700244 mIdToClientInfoMap.remove(globalId);
245 }
246
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700247 @Override
248 public boolean processMessage(Message msg) {
249 ClientInfo clientInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700250 NsdServiceInfo servInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700251 int id;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700252 switch (msg.what) {
Hugo Benichi23dba852017-04-05 14:43:29 +0900253 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700254 //First client
255 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
256 mClients.size() == 0) {
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900257 mDaemon.start();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700258 }
Hugo Benichi23dba852017-04-05 14:43:29 +0900259 return NOT_HANDLED;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700260 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Hugo Benichi23dba852017-04-05 14:43:29 +0900261 return NOT_HANDLED;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700262 case NsdManager.DISABLE:
263 //TODO: cleanup clients
264 transitionTo(mDisabledState);
265 break;
266 case NsdManager.DISCOVER_SERVICES:
267 if (DBG) Slog.d(TAG, "Discover services");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700268 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700269 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700270
271 if (requestLimitReached(clientInfo)) {
272 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
273 NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700274 break;
275 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700276
277 id = getUniqueId();
278 if (discoverServices(id, servInfo.getServiceType())) {
279 if (DBG) {
280 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
281 servInfo.getServiceType());
282 }
Dave Plattf31760c2014-03-07 14:48:22 -0800283 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700284 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700285 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700286 stopServiceDiscovery(id);
287 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
288 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700289 }
290 break;
291 case NsdManager.STOP_DISCOVERY:
292 if (DBG) Slog.d(TAG, "Stop service discovery");
293 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700294
295 try {
Hugo Benichi0f86b442017-04-11 14:42:47 +0900296 id = clientInfo.mClientIds.get(msg.arg2);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700297 } catch (NullPointerException e) {
298 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
299 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700300 break;
301 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700302 removeRequestMap(msg.arg2, id, clientInfo);
303 if (stopServiceDiscovery(id)) {
304 replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700305 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700306 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
307 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700308 }
309 break;
310 case NsdManager.REGISTER_SERVICE:
311 if (DBG) Slog.d(TAG, "Register service");
312 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700313 if (requestLimitReached(clientInfo)) {
314 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
315 NsdManager.FAILURE_MAX_LIMIT);
316 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700317 }
318
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700319 id = getUniqueId();
320 if (registerService(id, (NsdServiceInfo) msg.obj)) {
321 if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
Dave Plattf31760c2014-03-07 14:48:22 -0800322 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700323 // Return success after mDns reports success
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700324 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700325 unregisterService(id);
326 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
327 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700328 }
329 break;
330 case NsdManager.UNREGISTER_SERVICE:
331 if (DBG) Slog.d(TAG, "unregister service");
332 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700333 try {
Hugo Benichi0f86b442017-04-11 14:42:47 +0900334 id = clientInfo.mClientIds.get(msg.arg2);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700335 } catch (NullPointerException e) {
336 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
337 NsdManager.FAILURE_INTERNAL_ERROR);
338 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700339 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700340 removeRequestMap(msg.arg2, id, clientInfo);
341 if (unregisterService(id)) {
342 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
343 } else {
344 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
345 NsdManager.FAILURE_INTERNAL_ERROR);
346 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700347 break;
348 case NsdManager.RESOLVE_SERVICE:
349 if (DBG) Slog.d(TAG, "Resolve service");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700350 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700351 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700352
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700353
354 if (clientInfo.mResolvedService != null) {
355 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
356 NsdManager.FAILURE_ALREADY_ACTIVE);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700357 break;
358 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700359
360 id = getUniqueId();
361 if (resolveService(id, servInfo)) {
362 clientInfo.mResolvedService = new NsdServiceInfo();
Dave Plattf31760c2014-03-07 14:48:22 -0800363 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700364 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700365 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
366 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700367 }
368 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700369 case NsdManager.NATIVE_DAEMON_EVENT:
370 NativeEvent event = (NativeEvent) msg.obj;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700371 if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
Hugo Benichi23dba852017-04-05 14:43:29 +0900372 return NOT_HANDLED;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700373 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700374 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700375 default:
Hugo Benichi23dba852017-04-05 14:43:29 +0900376 return NOT_HANDLED;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700377 }
Hugo Benichi23dba852017-04-05 14:43:29 +0900378 return HANDLED;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700379 }
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700380
381 private boolean handleNativeEvent(int code, String raw, String[] cooked) {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700382 NsdServiceInfo servInfo;
383 int id = Integer.parseInt(cooked[1]);
384 ClientInfo clientInfo = mIdToClientInfoMap.get(id);
385 if (clientInfo == null) {
Hugo Benichi2183ba92017-04-05 14:06:11 +0900386 String name = NativeResponseCode.nameOf(code);
387 Slog.e(TAG, String.format("id %d for %s has no client mapping", id, name));
Hugo Benichi23dba852017-04-05 14:43:29 +0900388 return false;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700389 }
390
391 /* This goes in response as msg.arg2 */
Christopher Lane5a577902014-04-25 18:39:07 -0700392 int clientId = clientInfo.getClientId(id);
393 if (clientId < 0) {
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700394 // This can happen because of race conditions. For example,
395 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
396 // and we may get in this situation.
Hugo Benichi2183ba92017-04-05 14:06:11 +0900397 String name = NativeResponseCode.nameOf(code);
398 Slog.d(TAG, String.format(
399 "Notification %s for listener id %d that is no longer active",
400 name, id));
Hugo Benichi23dba852017-04-05 14:43:29 +0900401 return false;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700402 }
Hugo Benichi2183ba92017-04-05 14:06:11 +0900403 if (DBG) {
404 String name = NativeResponseCode.nameOf(code);
405 Slog.d(TAG, String.format("Native daemon message %s: %s", name, raw));
406 }
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700407 switch (code) {
408 case NativeResponseCode.SERVICE_FOUND:
409 /* NNN uniqueId serviceName regType domain */
Christopher Laneb72d8b42014-03-17 16:35:45 -0700410 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700411 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
412 clientId, servInfo);
413 break;
414 case NativeResponseCode.SERVICE_LOST:
415 /* NNN uniqueId serviceName regType domain */
Christopher Laneb72d8b42014-03-17 16:35:45 -0700416 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700417 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
418 clientId, servInfo);
419 break;
420 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
421 /* NNN uniqueId errorCode */
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700422 clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
423 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
424 break;
425 case NativeResponseCode.SERVICE_REGISTERED:
426 /* NNN regId serviceName regType */
Christopher Laneb72d8b42014-03-17 16:35:45 -0700427 servInfo = new NsdServiceInfo(cooked[2], null);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700428 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
429 id, clientId, servInfo);
430 break;
431 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
432 /* NNN regId errorCode */
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700433 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
434 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
435 break;
436 case NativeResponseCode.SERVICE_UPDATED:
437 /* NNN regId */
438 break;
439 case NativeResponseCode.SERVICE_UPDATE_FAILED:
440 /* NNN regId errorCode */
441 break;
442 case NativeResponseCode.SERVICE_RESOLVED:
443 /* NNN resolveId fullName hostName port txtlen txtdata */
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700444 int index = 0;
445 while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
446 if (cooked[2].charAt(index) == '\\') {
447 ++index;
448 }
449 ++index;
450 }
451 if (index >= cooked[2].length()) {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700452 Slog.e(TAG, "Invalid service found " + raw);
453 break;
454 }
455 String name = cooked[2].substring(0, index);
456 String rest = cooked[2].substring(index);
457 String type = rest.replace(".local.", "");
458
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700459 name = unescape(name);
460
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700461 clientInfo.mResolvedService.setServiceName(name);
462 clientInfo.mResolvedService.setServiceType(type);
463 clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
Philip P. Moltmann312c61e2016-03-16 10:15:39 -0700464 clientInfo.mResolvedService.setTxtRecords(cooked[6]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700465
466 stopResolveService(id);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800467 removeRequestMap(clientId, id, clientInfo);
468
469 int id2 = getUniqueId();
470 if (getAddrInfo(id2, cooked[3])) {
Dave Plattf31760c2014-03-07 14:48:22 -0800471 storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800472 } else {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700473 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
474 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700475 clientInfo.mResolvedService = null;
476 }
477 break;
478 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
479 /* NNN resolveId errorCode */
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700480 stopResolveService(id);
481 removeRequestMap(clientId, id, clientInfo);
482 clientInfo.mResolvedService = null;
483 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
484 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
485 break;
486 case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
487 /* NNN resolveId errorCode */
488 stopGetAddrInfo(id);
489 removeRequestMap(clientId, id, clientInfo);
490 clientInfo.mResolvedService = null;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700491 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
492 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
493 break;
494 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
495 /* NNN resolveId hostname ttl addr */
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700496 try {
497 clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
498 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
499 0, clientId, clientInfo.mResolvedService);
500 } catch (java.net.UnknownHostException e) {
501 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
502 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
503 }
504 stopGetAddrInfo(id);
505 removeRequestMap(clientId, id, clientInfo);
506 clientInfo.mResolvedService = null;
507 break;
508 default:
Hugo Benichi23dba852017-04-05 14:43:29 +0900509 return false;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700510 }
Hugo Benichi23dba852017-04-05 14:43:29 +0900511 return true;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700512 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700513 }
514 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700515
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700516 private String unescape(String s) {
517 StringBuilder sb = new StringBuilder(s.length());
518 for (int i = 0; i < s.length(); ++i) {
519 char c = s.charAt(i);
520 if (c == '\\') {
521 if (++i >= s.length()) {
522 Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
523 break;
524 }
525 c = s.charAt(i);
526 if (c != '.' && c != '\\') {
527 if (i + 2 >= s.length()) {
528 Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
529 break;
530 }
531 c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
532 i += 2;
533 }
534 }
535 sb.append(c);
536 }
537 return sb.toString();
538 }
539
Hugo Benichicbb13672017-04-24 11:35:06 +0900540 @VisibleForTesting
Hugo Benichi1fac3192017-04-24 16:19:58 +0900541 NsdService(Context ctx, NsdSettings settings, Handler handler, DaemonConnectionSupplier fn) {
Hugo Benichicbb13672017-04-24 11:35:06 +0900542 mContext = ctx;
543 mNsdSettings = settings;
Hugo Benichicbb13672017-04-24 11:35:06 +0900544 mNsdStateMachine = new NsdStateMachine(TAG, handler);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700545 mNsdStateMachine.start();
Hugo Benichi1fac3192017-04-24 16:19:58 +0900546 mDaemonCallback = new NativeCallbackReceiver();
547 mDaemon = fn.get(mDaemonCallback);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700548 }
549
550 public static NsdService create(Context context) throws InterruptedException {
Hugo Benichicbb13672017-04-24 11:35:06 +0900551 NsdSettings settings = NsdSettings.makeDefault(context);
552 HandlerThread thread = new HandlerThread(TAG);
553 thread.start();
554 Handler handler = new Handler(thread.getLooper());
Hugo Benichi1fac3192017-04-24 16:19:58 +0900555 NsdService service = new NsdService(context, settings, handler, DaemonConnection::new);
556 service.mDaemonCallback.awaitConnection();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700557 return service;
558 }
559
560 public Messenger getMessenger() {
Hugo Benichicbb13672017-04-24 11:35:06 +0900561 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET, "NsdService");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700562 return new Messenger(mNsdStateMachine.getHandler());
563 }
564
Hugo Benichi2d968b42017-04-24 16:41:03 +0900565 public void setEnabled(boolean isEnabled) {
paulhu59148b72019-08-12 16:25:11 +0800566 NetworkStack.checkNetworkStackPermission(mContext);
Hugo Benichi2d968b42017-04-24 16:41:03 +0900567 mNsdSettings.putEnabledStatus(isEnabled);
568 notifyEnabled(isEnabled);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700569 }
570
Hugo Benichi2d968b42017-04-24 16:41:03 +0900571 private void notifyEnabled(boolean isEnabled) {
572 mNsdStateMachine.sendMessage(isEnabled ? NsdManager.ENABLE : NsdManager.DISABLE);
573 }
574
575 private void sendNsdStateChangeBroadcast(boolean isEnabled) {
Irfan Sheriff54ac7a52012-04-19 10:26:34 -0700576 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700577 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
Hugo Benichi2d968b42017-04-24 16:41:03 +0900578 int nsdState = isEnabled ? NsdManager.NSD_STATE_ENABLED : NsdManager.NSD_STATE_DISABLED;
579 intent.putExtra(NsdManager.EXTRA_NSD_STATE, nsdState);
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700580 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700581 }
582
583 private boolean isNsdEnabled() {
Hugo Benichicbb13672017-04-24 11:35:06 +0900584 boolean ret = mNsdSettings.isEnabled();
585 if (DBG) {
586 Slog.d(TAG, "Network service discovery is " + (ret ? "enabled" : "disabled"));
587 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700588 return ret;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700589 }
590
Irfan Sheriff817388e2012-04-11 14:52:19 -0700591 private int getUniqueId() {
592 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
593 return mUniqueId;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700594 }
595
Sreeram Ramachandran03666c72014-07-19 23:21:46 -0700596 /* These should be in sync with system/netd/server/ResponseCode.h */
Hugo Benichi2183ba92017-04-05 14:06:11 +0900597 static final class NativeResponseCode {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700598 public static final int SERVICE_DISCOVERY_FAILED = 602;
599 public static final int SERVICE_FOUND = 603;
600 public static final int SERVICE_LOST = 604;
601
602 public static final int SERVICE_REGISTRATION_FAILED = 605;
603 public static final int SERVICE_REGISTERED = 606;
604
605 public static final int SERVICE_RESOLUTION_FAILED = 607;
606 public static final int SERVICE_RESOLVED = 608;
607
608 public static final int SERVICE_UPDATED = 609;
609 public static final int SERVICE_UPDATE_FAILED = 610;
610
611 public static final int SERVICE_GET_ADDR_FAILED = 611;
612 public static final int SERVICE_GET_ADDR_SUCCESS = 612;
Hugo Benichi2183ba92017-04-05 14:06:11 +0900613
614 private static final SparseArray<String> CODE_NAMES = new SparseArray<>();
615 static {
616 CODE_NAMES.put(SERVICE_DISCOVERY_FAILED, "SERVICE_DISCOVERY_FAILED");
617 CODE_NAMES.put(SERVICE_FOUND, "SERVICE_FOUND");
618 CODE_NAMES.put(SERVICE_LOST, "SERVICE_LOST");
619 CODE_NAMES.put(SERVICE_REGISTRATION_FAILED, "SERVICE_REGISTRATION_FAILED");
620 CODE_NAMES.put(SERVICE_REGISTERED, "SERVICE_REGISTERED");
621 CODE_NAMES.put(SERVICE_RESOLUTION_FAILED, "SERVICE_RESOLUTION_FAILED");
622 CODE_NAMES.put(SERVICE_RESOLVED, "SERVICE_RESOLVED");
623 CODE_NAMES.put(SERVICE_UPDATED, "SERVICE_UPDATED");
624 CODE_NAMES.put(SERVICE_UPDATE_FAILED, "SERVICE_UPDATE_FAILED");
625 CODE_NAMES.put(SERVICE_GET_ADDR_FAILED, "SERVICE_GET_ADDR_FAILED");
626 CODE_NAMES.put(SERVICE_GET_ADDR_SUCCESS, "SERVICE_GET_ADDR_SUCCESS");
627 }
628
629 static String nameOf(int code) {
630 String name = CODE_NAMES.get(code);
631 if (name == null) {
632 return Integer.toString(code);
633 }
634 return name;
635 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700636 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700637
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700638 private class NativeEvent {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700639 final int code;
640 final String raw;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700641 final String[] cooked;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700642
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700643 NativeEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700644 this.code = code;
645 this.raw = raw;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700646 this.cooked = cooked;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700647 }
648 }
649
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700650 class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900651 private final CountDownLatch connected = new CountDownLatch(1);
652
653 public void awaitConnection() throws InterruptedException {
654 connected.await();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700655 }
656
Hugo Benichi1fac3192017-04-24 16:19:58 +0900657 @Override
658 public void onDaemonConnected() {
659 connected.countDown();
660 }
661
662 @Override
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800663 public boolean onCheckHoldWakeLock(int code) {
664 return false;
665 }
666
Hugo Benichi1fac3192017-04-24 16:19:58 +0900667 @Override
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700668 public boolean onEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700669 // TODO: NDC translates a message to a callback, we could enhance NDC to
670 // directly interact with a state machine through messages
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700671 NativeEvent event = new NativeEvent(code, raw, cooked);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700672 mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
673 return true;
674 }
675 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700676
Hugo Benichi1fac3192017-04-24 16:19:58 +0900677 interface DaemonConnectionSupplier {
678 DaemonConnection get(NativeCallbackReceiver callback);
679 }
680
681 @VisibleForTesting
682 public static class DaemonConnection {
683 final NativeDaemonConnector mNativeConnector;
684
685 DaemonConnection(NativeCallbackReceiver callback) {
686 mNativeConnector = new NativeDaemonConnector(callback, "mdns", 10, MDNS_TAG, 25, null);
687 new Thread(mNativeConnector, MDNS_TAG).start();
Irfan Sheriff817388e2012-04-11 14:52:19 -0700688 }
Hugo Benichi1fac3192017-04-24 16:19:58 +0900689
690 public boolean execute(Object... args) {
691 if (DBG) {
692 Slog.d(TAG, "mdnssd " + Arrays.toString(args));
693 }
694 try {
695 mNativeConnector.execute("mdnssd", args);
696 } catch (NativeDaemonConnectorException e) {
697 Slog.e(TAG, "Failed to execute mdnssd " + Arrays.toString(args), e);
698 return false;
699 }
700 return true;
701 }
702
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900703 public void start() {
704 execute("start-service");
Hugo Benichi1fac3192017-04-24 16:19:58 +0900705 }
Hugo Benichi1fac3192017-04-24 16:19:58 +0900706
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900707 public void stop() {
708 execute("stop-service");
709 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700710 }
711
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700712 private boolean registerService(int regId, NsdServiceInfo service) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900713 if (DBG) {
714 Slog.d(TAG, "registerService: " + regId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700715 }
Hugo Benichi1fac3192017-04-24 16:19:58 +0900716 String name = service.getServiceName();
717 String type = service.getServiceType();
718 int port = service.getPort();
719 byte[] textRecord = service.getTxtRecord();
720 String record = Base64.encodeToString(textRecord, Base64.DEFAULT).replace("\n", "");
Hugo Benichiab5bdbf2017-04-28 15:31:10 +0900721 return mDaemon.execute("register", regId, name, type, port, record);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700722 }
723
Irfan Sheriff817388e2012-04-11 14:52:19 -0700724 private boolean unregisterService(int regId) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900725 return mDaemon.execute("stop-register", regId);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700726 }
727
728 private boolean updateService(int regId, DnsSdTxtRecord t) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900729 if (t == null) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700730 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700731 }
Hugo Benichi1fac3192017-04-24 16:19:58 +0900732 return mDaemon.execute("update", regId, t.size(), t.getRawData());
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700733 }
734
Irfan Sheriff817388e2012-04-11 14:52:19 -0700735 private boolean discoverServices(int discoveryId, String serviceType) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900736 return mDaemon.execute("discover", discoveryId, serviceType);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700737 }
738
Irfan Sheriff817388e2012-04-11 14:52:19 -0700739 private boolean stopServiceDiscovery(int discoveryId) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900740 return mDaemon.execute("stop-discover", discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700741 }
742
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700743 private boolean resolveService(int resolveId, NsdServiceInfo service) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900744 String name = service.getServiceName();
745 String type = service.getServiceType();
746 return mDaemon.execute("resolve", resolveId, name, type, "local.");
Irfan Sheriff817388e2012-04-11 14:52:19 -0700747 }
748
749 private boolean stopResolveService(int resolveId) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900750 return mDaemon.execute("stop-resolve", resolveId);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700751 }
752
753 private boolean getAddrInfo(int resolveId, String hostname) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900754 return mDaemon.execute("getaddrinfo", resolveId, hostname);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700755 }
756
757 private boolean stopGetAddrInfo(int resolveId) {
Hugo Benichi1fac3192017-04-24 16:19:58 +0900758 return mDaemon.execute("stop-getaddrinfo", resolveId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700759 }
760
761 @Override
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700762 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Jeff Sharkeyfe9a53b2017-03-31 14:08:23 -0600763 if (!DumpUtils.checkDumpPermission(mContext, TAG, pw)) return;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700764
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700765 for (ClientInfo client : mClients.values()) {
766 pw.println("Client Info");
767 pw.println(client);
768 }
769
770 mNsdStateMachine.dump(fd, pw, args);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700771 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700772
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700773 /* arg2 on the source message has an id that needs to be retained in replies
774 * see NsdManager for details */
775 private Message obtainMessage(Message srcMsg) {
776 Message msg = Message.obtain();
777 msg.arg2 = srcMsg.arg2;
778 return msg;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700779 }
780
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700781 private void replyToMessage(Message msg, int what) {
782 if (msg.replyTo == null) return;
783 Message dstMsg = obtainMessage(msg);
784 dstMsg.what = what;
785 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700786 }
787
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700788 private void replyToMessage(Message msg, int what, int arg1) {
789 if (msg.replyTo == null) return;
790 Message dstMsg = obtainMessage(msg);
791 dstMsg.what = what;
792 dstMsg.arg1 = arg1;
793 mReplyChannel.replyToMessage(msg, dstMsg);
794 }
795
796 private void replyToMessage(Message msg, int what, Object obj) {
797 if (msg.replyTo == null) return;
798 Message dstMsg = obtainMessage(msg);
799 dstMsg.what = what;
800 dstMsg.obj = obj;
801 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700802 }
803
804 /* Information tracked per client */
805 private class ClientInfo {
806
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700807 private static final int MAX_LIMIT = 10;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700808 private final AsyncChannel mChannel;
809 private final Messenger mMessenger;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700810 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700811 private NsdServiceInfo mResolvedService;
812
813 /* A map from client id to unique id sent to mDns */
Hugo Benichi0f86b442017-04-11 14:42:47 +0900814 private final SparseIntArray mClientIds = new SparseIntArray();
Irfan Sheriff817388e2012-04-11 14:52:19 -0700815
Dave Plattf31760c2014-03-07 14:48:22 -0800816 /* A map from client id to the type of the request we had received */
Hugo Benichi0f86b442017-04-11 14:42:47 +0900817 private final SparseIntArray mClientRequests = new SparseIntArray();
Dave Plattf31760c2014-03-07 14:48:22 -0800818
Irfan Sheriff817388e2012-04-11 14:52:19 -0700819 private ClientInfo(AsyncChannel c, Messenger m) {
820 mChannel = c;
821 mMessenger = m;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700822 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
823 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700824
825 @Override
826 public String toString() {
827 StringBuffer sb = new StringBuffer();
828 sb.append("mChannel ").append(mChannel).append("\n");
829 sb.append("mMessenger ").append(mMessenger).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700830 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700831 for(int i = 0; i< mClientIds.size(); i++) {
Dave Plattf31760c2014-03-07 14:48:22 -0800832 int clientID = mClientIds.keyAt(i);
833 sb.append("clientId ").append(clientID).
834 append(" mDnsId ").append(mClientIds.valueAt(i)).
835 append(" type ").append(mClientRequests.get(clientID)).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700836 }
837 return sb.toString();
838 }
Dave Plattf31760c2014-03-07 14:48:22 -0800839
840 // Remove any pending requests from the global map when we get rid of a client,
841 // and send cancellations to the daemon.
842 private void expungeAllRequests() {
843 int globalId, clientId, i;
Hugo Benichi0f86b442017-04-11 14:42:47 +0900844 // TODO: to keep handler responsive, do not clean all requests for that client at once.
Dave Plattf31760c2014-03-07 14:48:22 -0800845 for (i = 0; i < mClientIds.size(); i++) {
846 clientId = mClientIds.keyAt(i);
847 globalId = mClientIds.valueAt(i);
848 mIdToClientInfoMap.remove(globalId);
849 if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
850 " global-ID " + globalId + " type " + mClientRequests.get(clientId));
851 switch (mClientRequests.get(clientId)) {
852 case NsdManager.DISCOVER_SERVICES:
853 stopServiceDiscovery(globalId);
854 break;
855 case NsdManager.RESOLVE_SERVICE:
856 stopResolveService(globalId);
857 break;
858 case NsdManager.REGISTER_SERVICE:
859 unregisterService(globalId);
860 break;
861 default:
862 break;
863 }
864 }
865 mClientIds.clear();
866 mClientRequests.clear();
867 }
868
Christopher Lane5a577902014-04-25 18:39:07 -0700869 // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id,
870 // return the corresponding listener id. mDnsClient id is also called a global id.
871 private int getClientId(final int globalId) {
Hugo Benichi0f86b442017-04-11 14:42:47 +0900872 int idx = mClientIds.indexOfValue(globalId);
873 if (idx < 0) {
874 return idx;
Christopher Lane5a577902014-04-25 18:39:07 -0700875 }
Hugo Benichi0f86b442017-04-11 14:42:47 +0900876 return mClientIds.keyAt(idx);
Christopher Lane5a577902014-04-25 18:39:07 -0700877 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700878 }
Hugo Benichicbb13672017-04-24 11:35:06 +0900879
Hugo Benichi03f6e1d2017-05-25 13:49:32 +0900880 /**
881 * Interface which encapsulates dependencies of NsdService that are hard to mock, hard to
882 * override, or have side effects on global state in unit tests.
883 */
Hugo Benichicbb13672017-04-24 11:35:06 +0900884 @VisibleForTesting
885 public interface NsdSettings {
886 boolean isEnabled();
887 void putEnabledStatus(boolean isEnabled);
Hugo Benichi03f6e1d2017-05-25 13:49:32 +0900888 void registerContentObserver(Uri uri, ContentObserver observer);
Hugo Benichicbb13672017-04-24 11:35:06 +0900889
890 static NsdSettings makeDefault(Context context) {
Hugo Benichi03f6e1d2017-05-25 13:49:32 +0900891 final ContentResolver resolver = context.getContentResolver();
Hugo Benichicbb13672017-04-24 11:35:06 +0900892 return new NsdSettings() {
893 @Override
894 public boolean isEnabled() {
895 return Settings.Global.getInt(resolver, Settings.Global.NSD_ON, 1) == 1;
896 }
897
898 @Override
899 public void putEnabledStatus(boolean isEnabled) {
900 Settings.Global.putInt(resolver, Settings.Global.NSD_ON, isEnabled ? 1 : 0);
901 }
Hugo Benichi03f6e1d2017-05-25 13:49:32 +0900902
903 @Override
904 public void registerContentObserver(Uri uri, ContentObserver observer) {
905 resolver.registerContentObserver(uri, false, observer);
906 }
Hugo Benichicbb13672017-04-24 11:35:06 +0900907 };
908 }
909 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700910}