1 /** 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 17 package com.android.internal.util; 18 19 import android.content.ComponentName; 20 import android.content.Context; 21 import android.content.Intent; 22 import android.content.ServiceConnection; 23 import android.os.Handler; 24 import android.os.HandlerThread; 25 import android.os.IBinder; 26 import android.os.Looper; 27 import android.os.Message; 28 import android.os.Messenger; 29 import android.os.RemoteException; 30 import android.util.Slog; 31 32 import java.util.Stack; 33 34 /** 35 * <p>An asynchronous channel between two handlers.</p> 36 * 37 * <p>The handlers maybe in the same process or in another process. There 38 * are two protocol styles that can be used with an AysncChannel. The 39 * first is a simple request/reply protocol where the server does 40 * not need to know which client is issuing the request.</p> 41 * 42 * <p>In a simple request/reply protocol the client/source sends requests to the 43 * server/destination. And the server uses the replyToMessage methods. 44 * In this usage model there is no need for the destination to 45 * use the connect methods. The typical sequence of operations is:</p> 46 *<ol> 47 * <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> 51 * <li><code>comm-loop:</code></li> 52 * <li>Client calls AsyncChannel#sendMessage</li> 53 * <li>Server processes messages and optionally replies using AsyncChannel#replyToMessage 54 * <li>Loop to <code>comm-loop</code> until done</li> 55 * <li>When done Client calls {@link AsyncChannel#disconnect}</li> 56 * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li> 57 *</ol> 58 *<br/> 59 * <p>A second usage model is where the server/destination needs to know 60 * 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 63 * use the connect methods. The typical sequence of operation is:</p> 64 *<ol> 65 * <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> 70 * <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li> 71 * <li>Server calls AsyncChannel#connected</li> 72 * <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> 78 * <li>When done Client/Server calls {@link AsyncChannel#disconnect}</li> 79 * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li> 80 *</ol> 81 * 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. 85 */ 86 public 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 93 private static final int BASE = Protocol.BASE_SYSTEM_ASYNC_CHANNEL; 94 95 /** 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 105 * msg.obj == the AsyncChannel 106 * msg.replyTo == dstMessenger if successful 107 */ 108 public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0; 109 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 */ 117 public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1; 118 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 125 * and {@link AsyncChannel#disconnect} would typically be called. 126 */ 127 public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2; 128 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 132 * the state of the connection. The receiver should call {@link AsyncChannel#disconnect} 133 * 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 */ 138 public static final int CMD_CHANNEL_DISCONNECT = BASE + 3; 139 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 145 * 1 : STATUS_BINDING_UNSUCCESSFUL 146 * 2 : STATUS_SEND_UNSUCCESSFUL 147 * : All other values signify failure and the channel state is indeterminate 148 * msg.obj == the AsyncChannel 149 * msg.replyTo = messenger disconnecting or null if it was never connected. 150 */ 151 public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4; 152 153 private static final int CMD_TO_STRING_COUNT = CMD_CHANNEL_DISCONNECTED - BASE + 1; 154 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 } cmdToString(int cmd)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 171 /** 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 177 /** 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 183 /** Error indicating abnormal termination of destination messenger */ 184 public static final int STATUS_REMOTE_DISCONNECTION = 4; 185 186 /** 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 201 /** Death Monitor for destination messenger */ 202 private DeathMonitor mDeathMonitor; 203 204 /** 205 * AsyncChannel constructor 206 */ AsyncChannel()207 public AsyncChannel() { 208 } 209 210 /** 211 * Connect handler to named package/class synchronously. 212 * 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) 219 * 220 * @return STATUS_SUCCESSFUL on success any other value is an error. 221 */ connectSrcHandlerToPackageSync( Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName)222 public int connectSrcHandlerToPackageSync( 223 Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) { 224 if (DBG) log("connect srcHandler to dst Package & class E"); 225 226 mConnection = new AsyncChannelConnection(); 227 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); 244 if (DBG) log("connect srcHandler to dst Package & class X result=" + result); 245 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 */ connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger)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 */ connectSync(Context srcContext, Handler srcHandler, Handler dstHandler)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 */ fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler)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; 299 } 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 306 * msg.obj = the AsyncChannel 307 * 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) 314 */ connect(Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName)315 public void connect(Context srcContext, Handler srcHandler, String dstPackageName, 316 String dstClassName) { 317 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; 324 325 ConnectAsync(Context srcContext, Handler srcHandler, String dstPackageName, 326 String dstClassName) { 327 mSrcCtx = srcContext; 328 mSrcHdlr = srcHandler; 329 mDstPackageName = dstPackageName; 330 mDstClassName = dstClassName; 331 } 332 333 @Override 334 public void run() { 335 int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName, 336 mDstClassName); 337 replyHalfConnected(result); 338 } 339 } 340 341 ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName); 342 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 352 * msg.obj = the AsyncChannel 353 * 354 * @param srcContext 355 * @param srcHandler 356 * @param klass is the class to send messages to. 357 */ connect(Context srcContext, Handler srcHandler, Class<?> klass)358 public void connect(Context srcContext, Handler srcHandler, Class<?> klass) { 359 connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName()); 360 } 361 362 /** 363 * Connect handler and messenger. 364 * 365 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. 366 * msg.arg1 = status 367 * msg.obj = the AsyncChannel 368 * 369 * @param srcContext 370 * @param srcHandler 371 * @param dstMessenger 372 */ connect(Context srcContext, Handler srcHandler, Messenger dstMessenger)373 public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) { 374 if (DBG) log("connect srcHandler to the dstMessenger E"); 375 376 // We are connected 377 connected(srcContext, srcHandler, dstMessenger); 378 379 // Tell source we are half connected 380 replyHalfConnected(STATUS_SUCCESSFUL); 381 382 if (DBG) log("connect srcHandler to the dstMessenger X"); 383 } 384 385 /** 386 * 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. 390 * 391 * @param srcContext 392 * @param srcHandler 393 * @param dstMessenger 394 */ connected(Context srcContext, Handler srcHandler, Messenger dstMessenger)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; 405 if (DBG) log("connected srcHandler to the dstMessenger X"); 406 } 407 408 /** 409 * Connect two local Handlers. 410 * 411 * @param srcContext is the context of the source 412 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED 413 * messages 414 * @param dstHandler is the hander to send messages to. 415 */ connect(Context srcContext, Handler srcHandler, Handler dstHandler)416 public void connect(Context srcContext, Handler srcHandler, Handler dstHandler) { 417 connect(srcContext, srcHandler, new Messenger(dstHandler)); 418 } 419 420 /** 421 * Connect service and messenger. 422 * 423 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcAsyncService when complete. 424 * msg.arg1 = status 425 * msg.obj = the AsyncChannel 426 * 427 * @param srcAsyncService 428 * @param dstMessenger 429 */ connect(AsyncService srcAsyncService, Messenger dstMessenger)430 public void connect(AsyncService srcAsyncService, Messenger dstMessenger) { 431 connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger); 432 } 433 434 /** 435 * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED 436 */ disconnected()437 public void disconnected() { 438 mSrcContext = null; 439 mSrcHandler = null; 440 mSrcMessenger = null; 441 mDstMessenger = null; 442 mDeathMonitor = null; 443 mConnection = null; 444 } 445 446 /** 447 * Disconnect 448 */ disconnect()449 public void disconnect() { 450 if ((mConnection != null) && (mSrcContext != null)) { 451 mSrcContext.unbindService(mConnection); 452 mConnection = null; 453 } 454 try { 455 // Send the DISCONNECTED, although it may not be received 456 // but its the best we can do. 457 Message msg = Message.obtain(); 458 msg.what = CMD_CHANNEL_DISCONNECTED; 459 msg.replyTo = mSrcMessenger; 460 mDstMessenger.send(msg); 461 } catch(Exception e) { 462 } 463 // Tell source we're disconnected. 464 replyDisconnected(STATUS_SUCCESSFUL); 465 mSrcHandler = null; 466 // Unlink only when bindService isn't used 467 if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) { 468 mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0); 469 mDeathMonitor = null; 470 } 471 } 472 473 /** 474 * Send a message to the destination handler. 475 * 476 * @param msg 477 */ sendMessage(Message msg)478 public void sendMessage(Message msg) { 479 msg.replyTo = mSrcMessenger; 480 try { 481 mDstMessenger.send(msg); 482 } catch (RemoteException e) { 483 replyDisconnected(STATUS_SEND_UNSUCCESSFUL); 484 } 485 } 486 487 /** 488 * Send a message to the destination handler 489 * 490 * @param what 491 */ sendMessage(int what)492 public void sendMessage(int what) { 493 Message msg = Message.obtain(); 494 msg.what = what; 495 sendMessage(msg); 496 } 497 498 /** 499 * Send a message to the destination handler 500 * 501 * @param what 502 * @param arg1 503 */ sendMessage(int what, int arg1)504 public void sendMessage(int what, int arg1) { 505 Message msg = Message.obtain(); 506 msg.what = what; 507 msg.arg1 = arg1; 508 sendMessage(msg); 509 } 510 511 /** 512 * Send a message to the destination handler 513 * 514 * @param what 515 * @param arg1 516 * @param arg2 517 */ sendMessage(int what, int arg1, int arg2)518 public void sendMessage(int what, int arg1, int arg2) { 519 Message msg = Message.obtain(); 520 msg.what = what; 521 msg.arg1 = arg1; 522 msg.arg2 = arg2; 523 sendMessage(msg); 524 } 525 526 /** 527 * Send a message to the destination handler 528 * 529 * @param what 530 * @param arg1 531 * @param arg2 532 * @param obj 533 */ sendMessage(int what, int arg1, int arg2, Object obj)534 public void sendMessage(int what, int arg1, int arg2, Object obj) { 535 Message msg = Message.obtain(); 536 msg.what = what; 537 msg.arg1 = arg1; 538 msg.arg2 = arg2; 539 msg.obj = obj; 540 sendMessage(msg); 541 } 542 543 /** 544 * Send a message to the destination handler 545 * 546 * @param what 547 * @param obj 548 */ sendMessage(int what, Object obj)549 public void sendMessage(int what, Object obj) { 550 Message msg = Message.obtain(); 551 msg.what = what; 552 msg.obj = obj; 553 sendMessage(msg); 554 } 555 556 /** 557 * Reply to srcMsg sending dstMsg 558 * 559 * @param srcMsg 560 * @param dstMsg 561 */ replyToMessage(Message srcMsg, Message dstMsg)562 public void replyToMessage(Message srcMsg, Message dstMsg) { 563 try { 564 dstMsg.replyTo = mSrcMessenger; 565 srcMsg.replyTo.send(dstMsg); 566 } catch (RemoteException e) { 567 log("TODO: handle replyToMessage RemoteException" + e); 568 e.printStackTrace(); 569 } 570 } 571 572 /** 573 * Reply to srcMsg 574 * 575 * @param srcMsg 576 * @param what 577 */ replyToMessage(Message srcMsg, int what)578 public void replyToMessage(Message srcMsg, int what) { 579 Message msg = Message.obtain(); 580 msg.what = what; 581 replyToMessage(srcMsg, msg); 582 } 583 584 /** 585 * Reply to srcMsg 586 * 587 * @param srcMsg 588 * @param what 589 * @param arg1 590 */ replyToMessage(Message srcMsg, int what, int arg1)591 public void replyToMessage(Message srcMsg, int what, int arg1) { 592 Message msg = Message.obtain(); 593 msg.what = what; 594 msg.arg1 = arg1; 595 replyToMessage(srcMsg, msg); 596 } 597 598 /** 599 * Reply to srcMsg 600 * 601 * @param srcMsg 602 * @param what 603 * @param arg1 604 * @param arg2 605 */ replyToMessage(Message srcMsg, int what, int arg1, int arg2)606 public void replyToMessage(Message srcMsg, int what, int arg1, int arg2) { 607 Message msg = Message.obtain(); 608 msg.what = what; 609 msg.arg1 = arg1; 610 msg.arg2 = arg2; 611 replyToMessage(srcMsg, msg); 612 } 613 614 /** 615 * Reply to srcMsg 616 * 617 * @param srcMsg 618 * @param what 619 * @param arg1 620 * @param arg2 621 * @param obj 622 */ replyToMessage(Message srcMsg, int what, int arg1, int arg2, Object obj)623 public void replyToMessage(Message srcMsg, int what, int arg1, int arg2, Object obj) { 624 Message msg = Message.obtain(); 625 msg.what = what; 626 msg.arg1 = arg1; 627 msg.arg2 = arg2; 628 msg.obj = obj; 629 replyToMessage(srcMsg, msg); 630 } 631 632 /** 633 * Reply to srcMsg 634 * 635 * @param srcMsg 636 * @param what 637 * @param obj 638 */ replyToMessage(Message srcMsg, int what, Object obj)639 public void replyToMessage(Message srcMsg, int what, Object obj) { 640 Message msg = Message.obtain(); 641 msg.what = what; 642 msg.obj = obj; 643 replyToMessage(srcMsg, msg); 644 } 645 646 /** 647 * Send the Message synchronously. 648 * 649 * @param msg to send 650 * @return reply message or null if an error. 651 */ sendMessageSynchronously(Message msg)652 public Message sendMessageSynchronously(Message msg) { 653 Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg); 654 return resultMsg; 655 } 656 657 /** 658 * Send the Message synchronously. 659 * 660 * @param what 661 * @return reply message or null if an error. 662 */ sendMessageSynchronously(int what)663 public Message sendMessageSynchronously(int what) { 664 Message msg = Message.obtain(); 665 msg.what = what; 666 Message resultMsg = sendMessageSynchronously(msg); 667 return resultMsg; 668 } 669 670 /** 671 * Send the Message synchronously. 672 * 673 * @param what 674 * @param arg1 675 * @return reply message or null if an error. 676 */ sendMessageSynchronously(int what, int arg1)677 public Message sendMessageSynchronously(int what, int arg1) { 678 Message msg = Message.obtain(); 679 msg.what = what; 680 msg.arg1 = arg1; 681 Message resultMsg = sendMessageSynchronously(msg); 682 return resultMsg; 683 } 684 685 /** 686 * Send the Message synchronously. 687 * 688 * @param what 689 * @param arg1 690 * @param arg2 691 * @return reply message or null if an error. 692 */ sendMessageSynchronously(int what, int arg1, int arg2)693 public Message sendMessageSynchronously(int what, int arg1, int arg2) { 694 Message msg = Message.obtain(); 695 msg.what = what; 696 msg.arg1 = arg1; 697 msg.arg2 = arg2; 698 Message resultMsg = sendMessageSynchronously(msg); 699 return resultMsg; 700 } 701 702 /** 703 * Send the Message synchronously. 704 * 705 * @param what 706 * @param arg1 707 * @param arg2 708 * @param obj 709 * @return reply message or null if an error. 710 */ sendMessageSynchronously(int what, int arg1, int arg2, Object obj)711 public Message sendMessageSynchronously(int what, int arg1, int arg2, Object obj) { 712 Message msg = Message.obtain(); 713 msg.what = what; 714 msg.arg1 = arg1; 715 msg.arg2 = arg2; 716 msg.obj = obj; 717 Message resultMsg = sendMessageSynchronously(msg); 718 return resultMsg; 719 } 720 721 /** 722 * Send the Message synchronously. 723 * 724 * @param what 725 * @param obj 726 * @return reply message or null if an error. 727 */ sendMessageSynchronously(int what, Object obj)728 public Message sendMessageSynchronously(int what, Object obj) { 729 Message msg = Message.obtain(); 730 msg.what = what; 731 msg.obj = obj; 732 Message resultMsg = sendMessageSynchronously(msg); 733 return resultMsg; 734 } 735 736 /** 737 * Helper class to send messages synchronously 738 */ 739 private static class SyncMessenger { 740 /** A stack of SyncMessengers */ 741 private static Stack<SyncMessenger> sStack = new Stack<SyncMessenger>(); 742 /** A number of SyncMessengers created */ 743 private static int sCount = 0; 744 /** The handler thread */ 745 private HandlerThread mHandlerThread; 746 /** The handler that will receive the result */ 747 private SyncHandler mHandler; 748 /** The messenger used to send the message */ 749 private Messenger mMessenger; 750 751 /** private constructor */ SyncMessenger()752 private SyncMessenger() { 753 } 754 755 /** Synchronous Handler class */ 756 private class SyncHandler extends Handler { 757 /** The object used to wait/notify */ 758 private Object mLockObject = new Object(); 759 /** The resulting message */ 760 private Message mResultMsg; 761 762 /** Constructor */ SyncHandler(Looper looper)763 private SyncHandler(Looper looper) { 764 super(looper); 765 } 766 767 /** Handle of the reply message */ 768 @Override handleMessage(Message msg)769 public void handleMessage(Message msg) { 770 Message msgCopy = Message.obtain(); 771 msgCopy.copyFrom(msg); 772 synchronized(mLockObject) { 773 mResultMsg = msgCopy; 774 mLockObject.notify(); 775 } 776 } 777 } 778 779 /** 780 * @return the SyncMessenger 781 */ obtain()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 */ recycle()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 */ sendMessageSynchronously(Messenger dstMessenger, Message msg)813 private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) { 814 SyncMessenger sm = SyncMessenger.obtain(); 815 Message resultMsg = null; 816 try { 817 if (dstMessenger != null && msg != null) { 818 msg.replyTo = sm.mMessenger; 819 synchronized (sm.mHandler.mLockObject) { 820 if (sm.mHandler.mResultMsg != null) { 821 Slog.wtf(TAG, "mResultMsg should be null here"); 822 sm.mHandler.mResultMsg = null; 823 } 824 dstMessenger.send(msg); 825 sm.mHandler.mLockObject.wait(); 826 resultMsg = sm.mHandler.mResultMsg; 827 sm.mHandler.mResultMsg = null; 828 } 829 } 830 } catch (InterruptedException e) { 831 Slog.e(TAG, "error in sendMessageSynchronously", e); 832 } catch (RemoteException e) { 833 Slog.e(TAG, "error in sendMessageSynchronously", e); 834 } 835 sm.recycle(); 836 return resultMsg; 837 } 838 } 839 840 /** 841 * Reply to the src handler that we're half connected. 842 * see: CMD_CHANNEL_HALF_CONNECTED for message contents 843 * 844 * @param status to be stored in msg.arg1 845 */ replyHalfConnected(int status)846 private void replyHalfConnected(int status) { 847 Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED); 848 msg.arg1 = status; 849 msg.obj = this; 850 msg.replyTo = mDstMessenger; 851 if (!linkToDeathMonitor()) { 852 // Override status to indicate failure 853 msg.arg1 = STATUS_BINDING_UNSUCCESSFUL; 854 } 855 856 mSrcHandler.sendMessage(msg); 857 } 858 859 /** 860 * Link to death monitor for destination messenger. Returns true if successfully binded to 861 * destination messenger; false otherwise. 862 */ linkToDeathMonitor()863 private boolean linkToDeathMonitor() { 864 // Link to death only when bindService isn't used and not already linked. 865 if (mConnection == null && mDeathMonitor == null) { 866 mDeathMonitor = new DeathMonitor(); 867 try { 868 mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0); 869 } catch (RemoteException e) { 870 mDeathMonitor = null; 871 return false; 872 } 873 } 874 return true; 875 } 876 877 /** 878 * Reply to the src handler that we are disconnected 879 * see: CMD_CHANNEL_DISCONNECTED for message contents 880 * 881 * @param status to be stored in msg.arg1 882 */ replyDisconnected(int status)883 private void replyDisconnected(int status) { 884 // Can't reply if already disconnected. Avoid NullPointerException. 885 if (mSrcHandler == null) return; 886 Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED); 887 msg.arg1 = status; 888 msg.obj = this; 889 msg.replyTo = mDstMessenger; 890 mSrcHandler.sendMessage(msg); 891 } 892 893 894 /** 895 * ServiceConnection to receive call backs. 896 */ 897 class AsyncChannelConnection implements ServiceConnection { AsyncChannelConnection()898 AsyncChannelConnection() { 899 } 900 901 @Override onServiceConnected(ComponentName className, IBinder service)902 public void onServiceConnected(ComponentName className, IBinder service) { 903 mDstMessenger = new Messenger(service); 904 replyHalfConnected(STATUS_SUCCESSFUL); 905 } 906 907 @Override onServiceDisconnected(ComponentName className)908 public void onServiceDisconnected(ComponentName className) { 909 replyDisconnected(STATUS_SUCCESSFUL); 910 } 911 } 912 913 /** 914 * Log the string. 915 * 916 * @param s 917 */ log(String s)918 private static void log(String s) { 919 Slog.d(TAG, s); 920 } 921 922 private final class DeathMonitor implements IBinder.DeathRecipient { 923 DeathMonitor()924 DeathMonitor() { 925 } 926 binderDied()927 public void binderDied() { 928 replyDisconnected(STATUS_REMOTE_DISCONNECTION); 929 } 930 931 } 932 } 933