blob: 8df93f1283546921b5ed37fb93e4db6aab973cc1 [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;
29import android.os.Handler;
30import android.os.HandlerThread;
31import android.os.Message;
32import android.os.Messenger;
33import android.os.IBinder;
Dianne Hackborn5ac72a22012-08-29 18:32:08 -070034import android.os.UserHandle;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070035import android.provider.Settings;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070036import android.util.Slog;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070037import android.util.SparseArray;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070038
39import java.io.FileDescriptor;
40import java.io.PrintWriter;
Christopher Laneb72d8b42014-03-17 16:35:45 -070041import java.io.UnsupportedEncodingException;
Irfan Sheriff817388e2012-04-11 14:52:19 -070042import java.net.InetAddress;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070043import java.util.ArrayList;
Irfan Sheriff817388e2012-04-11 14:52:19 -070044import java.util.HashMap;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070045import java.util.List;
Christopher Laneb72d8b42014-03-17 16:35:45 -070046import java.util.Locale;
47import java.util.Map;
Irfan Sheriff817388e2012-04-11 14:52:19 -070048import java.util.concurrent.CountDownLatch;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070049
50import com.android.internal.app.IBatteryStats;
51import com.android.internal.telephony.TelephonyIntents;
52import com.android.internal.util.AsyncChannel;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070053import com.android.internal.util.Protocol;
54import com.android.internal.util.State;
55import com.android.internal.util.StateMachine;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070056import com.android.server.am.BatteryStatsService;
57import com.android.server.NativeDaemonConnector.Command;
58import com.android.internal.R;
59
60/**
61 * Network Service Discovery Service handles remote service discovery operation requests by
62 * implementing the INsdManager interface.
63 *
64 * @hide
65 */
66public class NsdService extends INsdManager.Stub {
67 private static final String TAG = "NsdService";
68 private static final String MDNS_TAG = "mDnsConnector";
69
70 private static final boolean DBG = true;
71
72 private Context mContext;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070073 private ContentResolver mContentResolver;
74 private NsdStateMachine mNsdStateMachine;
Irfan Sheriff7d024d32012-03-22 17:01:39 -070075
76 /**
77 * Clients receiving asynchronous messages
78 */
Irfan Sheriff817388e2012-04-11 14:52:19 -070079 private HashMap<Messenger, ClientInfo> mClients = new HashMap<Messenger, ClientInfo>();
Irfan Sheriff7d024d32012-03-22 17:01:39 -070080
Irfan Sheriff22af38c2012-05-03 16:44:27 -070081 /* A map from unique id to client info */
82 private SparseArray<ClientInfo> mIdToClientInfoMap= new SparseArray<ClientInfo>();
83
Irfan Sheriff7d024d32012-03-22 17:01:39 -070084 private AsyncChannel mReplyChannel = new AsyncChannel();
85
Irfan Sheriff817388e2012-04-11 14:52:19 -070086 private int INVALID_ID = 0;
87 private int mUniqueId = 1;
88
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070089 private static final int BASE = Protocol.BASE_NSD_MANAGER;
Irfan Sheriff22af38c2012-05-03 16:44:27 -070090 private static final int CMD_TO_STRING_COUNT = NsdManager.RESOLVE_SERVICE - BASE + 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070091 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
Irfan Sheriff7d024d32012-03-22 17:01:39 -070092
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070093 static {
94 sCmdToString[NsdManager.DISCOVER_SERVICES - BASE] = "DISCOVER";
95 sCmdToString[NsdManager.STOP_DISCOVERY - BASE] = "STOP-DISCOVER";
96 sCmdToString[NsdManager.REGISTER_SERVICE - BASE] = "REGISTER";
97 sCmdToString[NsdManager.UNREGISTER_SERVICE - BASE] = "UNREGISTER";
98 sCmdToString[NsdManager.RESOLVE_SERVICE - BASE] = "RESOLVE";
Irfan Sheriff3ef889b2012-04-17 23:15:29 -070099 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700100
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700101 private static String cmdToString(int cmd) {
102 cmd -= BASE;
103 if ((cmd >= 0) && (cmd < sCmdToString.length)) {
104 return sCmdToString[cmd];
105 } else {
106 return null;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700107 }
108 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700109
110 private class NsdStateMachine extends StateMachine {
111
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700112 private final DefaultState mDefaultState = new DefaultState();
113 private final DisabledState mDisabledState = new DisabledState();
114 private final EnabledState mEnabledState = new EnabledState();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700115
116 @Override
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700117 protected String getWhatToString(int what) {
118 return cmdToString(what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700119 }
120
Irfan Sheriff919aca52012-06-01 16:44:13 -0700121 /**
122 * Observes the NSD on/off setting, and takes action when changed.
123 */
124 private void registerForNsdSetting() {
125 ContentObserver contentObserver = new ContentObserver(this.getHandler()) {
126 @Override
127 public void onChange(boolean selfChange) {
128 if (isNsdEnabled()) {
129 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
130 } else {
131 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
132 }
133 }
134 };
135
136 mContext.getContentResolver().registerContentObserver(
Jeff Sharkey625239a2012-09-26 22:03:49 -0700137 Settings.Global.getUriFor(Settings.Global.NSD_ON),
Irfan Sheriff919aca52012-06-01 16:44:13 -0700138 false, contentObserver);
139 }
140
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700141 NsdStateMachine(String name) {
142 super(name);
143 addState(mDefaultState);
144 addState(mDisabledState, mDefaultState);
145 addState(mEnabledState, mDefaultState);
146 if (isNsdEnabled()) {
147 setInitialState(mEnabledState);
148 } else {
149 setInitialState(mDisabledState);
150 }
Wink Savillebbf30dfd2012-05-29 12:40:46 -0700151 setLogRecSize(25);
Irfan Sheriff919aca52012-06-01 16:44:13 -0700152 registerForNsdSetting();
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700153 }
154
155 class DefaultState extends State {
156 @Override
157 public boolean processMessage(Message msg) {
Dave Platt8e5df442014-03-13 23:35:15 +0000158 ClientInfo cInfo = null;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700159 switch (msg.what) {
160 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
161 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL) {
162 AsyncChannel c = (AsyncChannel) msg.obj;
163 if (DBG) Slog.d(TAG, "New client listening to asynchronous messages");
164 c.sendMessage(AsyncChannel.CMD_CHANNEL_FULLY_CONNECTED);
Dave Platt8e5df442014-03-13 23:35:15 +0000165 cInfo = new ClientInfo(c, msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700166 mClients.put(msg.replyTo, cInfo);
167 } else {
168 Slog.e(TAG, "Client connection failure, error=" + msg.arg1);
169 }
170 break;
171 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Dave Platt8e5df442014-03-13 23:35:15 +0000172 switch (msg.arg1) {
173 case AsyncChannel.STATUS_SEND_UNSUCCESSFUL:
174 Slog.e(TAG, "Send failed, client connection lost");
175 break;
176 case AsyncChannel.STATUS_REMOTE_DISCONNECTION:
177 if (DBG) Slog.d(TAG, "Client disconnected");
178 break;
179 default:
180 if (DBG) Slog.d(TAG, "Client connection lost with reason: " + msg.arg1);
181 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700182 }
Dave Platt8e5df442014-03-13 23:35:15 +0000183 cInfo = mClients.get(msg.replyTo);
184 if (cInfo != null) {
185 cInfo.expungeAllRequests();
186 mClients.remove(msg.replyTo);
187 }
188 //Last client
189 if (mClients.size() == 0) {
190 stopMDnsDaemon();
191 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700192 break;
193 case AsyncChannel.CMD_CHANNEL_FULL_CONNECTION:
194 AsyncChannel ac = new AsyncChannel();
195 ac.connect(mContext, getHandler(), msg.replyTo);
196 break;
197 case NsdManager.DISCOVER_SERVICES:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700198 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
199 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700200 break;
201 case NsdManager.STOP_DISCOVERY:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700202 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
203 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700204 break;
205 case NsdManager.REGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700206 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
207 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700208 break;
209 case NsdManager.UNREGISTER_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700210 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
211 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700212 break;
213 case NsdManager.RESOLVE_SERVICE:
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700214 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
215 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700216 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700217 case NsdManager.NATIVE_DAEMON_EVENT:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700218 default:
219 Slog.e(TAG, "Unhandled " + msg);
220 return NOT_HANDLED;
221 }
222 return HANDLED;
223 }
224 }
225
226 class DisabledState extends State {
227 @Override
228 public void enter() {
229 sendNsdStateChangeBroadcast(false);
230 }
231
232 @Override
233 public boolean processMessage(Message msg) {
234 switch (msg.what) {
235 case NsdManager.ENABLE:
236 transitionTo(mEnabledState);
237 break;
238 default:
239 return NOT_HANDLED;
240 }
241 return HANDLED;
242 }
243 }
244
245 class EnabledState extends State {
246 @Override
247 public void enter() {
248 sendNsdStateChangeBroadcast(true);
249 if (mClients.size() > 0) {
250 startMDnsDaemon();
251 }
252 }
253
254 @Override
255 public void exit() {
256 if (mClients.size() > 0) {
257 stopMDnsDaemon();
258 }
259 }
260
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700261 private boolean requestLimitReached(ClientInfo clientInfo) {
262 if (clientInfo.mClientIds.size() >= ClientInfo.MAX_LIMIT) {
263 if (DBG) Slog.d(TAG, "Exceeded max outstanding requests " + clientInfo);
264 return true;
265 }
266 return false;
267 }
268
Dave Platt8e5df442014-03-13 23:35:15 +0000269 private void storeRequestMap(int clientId, int globalId, ClientInfo clientInfo, int what) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700270 clientInfo.mClientIds.put(clientId, globalId);
Dave Platt8e5df442014-03-13 23:35:15 +0000271 clientInfo.mClientRequests.put(clientId, what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700272 mIdToClientInfoMap.put(globalId, clientInfo);
273 }
274
275 private void removeRequestMap(int clientId, int globalId, ClientInfo clientInfo) {
276 clientInfo.mClientIds.remove(clientId);
Dave Platt8e5df442014-03-13 23:35:15 +0000277 clientInfo.mClientRequests.remove(clientId);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700278 mIdToClientInfoMap.remove(globalId);
279 }
280
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700281 @Override
282 public boolean processMessage(Message msg) {
283 ClientInfo clientInfo;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700284 NsdServiceInfo servInfo;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700285 boolean result = HANDLED;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700286 int id;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700287 switch (msg.what) {
288 case AsyncChannel.CMD_CHANNEL_HALF_CONNECTED:
289 //First client
290 if (msg.arg1 == AsyncChannel.STATUS_SUCCESSFUL &&
291 mClients.size() == 0) {
292 startMDnsDaemon();
293 }
294 result = NOT_HANDLED;
295 break;
296 case AsyncChannel.CMD_CHANNEL_DISCONNECTED:
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700297 result = NOT_HANDLED;
298 break;
299 case NsdManager.DISABLE:
300 //TODO: cleanup clients
301 transitionTo(mDisabledState);
302 break;
303 case NsdManager.DISCOVER_SERVICES:
304 if (DBG) Slog.d(TAG, "Discover services");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700305 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700306 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700307
308 if (requestLimitReached(clientInfo)) {
309 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
310 NsdManager.FAILURE_MAX_LIMIT);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700311 break;
312 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700313
314 id = getUniqueId();
315 if (discoverServices(id, servInfo.getServiceType())) {
316 if (DBG) {
317 Slog.d(TAG, "Discover " + msg.arg2 + " " + id +
318 servInfo.getServiceType());
319 }
Dave Platt8e5df442014-03-13 23:35:15 +0000320 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700321 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_STARTED, servInfo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700322 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700323 stopServiceDiscovery(id);
324 replyToMessage(msg, NsdManager.DISCOVER_SERVICES_FAILED,
325 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700326 }
327 break;
328 case NsdManager.STOP_DISCOVERY:
329 if (DBG) Slog.d(TAG, "Stop service discovery");
330 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700331
332 try {
333 id = clientInfo.mClientIds.get(msg.arg2).intValue();
334 } catch (NullPointerException e) {
335 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
336 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700337 break;
338 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700339 removeRequestMap(msg.arg2, id, clientInfo);
340 if (stopServiceDiscovery(id)) {
341 replyToMessage(msg, NsdManager.STOP_DISCOVERY_SUCCEEDED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700342 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700343 replyToMessage(msg, NsdManager.STOP_DISCOVERY_FAILED,
344 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700345 }
346 break;
347 case NsdManager.REGISTER_SERVICE:
348 if (DBG) Slog.d(TAG, "Register service");
349 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700350 if (requestLimitReached(clientInfo)) {
351 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
352 NsdManager.FAILURE_MAX_LIMIT);
353 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700354 }
355
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700356 id = getUniqueId();
357 if (registerService(id, (NsdServiceInfo) msg.obj)) {
358 if (DBG) Slog.d(TAG, "Register " + msg.arg2 + " " + id);
Dave Platt8e5df442014-03-13 23:35:15 +0000359 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700360 // Return success after mDns reports success
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700361 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700362 unregisterService(id);
363 replyToMessage(msg, NsdManager.REGISTER_SERVICE_FAILED,
364 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700365 }
366 break;
367 case NsdManager.UNREGISTER_SERVICE:
368 if (DBG) Slog.d(TAG, "unregister service");
369 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700370 try {
371 id = clientInfo.mClientIds.get(msg.arg2).intValue();
372 } catch (NullPointerException e) {
373 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
374 NsdManager.FAILURE_INTERNAL_ERROR);
375 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700376 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700377 removeRequestMap(msg.arg2, id, clientInfo);
378 if (unregisterService(id)) {
379 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_SUCCEEDED);
380 } else {
381 replyToMessage(msg, NsdManager.UNREGISTER_SERVICE_FAILED,
382 NsdManager.FAILURE_INTERNAL_ERROR);
383 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700384 break;
385 case NsdManager.RESOLVE_SERVICE:
386 if (DBG) Slog.d(TAG, "Resolve service");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700387 servInfo = (NsdServiceInfo) msg.obj;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700388 clientInfo = mClients.get(msg.replyTo);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700389
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700390
391 if (clientInfo.mResolvedService != null) {
392 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
393 NsdManager.FAILURE_ALREADY_ACTIVE);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700394 break;
395 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700396
397 id = getUniqueId();
398 if (resolveService(id, servInfo)) {
399 clientInfo.mResolvedService = new NsdServiceInfo();
Dave Platt8e5df442014-03-13 23:35:15 +0000400 storeRequestMap(msg.arg2, id, clientInfo, msg.what);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700401 } else {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700402 replyToMessage(msg, NsdManager.RESOLVE_SERVICE_FAILED,
403 NsdManager.FAILURE_INTERNAL_ERROR);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700404 }
405 break;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700406 case NsdManager.NATIVE_DAEMON_EVENT:
407 NativeEvent event = (NativeEvent) msg.obj;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700408 if (!handleNativeEvent(event.code, event.raw,
409 NativeDaemonEvent.unescapeArgs(event.raw))) {
410 result = NOT_HANDLED;
411 }
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700412 break;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700413 default:
414 result = NOT_HANDLED;
415 break;
416 }
417 return result;
418 }
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700419
420 private boolean handleNativeEvent(int code, String raw, String[] cooked) {
421 boolean handled = true;
422 NsdServiceInfo servInfo;
423 int id = Integer.parseInt(cooked[1]);
424 ClientInfo clientInfo = mIdToClientInfoMap.get(id);
425 if (clientInfo == null) {
426 Slog.e(TAG, "Unique id with no client mapping: " + id);
427 handled = false;
428 return handled;
429 }
430
431 /* This goes in response as msg.arg2 */
432 int clientId = -1;
433 int keyId = clientInfo.mClientIds.indexOfValue(id);
434 if (keyId != -1) {
435 clientId = clientInfo.mClientIds.keyAt(keyId);
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700436 } else {
437 // This can happen because of race conditions. For example,
438 // SERVICE_FOUND may race with STOP_SERVICE_DISCOVERY,
439 // and we may get in this situation.
440 Slog.d(TAG, "Notification for a listener that is no longer active: " + id);
441 handled = false;
442 return handled;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700443 }
Vinit Deshapnde8ed09e82013-06-25 19:45:03 -0700444
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700445 switch (code) {
446 case NativeResponseCode.SERVICE_FOUND:
447 /* NNN uniqueId serviceName regType domain */
448 if (DBG) Slog.d(TAG, "SERVICE_FOUND Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700449 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700450 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_FOUND, 0,
451 clientId, servInfo);
452 break;
453 case NativeResponseCode.SERVICE_LOST:
454 /* NNN uniqueId serviceName regType domain */
455 if (DBG) Slog.d(TAG, "SERVICE_LOST Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700456 servInfo = new NsdServiceInfo(cooked[2], cooked[3]);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700457 clientInfo.mChannel.sendMessage(NsdManager.SERVICE_LOST, 0,
458 clientId, servInfo);
459 break;
460 case NativeResponseCode.SERVICE_DISCOVERY_FAILED:
461 /* NNN uniqueId errorCode */
462 if (DBG) Slog.d(TAG, "SERVICE_DISC_FAILED Raw: " + raw);
463 clientInfo.mChannel.sendMessage(NsdManager.DISCOVER_SERVICES_FAILED,
464 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
465 break;
466 case NativeResponseCode.SERVICE_REGISTERED:
467 /* NNN regId serviceName regType */
468 if (DBG) Slog.d(TAG, "SERVICE_REGISTERED Raw: " + raw);
Christopher Laneb72d8b42014-03-17 16:35:45 -0700469 servInfo = new NsdServiceInfo(cooked[2], null);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700470 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_SUCCEEDED,
471 id, clientId, servInfo);
472 break;
473 case NativeResponseCode.SERVICE_REGISTRATION_FAILED:
474 /* NNN regId errorCode */
475 if (DBG) Slog.d(TAG, "SERVICE_REGISTER_FAILED Raw: " + raw);
476 clientInfo.mChannel.sendMessage(NsdManager.REGISTER_SERVICE_FAILED,
477 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
478 break;
479 case NativeResponseCode.SERVICE_UPDATED:
480 /* NNN regId */
481 break;
482 case NativeResponseCode.SERVICE_UPDATE_FAILED:
483 /* NNN regId errorCode */
484 break;
485 case NativeResponseCode.SERVICE_RESOLVED:
486 /* NNN resolveId fullName hostName port txtlen txtdata */
487 if (DBG) Slog.d(TAG, "SERVICE_RESOLVED Raw: " + raw);
488 int index = cooked[2].indexOf(".");
489 if (index == -1) {
490 Slog.e(TAG, "Invalid service found " + raw);
491 break;
492 }
493 String name = cooked[2].substring(0, index);
494 String rest = cooked[2].substring(index);
495 String type = rest.replace(".local.", "");
496
497 clientInfo.mResolvedService.setServiceName(name);
498 clientInfo.mResolvedService.setServiceType(type);
499 clientInfo.mResolvedService.setPort(Integer.parseInt(cooked[4]));
500
501 stopResolveService(id);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800502 removeRequestMap(clientId, id, clientInfo);
503
504 int id2 = getUniqueId();
505 if (getAddrInfo(id2, cooked[3])) {
Dave Platt8e5df442014-03-13 23:35:15 +0000506 storeRequestMap(clientId, id2, clientInfo, NsdManager.RESOLVE_SERVICE);
Vinit Deshapnde40387242013-11-12 15:36:37 -0800507 } else {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700508 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
509 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700510 clientInfo.mResolvedService = null;
511 }
512 break;
513 case NativeResponseCode.SERVICE_RESOLUTION_FAILED:
514 /* NNN resolveId errorCode */
515 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
516 stopResolveService(id);
517 removeRequestMap(clientId, id, clientInfo);
518 clientInfo.mResolvedService = null;
519 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
520 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
521 break;
522 case NativeResponseCode.SERVICE_GET_ADDR_FAILED:
523 /* NNN resolveId errorCode */
524 stopGetAddrInfo(id);
525 removeRequestMap(clientId, id, clientInfo);
526 clientInfo.mResolvedService = null;
527 if (DBG) Slog.d(TAG, "SERVICE_RESOLVE_FAILED Raw: " + raw);
528 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
529 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
530 break;
531 case NativeResponseCode.SERVICE_GET_ADDR_SUCCESS:
532 /* NNN resolveId hostname ttl addr */
533 if (DBG) Slog.d(TAG, "SERVICE_GET_ADDR_SUCCESS Raw: " + raw);
534 try {
535 clientInfo.mResolvedService.setHost(InetAddress.getByName(cooked[4]));
536 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_SUCCEEDED,
537 0, clientId, clientInfo.mResolvedService);
538 } catch (java.net.UnknownHostException e) {
539 clientInfo.mChannel.sendMessage(NsdManager.RESOLVE_SERVICE_FAILED,
540 NsdManager.FAILURE_INTERNAL_ERROR, clientId);
541 }
542 stopGetAddrInfo(id);
543 removeRequestMap(clientId, id, clientInfo);
544 clientInfo.mResolvedService = null;
545 break;
546 default:
547 handled = false;
548 break;
549 }
550 return handled;
551 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700552 }
553 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700554
555 private NativeDaemonConnector mNativeConnector;
556 private final CountDownLatch mNativeDaemonConnected = new CountDownLatch(1);
557
558 private NsdService(Context context) {
559 mContext = context;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700560 mContentResolver = context.getContentResolver();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700561
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700562 mNativeConnector = new NativeDaemonConnector(new NativeCallbackReceiver(), "mdns", 10,
563 MDNS_TAG, 25);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700564
565 mNsdStateMachine = new NsdStateMachine(TAG);
566 mNsdStateMachine.start();
567
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700568 Thread th = new Thread(mNativeConnector, MDNS_TAG);
569 th.start();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700570 }
571
572 public static NsdService create(Context context) throws InterruptedException {
573 NsdService service = new NsdService(context);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700574 service.mNativeDaemonConnected.await();
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700575 return service;
576 }
577
578 public Messenger getMessenger() {
Irfan Sheriff92784672012-04-13 12:15:41 -0700579 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.INTERNET,
580 "NsdService");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700581 return new Messenger(mNsdStateMachine.getHandler());
582 }
583
584 public void setEnabled(boolean enable) {
585 mContext.enforceCallingOrSelfPermission(android.Manifest.permission.CONNECTIVITY_INTERNAL,
586 "NsdService");
Jeff Sharkey625239a2012-09-26 22:03:49 -0700587 Settings.Global.putInt(mContentResolver, Settings.Global.NSD_ON, enable ? 1 : 0);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700588 if (enable) {
589 mNsdStateMachine.sendMessage(NsdManager.ENABLE);
590 } else {
591 mNsdStateMachine.sendMessage(NsdManager.DISABLE);
592 }
593 }
594
595 private void sendNsdStateChangeBroadcast(boolean enabled) {
Irfan Sheriff54ac7a52012-04-19 10:26:34 -0700596 final Intent intent = new Intent(NsdManager.ACTION_NSD_STATE_CHANGED);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700597 intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
598 if (enabled) {
599 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_ENABLED);
600 } else {
601 intent.putExtra(NsdManager.EXTRA_NSD_STATE, NsdManager.NSD_STATE_DISABLED);
602 }
Dianne Hackborn5ac72a22012-08-29 18:32:08 -0700603 mContext.sendStickyBroadcastAsUser(intent, UserHandle.ALL);
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700604 }
605
606 private boolean isNsdEnabled() {
Jeff Sharkey625239a2012-09-26 22:03:49 -0700607 boolean ret = Settings.Global.getInt(mContentResolver, Settings.Global.NSD_ON, 1) == 1;
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700608 if (DBG) Slog.d(TAG, "Network service discovery enabled " + ret);
609 return ret;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700610 }
611
Irfan Sheriff817388e2012-04-11 14:52:19 -0700612 private int getUniqueId() {
613 if (++mUniqueId == INVALID_ID) return ++mUniqueId;
614 return mUniqueId;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700615 }
616
Irfan Sheriff817388e2012-04-11 14:52:19 -0700617 /* These should be in sync with system/netd/mDnsResponseCode.h */
618 class NativeResponseCode {
619 public static final int SERVICE_DISCOVERY_FAILED = 602;
620 public static final int SERVICE_FOUND = 603;
621 public static final int SERVICE_LOST = 604;
622
623 public static final int SERVICE_REGISTRATION_FAILED = 605;
624 public static final int SERVICE_REGISTERED = 606;
625
626 public static final int SERVICE_RESOLUTION_FAILED = 607;
627 public static final int SERVICE_RESOLVED = 608;
628
629 public static final int SERVICE_UPDATED = 609;
630 public static final int SERVICE_UPDATE_FAILED = 610;
631
632 public static final int SERVICE_GET_ADDR_FAILED = 611;
633 public static final int SERVICE_GET_ADDR_SUCCESS = 612;
634 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700635
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700636 private class NativeEvent {
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700637 final int code;
638 final String raw;
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700639
640 NativeEvent(int code, String raw) {
641 this.code = code;
642 this.raw = raw;
643 }
644 }
645
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700646 class NativeCallbackReceiver implements INativeDaemonConnectorCallbacks {
647 public void onDaemonConnected() {
648 mNativeDaemonConnected.countDown();
649 }
650
651 public boolean onEvent(int code, String raw, String[] cooked) {
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700652 // TODO: NDC translates a message to a callback, we could enhance NDC to
653 // directly interact with a state machine through messages
654 NativeEvent event = new NativeEvent(code, raw);
655 mNsdStateMachine.sendMessage(NsdManager.NATIVE_DAEMON_EVENT, event);
656 return true;
657 }
658 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700659
Irfan Sheriff817388e2012-04-11 14:52:19 -0700660 private boolean startMDnsDaemon() {
661 if (DBG) Slog.d(TAG, "startMDnsDaemon");
662 try {
663 mNativeConnector.execute("mdnssd", "start-service");
664 } catch(NativeDaemonConnectorException e) {
665 Slog.e(TAG, "Failed to start daemon" + e);
666 return false;
667 }
668 return true;
669 }
670
671 private boolean stopMDnsDaemon() {
672 if (DBG) Slog.d(TAG, "stopMDnsDaemon");
673 try {
674 mNativeConnector.execute("mdnssd", "stop-service");
675 } catch(NativeDaemonConnectorException e) {
676 Slog.e(TAG, "Failed to start daemon" + e);
677 return false;
678 }
679 return true;
680 }
681
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700682 private boolean registerService(int regId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700683 if (DBG) Slog.d(TAG, "registerService: " + regId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700684 try {
Christopher Laneb72d8b42014-03-17 16:35:45 -0700685 Command cmd = new Command("mdnssd", "register", regId, service.getServiceName(),
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700686 service.getServiceType(), service.getPort());
Christopher Laneb72d8b42014-03-17 16:35:45 -0700687
688 // Add TXT records as additional arguments.
689 Map<String, byte[]> txtRecords = service.getAttributes();
690 for (String key : txtRecords.keySet()) {
691 try {
692 // TODO: Send encoded TXT record as bytes once NDC/netd supports binary data.
693 cmd.appendArg(String.format(Locale.US, "%s=%s", key,
694 new String(txtRecords.get(key), "UTF_8")));
695 } catch (UnsupportedEncodingException e) {
696 Slog.e(TAG, "Failed to encode txtRecord " + e);
697 }
698 }
699
700 mNativeConnector.execute(cmd);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700701 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700702 Slog.e(TAG, "Failed to execute registerService " + e);
703 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700704 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700705 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700706 }
707
Irfan Sheriff817388e2012-04-11 14:52:19 -0700708 private boolean unregisterService(int regId) {
709 if (DBG) Slog.d(TAG, "unregisterService: " + regId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700710 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700711 mNativeConnector.execute("mdnssd", "stop-register", regId);
712 } catch(NativeDaemonConnectorException e) {
713 Slog.e(TAG, "Failed to execute unregisterService " + e);
714 return false;
715 }
716 return true;
717 }
718
719 private boolean updateService(int regId, DnsSdTxtRecord t) {
720 if (DBG) Slog.d(TAG, "updateService: " + regId + " " + t);
721 try {
722 if (t == null) return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700723 mNativeConnector.execute("mdnssd", "update", regId, t.size(), t.getRawData());
724 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700725 Slog.e(TAG, "Failed to updateServices " + e);
726 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700727 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700728 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700729 }
730
Irfan Sheriff817388e2012-04-11 14:52:19 -0700731 private boolean discoverServices(int discoveryId, String serviceType) {
732 if (DBG) Slog.d(TAG, "discoverServices: " + discoveryId + " " + serviceType);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700733 try {
734 mNativeConnector.execute("mdnssd", "discover", discoveryId, serviceType);
735 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700736 Slog.e(TAG, "Failed to discoverServices " + e);
737 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700738 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700739 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700740 }
741
Irfan Sheriff817388e2012-04-11 14:52:19 -0700742 private boolean stopServiceDiscovery(int discoveryId) {
743 if (DBG) Slog.d(TAG, "stopServiceDiscovery: " + discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700744 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700745 mNativeConnector.execute("mdnssd", "stop-discover", discoveryId);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700746 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700747 Slog.e(TAG, "Failed to stopServiceDiscovery " + e);
748 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700749 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700750 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700751 }
752
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700753 private boolean resolveService(int resolveId, NsdServiceInfo service) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700754 if (DBG) Slog.d(TAG, "resolveService: " + resolveId + " " + service);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700755 try {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700756 mNativeConnector.execute("mdnssd", "resolve", resolveId, service.getServiceName(),
757 service.getServiceType(), "local.");
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700758 } catch(NativeDaemonConnectorException e) {
Irfan Sheriff817388e2012-04-11 14:52:19 -0700759 Slog.e(TAG, "Failed to resolveService " + e);
760 return false;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700761 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700762 return true;
763 }
764
765 private boolean stopResolveService(int resolveId) {
766 if (DBG) Slog.d(TAG, "stopResolveService: " + resolveId);
767 try {
768 mNativeConnector.execute("mdnssd", "stop-resolve", resolveId);
769 } catch(NativeDaemonConnectorException e) {
770 Slog.e(TAG, "Failed to stop resolve " + e);
771 return false;
772 }
773 return true;
774 }
775
776 private boolean getAddrInfo(int resolveId, String hostname) {
777 if (DBG) Slog.d(TAG, "getAdddrInfo: " + resolveId);
778 try {
779 mNativeConnector.execute("mdnssd", "getaddrinfo", resolveId, hostname);
780 } catch(NativeDaemonConnectorException e) {
781 Slog.e(TAG, "Failed to getAddrInfo " + e);
782 return false;
783 }
784 return true;
785 }
786
787 private boolean stopGetAddrInfo(int resolveId) {
788 if (DBG) Slog.d(TAG, "stopGetAdddrInfo: " + resolveId);
789 try {
790 mNativeConnector.execute("mdnssd", "stop-getaddrinfo", resolveId);
791 } catch(NativeDaemonConnectorException e) {
792 Slog.e(TAG, "Failed to stopGetAddrInfo " + e);
793 return false;
794 }
795 return true;
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700796 }
797
798 @Override
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700799 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700800 if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
801 != PackageManager.PERMISSION_GRANTED) {
802 pw.println("Permission Denial: can't dump ServiceDiscoverService from from pid="
803 + Binder.getCallingPid()
804 + ", uid=" + Binder.getCallingUid());
805 return;
806 }
807
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700808 for (ClientInfo client : mClients.values()) {
809 pw.println("Client Info");
810 pw.println(client);
811 }
812
813 mNsdStateMachine.dump(fd, pw, args);
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700814 }
Irfan Sheriff817388e2012-04-11 14:52:19 -0700815
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700816 /* arg2 on the source message has an id that needs to be retained in replies
817 * see NsdManager for details */
818 private Message obtainMessage(Message srcMsg) {
819 Message msg = Message.obtain();
820 msg.arg2 = srcMsg.arg2;
821 return msg;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700822 }
823
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700824 private void replyToMessage(Message msg, int what) {
825 if (msg.replyTo == null) return;
826 Message dstMsg = obtainMessage(msg);
827 dstMsg.what = what;
828 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700829 }
830
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700831 private void replyToMessage(Message msg, int what, int arg1) {
832 if (msg.replyTo == null) return;
833 Message dstMsg = obtainMessage(msg);
834 dstMsg.what = what;
835 dstMsg.arg1 = arg1;
836 mReplyChannel.replyToMessage(msg, dstMsg);
837 }
838
839 private void replyToMessage(Message msg, int what, Object obj) {
840 if (msg.replyTo == null) return;
841 Message dstMsg = obtainMessage(msg);
842 dstMsg.what = what;
843 dstMsg.obj = obj;
844 mReplyChannel.replyToMessage(msg, dstMsg);
Irfan Sheriff817388e2012-04-11 14:52:19 -0700845 }
846
847 /* Information tracked per client */
848 private class ClientInfo {
849
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700850 private static final int MAX_LIMIT = 10;
Vairavan Srinivasan6727e732012-08-05 13:14:12 -0700851 private final AsyncChannel mChannel;
852 private final Messenger mMessenger;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700853 /* Remembers a resolved service until getaddrinfo completes */
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700854 private NsdServiceInfo mResolvedService;
855
856 /* A map from client id to unique id sent to mDns */
857 private SparseArray<Integer> mClientIds = new SparseArray<Integer>();
Irfan Sheriff817388e2012-04-11 14:52:19 -0700858
Dave Platt8e5df442014-03-13 23:35:15 +0000859 /* A map from client id to the type of the request we had received */
860 private SparseArray<Integer> mClientRequests = new SparseArray<Integer>();
861
Irfan Sheriff817388e2012-04-11 14:52:19 -0700862 private ClientInfo(AsyncChannel c, Messenger m) {
863 mChannel = c;
864 mMessenger = m;
Irfan Sheriff817388e2012-04-11 14:52:19 -0700865 if (DBG) Slog.d(TAG, "New client, channel: " + c + " messenger: " + m);
866 }
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700867
868 @Override
869 public String toString() {
870 StringBuffer sb = new StringBuffer();
871 sb.append("mChannel ").append(mChannel).append("\n");
872 sb.append("mMessenger ").append(mMessenger).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700873 sb.append("mResolvedService ").append(mResolvedService).append("\n");
Irfan Sheriff22af38c2012-05-03 16:44:27 -0700874 for(int i = 0; i< mClientIds.size(); i++) {
Dave Platt8e5df442014-03-13 23:35:15 +0000875 int clientID = mClientIds.keyAt(i);
876 sb.append("clientId ").append(clientID).
877 append(" mDnsId ").append(mClientIds.valueAt(i)).
878 append(" type ").append(mClientRequests.get(clientID)).append("\n");
Irfan Sheriff3ef889b2012-04-17 23:15:29 -0700879 }
880 return sb.toString();
881 }
Dave Platt8e5df442014-03-13 23:35:15 +0000882
883 // Remove any pending requests from the global map when we get rid of a client,
884 // and send cancellations to the daemon.
885 private void expungeAllRequests() {
886 int globalId, clientId, i;
887 for (i = 0; i < mClientIds.size(); i++) {
888 clientId = mClientIds.keyAt(i);
889 globalId = mClientIds.valueAt(i);
890 mIdToClientInfoMap.remove(globalId);
891 if (DBG) Slog.d(TAG, "Terminating client-ID " + clientId +
892 " global-ID " + globalId + " type " + mClientRequests.get(clientId));
893 switch (mClientRequests.get(clientId)) {
894 case NsdManager.DISCOVER_SERVICES:
895 stopServiceDiscovery(globalId);
896 break;
897 case NsdManager.RESOLVE_SERVICE:
898 stopResolveService(globalId);
899 break;
900 case NsdManager.REGISTER_SERVICE:
901 unregisterService(globalId);
902 break;
903 default:
904 break;
905 }
906 }
907 mClientIds.clear();
908 mClientRequests.clear();
909 }
910
Irfan Sheriff817388e2012-04-11 14:52:19 -0700911 }
Irfan Sheriff7d024d32012-03-22 17:01:39 -0700912}