blob: f4c62259e1949c55a58c1755f05cf76d42004f34 [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;
Christopher Laneb72d8b42014-03-17 16:35:45 -070041import java.util.Locale;
42import java.util.Map;
Irfan Sheriff817388e2012-04-11 14:52:19 -070043import java.util.concurrent.CountDownLatch;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070044
Irfan Sheriff7d024d32012-03-22 17:01:39 -070045import com.android.internal.util.AsyncChannel;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070046import com.android.internal.util.Protocol;
47import com.android.internal.util.State;
48import com.android.internal.util.StateMachine;
Christopher Lane771cd652014-04-14 16:31:27 -070049import com.android.server.NativeDaemonConnector.Command;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070050
51/**
52 * Network Service Discovery Service handles remote service discovery operation requests by
53 * implementing the INsdManager interface.
54 *
55 * @hide
56 */
57public class NsdService extends INsdManager.Stub {
58 private static final String TAG = "NsdService";
59 private static final String MDNS_TAG = "mDnsConnector";
60
61 private static final boolean DBG = true;
62
63 private Context mContext;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070064 private ContentResolver mContentResolver;
65 private NsdStateMachine mNsdStateMachine;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070066
67 /**
68 * Clients receiving asynchronous messages
69 */
Irfan Sheriff817388e2012-04-11 14:52:19 -070070 private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070071
Irfan Sheriff22af38c2012-05-03 16:44:27 -070072 /* A map from unique id to client info */
73 private SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<ClientInfo>();
74
Irfan Sheriff7d024d32012-03-22 17:01:39 -070075 private AsyncChannel mReplyChannel = new AsyncChannel();
76
Irfan Sheriff817388e2012-04-11 14:52:19 -070077 private int INVALID_ID = 0;
78 private int mUniqueId = 1;
79
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070080 private static final int BASE = Protocol.BASE_NSD_MANAGER;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070081 private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070082 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
Irfan Sheriff7d024d32012-03-22 17:01:39 -070083
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070084 static {
85 sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
86 sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
87 sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
88 sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
89 sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070090 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -070091
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070092 private static String cmdToString(int cmd) {
93 cmd -= BASE;
94 if ((cmd >= 0) && (cmd < sCmdToString.length)) {
95 return sCmdToString[cmd];
96 } else {
97 return null;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070098 }
99 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700100
101 private class NsdStateMachine extends StateMachine {
102
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700103 private final DefaultState mDefaultState = new DefaultState();
104 private final DisabledState mDisabledState = new DisabledState();
105 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700106
107 @Override
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700108 protected String getWhatToString(int what) {
109 return cmdToString(what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700110 }
111
Irfan Sheriff919aca52012-06-01 16:44:13 -0700112 /**
113 * Observes the NSD on/off setting, and takes action when changed.
114 */
115 private void registerForNsdSetting() {
116 ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
117 @Override
118 public void onChange(boolean selfChange) {
119 if (isNsdEnabled()) {
120 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
121 } else {
122 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
123 }
124 }
125 };
126
127 mContext.getContentResolver().registerContentObserver(
Jeff Sharkey625239a2012-09-26 22:03:49 -0700128 Settings.Global.getUriFor(Settings.Global.NSD_ON),
Irfan Sheriff919aca52012-06-01 16:44:13 -0700129 false, contentObserver);
130 }
131
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700132 NsdStateMachine(String name) {
133 super(name);
134 addState(mDefaultState);
135 addState(mDisabledState, mDefaultState);
136 addState(mEnabledState, mDefaultState);
137 if (isNsdEnabled()) {
138 setInitialState(mEnabledState);
139 } else {
140 setInitialState(mDisabledState);
141 }
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700142 setLogRecSize(25);
Irfan Sheriff919aca52012-06-01 16:44:13 -0700143 registerForNsdSetting();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700144 }
145
146 class DefaultState extends State {
147 @Override
148 public boolean processMessage(Message msg) {
Dave Plattf31760c2014-03-07 14:48:22 -0800149 ClientInfo cInfo = null;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700150 switch (msg.what) {
151 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
152 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
153 AsyncChannel c = (AsyncChannel) msg.obj;
154 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
155 c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
Dave Plattf31760c2014-03-07 14:48:22 -0800156 cInfo = new ClientInfo(c, msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700157 mClients.put(msg.replyTo, cInfo);
158 } else {
159 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
160 }
161 break;
162 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Dave Plattf31760c2014-03-07 14:48:22 -0800163 switch (msg.arg1) {
164 case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
165 Slog.e(TAG, "Send failed, client connection lost");
166 break;
167 case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
168 if (DBG) Slog.d(TAG, "Client disconnected");
169 break;
170 default:
171 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
172 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700173 }
Dave Plattf31760c2014-03-07 14:48:22 -0800174 cInfo = mClients.get(msg.replyTo);
175 if (cInfo != null) {
176 cInfo.expungeAllRequests();
177 mClients.remove(msg.replyTo);
178 }
179 //Last client
180 if (mClients.size() == 0) {
181 stopMDnsDaemon();
182 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700183 break;
184 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
185 AsyncChannel ac = new AsyncChannel();
186 ac.connect(mContext, getHandler(), msg.replyTo);
187 break;
188 case NsdManager.DISCOVER_SERVICES:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700189 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
190 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700191 break;
192 case NsdManager.STOP_DISCOVERY:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700193 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
194 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700195 break;
196 case NsdManager.REGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700197 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
198 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700199 break;
200 case NsdManager.UNREGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700201 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
202 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700203 break;
204 case NsdManager.RESOLVE_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700205 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
206 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700207 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700208 case NsdManager.NATIVE_DAEMON_EVENT:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700209 default:
210 Slog.e(TAG, "Unhandled " + msg);
211 return NOT_HANDLED;
212 }
213 return HANDLED;
214 }
215 }
216
217 class DisabledState extends State {
218 @Override
219 public void enter() {
220 sendNsdStateChangeBroadcast(false);
221 }
222
223 @Override
224 public boolean processMessage(Message msg) {
225 switch (msg.what) {
226 case NsdManager.ENABLE:
227 transitionTo(mEnabledState);
228 break;
229 default:
230 return NOT_HANDLED;
231 }
232 return HANDLED;
233 }
234 }
235
236 class EnabledState extends State {
237 @Override
238 public void enter() {
239 sendNsdStateChangeBroadcast(true);
240 if (mClients.size() > 0) {
241 startMDnsDaemon();
242 }
243 }
244
245 @Override
246 public void exit() {
247 if (mClients.size() > 0) {
248 stopMDnsDaemon();
249 }
250 }
251
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700252 private boolean requestLimitReached(ClientInfo clientInfo) {
253 if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
254 if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
255 return true;
256 }
257 return false;
258 }
259
Dave Plattf31760c2014-03-07 14:48:22 -0800260 private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700261 clientInfo.mClientIds.put(clientId, globalId);
Dave Plattf31760c2014-03-07 14:48:22 -0800262 clientInfo.mClientRequests.put(clientId, what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700263 mIdToClientInfoMap.put(globalId, clientInfo);
264 }
265
266 private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
267 clientInfo.mClientIds.remove(clientId);
Dave Plattf31760c2014-03-07 14:48:22 -0800268 clientInfo.mClientRequests.remove(clientId);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700269 mIdToClientInfoMap.remove(globalId);
270 }
271
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700272 @Override
273 public boolean processMessage(Message msg) {
274 ClientInfo clientInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700275 NsdServiceInfo servInfo;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700276 boolean result = HANDLED;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700277 int id;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700278 switch (msg.what) {
279 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
280 //First client
281 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
282 mClients.size() == 0) {
283 startMDnsDaemon();
284 }
285 result = NOT_HANDLED;
286 break;
287 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700288 result = NOT_HANDLED;
289 break;
290 case NsdManager.DISABLE:
291 //TODO: cleanup clients
292 transitionTo(mDisabledState);
293 break;
294 case NsdManager.DISCOVER_SERVICES:
295 if (DBG) Slog.d(TAG, "Discover services");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700296 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700297 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700298
299 if (requestLimitReached(clientInfo)) {
300 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
301 NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700302 break;
303 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700304
305 id = getUniqueId();
306 if (discoverServices(id, servInfo.getServiceType())) {
307 if (DBG) {
308 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
309 servInfo.getServiceType());
310 }
Dave Plattf31760c2014-03-07 14:48:22 -0800311 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700312 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700313 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700314 stopServiceDiscovery(id);
315 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
316 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700317 }
318 break;
319 case NsdManager.STOP_DISCOVERY:
320 if (DBG) Slog.d(TAG, "Stop service discovery");
321 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700322
323 try {
324 id = clientInfo.mClientIds.get(msg.arg2).intValue();
325 } catch (NullPointerException e) {
326 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
327 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700328 break;
329 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700330 removeRequestMap(msg.arg2, id, clientInfo);
331 if (stopServiceDiscovery(id)) {
332 replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700333 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700334 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
335 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700336 }
337 break;
338 case NsdManager.REGISTER_SERVICE:
339 if (DBG) Slog.d(TAG, "Register service");
340 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700341 if (requestLimitReached(clientInfo)) {
342 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
343 NsdManager.FAILURE_MAX_LIMIT);
344 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700345 }
346
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700347 id = getUniqueId();
348 if (registerService(id, (NsdServiceInfo) msg.obj)) {
349 if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
Dave Plattf31760c2014-03-07 14:48:22 -0800350 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700351 // Return success after mDns reports success
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700352 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700353 unregisterService(id);
354 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
355 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700356 }
357 break;
358 case NsdManager.UNREGISTER_SERVICE:
359 if (DBG) Slog.d(TAG, "unregister service");
360 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700361 try {
362 id = clientInfo.mClientIds.get(msg.arg2).intValue();
363 } catch (NullPointerException e) {
364 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
365 NsdManager.FAILURE_INTERNAL_ERROR);
366 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700367 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700368 removeRequestMap(msg.arg2, id, clientInfo);
369 if (unregisterService(id)) {
370 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
371 } else {
372 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
373 NsdManager.FAILURE_INTERNAL_ERROR);
374 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700375 break;
376 case NsdManager.RESOLVE_SERVICE:
377 if (DBG) Slog.d(TAG, "Resolve service");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700378 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700379 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700380
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700381
382 if (clientInfo.mResolvedService != null) {
383 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
384 NsdManager.FAILURE_ALREADY_ACTIVE);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700385 break;
386 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700387
388 id = getUniqueId();
389 if (resolveService(id, servInfo)) {
390 clientInfo.mResolvedService = new NsdServiceInfo();
Dave Plattf31760c2014-03-07 14:48:22 -0800391 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700392 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700393 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
394 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700395 }
396 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700397 case NsdManager.NATIVE_DAEMON_EVENT:
398 NativeEvent event = (NativeEvent) msg.obj;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700399 if (!handleNativeEvent(event.code, event.raw, event.cooked)) {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700400 result = NOT_HANDLED;
401 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700402 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700403 default:
404 result = NOT_HANDLED;
405 break;
406 }
407 return result;
408 }
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700409
410 private boolean handleNativeEvent(int code, String raw, String[] cooked) {
411 boolean handled = true;
412 NsdServiceInfo servInfo;
413 int id = Integer.parseInt(cooked[1]);
414 ClientInfo clientInfo = mIdToClientInfoMap.get(id);
415 if (clientInfo == null) {
416 Slog.e(TAG, "Unique id with no client mapping: " + id);
417 handled = false;
418 return handled;
419 }
420
421 /* This goes in response as msg.arg2 */
Christopher Lane5a577902014-04-25 18:39:07 -0700422 int clientId = clientInfo.getClientId(id);
423 if (clientId < 0) {
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700424 // This can happen because of race conditions. For example,
425 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
426 // and we may get in this situation.
427 Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
428 handled = false;
429 return handled;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700430 }
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700431
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700432 switch (code) {
433 case NativeResponseCode.SERVICE_FOUND:
434 /* NNN uniqueId serviceName regType domain */
435 if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700436 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700437 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
438 clientId, servInfo);
439 break;
440 case NativeResponseCode.SERVICE_LOST:
441 /* NNN uniqueId serviceName regType domain */
442 if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700443 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700444 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
445 clientId, servInfo);
446 break;
447 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
448 /* NNN uniqueId errorCode */
449 if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
450 clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
451 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
452 break;
453 case NativeResponseCode.SERVICE_REGISTERED:
454 /* NNN regId serviceName regType */
455 if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700456 servInfo = new NsdServiceInfo(cooked[2], null);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700457 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
458 id, clientId, servInfo);
459 break;
460 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
461 /* NNN regId errorCode */
462 if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
463 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
464 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
465 break;
466 case NativeResponseCode.SERVICE_UPDATED:
467 /* NNN regId */
468 break;
469 case NativeResponseCode.SERVICE_UPDATE_FAILED:
470 /* NNN regId errorCode */
471 break;
472 case NativeResponseCode.SERVICE_RESOLVED:
473 /* NNN resolveId fullName hostName port txtlen txtdata */
474 if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700475 int index = 0;
476 while (index < cooked[2].length() && cooked[2].charAt(index) != '.') {
477 if (cooked[2].charAt(index) == '\\') {
478 ++index;
479 }
480 ++index;
481 }
482 if (index >= cooked[2].length()) {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700483 Slog.e(TAG, "Invalid service found " + raw);
484 break;
485 }
486 String name = cooked[2].substring(0, index);
487 String rest = cooked[2].substring(index);
488 String type = rest.replace(".local.", "");
489
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700490 name = unescape(name);
491
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700492 clientInfo.mResolvedService.setServiceName(name);
493 clientInfo.mResolvedService.setServiceType(type);
494 clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
495
496 stopResolveService(id);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800497 removeRequestMap(clientId, id, clientInfo);
498
499 int id2 = getUniqueId();
500 if (getAddrInfo(id2, cooked[3])) {
Dave Plattf31760c2014-03-07 14:48:22 -0800501 storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800502 } else {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700503 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
504 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700505 clientInfo.mResolvedService = null;
506 }
507 break;
508 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
509 /* NNN resolveId errorCode */
510 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
511 stopResolveService(id);
512 removeRequestMap(clientId, id, clientInfo);
513 clientInfo.mResolvedService = null;
514 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
515 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
516 break;
517 case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
518 /* NNN resolveId errorCode */
519 stopGetAddrInfo(id);
520 removeRequestMap(clientId, id, clientInfo);
521 clientInfo.mResolvedService = null;
522 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
523 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
524 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
525 break;
526 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
527 /* NNN resolveId hostname ttl addr */
528 if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
529 try {
530 clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
531 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
532 0, clientId, clientInfo.mResolvedService);
533 } catch (java.net.UnknownHostException e) {
534 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
535 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
536 }
537 stopGetAddrInfo(id);
538 removeRequestMap(clientId, id, clientInfo);
539 clientInfo.mResolvedService = null;
540 break;
541 default:
542 handled = false;
543 break;
544 }
545 return handled;
546 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700547 }
548 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700549
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700550 private String unescape(String s) {
551 StringBuilder sb = new StringBuilder(s.length());
552 for (int i = 0; i < s.length(); ++i) {
553 char c = s.charAt(i);
554 if (c == '\\') {
555 if (++i >= s.length()) {
556 Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
557 break;
558 }
559 c = s.charAt(i);
560 if (c != '.' && c != '\\') {
561 if (i + 2 >= s.length()) {
562 Slog.e(TAG, "Unexpected end of escape sequence in: " + s);
563 break;
564 }
565 c = (char) ((c-'0') * 100 + (s.charAt(i+1)-'0') * 10 + (s.charAt(i+2)-'0'));
566 i += 2;
567 }
568 }
569 sb.append(c);
570 }
571 return sb.toString();
572 }
573
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700574 private NativeDaemonConnector mNativeConnector;
575 private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
576
577 private NsdService(Context context) {
578 mContext = context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700579 mContentResolver = context.getContentResolver();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700580
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700581 mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800582 MDNS_TAG, 25, null);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700583
584 mNsdStateMachine = new NsdStateMachine(TAG);
585 mNsdStateMachine.start();
586
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700587 Thread th = new Thread(mNativeConnector, MDNS_TAG);
588 th.start();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700589 }
590
591 public static NsdService create(Context context) throws InterruptedException {
592 NsdService service = new NsdService(context);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700593 service.mNativeDaemonConnected.await();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700594 return service;
595 }
596
597 public Messenger getMessenger() {
Irfan Sheriff92784672012-04-13 12:15:41 -0700598 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
599 "NsdService");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700600 return new Messenger(mNsdStateMachine.getHandler());
601 }
602
603 public void setEnabled(boolean enable) {
604 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
605 "NsdService");
Jeff Sharkey625239a2012-09-26 22:03:49 -0700606 Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700607 if (enable) {
608 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
609 } else {
610 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
611 }
612 }
613
614 private void sendNsdStateChangeBroadcast(boolean enabled) {
Irfan Sheriff54ac7a52012-04-19 10:26:34 -0700615 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700616 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
617 if (enabled) {
618 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
619 } else {
620 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
621 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700622 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700623 }
624
625 private boolean isNsdEnabled() {
Jeff Sharkey625239a2012-09-26 22:03:49 -0700626 boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700627 if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
628 return ret;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700629 }
630
Irfan Sheriff817388e2012-04-11 14:52:19 -0700631 private int getUniqueId() {
632 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
633 return mUniqueId;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700634 }
635
Sreeram Ramachandran03666c72014-07-19 23:21:46 -0700636 /* These should be in sync with system/netd/server/ResponseCode.h */
Irfan Sheriff817388e2012-04-11 14:52:19 -0700637 class NativeResponseCode {
638 public static final int SERVICE_DISCOVERY_FAILED = 602;
639 public static final int SERVICE_FOUND = 603;
640 public static final int SERVICE_LOST = 604;
641
642 public static final int SERVICE_REGISTRATION_FAILED = 605;
643 public static final int SERVICE_REGISTERED = 606;
644
645 public static final int SERVICE_RESOLUTION_FAILED = 607;
646 public static final int SERVICE_RESOLVED = 608;
647
648 public static final int SERVICE_UPDATED = 609;
649 public static final int SERVICE_UPDATE_FAILED = 610;
650
651 public static final int SERVICE_GET_ADDR_FAILED = 611;
652 public static final int SERVICE_GET_ADDR_SUCCESS = 612;
653 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700654
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700655 private class NativeEvent {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700656 final int code;
657 final String raw;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700658 final String[] cooked;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700659
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700660 NativeEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700661 this.code = code;
662 this.raw = raw;
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700663 this.cooked = cooked;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700664 }
665 }
666
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700667 class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
668 public void onDaemonConnected() {
669 mNativeDaemonConnected.countDown();
670 }
671
Dianne Hackborn77b987f2014-02-26 16:20:52 -0800672 public boolean onCheckHoldWakeLock(int code) {
673 return false;
674 }
675
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700676 public boolean onEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700677 // TODO: NDC translates a message to a callback, we could enhance NDC to
678 // directly interact with a state machine through messages
Sreeram Ramachandranef128842014-09-03 15:45:59 -0700679 NativeEvent event = new NativeEvent(code, raw, cooked);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700680 mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
681 return true;
682 }
683 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700684
Irfan Sheriff817388e2012-04-11 14:52:19 -0700685 private boolean startMDnsDaemon() {
686 if (DBG) Slog.d(TAG, "startMDnsDaemon");
687 try {
688 mNativeConnector.execute("mdnssd", "start-service");
689 } catch(NativeDaemonConnectorException e) {
690 Slog.e(TAG, "Failed to start daemon" + e);
691 return false;
692 }
693 return true;
694 }
695
696 private boolean stopMDnsDaemon() {
697 if (DBG) Slog.d(TAG, "stopMDnsDaemon");
698 try {
699 mNativeConnector.execute("mdnssd", "stop-service");
700 } catch(NativeDaemonConnectorException e) {
701 Slog.e(TAG, "Failed to start daemon" + e);
702 return false;
703 }
704 return true;
705 }
706
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700707 private boolean registerService(int regId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700708 if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700709 try {
Christopher Laneb72d8b42014-03-17 16:35:45 -0700710 Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700711 service.getServiceType(), service.getPort());
Christopher Laneb72d8b42014-03-17 16:35:45 -0700712
713 // Add TXT records as additional arguments.
714 Map<String, byte[]> txtRecords = service.getAttributes();
715 for (String key : txtRecords.keySet()) {
716 try {
717 // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
Christopher Lane0f35cdd2014-09-13 11:13:39 -0700718 byte[] recordValue = txtRecords.get(key);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700719 cmd.appendArg(String.format(Locale.US, "%s=%s", key,
Christopher Lane0f35cdd2014-09-13 11:13:39 -0700720 recordValue != null ? new String(recordValue, "UTF_8") : ""));
Christopher Laneb72d8b42014-03-17 16:35:45 -0700721 } catch (UnsupportedEncodingException e) {
722 Slog.e(TAG, "Failed to encode txtRecord " + e);
723 }
724 }
725
726 mNativeConnector.execute(cmd);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700727 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700728 Slog.e(TAG, "Failed to execute registerService " + e);
729 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700730 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700731 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700732 }
733
Irfan Sheriff817388e2012-04-11 14:52:19 -0700734 private boolean unregisterService(int regId) {
735 if (DBG) Slog.d(TAG, "unregisterService: " + regId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700736 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700737 mNativeConnector.execute("mdnssd", "stop-register", regId);
738 } catch(NativeDaemonConnectorException e) {
739 Slog.e(TAG, "Failed to execute unregisterService " + e);
740 return false;
741 }
742 return true;
743 }
744
745 private boolean updateService(int regId, DnsSdTxtRecord t) {
746 if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
747 try {
748 if (t == null) return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700749 mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
750 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700751 Slog.e(TAG, "Failed to updateServices " + e);
752 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700753 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700754 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700755 }
756
Irfan Sheriff817388e2012-04-11 14:52:19 -0700757 private boolean discoverServices(int discoveryId, String serviceType) {
758 if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700759 try {
760 mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
761 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700762 Slog.e(TAG, "Failed to discoverServices " + e);
763 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700764 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700765 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700766 }
767
Irfan Sheriff817388e2012-04-11 14:52:19 -0700768 private boolean stopServiceDiscovery(int discoveryId) {
769 if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700770 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700771 mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700772 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700773 Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
774 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700775 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700776 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700777 }
778
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700779 private boolean resolveService(int resolveId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700780 if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700781 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700782 mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
783 service.getServiceType(), "local.");
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700784 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700785 Slog.e(TAG, "Failed to resolveService " + e);
786 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700787 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700788 return true;
789 }
790
791 private boolean stopResolveService(int resolveId) {
792 if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
793 try {
794 mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
795 } catch(NativeDaemonConnectorException e) {
796 Slog.e(TAG, "Failed to stop resolve " + e);
797 return false;
798 }
799 return true;
800 }
801
802 private boolean getAddrInfo(int resolveId, String hostname) {
803 if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
804 try {
805 mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
806 } catch(NativeDaemonConnectorException e) {
807 Slog.e(TAG, "Failed to getAddrInfo " + e);
808 return false;
809 }
810 return true;
811 }
812
813 private boolean stopGetAddrInfo(int resolveId) {
814 if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
815 try {
816 mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
817 } catch(NativeDaemonConnectorException e) {
818 Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
819 return false;
820 }
821 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700822 }
823
824 @Override
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700825 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700826 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
827 != PackageManager.PERMISSION_GRANTED) {
828 pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
829 + Binder.getCallingPid()
830 + ", uid=" + Binder.getCallingUid());
831 return;
832 }
833
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700834 for (ClientInfo client : mClients.values()) {
835 pw.println("Client Info");
836 pw.println(client);
837 }
838
839 mNsdStateMachine.dump(fd, pw, args);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700840 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700841
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700842 /* arg2 on the source message has an id that needs to be retained in replies
843 * see NsdManager for details */
844 private Message obtainMessage(Message srcMsg) {
845 Message msg = Message.obtain();
846 msg.arg2 = srcMsg.arg2;
847 return msg;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700848 }
849
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700850 private void replyToMessage(Message msg, int what) {
851 if (msg.replyTo == null) return;
852 Message dstMsg = obtainMessage(msg);
853 dstMsg.what = what;
854 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700855 }
856
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700857 private void replyToMessage(Message msg, int what, int arg1) {
858 if (msg.replyTo == null) return;
859 Message dstMsg = obtainMessage(msg);
860 dstMsg.what = what;
861 dstMsg.arg1 = arg1;
862 mReplyChannel.replyToMessage(msg, dstMsg);
863 }
864
865 private void replyToMessage(Message msg, int what, Object obj) {
866 if (msg.replyTo == null) return;
867 Message dstMsg = obtainMessage(msg);
868 dstMsg.what = what;
869 dstMsg.obj = obj;
870 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700871 }
872
873 /* Information tracked per client */
874 private class ClientInfo {
875
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700876 private static final int MAX_LIMIT = 10;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700877 private final AsyncChannel mChannel;
878 private final Messenger mMessenger;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700879 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700880 private NsdServiceInfo mResolvedService;
881
882 /* A map from client id to unique id sent to mDns */
883 private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
Irfan Sheriff817388e2012-04-11 14:52:19 -0700884
Dave Plattf31760c2014-03-07 14:48:22 -0800885 /* A map from client id to the type of the request we had received */
886 private SparseArray<Integer> mClientRequests = new SparseArray<Integer>();
887
Irfan Sheriff817388e2012-04-11 14:52:19 -0700888 private ClientInfo(AsyncChannel c, Messenger m) {
889 mChannel = c;
890 mMessenger = m;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700891 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
892 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700893
894 @Override
895 public String toString() {
896 StringBuffer sb = new StringBuffer();
897 sb.append("mChannel ").append(mChannel).append("\n");
898 sb.append("mMessenger ").append(mMessenger).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700899 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700900 for(int i = 0; i< mClientIds.size(); i++) {
Dave Plattf31760c2014-03-07 14:48:22 -0800901 int clientID = mClientIds.keyAt(i);
902 sb.append("clientId ").append(clientID).
903 append(" mDnsId ").append(mClientIds.valueAt(i)).
904 append(" type ").append(mClientRequests.get(clientID)).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700905 }
906 return sb.toString();
907 }
Dave Plattf31760c2014-03-07 14:48:22 -0800908
909 // Remove any pending requests from the global map when we get rid of a client,
910 // and send cancellations to the daemon.
911 private void expungeAllRequests() {
912 int globalId, clientId, i;
913 for (i = 0; i < mClientIds.size(); i++) {
914 clientId = mClientIds.keyAt(i);
915 globalId = mClientIds.valueAt(i);
916 mIdToClientInfoMap.remove(globalId);
917 if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
918 " global-ID " + globalId + " type " + mClientRequests.get(clientId));
919 switch (mClientRequests.get(clientId)) {
920 case NsdManager.DISCOVER_SERVICES:
921 stopServiceDiscovery(globalId);
922 break;
923 case NsdManager.RESOLVE_SERVICE:
924 stopResolveService(globalId);
925 break;
926 case NsdManager.REGISTER_SERVICE:
927 unregisterService(globalId);
928 break;
929 default:
930 break;
931 }
932 }
933 mClientIds.clear();
934 mClientRequests.clear();
935 }
936
Christopher Lane5a577902014-04-25 18:39:07 -0700937 // mClientIds is a sparse array of listener id -> mDnsClient id. For a given mDnsClient id,
938 // return the corresponding listener id. mDnsClient id is also called a global id.
939 private int getClientId(final int globalId) {
940 // This doesn't use mClientIds.indexOfValue because indexOfValue uses == (not .equals)
941 // while also coercing the int primitives to Integer objects.
942 for (int i = 0, nSize = mClientIds.size(); i < nSize; i++) {
943 int mDnsId = mClientIds.valueAt(i);
944 if (globalId == mDnsId) {
945 return mClientIds.keyAt(i);
946 }
947 }
948 return -1;
949 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700950 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700951}