blob: d8be9fdc33bda2b46c39dbf8fd6316341dc1cefc [file] [log] [blame]
Wink Savilled20a5d62010-10-20 15:17:28 -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.internal.util;
18
19import android.content.ComponentName;
20import android.content.Context;
21import android.content.Intent;
22import android.content.ServiceConnection;
23import android.os.Handler;
24import android.os.HandlerThread;
25import android.os.IBinder;
26import android.os.Looper;
27import android.os.Message;
28import android.os.Messenger;
29import android.os.RemoteException;
30import android.util.Slog;
31
32import java.util.Stack;
33
34/**
Wink Saville33c54e32010-11-15 10:50:34 -080035 * <p>An asynchronous channel between two handlers.</p>
Wink Savilled20a5d62010-10-20 15:17:28 -070036 *
Wink Saville33c54e32010-11-15 10:50:34 -080037 * <p>The handlers maybe in the same process or in another process. There
Wink Savilled20a5d62010-10-20 15:17:28 -070038 * are two protocol styles that can be used with an AysncChannel. The
39 * first is a simple request/reply protocol where the server does
Wink Saville33c54e32010-11-15 10:50:34 -080040 * not need to know which client is issuing the request.</p>
Wink Savilled20a5d62010-10-20 15:17:28 -070041 *
Wink Saville33c54e32010-11-15 10:50:34 -080042 * <p>In a simple request/reply protocol the client/source sends requests to the
Wink Savilled20a5d62010-10-20 15:17:28 -070043 * server/destination. And the server uses the replyToMessage methods.
44 * In this usage model there is no need for the destination to
Wink Saville33c54e32010-11-15 10:50:34 -080045 * use the connect methods. The typical sequence of operations is:</p>
46 *<ol>
Wink Saville0246bbc2011-05-02 10:44:56 -070047 * <li>Client calls AsyncChannel#connectSync or Asynchronously:</li>
48 * <ol>For an asynchronous half connection client calls AsyncChannel#connect.</ol>
49 * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
50 * </ol>
Wink Saville33c54e32010-11-15 10:50:34 -080051 * <li><code>comm-loop:</code></li>
Wink Saville0246bbc2011-05-02 10:44:56 -070052 * <li>Client calls AsyncChannel#sendMessage</li>
53 * <li>Server processes messages and optionally replies using AsyncChannel#replyToMessage
Wink Saville33c54e32010-11-15 10:50:34 -080054 * <li>Loop to <code>comm-loop</code> until done</li>
Wink Saville0246bbc2011-05-02 10:44:56 -070055 * <li>When done Client calls {@link AsyncChannel#disconnect}</li>
56 * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
Wink Saville33c54e32010-11-15 10:50:34 -080057 *</ol>
58 *<br/>
59 * <p>A second usage model is where the server/destination needs to know
Wink Savilled20a5d62010-10-20 15:17:28 -070060 * which client it's connected too. For example the server needs to
61 * send unsolicited messages back to the client. Or the server keeps
62 * different state for each client. In this model the server will also
Wink Saville33c54e32010-11-15 10:50:34 -080063 * use the connect methods. The typical sequence of operation is:</p>
64 *<ol>
Wink Saville0246bbc2011-05-02 10:44:56 -070065 * <li>Client calls AsyncChannel#fullyConnectSync or Asynchronously:<li>
66 * <ol>For an asynchronous full connection it calls AsyncChannel#connect</li>
67 * <li>Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel</li>
68 * <li>Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION)</li>
69 * </ol>
Wink Saville33c54e32010-11-15 10:50:34 -080070 * <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li>
Wink Saville0246bbc2011-05-02 10:44:56 -070071 * <li>Server calls AsyncChannel#connected</li>
Wink Saville33c54e32010-11-15 10:50:34 -080072 * <li>Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED)</li>
73 * <li>Client receives CMD_CHANNEL_FULLY_CONNECTED</li>
74 * <li><code>comm-loop:</code></li>
75 * <li>Client/Server uses AsyncChannel#sendMessage/replyToMessage
76 * to communicate and perform work</li>
77 * <li>Loop to <code>comm-loop</code> until done</li>
Wink Saville0246bbc2011-05-02 10:44:56 -070078 * <li>When done Client/Server calls {@link AsyncChannel#disconnect}</li>
Wink Saville33c54e32010-11-15 10:50:34 -080079 * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li>
80 *</ol>
Wink Saville0246bbc2011-05-02 10:44:56 -070081 *
82 * TODO: Consider simplifying where we have connect and fullyConnect with only one response
83 * message RSP_CHANNEL_CONNECT instead of two, CMD_CHANNEL_HALF_CONNECTED and
84 * CMD_CHANNEL_FULLY_CONNECTED. We'd also change CMD_CHANNEL_FULL_CONNECTION to REQ_CHANNEL_CONNECT.
Wink Savilled20a5d62010-10-20 15:17:28 -070085 */
86public class AsyncChannel {
87 /** Log tag */
88 private static final String TAG = "AsyncChannel";
89
90 /** Enable to turn on debugging */
91 private static final boolean DBG = false;
92
Wink Saville0246bbc2011-05-02 10:44:56 -070093 private static final int BASE = Protocol.BASE_SYSTEM_ASYNC_CHANNEL;
94
Wink Savilled20a5d62010-10-20 15:17:28 -070095 /**
96 * Command sent when the channel is half connected. Half connected
97 * means that the channel can be used to send commends to the destination
98 * but the destination is unaware that the channel exists. The first
99 * command sent to the destination is typically CMD_CHANNEL_FULL_CONNECTION if
100 * it is desired to establish a long term connection, but any command maybe
101 * sent.
102 *
103 * msg.arg1 == 0 : STATUS_SUCCESSFUL
104 * 1 : STATUS_BINDING_UNSUCCESSFUL
Wink Savillecfce3032010-12-01 23:20:25 -0800105 * msg.obj == the AsyncChannel
Wink Savilled20a5d62010-10-20 15:17:28 -0700106 * msg.replyTo == dstMessenger if successful
107 */
Wink Saville0246bbc2011-05-02 10:44:56 -0700108 public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0;
Wink Savilled20a5d62010-10-20 15:17:28 -0700109
110 /**
111 * Command typically sent when after receiving the CMD_CHANNEL_HALF_CONNECTED.
112 * This is used to initiate a long term connection with the destination and
113 * typically the destination will reply with CMD_CHANNEL_FULLY_CONNECTED.
114 *
115 * msg.replyTo = srcMessenger.
116 */
Wink Saville0246bbc2011-05-02 10:44:56 -0700117 public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1;
Wink Savilled20a5d62010-10-20 15:17:28 -0700118
119 /**
120 * Command typically sent after the destination receives a CMD_CHANNEL_FULL_CONNECTION.
121 * This signifies the acceptance or rejection of the channel by the sender.
122 *
123 * msg.arg1 == 0 : Accept connection
124 * : All other values signify the destination rejected the connection
Wink Saville0246bbc2011-05-02 10:44:56 -0700125 * and {@link AsyncChannel#disconnect} would typically be called.
Wink Savilled20a5d62010-10-20 15:17:28 -0700126 */
Wink Saville0246bbc2011-05-02 10:44:56 -0700127 public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2;
Wink Savilled20a5d62010-10-20 15:17:28 -0700128
129 /**
130 * Command sent when one side or the other wishes to disconnect. The sender
131 * may or may not be able to receive a reply depending upon the protocol and
Wink Saville0246bbc2011-05-02 10:44:56 -0700132 * the state of the connection. The receiver should call {@link AsyncChannel#disconnect}
Wink Savilled20a5d62010-10-20 15:17:28 -0700133 * to close its side of the channel and it will receive a CMD_CHANNEL_DISCONNECTED
134 * when the channel is closed.
135 *
136 * msg.replyTo = messenger that is disconnecting
137 */
Wink Saville0246bbc2011-05-02 10:44:56 -0700138 public static final int CMD_CHANNEL_DISCONNECT = BASE + 3;
Wink Savilled20a5d62010-10-20 15:17:28 -0700139
140 /**
141 * Command sent when the channel becomes disconnected. This is sent when the
142 * channel is forcibly disconnected by the system or as a reply to CMD_CHANNEL_DISCONNECT.
143 *
144 * msg.arg1 == 0 : STATUS_SUCCESSFUL
Wink Saville0246bbc2011-05-02 10:44:56 -0700145 * 1 : STATUS_BINDING_UNSUCCESSFUL
146 * 2 : STATUS_SEND_UNSUCCESSFUL
Wink Savilled20a5d62010-10-20 15:17:28 -0700147 * : All other values signify failure and the channel state is indeterminate
Wink Savillecfce3032010-12-01 23:20:25 -0800148 * msg.obj == the AsyncChannel
Wink Savilled20a5d62010-10-20 15:17:28 -0700149 * msg.replyTo = messenger disconnecting or null if it was never connected.
150 */
Wink Saville0246bbc2011-05-02 10:44:56 -0700151 public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4;
Wink Savilled20a5d62010-10-20 15:17:28 -0700152
Wink Saville01ce0ce2012-04-18 21:42:44 -0700153 private static final int CMD_TO_STRING_COUNT = CMD_CHANNEL_DISCONNECTED - BASE + 1;
Wink Saville583eaaa2012-04-13 16:11:20 -0700154 private static String[] sCmdToString = new String[CMD_TO_STRING_COUNT];
155 static {
156 sCmdToString[CMD_CHANNEL_HALF_CONNECTED - BASE] = "CMD_CHANNEL_HALF_CONNECTED";
157 sCmdToString[CMD_CHANNEL_FULL_CONNECTION - BASE] = "CMD_CHANNEL_FULL_CONNECTION";
158 sCmdToString[CMD_CHANNEL_FULLY_CONNECTED - BASE] = "CMD_CHANNEL_FULLY_CONNECTED";
159 sCmdToString[CMD_CHANNEL_DISCONNECT - BASE] = "CMD_CHANNEL_DISCONNECT";
160 sCmdToString[CMD_CHANNEL_DISCONNECTED - BASE] = "CMD_CHANNEL_DISCONNECTED";
161 }
162 protected static String cmdToString(int cmd) {
163 cmd -= BASE;
164 if ((cmd >= 0) && (cmd < sCmdToString.length)) {
165 return sCmdToString[cmd];
166 } else {
167 return null;
168 }
169 }
170
Wink Savilled20a5d62010-10-20 15:17:28 -0700171 /** Successful status always 0, !0 is an unsuccessful status */
172 public static final int STATUS_SUCCESSFUL = 0;
173
174 /** Error attempting to bind on a connect */
175 public static final int STATUS_BINDING_UNSUCCESSFUL = 1;
176
Wink Saville0246bbc2011-05-02 10:44:56 -0700177 /** Error attempting to send a message */
178 public static final int STATUS_SEND_UNSUCCESSFUL = 2;
179
180 /** CMD_FULLY_CONNECTED refused because a connection already exists*/
181 public static final int STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3;
182
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700183 /** Error indicating abnormal termination of destination messenger */
184 public static final int STATUS_REMOTE_DISCONNECTION = 4;
185
Wink Savilled20a5d62010-10-20 15:17:28 -0700186 /** Service connection */
187 private AsyncChannelConnection mConnection;
188
189 /** Context for source */
190 private Context mSrcContext;
191
192 /** Handler for source */
193 private Handler mSrcHandler;
194
195 /** Messenger for source */
196 private Messenger mSrcMessenger;
197
198 /** Messenger for destination */
199 private Messenger mDstMessenger;
200
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700201 /** Death Monitor for destination messenger */
202 private DeathMonitor mDeathMonitor;
203
Wink Savilled20a5d62010-10-20 15:17:28 -0700204 /**
205 * AsyncChannel constructor
206 */
207 public AsyncChannel() {
208 }
209
210 /**
Wink Saville0246bbc2011-05-02 10:44:56 -0700211 * Connect handler to named package/class synchronously.
Wink Savilled20a5d62010-10-20 15:17:28 -0700212 *
213 * @param srcContext is the context of the source
214 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
215 * messages
216 * @param dstPackageName is the destination package name
217 * @param dstClassName is the fully qualified class name (i.e. contains
218 * package name)
Wink Saville0246bbc2011-05-02 10:44:56 -0700219 *
220 * @return STATUS_SUCCESSFUL on success any other value is an error.
Wink Savilled20a5d62010-10-20 15:17:28 -0700221 */
Wink Saville0246bbc2011-05-02 10:44:56 -0700222 public int connectSrcHandlerToPackageSync(
Wink Savillecfce3032010-12-01 23:20:25 -0800223 Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) {
Wink Savilled20a5d62010-10-20 15:17:28 -0700224 if (DBG) log("connect srcHandler to dst Package & class E");
225
Wink Savillecfce3032010-12-01 23:20:25 -0800226 mConnection = new AsyncChannelConnection();
Wink Savilled20a5d62010-10-20 15:17:28 -0700227
228 /* Initialize the source information */
229 mSrcContext = srcContext;
230 mSrcHandler = srcHandler;
231 mSrcMessenger = new Messenger(srcHandler);
232
233 /*
234 * Initialize destination information to null they will
235 * be initialized when the AsyncChannelConnection#onServiceConnected
236 * is called
237 */
238 mDstMessenger = null;
239
240 /* Send intent to create the connection */
241 Intent intent = new Intent(Intent.ACTION_MAIN);
242 intent.setClassName(dstPackageName, dstClassName);
243 boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
Wink Savilled20a5d62010-10-20 15:17:28 -0700244 if (DBG) log("connect srcHandler to dst Package & class X result=" + result);
Wink Saville0246bbc2011-05-02 10:44:56 -0700245 return result ? STATUS_SUCCESSFUL : STATUS_BINDING_UNSUCCESSFUL;
246 }
247
248 /**
249 * Connect a handler to Messenger synchronously.
250 *
251 * @param srcContext is the context of the source
252 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
253 * messages
254 * @param dstMessenger is the hander to send messages to.
255 *
256 * @return STATUS_SUCCESSFUL on success any other value is an error.
257 */
258 public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
259 if (DBG) log("halfConnectSync srcHandler to the dstMessenger E");
260
261 // We are connected
262 connected(srcContext, srcHandler, dstMessenger);
263
264 if (DBG) log("halfConnectSync srcHandler to the dstMessenger X");
265 return STATUS_SUCCESSFUL;
266 }
267
268 /**
269 * connect two local Handlers synchronously.
270 *
271 * @param srcContext is the context of the source
272 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
273 * messages
274 * @param dstHandler is the hander to send messages to.
275 *
276 * @return STATUS_SUCCESSFUL on success any other value is an error.
277 */
278 public int connectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
279 return connectSync(srcContext, srcHandler, new Messenger(dstHandler));
280 }
281
282 /**
283 * Fully connect two local Handlers synchronously.
284 *
285 * @param srcContext is the context of the source
286 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
287 * messages
288 * @param dstHandler is the hander to send messages to.
289 *
290 * @return STATUS_SUCCESSFUL on success any other value is an error.
291 */
292 public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler) {
293 int status = connectSync(srcContext, srcHandler, dstHandler);
294 if (status == STATUS_SUCCESSFUL) {
295 Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION);
296 status = response.arg1;
297 }
298 return status;
Wink Savilled20a5d62010-10-20 15:17:28 -0700299 }
300
301 /**
302 * Connect handler to named package/class.
303 *
304 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
305 * msg.arg1 = status
Wink Savillecfce3032010-12-01 23:20:25 -0800306 * msg.obj = the AsyncChannel
Wink Savilled20a5d62010-10-20 15:17:28 -0700307 *
308 * @param srcContext is the context of the source
309 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
310 * messages
311 * @param dstPackageName is the destination package name
312 * @param dstClassName is the fully qualified class name (i.e. contains
313 * package name)
Wink Savilled20a5d62010-10-20 15:17:28 -0700314 */
315 public void connect(Context srcContext, Handler srcHandler, String dstPackageName,
Wink Savillecfce3032010-12-01 23:20:25 -0800316 String dstClassName) {
Wink Savilled20a5d62010-10-20 15:17:28 -0700317 if (DBG) log("connect srcHandler to dst Package & class E");
318
319 final class ConnectAsync implements Runnable {
320 Context mSrcCtx;
321 Handler mSrcHdlr;
322 String mDstPackageName;
323 String mDstClassName;
Wink Savilled20a5d62010-10-20 15:17:28 -0700324
325 ConnectAsync(Context srcContext, Handler srcHandler, String dstPackageName,
Wink Savillecfce3032010-12-01 23:20:25 -0800326 String dstClassName) {
Wink Savilled20a5d62010-10-20 15:17:28 -0700327 mSrcCtx = srcContext;
328 mSrcHdlr = srcHandler;
329 mDstPackageName = dstPackageName;
330 mDstClassName = dstClassName;
Wink Savilled20a5d62010-10-20 15:17:28 -0700331 }
332
Wink Saville0246bbc2011-05-02 10:44:56 -0700333 @Override
Wink Savilled20a5d62010-10-20 15:17:28 -0700334 public void run() {
Wink Saville0246bbc2011-05-02 10:44:56 -0700335 int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName,
336 mDstClassName);
337 replyHalfConnected(result);
Wink Savilled20a5d62010-10-20 15:17:28 -0700338 }
339 }
340
Wink Savillecfce3032010-12-01 23:20:25 -0800341 ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName);
Wink Savilled20a5d62010-10-20 15:17:28 -0700342 new Thread(ca).start();
343
344 if (DBG) log("connect srcHandler to dst Package & class X");
345 }
346
347 /**
348 * Connect handler to a class
349 *
350 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
351 * msg.arg1 = status
Wink Savillecfce3032010-12-01 23:20:25 -0800352 * msg.obj = the AsyncChannel
Wink Savilled20a5d62010-10-20 15:17:28 -0700353 *
354 * @param srcContext
355 * @param srcHandler
356 * @param klass is the class to send messages to.
Wink Savilled20a5d62010-10-20 15:17:28 -0700357 */
Wink Savillecfce3032010-12-01 23:20:25 -0800358 public void connect(Context srcContext, Handler srcHandler, Class<?> klass) {
359 connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName());
Wink Savilled20a5d62010-10-20 15:17:28 -0700360 }
361
362 /**
363 * Connect handler and messenger.
364 *
365 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete.
366 * msg.arg1 = status
Wink Savillecfce3032010-12-01 23:20:25 -0800367 * msg.obj = the AsyncChannel
Wink Savilled20a5d62010-10-20 15:17:28 -0700368 *
369 * @param srcContext
370 * @param srcHandler
371 * @param dstMessenger
Wink Savilled20a5d62010-10-20 15:17:28 -0700372 */
Wink Savillecfce3032010-12-01 23:20:25 -0800373 public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
Wink Savilled20a5d62010-10-20 15:17:28 -0700374 if (DBG) log("connect srcHandler to the dstMessenger E");
375
Wink Saville0246bbc2011-05-02 10:44:56 -0700376 // We are connected
377 connected(srcContext, srcHandler, dstMessenger);
Wink Savilled20a5d62010-10-20 15:17:28 -0700378
379 // Tell source we are half connected
Wink Savillecfce3032010-12-01 23:20:25 -0800380 replyHalfConnected(STATUS_SUCCESSFUL);
Wink Savilled20a5d62010-10-20 15:17:28 -0700381
382 if (DBG) log("connect srcHandler to the dstMessenger X");
383 }
384
385 /**
Wink Saville0246bbc2011-05-02 10:44:56 -0700386 * Connect handler to messenger. This method is typically called
387 * when a server receives a CMD_CHANNEL_FULL_CONNECTION request
388 * and initializes the internal instance variables to allow communication
389 * with the dstMessenger.
Wink Savilled20a5d62010-10-20 15:17:28 -0700390 *
Wink Saville0246bbc2011-05-02 10:44:56 -0700391 * @param srcContext
392 * @param srcHandler
393 * @param dstMessenger
394 */
395 public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) {
396 if (DBG) log("connected srcHandler to the dstMessenger E");
397
398 // Initialize source fields
399 mSrcContext = srcContext;
400 mSrcHandler = srcHandler;
401 mSrcMessenger = new Messenger(mSrcHandler);
402
403 // Initialize destination fields
404 mDstMessenger = dstMessenger;
Wei Wang19c48832016-03-28 12:50:52 -0700405 linkToDeathMonitor();
Wink Saville0246bbc2011-05-02 10:44:56 -0700406 if (DBG) log("connected srcHandler to the dstMessenger X");
407 }
408
409 /**
410 * Connect two local Handlers.
Wink Savilled20a5d62010-10-20 15:17:28 -0700411 *
412 * @param srcContext is the context of the source
413 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED
414 * messages
415 * @param dstHandler is the hander to send messages to.
Wink Savilled20a5d62010-10-20 15:17:28 -0700416 */
Wink Savillecfce3032010-12-01 23:20:25 -0800417 public void connect(Context srcContext, Handler srcHandler, Handler dstHandler) {
418 connect(srcContext, srcHandler, new Messenger(dstHandler));
Wink Savilled20a5d62010-10-20 15:17:28 -0700419 }
420
421 /**
422 * Connect service and messenger.
423 *
424 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcAsyncService when complete.
425 * msg.arg1 = status
Wink Savillecfce3032010-12-01 23:20:25 -0800426 * msg.obj = the AsyncChannel
Wink Savilled20a5d62010-10-20 15:17:28 -0700427 *
428 * @param srcAsyncService
429 * @param dstMessenger
Wink Savilled20a5d62010-10-20 15:17:28 -0700430 */
Wink Savillecfce3032010-12-01 23:20:25 -0800431 public void connect(AsyncService srcAsyncService, Messenger dstMessenger) {
432 connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger);
Wink Savilled20a5d62010-10-20 15:17:28 -0700433 }
434
435 /**
436 * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED
437 */
438 public void disconnected() {
Wink Saville0246bbc2011-05-02 10:44:56 -0700439 mSrcContext = null;
Wink Savilled20a5d62010-10-20 15:17:28 -0700440 mSrcHandler = null;
441 mSrcMessenger = null;
442 mDstMessenger = null;
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700443 mDeathMonitor = null;
Wink Savilled20a5d62010-10-20 15:17:28 -0700444 mConnection = null;
445 }
446
447 /**
448 * Disconnect
449 */
Wink Savillecfce3032010-12-01 23:20:25 -0800450 public void disconnect() {
Wink Saville0246bbc2011-05-02 10:44:56 -0700451 if ((mConnection != null) && (mSrcContext != null)) {
Wink Savilled20a5d62010-10-20 15:17:28 -0700452 mSrcContext.unbindService(mConnection);
Robert Greenwaltb7fbb9b2014-05-07 23:56:50 -0700453 mConnection = null;
Wink Savilled20a5d62010-10-20 15:17:28 -0700454 }
Wink Savillef3110df2012-05-27 22:12:07 -0700455 try {
456 // Send the DISCONNECTED, although it may not be received
457 // but its the best we can do.
458 Message msg = Message.obtain();
459 msg.what = CMD_CHANNEL_DISCONNECTED;
460 msg.replyTo = mSrcMessenger;
461 mDstMessenger.send(msg);
462 } catch(Exception e) {
463 }
464 // Tell source we're disconnected.
Paul Jensend0d42052015-05-07 10:44:32 -0400465 replyDisconnected(STATUS_SUCCESSFUL);
466 mSrcHandler = null;
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700467 // Unlink only when bindService isn't used
468 if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) {
469 mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0);
Robert Greenwaltb7fbb9b2014-05-07 23:56:50 -0700470 mDeathMonitor = null;
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700471 }
Wink Savilled20a5d62010-10-20 15:17:28 -0700472 }
473
474 /**
475 * Send a message to the destination handler.
476 *
477 * @param msg
478 */
479 public void sendMessage(Message msg) {
480 msg.replyTo = mSrcMessenger;
481 try {
482 mDstMessenger.send(msg);
483 } catch (RemoteException e) {
Wink Saville0246bbc2011-05-02 10:44:56 -0700484 replyDisconnected(STATUS_SEND_UNSUCCESSFUL);
Wink Savilled20a5d62010-10-20 15:17:28 -0700485 }
486 }
487
488 /**
489 * Send a message to the destination handler
490 *
491 * @param what
492 */
493 public void sendMessage(int what) {
494 Message msg = Message.obtain();
495 msg.what = what;
496 sendMessage(msg);
497 }
498
499 /**
500 * Send a message to the destination handler
501 *
502 * @param what
503 * @param arg1
504 */
505 public void sendMessage(int what, int arg1) {
506 Message msg = Message.obtain();
507 msg.what = what;
508 msg.arg1 = arg1;
509 sendMessage(msg);
510 }
511
512 /**
513 * Send a message to the destination handler
514 *
515 * @param what
516 * @param arg1
517 * @param arg2
518 */
519 public void sendMessage(int what, int arg1, int arg2) {
520 Message msg = Message.obtain();
521 msg.what = what;
522 msg.arg1 = arg1;
523 msg.arg2 = arg2;
524 sendMessage(msg);
525 }
526
527 /**
528 * Send a message to the destination handler
529 *
530 * @param what
531 * @param arg1
532 * @param arg2
533 * @param obj
534 */
535 public void sendMessage(int what, int arg1, int arg2, Object obj) {
536 Message msg = Message.obtain();
537 msg.what = what;
538 msg.arg1 = arg1;
539 msg.arg2 = arg2;
540 msg.obj = obj;
541 sendMessage(msg);
542 }
543
544 /**
545 * Send a message to the destination handler
546 *
547 * @param what
548 * @param obj
549 */
550 public void sendMessage(int what, Object obj) {
551 Message msg = Message.obtain();
552 msg.what = what;
553 msg.obj = obj;
554 sendMessage(msg);
555 }
556
557 /**
558 * Reply to srcMsg sending dstMsg
559 *
560 * @param srcMsg
561 * @param dstMsg
562 */
563 public void replyToMessage(Message srcMsg, Message dstMsg) {
564 try {
Wink Saville0246bbc2011-05-02 10:44:56 -0700565 dstMsg.replyTo = mSrcMessenger;
Wink Savilled20a5d62010-10-20 15:17:28 -0700566 srcMsg.replyTo.send(dstMsg);
567 } catch (RemoteException e) {
568 log("TODO: handle replyToMessage RemoteException" + e);
569 e.printStackTrace();
570 }
571 }
572
573 /**
574 * Reply to srcMsg
575 *
576 * @param srcMsg
577 * @param what
578 */
579 public void replyToMessage(Message srcMsg, int what) {
580 Message msg = Message.obtain();
581 msg.what = what;
582 replyToMessage(srcMsg, msg);
583 }
584
585 /**
586 * Reply to srcMsg
587 *
588 * @param srcMsg
589 * @param what
590 * @param arg1
591 */
592 public void replyToMessage(Message srcMsg, int what, int arg1) {
593 Message msg = Message.obtain();
594 msg.what = what;
595 msg.arg1 = arg1;
596 replyToMessage(srcMsg, msg);
597 }
598
599 /**
600 * Reply to srcMsg
601 *
602 * @param srcMsg
603 * @param what
604 * @param arg1
605 * @param arg2
606 */
607 public void replyToMessage(Message srcMsg, int what, int arg1, int arg2) {
608 Message msg = Message.obtain();
609 msg.what = what;
610 msg.arg1 = arg1;
611 msg.arg2 = arg2;
612 replyToMessage(srcMsg, msg);
613 }
614
615 /**
616 * Reply to srcMsg
617 *
618 * @param srcMsg
619 * @param what
620 * @param arg1
621 * @param arg2
622 * @param obj
623 */
624 public void replyToMessage(Message srcMsg, int what, int arg1, int arg2, Object obj) {
625 Message msg = Message.obtain();
626 msg.what = what;
627 msg.arg1 = arg1;
628 msg.arg2 = arg2;
629 msg.obj = obj;
630 replyToMessage(srcMsg, msg);
631 }
632
633 /**
634 * Reply to srcMsg
635 *
636 * @param srcMsg
637 * @param what
638 * @param obj
639 */
640 public void replyToMessage(Message srcMsg, int what, Object obj) {
641 Message msg = Message.obtain();
642 msg.what = what;
643 msg.obj = obj;
644 replyToMessage(srcMsg, msg);
645 }
646
647 /**
648 * Send the Message synchronously.
649 *
650 * @param msg to send
651 * @return reply message or null if an error.
652 */
653 public Message sendMessageSynchronously(Message msg) {
654 Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg);
655 return resultMsg;
656 }
657
658 /**
659 * Send the Message synchronously.
660 *
661 * @param what
662 * @return reply message or null if an error.
663 */
664 public Message sendMessageSynchronously(int what) {
665 Message msg = Message.obtain();
666 msg.what = what;
667 Message resultMsg = sendMessageSynchronously(msg);
668 return resultMsg;
669 }
670
671 /**
672 * Send the Message synchronously.
673 *
674 * @param what
675 * @param arg1
676 * @return reply message or null if an error.
677 */
678 public Message sendMessageSynchronously(int what, int arg1) {
679 Message msg = Message.obtain();
680 msg.what = what;
681 msg.arg1 = arg1;
682 Message resultMsg = sendMessageSynchronously(msg);
683 return resultMsg;
684 }
685
686 /**
687 * Send the Message synchronously.
688 *
689 * @param what
690 * @param arg1
691 * @param arg2
692 * @return reply message or null if an error.
693 */
694 public Message sendMessageSynchronously(int what, int arg1, int arg2) {
695 Message msg = Message.obtain();
696 msg.what = what;
697 msg.arg1 = arg1;
698 msg.arg2 = arg2;
699 Message resultMsg = sendMessageSynchronously(msg);
700 return resultMsg;
701 }
702
703 /**
704 * Send the Message synchronously.
705 *
706 * @param what
707 * @param arg1
708 * @param arg2
709 * @param obj
710 * @return reply message or null if an error.
711 */
712 public Message sendMessageSynchronously(int what, int arg1, int arg2, Object obj) {
713 Message msg = Message.obtain();
714 msg.what = what;
715 msg.arg1 = arg1;
716 msg.arg2 = arg2;
717 msg.obj = obj;
718 Message resultMsg = sendMessageSynchronously(msg);
719 return resultMsg;
720 }
721
722 /**
723 * Send the Message synchronously.
724 *
725 * @param what
726 * @param obj
727 * @return reply message or null if an error.
728 */
729 public Message sendMessageSynchronously(int what, Object obj) {
730 Message msg = Message.obtain();
731 msg.what = what;
732 msg.obj = obj;
733 Message resultMsg = sendMessageSynchronously(msg);
734 return resultMsg;
735 }
736
737 /**
738 * Helper class to send messages synchronously
739 */
740 private static class SyncMessenger {
741 /** A stack of SyncMessengers */
742 private static Stack<SyncMessenger> sStack = new Stack<SyncMessenger>();
743 /** A number of SyncMessengers created */
744 private static int sCount = 0;
745 /** The handler thread */
746 private HandlerThread mHandlerThread;
747 /** The handler that will receive the result */
748 private SyncHandler mHandler;
749 /** The messenger used to send the message */
750 private Messenger mMessenger;
751
752 /** private constructor */
753 private SyncMessenger() {
754 }
755
756 /** Synchronous Handler class */
757 private class SyncHandler extends Handler {
758 /** The object used to wait/notify */
759 private Object mLockObject = new Object();
760 /** The resulting message */
761 private Message mResultMsg;
762
763 /** Constructor */
764 private SyncHandler(Looper looper) {
765 super(looper);
766 }
767
768 /** Handle of the reply message */
769 @Override
770 public void handleMessage(Message msg) {
771 mResultMsg = Message.obtain();
772 mResultMsg.copyFrom(msg);
773 synchronized(mLockObject) {
774 mLockObject.notify();
775 }
776 }
777 }
778
779 /**
780 * @return the SyncMessenger
781 */
782 private static SyncMessenger obtain() {
783 SyncMessenger sm;
784 synchronized (sStack) {
785 if (sStack.isEmpty()) {
786 sm = new SyncMessenger();
787 sm.mHandlerThread = new HandlerThread("SyncHandler-" + sCount++);
788 sm.mHandlerThread.start();
789 sm.mHandler = sm.new SyncHandler(sm.mHandlerThread.getLooper());
790 sm.mMessenger = new Messenger(sm.mHandler);
791 } else {
792 sm = sStack.pop();
793 }
794 }
795 return sm;
796 }
797
798 /**
799 * Recycle this object
800 */
801 private void recycle() {
802 synchronized (sStack) {
803 sStack.push(this);
804 }
805 }
806
807 /**
808 * Send a message synchronously.
809 *
810 * @param msg to send
811 * @return result message or null if an error occurs
812 */
813 private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) {
814 SyncMessenger sm = SyncMessenger.obtain();
815 try {
Wink Saville0246bbc2011-05-02 10:44:56 -0700816 if (dstMessenger != null && msg != null) {
817 msg.replyTo = sm.mMessenger;
818 synchronized (sm.mHandler.mLockObject) {
819 dstMessenger.send(msg);
820 sm.mHandler.mLockObject.wait();
821 }
822 } else {
823 sm.mHandler.mResultMsg = null;
Wink Savilled20a5d62010-10-20 15:17:28 -0700824 }
825 } catch (InterruptedException e) {
826 sm.mHandler.mResultMsg = null;
827 } catch (RemoteException e) {
828 sm.mHandler.mResultMsg = null;
829 }
830 Message resultMsg = sm.mHandler.mResultMsg;
831 sm.recycle();
832 return resultMsg;
833 }
834 }
835
836 /**
837 * Reply to the src handler that we're half connected.
Wink Saville0246bbc2011-05-02 10:44:56 -0700838 * see: CMD_CHANNEL_HALF_CONNECTED for message contents
Wink Savilled20a5d62010-10-20 15:17:28 -0700839 *
840 * @param status to be stored in msg.arg1
841 */
Wink Savillecfce3032010-12-01 23:20:25 -0800842 private void replyHalfConnected(int status) {
Wink Savilled20a5d62010-10-20 15:17:28 -0700843 Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED);
844 msg.arg1 = status;
Wink Savillecfce3032010-12-01 23:20:25 -0800845 msg.obj = this;
Wink Savilled20a5d62010-10-20 15:17:28 -0700846 msg.replyTo = mDstMessenger;
Wei Wang19c48832016-03-28 12:50:52 -0700847 if (!linkToDeathMonitor()) {
848 // Override status to indicate failure
849 msg.arg1 = STATUS_BINDING_UNSUCCESSFUL;
850 }
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700851
Wei Wang19c48832016-03-28 12:50:52 -0700852 mSrcHandler.sendMessage(msg);
853 }
854
855 /**
856 * Link to death monitor for destination messenger. Returns true if successfully binded to
857 * destination messenger; false otherwise.
858 */
859 private boolean linkToDeathMonitor() {
860 // Link to death only when bindService isn't used and not already linked.
861 if (mConnection == null && mDeathMonitor == null) {
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700862 mDeathMonitor = new DeathMonitor();
863 try {
864 mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0);
865 } catch (RemoteException e) {
866 mDeathMonitor = null;
Wei Wang19c48832016-03-28 12:50:52 -0700867 return false;
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700868 }
869 }
Wei Wang19c48832016-03-28 12:50:52 -0700870 return true;
Wink Savilled20a5d62010-10-20 15:17:28 -0700871 }
872
873 /**
Wink Saville0246bbc2011-05-02 10:44:56 -0700874 * Reply to the src handler that we are disconnected
875 * see: CMD_CHANNEL_DISCONNECTED for message contents
876 *
877 * @param status to be stored in msg.arg1
878 */
879 private void replyDisconnected(int status) {
Paul Jensend0d42052015-05-07 10:44:32 -0400880 // Can't reply if already disconnected. Avoid NullPointerException.
881 if (mSrcHandler == null) return;
Wink Saville0246bbc2011-05-02 10:44:56 -0700882 Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED);
883 msg.arg1 = status;
884 msg.obj = this;
885 msg.replyTo = mDstMessenger;
886 mSrcHandler.sendMessage(msg);
887 }
888
889
890 /**
Wink Savilled20a5d62010-10-20 15:17:28 -0700891 * ServiceConnection to receive call backs.
892 */
893 class AsyncChannelConnection implements ServiceConnection {
Wink Savillecfce3032010-12-01 23:20:25 -0800894 AsyncChannelConnection() {
Wink Savilled20a5d62010-10-20 15:17:28 -0700895 }
896
Wink Saville0246bbc2011-05-02 10:44:56 -0700897 @Override
Wink Savilled20a5d62010-10-20 15:17:28 -0700898 public void onServiceConnected(ComponentName className, IBinder service) {
899 mDstMessenger = new Messenger(service);
Wink Savillecfce3032010-12-01 23:20:25 -0800900 replyHalfConnected(STATUS_SUCCESSFUL);
Wink Savilled20a5d62010-10-20 15:17:28 -0700901 }
902
Wink Saville0246bbc2011-05-02 10:44:56 -0700903 @Override
Wink Savilled20a5d62010-10-20 15:17:28 -0700904 public void onServiceDisconnected(ComponentName className) {
Wink Saville0246bbc2011-05-02 10:44:56 -0700905 replyDisconnected(STATUS_SUCCESSFUL);
Wink Savilled20a5d62010-10-20 15:17:28 -0700906 }
907 }
908
909 /**
910 * Log the string.
911 *
912 * @param s
913 */
914 private static void log(String s) {
915 Slog.d(TAG, s);
916 }
Vairavan Srinivasanba059bf2012-08-01 00:38:08 -0700917
918 private final class DeathMonitor implements IBinder.DeathRecipient {
919
920 DeathMonitor() {
921 }
922
923 public void binderDied() {
924 replyDisconnected(STATUS_REMOTE_DISCONNECTION);
925 }
926
927 }
Wink Savilled20a5d62010-10-20 15:17:28 -0700928}