blob: 39aa972bab4b3257f926552d1ebffe39ff62597b [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
19import android.content.Context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070020import android.content.ContentResolver;
21import android.content.Intent;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070022import android.content.pm.PackageManager;
Irfan Sheriff919aca52012-06-01 16:44:13 -070023import android.database.ContentObserver;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070024import android.net.nsd.NsdServiceInfo;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070025import android.net.nsd.DnsSdTxtRecord;
26import android.net.nsd.INsdManager;
27import android.net.nsd.NsdManager;
28import android.os.Binder;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070029import android.os.Message;
30import android.os.Messenger;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070031import android.os.UserHandle;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070032import android.provider.Settings;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070033import android.util.Slog;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070034import android.util.SparseArray;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070035
36import java.io.FileDescriptor;
37import java.io.PrintWriter;
Christopher Laneb72d8b42014-03-17 16:35:45 -070038import java.io.UnsupportedEncodingException;
Irfan Sheriff817388e2012-04-11 14:52:19 -070039import java.net.InetAddress;
Irfan Sheriff817388e2012-04-11 14:52:19 -070040import java.util.HashMap;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070041import java.util.List;
Christopher Laneb72d8b42014-03-17 16:35:45 -070042import java.util.Locale;
43import java.util.Map;
Irfan Sheriff817388e2012-04-11 14:52:19 -070044import java.util.concurrent.CountDownLatch;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070045
Irfan Sheriff7d024d32012-03-22 17:01:39 -070046import com.android.internal.util.AsyncChannel;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070047import com.android.internal.util.Protocol;
48import com.android.internal.util.State;
49import com.android.internal.util.StateMachine;
Christopher Lane771cd652014-04-14 16:31:27 -070050import com.android.server.NativeDaemonConnector.Command;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070051
52/**
53 * Network Service Discovery Service handles remote service discovery operation requests by
54 * implementing the INsdManager interface.
55 *
56 * @hide
57 */
58public class NsdService extends INsdManager.Stub {
59 private static final String TAG = "NsdService";
60 private static final String MDNS_TAG = "mDnsConnector";
61
62 private static final boolean DBG = true;
63
64 private Context mContext;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070065 private ContentResolver mContentResolver;
66 private NsdStateMachine mNsdStateMachine;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070067
68 /**
69 * Clients receiving asynchronous messages
70 */
Irfan Sheriff817388e2012-04-11 14:52:19 -070071 private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070072
Irfan Sheriff22af38c2012-05-03 16:44:27 -070073 /* A map from unique id to client info */
74 private SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<ClientInfo>();
75
Irfan Sheriff7d024d32012-03-22 17:01:39 -070076 private AsyncChannel mReplyChannel = new AsyncChannel();
77
Irfan Sheriff817388e2012-04-11 14:52:19 -070078 private int INVALID_ID = 0;
79 private int mUniqueId = 1;
80
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070081 private static final int BASE = Protocol.BASE_NSD_MANAGER;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070082 private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070083 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
Irfan Sheriff7d024d32012-03-22 17:01:39 -070084
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070085 static {
86 sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
87 sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
88 sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
89 sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
90 sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070091 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -070092
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070093 private static String cmdToString(int cmd) {
94 cmd -= BASE;
95 if ((cmd >= 0) && (cmd < sCmdToString.length)) {
96 return sCmdToString[cmd];
97 } else {
98 return null;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070099 }
100 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700101
102 private class NsdStateMachine extends StateMachine {
103
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700104 private final DefaultState mDefaultState = new DefaultState();
105 private final DisabledState mDisabledState = new DisabledState();
106 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700107
108 @Override
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700109 protected String getWhatToString(int what) {
110 return cmdToString(what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700111 }
112
Irfan Sheriff919aca52012-06-01 16:44:13 -0700113 /**
114 * Observes the NSD on/off setting, and takes action when changed.
115 */
116 private void registerForNsdSetting() {
117 ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
118 @Override
119 public void onChange(boolean selfChange) {
120 if (isNsdEnabled()) {
121 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
122 } else {
123 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
124 }
125 }
126 };
127
128 mContext.getContentResolver().registerContentObserver(
Jeff Sharkey625239a2012-09-26 22:03:49 -0700129 Settings.Global.getUriFor(Settings.Global.NSD_ON),
Irfan Sheriff919aca52012-06-01 16:44:13 -0700130 false, contentObserver);
131 }
132
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700133 NsdStateMachine(String name) {
134 super(name);
135 addState(mDefaultState);
136 addState(mDisabledState, mDefaultState);
137 addState(mEnabledState, mDefaultState);
138 if (isNsdEnabled()) {
139 setInitialState(mEnabledState);
140 } else {
141 setInitialState(mDisabledState);
142 }
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700143 setLogRecSize(25);
Irfan Sheriff919aca52012-06-01 16:44:13 -0700144 registerForNsdSetting();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700145 }
146
147 class DefaultState extends State {
148 @Override
149 public boolean processMessage(Message msg) {
Dave Plattf31760c2014-03-07 14:48:22 -0800150 ClientInfo cInfo = null;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700151 switch (msg.what) {
152 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
153 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
154 AsyncChannel c = (AsyncChannel) msg.obj;
155 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
156 c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
Dave Plattf31760c2014-03-07 14:48:22 -0800157 cInfo = new ClientInfo(c, msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700158 mClients.put(msg.replyTo, cInfo);
159 } else {
160 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
161 }
162 break;
163 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Dave Plattf31760c2014-03-07 14:48:22 -0800164 switch (msg.arg1) {
165 case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
166 Slog.e(TAG, "Send failed, client connection lost");
167 break;
168 case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
169 if (DBG) Slog.d(TAG, "Client disconnected");
170 break;
171 default:
172 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
173 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700174 }
Dave Plattf31760c2014-03-07 14:48:22 -0800175 cInfo = mClients.get(msg.replyTo);
176 if (cInfo != null) {
177 cInfo.expungeAllRequests();
178 mClients.remove(msg.replyTo);
179 }
180 //Last client
181 if (mClients.size() == 0) {
182 stopMDnsDaemon();
183 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700184 break;
185 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
186 AsyncChannel ac = new AsyncChannel();
187 ac.connect(mContext, getHandler(), msg.replyTo);
188 break;
189 case NsdManager.DISCOVER_SERVICES:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700190 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
191 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700192 break;
193 case NsdManager.STOP_DISCOVERY:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700194 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
195 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700196 break;
197 case NsdManager.REGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700198 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
199 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700200 break;
201 case NsdManager.UNREGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700202 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
203 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700204 break;
205 case NsdManager.RESOLVE_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700206 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
207 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700208 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700209 case NsdManager.NATIVE_DAEMON_EVENT:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700210 default:
211 Slog.e(TAG, "Unhandled " + msg);
212 return NOT_HANDLED;
213 }
214 return HANDLED;
215 }
216 }
217
218 class DisabledState extends State {
219 @Override
220 public void enter() {
221 sendNsdStateChangeBroadcast(false);
222 }
223
224 @Override
225 public boolean processMessage(Message msg) {
226 switch (msg.what) {
227 case NsdManager.ENABLE:
228 transitionTo(mEnabledState);
229 break;
230 default:
231 return NOT_HANDLED;
232 }
233 return HANDLED;
234 }
235 }
236
237 class EnabledState extends State {
238 @Override
239 public void enter() {
240 sendNsdStateChangeBroadcast(true);
241 if (mClients.size() > 0) {
242 startMDnsDaemon();
243 }
244 }
245
246 @Override
247 public void exit() {
248 if (mClients.size() > 0) {
249 stopMDnsDaemon();
250 }
251 }
252
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700253 private boolean requestLimitReached(ClientInfo clientInfo) {
254 if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
255 if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
256 return true;
257 }
258 return false;
259 }
260
Dave Plattf31760c2014-03-07 14:48:22 -0800261 private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700262 clientInfo.mClientIds.put(clientId, globalId);
Dave Plattf31760c2014-03-07 14:48:22 -0800263 clientInfo.mClientRequests.put(clientId, what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700264 mIdToClientInfoMap.put(globalId, clientInfo);
265 }
266
267 private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
268 clientInfo.mClientIds.remove(clientId);
Dave Plattf31760c2014-03-07 14:48:22 -0800269 clientInfo.mClientRequests.remove(clientId);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700270 mIdToClientInfoMap.remove(globalId);
271 }
272
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700273 @Override
274 public boolean processMessage(Message msg) {
275 ClientInfo clientInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700276 NsdServiceInfo servInfo;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700277 boolean result = HANDLED;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700278 int id;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700279 switch (msg.what) {
280 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
281 //First client
282 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
283 mClients.size() == 0) {
284 startMDnsDaemon();
285 }
286 result = NOT_HANDLED;
287 break;
288 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700289 result = NOT_HANDLED;
290 break;
291 case NsdManager.DISABLE:
292 //TODO: cleanup clients
293 transitionTo(mDisabledState);
294 break;
295 case NsdManager.DISCOVER_SERVICES:
296 if (DBG) Slog.d(TAG, "Discover services");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700297 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700298 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700299
300 if (requestLimitReached(clientInfo)) {
301 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
302 NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700303 break;
304 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700305
306 id = getUniqueId();
307 if (discoverServices(id, servInfo.getServiceType())) {
308 if (DBG) {
309 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
310 servInfo.getServiceType());
311 }
Dave Plattf31760c2014-03-07 14:48:22 -0800312 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700313 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700314 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700315 stopServiceDiscovery(id);
316 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
317 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700318 }
319 break;
320 case NsdManager.STOP_DISCOVERY:
321 if (DBG) Slog.d(TAG, "Stop service discovery");
322 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700323
324 try {
325 id = clientInfo.mClientIds.get(msg.arg2).intValue();
326 } catch (NullPointerException e) {
327 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
328 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700329 break;
330 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700331 removeRequestMap(msg.arg2, id, clientInfo);
332 if (stopServiceDiscovery(id)) {
333 replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700334 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700335 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
336 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700337 }
338 break;
339 case NsdManager.REGISTER_SERVICE:
340 if (DBG) Slog.d(TAG, "Register service");
341 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700342 if (requestLimitReached(clientInfo)) {
343 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
344 NsdManager.FAILURE_MAX_LIMIT);
345 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700346 }
347
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700348 id = getUniqueId();
349 if (registerService(id, (NsdServiceInfo) msg.obj)) {
350 if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
Dave Plattf31760c2014-03-07 14:48:22 -0800351 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700352 // Return success after mDns reports success
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700353 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700354 unregisterService(id);
355 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
356 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700357 }
358 break;
359 case NsdManager.UNREGISTER_SERVICE:
360 if (DBG) Slog.d(TAG, "unregister service");
361 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700362 try {
363 id = clientInfo.mClientIds.get(msg.arg2).intValue();
364 } catch (NullPointerException e) {
365 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
366 NsdManager.FAILURE_INTERNAL_ERROR);
367 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700368 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700369 removeRequestMap(msg.arg2, id, clientInfo);
370 if (unregisterService(id)) {
371 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
372 } else {
373 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
374 NsdManager.FAILURE_INTERNAL_ERROR);
375 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700376 break;
377 case NsdManager.RESOLVE_SERVICE:
378 if (DBG) Slog.d(TAG, "Resolve service");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700379 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700380 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700381
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700382
383 if (clientInfo.mResolvedService != null) {
384 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
385 NsdManager.FAILURE_ALREADY_ACTIVE);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700386 break;
387 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700388
389 id = getUniqueId();
390 if (resolveService(id, servInfo)) {
391 clientInfo.mResolvedService = new NsdServiceInfo();
Dave Plattf31760c2014-03-07 14:48:22 -0800392 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700393 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700394 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
395 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700396 }
397 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700398 case NsdManager.NATIVE_DAEMON_EVENT:
399 NativeEvent event = (NativeEvent) msg.obj;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700400 if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700401 result = NOT_HANDLED;
402 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700403 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700404 default:
405 result = NOT_HANDLED;
406 break;
407 }
408 return result;
409 }
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700410
411 private boolean handleNativeEvent(int code, String raw, String[] cooked) {
412 boolean handled = true;
413 NsdServiceInfo servInfo;
414 int id = Integer.parseInt(cooked[1]);
415 ClientInfo clientInfo = mIdToClientInfoMap.get(id);
416 if (clientInfo == null) {
417 Slog.e(TAG, "Unique id with no client mapping: " + id);
418 handled = false;
419 return handled;
420 }
421
422 /* This goes in response as msg.arg2 */
Christopher Lane5a577902014-04-25 18:39:07 -0700423 int clientId = clientInfo.getClientId(id);
424 if (clientId < 0) {
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700425 // This can happen because of race conditions. For example,
426 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
427 // and we may get in this situation.
428 Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
429 handled = false;
430 return handled;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700431 }
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700432
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700433 switch (code) {
434 case NativeResponseCode.SERVICE_FOUND:
435 /* NNN uniqueId serviceName regType domain */
436 if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700437 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700438 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
439 clientId, servInfo);
440 break;
441 case NativeResponseCode.SERVICE_LOST:
442 /* NNN uniqueId serviceName regType domain */
443 if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700444 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700445 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
446 clientId, servInfo);
447 break;
448 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
449 /* NNN uniqueId errorCode */
450 if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
451 clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
452 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
453 break;
454 case NativeResponseCode.SERVICE_REGISTERED:
455 /* NNN regId serviceName regType */
456 if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700457 servInfo = new NsdServiceInfo(cooked[2], null);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700458 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
459 id, clientId, servInfo);
460 break;
461 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
462 /* NNN regId errorCode */
463 if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
464 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
465 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
466 break;
467 case NativeResponseCode.SERVICE_UPDATED:
468 /* NNN regId */
469 break;
470 case NativeResponseCode.SERVICE_UPDATE_FAILED:
471 /* NNN regId errorCode */
472 break;
473 case NativeResponseCode.SERVICE_RESOLVED:
474 /* NNN resolveId fullName hostName port txtlen txtdata */
475 if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700476 int index = 0;
477 while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
478 if (cooked[2].charAt(index) == '\\') {
479 ++index;
480 }
481 ++index;
482 }
483 if (index >= cooked[2].length()) {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700484 Slog.e(TAG, "Invalid service found " + raw);
485 break;
486 }
487 String name = cooked[2].substring(0, index);
488 String rest = cooked[2].substring(index);
489 String type = rest.replace(".local.", "");
490
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700491 name = unescape(name);
492
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700493 clientInfo.mResolvedService.setServiceName(name);
494 clientInfo.mResolvedService.setServiceType(type);
495 clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
496
497 stopResolveService(id);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800498 removeRequestMap(clientId, id, clientInfo);
499
500 int id2 = getUniqueId();
501 if (getAddrInfo(id2, cooked[3])) {
Dave Plattf31760c2014-03-07 14:48:22 -0800502 storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800503 } else {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700504 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
505 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700506 clientInfo.mResolvedService = null;
507 }
508 break;
509 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
510 /* NNN resolveId errorCode */
511 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
512 stopResolveService(id);
513 removeRequestMap(clientId, id, clientInfo);
514 clientInfo.mResolvedService = null;
515 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
516 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
517 break;
518 case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
519 /* NNN resolveId errorCode */
520 stopGetAddrInfo(id);
521 removeRequestMap(clientId, id, clientInfo);
522 clientInfo.mResolvedService = null;
523 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
524 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
525 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
526 break;
527 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
528 /* NNN resolveId hostname ttl addr */
529 if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
530 try {
531 clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
532 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
533 0, clientId, clientInfo.mResolvedService);
534 } catch (java.net.UnknownHostException e) {
535 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
536 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
537 }
538 stopGetAddrInfo(id);
539 removeRequestMap(clientId, id, clientInfo);
540 clientInfo.mResolvedService = null;
541 break;
542 default:
543 handled = false;
544 break;
545 }
546 return handled;
547 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700548 }
549 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700550
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700551 private String unescape(String s) {
552 StringBuilder sb = new StringBuilder(s.length());
553 for (int i = 0; i < s.length(); ++i) {
554 char c = s.charAt(i);
555 if (c == '\\') {
556 if (++i >= s.length()) {
557 Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
558 break;
559 }
560 c = s.charAt(i);
561 if (c != '.' && c != '\\') {
562 if (i + 2 >= s.length()) {
563 Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
564 break;
565 }
566 c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
567 i += 2;
568 }
569 }
570 sb.append(c);
571 }
572 return sb.toString();
573 }
574
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700575 private NativeDaemonConnector mNativeConnector;
576 private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
577
578 private NsdService(Context context) {
579 mContext = context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700580 mContentResolver = context.getContentResolver();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700581
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700582 mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800583 MDNS_TAG, 25, null);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700584
585 mNsdStateMachine = new NsdStateMachine(TAG);
586 mNsdStateMachine.start();
587
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700588 Thread th = new Thread(mNativeConnector, MDNS_TAG);
589 th.start();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700590 }
591
592 public static NsdService create(Context context) throws InterruptedException {
593 NsdService service = new NsdService(context);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700594 service.mNativeDaemonConnected.await();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700595 return service;
596 }
597
598 public Messenger getMessenger() {
Irfan Sheriff92784672012-04-13 12:15:41 -0700599 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
600 "NsdService");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700601 return new Messenger(mNsdStateMachine.getHandler());
602 }
603
604 public void setEnabled(boolean enable) {
605 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
606 "NsdService");
Jeff Sharkey625239a2012-09-26 22:03:49 -0700607 Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700608 if (enable) {
609 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
610 } else {
611 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
612 }
613 }
614
615 private void sendNsdStateChangeBroadcast(boolean enabled) {
Irfan Sheriff54ac7a52012-04-19 10:26:34 -0700616 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700617 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
618 if (enabled) {
619 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
620 } else {
621 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
622 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700623 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700624 }
625
626 private boolean isNsdEnabled() {
Jeff Sharkey625239a2012-09-26 22:03:49 -0700627 boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700628 if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
629 return ret;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700630 }
631
Irfan Sheriff817388e2012-04-11 14:52:19 -0700632 private int getUniqueId() {
633 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
634 return mUniqueId;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700635 }
636
Sreeram Ramachandran03666c72014-07-19 23:21:46 -0700637 /* These should be in sync with system/netd/server/ResponseCode.h */
Irfan Sheriff817388e2012-04-11 14:52:19 -0700638 class NativeResponseCode {
639 public static final int SERVICE_DISCOVERY_FAILED = 602;
640 public static final int SERVICE_FOUND = 603;
641 public static final int SERVICE_LOST = 604;
642
643 public static final int SERVICE_REGISTRATION_FAILED = 605;
644 public static final int SERVICE_REGISTERED = 606;
645
646 public static final int SERVICE_RESOLUTION_FAILED = 607;
647 public static final int SERVICE_RESOLVED = 608;
648
649 public static final int SERVICE_UPDATED = 609;
650 public static final int SERVICE_UPDATE_FAILED = 610;
651
652 public static final int SERVICE_GET_ADDR_FAILED = 611;
653 public static final int SERVICE_GET_ADDR_SUCCESS = 612;
654 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700655
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700656 private class NativeEvent {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700657 final int code;
658 final String raw;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700659 final String[] cooked;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700660
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700661 NativeEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700662 this.code = code;
663 this.raw = raw;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700664 this.cooked = cooked;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700665 }
666 }
667
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700668 class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
669 public void onDaemonConnected() {
670 mNativeDaemonConnected.countDown();
671 }
672
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800673 public boolean onCheckHoldWakeLock(int code) {
674 return false;
675 }
676
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700677 public boolean onEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700678 // TODO: NDC translates a message to a callback, we could enhance NDC to
679 // directly interact with a state machine through messages
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700680 NativeEvent event = new NativeEvent(code, raw, cooked);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700681 mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
682 return true;
683 }
684 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700685
Irfan Sheriff817388e2012-04-11 14:52:19 -0700686 private boolean startMDnsDaemon() {
687 if (DBG) Slog.d(TAG, "startMDnsDaemon");
688 try {
689 mNativeConnector.execute("mdnssd", "start-service");
690 } catch(NativeDaemonConnectorException e) {
691 Slog.e(TAG, "Failed to start daemon" + e);
692 return false;
693 }
694 return true;
695 }
696
697 private boolean stopMDnsDaemon() {
698 if (DBG) Slog.d(TAG, "stopMDnsDaemon");
699 try {
700 mNativeConnector.execute("mdnssd", "stop-service");
701 } catch(NativeDaemonConnectorException e) {
702 Slog.e(TAG, "Failed to start daemon" + e);
703 return false;
704 }
705 return true;
706 }
707
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700708 private boolean registerService(int regId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700709 if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700710 try {
Christopher Laneb72d8b42014-03-17 16:35:45 -0700711 Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700712 service.getServiceType(), service.getPort());
Christopher Laneb72d8b42014-03-17 16:35:45 -0700713
714 // Add TXT records as additional arguments.
715 Map<String, byte[]> txtRecords = service.getAttributes();
716 for (String key : txtRecords.keySet()) {
717 try {
718 // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
Christopher Lane0f35cdd2014-09-13 11:13:39 -0700719 byte[] recordValue = txtRecords.get(key);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700720 cmd.appendArg(String.format(Locale.US, "%s=%s", key,
Christopher Lane0f35cdd2014-09-13 11:13:39 -0700721 recordValue != null ? new String(recordValue, "UTF_8") : ""));
Christopher Laneb72d8b42014-03-17 16:35:45 -0700722 } catch (UnsupportedEncodingException e) {
723 Slog.e(TAG, "Failed to encode txtRecord " + e);
724 }
725 }
726
727 mNativeConnector.execute(cmd);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700728 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700729 Slog.e(TAG, "Failed to execute registerService " + e);
730 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700731 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700732 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700733 }
734
Irfan Sheriff817388e2012-04-11 14:52:19 -0700735 private boolean unregisterService(int regId) {
736 if (DBG) Slog.d(TAG, "unregisterService: " + regId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700737 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700738 mNativeConnector.execute("mdnssd", "stop-register", regId);
739 } catch(NativeDaemonConnectorException e) {
740 Slog.e(TAG, "Failed to execute unregisterService " + e);
741 return false;
742 }
743 return true;
744 }
745
746 private boolean updateService(int regId, DnsSdTxtRecord t) {
747 if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
748 try {
749 if (t == null) return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700750 mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
751 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700752 Slog.e(TAG, "Failed to updateServices " + e);
753 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700754 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700755 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700756 }
757
Irfan Sheriff817388e2012-04-11 14:52:19 -0700758 private boolean discoverServices(int discoveryId, String serviceType) {
759 if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700760 try {
761 mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
762 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700763 Slog.e(TAG, "Failed to discoverServices " + e);
764 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700765 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700766 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700767 }
768
Irfan Sheriff817388e2012-04-11 14:52:19 -0700769 private boolean stopServiceDiscovery(int discoveryId) {
770 if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700771 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700772 mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700773 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700774 Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
775 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700776 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700777 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700778 }
779
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700780 private boolean resolveService(int resolveId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700781 if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700782 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700783 mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
784 service.getServiceType(), "local.");
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700785 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700786 Slog.e(TAG, "Failed to resolveService " + e);
787 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700788 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700789 return true;
790 }
791
792 private boolean stopResolveService(int resolveId) {
793 if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
794 try {
795 mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
796 } catch(NativeDaemonConnectorException e) {
797 Slog.e(TAG, "Failed to stop resolve " + e);
798 return false;
799 }
800 return true;
801 }
802
803 private boolean getAddrInfo(int resolveId, String hostname) {
804 if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
805 try {
806 mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
807 } catch(NativeDaemonConnectorException e) {
808 Slog.e(TAG, "Failed to getAddrInfo " + e);
809 return false;
810 }
811 return true;
812 }
813
814 private boolean stopGetAddrInfo(int resolveId) {
815 if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
816 try {
817 mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
818 } catch(NativeDaemonConnectorException e) {
819 Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
820 return false;
821 }
822 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700823 }
824
825 @Override
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700826 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700827 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
828 != PackageManager.PERMISSION_GRANTED) {
829 pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
830 + Binder.getCallingPid()
831 + ", uid=" + Binder.getCallingUid());
832 return;
833 }
834
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700835 for (ClientInfo client : mClients.values()) {
836 pw.println("Client Info");
837 pw.println(client);
838 }
839
840 mNsdStateMachine.dump(fd, pw, args);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700841 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700842
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700843 /* arg2 on the source message has an id that needs to be retained in replies
844 * see NsdManager for details */
845 private Message obtainMessage(Message srcMsg) {
846 Message msg = Message.obtain();
847 msg.arg2 = srcMsg.arg2;
848 return msg;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700849 }
850
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700851 private void replyToMessage(Message msg, int what) {
852 if (msg.replyTo == null) return;
853 Message dstMsg = obtainMessage(msg);
854 dstMsg.what = what;
855 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700856 }
857
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700858 private void replyToMessage(Message msg, int what, int arg1) {
859 if (msg.replyTo == null) return;
860 Message dstMsg = obtainMessage(msg);
861 dstMsg.what = what;
862 dstMsg.arg1 = arg1;
863 mReplyChannel.replyToMessage(msg, dstMsg);
864 }
865
866 private void replyToMessage(Message msg, int what, Object obj) {
867 if (msg.replyTo == null) return;
868 Message dstMsg = obtainMessage(msg);
869 dstMsg.what = what;
870 dstMsg.obj = obj;
871 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700872 }
873
874 /* Information tracked per client */
875 private class ClientInfo {
876
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700877 private static final int MAX_LIMIT = 10;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700878 private final AsyncChannel mChannel;
879 private final Messenger mMessenger;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700880 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700881 private NsdServiceInfo mResolvedService;
882
883 /* A map from client id to unique id sent to mDns */
884 private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
Irfan Sheriff817388e2012-04-11 14:52:19 -0700885
Dave Plattf31760c2014-03-07 14:48:22 -0800886 /* A map from client id to the type of the request we had received */
887 private SparseArray<Integer> mClientRequests = new SparseArray<Integer>();
888
Irfan Sheriff817388e2012-04-11 14:52:19 -0700889 private ClientInfo(AsyncChannel c, Messenger m) {
890 mChannel = c;
891 mMessenger = m;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700892 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
893 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700894
895 @Override
896 public String toString() {
897 StringBuffer sb = new StringBuffer();
898 sb.append("mChannel ").append(mChannel).append("\n");
899 sb.append("mMessenger ").append(mMessenger).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700900 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700901 for(int i = 0; i< mClientIds.size(); i++) {
Dave Plattf31760c2014-03-07 14:48:22 -0800902 int clientID = mClientIds.keyAt(i);
903 sb.append("clientId ").append(clientID).
904 append(" mDnsId ").append(mClientIds.valueAt(i)).
905 append(" type ").append(mClientRequests.get(clientID)).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700906 }
907 return sb.toString();
908 }
Dave Plattf31760c2014-03-07 14:48:22 -0800909
910 // Remove any pending requests from the global map when we get rid of a client,
911 // and send cancellations to the daemon.
912 private void expungeAllRequests() {
913 int globalId, clientId, i;
914 for (i = 0; i < mClientIds.size(); i++) {
915 clientId = mClientIds.keyAt(i);
916 globalId = mClientIds.valueAt(i);
917 mIdToClientInfoMap.remove(globalId);
918 if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
919 " global-ID " + globalId + " type " + mClientRequests.get(clientId));
920 switch (mClientRequests.get(clientId)) {
921 case NsdManager.DISCOVER_SERVICES:
922 stopServiceDiscovery(globalId);
923 break;
924 case NsdManager.RESOLVE_SERVICE:
925 stopResolveService(globalId);
926 break;
927 case NsdManager.REGISTER_SERVICE:
928 unregisterService(globalId);
929 break;
930 default:
931 break;
932 }
933 }
934 mClientIds.clear();
935 mClientRequests.clear();
936 }
937
Christopher Lane5a577902014-04-25 18:39:07 -0700938 // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id,
939 // return the corresponding listener id. mDnsClient id is also called a global id.
940 private int getClientId(final int globalId) {
941 // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals)
942 // while also coercing the int primitives to Integer objects.
943 for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) {
944 int mDnsId = mClientIds.valueAt(i);
945 if (globalId == mDnsId) {
946 return mClientIds.keyAt(i);
947 }
948 }
949 return -1;
950 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700951 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700952}