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 /** Successful status always 0, !0 is an unsuccessful status */ 154 public static final int STATUS_SUCCESSFUL = 0; 155 156 /** Error attempting to bind on a connect */ 157 public static final int STATUS_BINDING_UNSUCCESSFUL = 1; 158 159 /** Error attempting to send a message */ 160 public static final int STATUS_SEND_UNSUCCESSFUL = 2; 161 162 /** CMD_FULLY_CONNECTED refused because a connection already exists*/ 163 public static final int STATUS_FULL_CONNECTION_REFUSED_ALREADY_CONNECTED = 3; 164 165 /** Service connection */ 166 private AsyncChannelConnection mConnection; 167 168 /** Context for source */ 169 private Context mSrcContext; 170 171 /** Handler for source */ 172 private Handler mSrcHandler; 173 174 /** Messenger for source */ 175 private Messenger mSrcMessenger; 176 177 /** Messenger for destination */ 178 private Messenger mDstMessenger; 179 180 /** 181 * AsyncChannel constructor 182 */ AsyncChannel()183 public AsyncChannel() { 184 } 185 186 /** 187 * Connect handler to named package/class synchronously. 188 * 189 * @param srcContext is the context of the source 190 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED 191 * messages 192 * @param dstPackageName is the destination package name 193 * @param dstClassName is the fully qualified class name (i.e. contains 194 * package name) 195 * 196 * @return STATUS_SUCCESSFUL on success any other value is an error. 197 */ connectSrcHandlerToPackageSync( Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName)198 public int connectSrcHandlerToPackageSync( 199 Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) { 200 if (DBG) log("connect srcHandler to dst Package & class E"); 201 202 mConnection = new AsyncChannelConnection(); 203 204 /* Initialize the source information */ 205 mSrcContext = srcContext; 206 mSrcHandler = srcHandler; 207 mSrcMessenger = new Messenger(srcHandler); 208 209 /* 210 * Initialize destination information to null they will 211 * be initialized when the AsyncChannelConnection#onServiceConnected 212 * is called 213 */ 214 mDstMessenger = null; 215 216 /* Send intent to create the connection */ 217 Intent intent = new Intent(Intent.ACTION_MAIN); 218 intent.setClassName(dstPackageName, dstClassName); 219 boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); 220 if (DBG) log("connect srcHandler to dst Package & class X result=" + result); 221 return result ? STATUS_SUCCESSFUL : STATUS_BINDING_UNSUCCESSFUL; 222 } 223 224 /** 225 * Connect a handler to Messenger synchronously. 226 * 227 * @param srcContext is the context of the source 228 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED 229 * messages 230 * @param dstMessenger is the hander to send messages to. 231 * 232 * @return STATUS_SUCCESSFUL on success any other value is an error. 233 */ connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger)234 public int connectSync(Context srcContext, Handler srcHandler, Messenger dstMessenger) { 235 if (DBG) log("halfConnectSync srcHandler to the dstMessenger E"); 236 237 // We are connected 238 connected(srcContext, srcHandler, dstMessenger); 239 240 if (DBG) log("halfConnectSync srcHandler to the dstMessenger X"); 241 return STATUS_SUCCESSFUL; 242 } 243 244 /** 245 * connect two local Handlers synchronously. 246 * 247 * @param srcContext is the context of the source 248 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED 249 * messages 250 * @param dstHandler is the hander to send messages to. 251 * 252 * @return STATUS_SUCCESSFUL on success any other value is an error. 253 */ connectSync(Context srcContext, Handler srcHandler, Handler dstHandler)254 public int connectSync(Context srcContext, Handler srcHandler, Handler dstHandler) { 255 return connectSync(srcContext, srcHandler, new Messenger(dstHandler)); 256 } 257 258 /** 259 * Fully connect two local Handlers synchronously. 260 * 261 * @param srcContext is the context of the source 262 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED 263 * messages 264 * @param dstHandler is the hander to send messages to. 265 * 266 * @return STATUS_SUCCESSFUL on success any other value is an error. 267 */ fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler)268 public int fullyConnectSync(Context srcContext, Handler srcHandler, Handler dstHandler) { 269 int status = connectSync(srcContext, srcHandler, dstHandler); 270 if (status == STATUS_SUCCESSFUL) { 271 Message response = sendMessageSynchronously(CMD_CHANNEL_FULL_CONNECTION); 272 status = response.arg1; 273 } 274 return status; 275 } 276 277 /** 278 * Connect handler to named package/class. 279 * 280 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. 281 * msg.arg1 = status 282 * msg.obj = the AsyncChannel 283 * 284 * @param srcContext is the context of the source 285 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED 286 * messages 287 * @param dstPackageName is the destination package name 288 * @param dstClassName is the fully qualified class name (i.e. contains 289 * package name) 290 */ connect(Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName)291 public void connect(Context srcContext, Handler srcHandler, String dstPackageName, 292 String dstClassName) { 293 if (DBG) log("connect srcHandler to dst Package & class E"); 294 295 final class ConnectAsync implements Runnable { 296 Context mSrcCtx; 297 Handler mSrcHdlr; 298 String mDstPackageName; 299 String mDstClassName; 300 301 ConnectAsync(Context srcContext, Handler srcHandler, String dstPackageName, 302 String dstClassName) { 303 mSrcCtx = srcContext; 304 mSrcHdlr = srcHandler; 305 mDstPackageName = dstPackageName; 306 mDstClassName = dstClassName; 307 } 308 309 @Override 310 public void run() { 311 int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName, 312 mDstClassName); 313 replyHalfConnected(result); 314 } 315 } 316 317 ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName); 318 new Thread(ca).start(); 319 320 if (DBG) log("connect srcHandler to dst Package & class X"); 321 } 322 323 /** 324 * Connect handler to a class 325 * 326 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. 327 * msg.arg1 = status 328 * msg.obj = the AsyncChannel 329 * 330 * @param srcContext 331 * @param srcHandler 332 * @param klass is the class to send messages to. 333 */ connect(Context srcContext, Handler srcHandler, Class<?> klass)334 public void connect(Context srcContext, Handler srcHandler, Class<?> klass) { 335 connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName()); 336 } 337 338 /** 339 * Connect handler and messenger. 340 * 341 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. 342 * msg.arg1 = status 343 * msg.obj = the AsyncChannel 344 * 345 * @param srcContext 346 * @param srcHandler 347 * @param dstMessenger 348 */ connect(Context srcContext, Handler srcHandler, Messenger dstMessenger)349 public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) { 350 if (DBG) log("connect srcHandler to the dstMessenger E"); 351 352 // We are connected 353 connected(srcContext, srcHandler, dstMessenger); 354 355 // Tell source we are half connected 356 replyHalfConnected(STATUS_SUCCESSFUL); 357 358 if (DBG) log("connect srcHandler to the dstMessenger X"); 359 } 360 361 /** 362 * Connect handler to messenger. This method is typically called 363 * when a server receives a CMD_CHANNEL_FULL_CONNECTION request 364 * and initializes the internal instance variables to allow communication 365 * with the dstMessenger. 366 * 367 * @param srcContext 368 * @param srcHandler 369 * @param dstMessenger 370 */ connected(Context srcContext, Handler srcHandler, Messenger dstMessenger)371 public void connected(Context srcContext, Handler srcHandler, Messenger dstMessenger) { 372 if (DBG) log("connected srcHandler to the dstMessenger E"); 373 374 // Initialize source fields 375 mSrcContext = srcContext; 376 mSrcHandler = srcHandler; 377 mSrcMessenger = new Messenger(mSrcHandler); 378 379 // Initialize destination fields 380 mDstMessenger = dstMessenger; 381 382 if (DBG) log("connected srcHandler to the dstMessenger X"); 383 } 384 385 /** 386 * Connect two local Handlers. 387 * 388 * @param srcContext is the context of the source 389 * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED 390 * messages 391 * @param dstHandler is the hander to send messages to. 392 */ connect(Context srcContext, Handler srcHandler, Handler dstHandler)393 public void connect(Context srcContext, Handler srcHandler, Handler dstHandler) { 394 connect(srcContext, srcHandler, new Messenger(dstHandler)); 395 } 396 397 /** 398 * Connect service and messenger. 399 * 400 * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcAsyncService when complete. 401 * msg.arg1 = status 402 * msg.obj = the AsyncChannel 403 * 404 * @param srcAsyncService 405 * @param dstMessenger 406 */ connect(AsyncService srcAsyncService, Messenger dstMessenger)407 public void connect(AsyncService srcAsyncService, Messenger dstMessenger) { 408 connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger); 409 } 410 411 /** 412 * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED 413 */ disconnected()414 public void disconnected() { 415 mSrcContext = null; 416 mSrcHandler = null; 417 mSrcMessenger = null; 418 mDstMessenger = null; 419 mConnection = null; 420 } 421 422 /** 423 * Disconnect 424 */ disconnect()425 public void disconnect() { 426 if ((mConnection != null) && (mSrcContext != null)) { 427 mSrcContext.unbindService(mConnection); 428 } 429 if (mSrcHandler != null) { 430 replyDisconnected(STATUS_SUCCESSFUL); 431 } 432 } 433 434 /** 435 * Send a message to the destination handler. 436 * 437 * @param msg 438 */ sendMessage(Message msg)439 public void sendMessage(Message msg) { 440 msg.replyTo = mSrcMessenger; 441 try { 442 mDstMessenger.send(msg); 443 } catch (RemoteException e) { 444 replyDisconnected(STATUS_SEND_UNSUCCESSFUL); 445 } 446 } 447 448 /** 449 * Send a message to the destination handler 450 * 451 * @param what 452 */ sendMessage(int what)453 public void sendMessage(int what) { 454 Message msg = Message.obtain(); 455 msg.what = what; 456 sendMessage(msg); 457 } 458 459 /** 460 * Send a message to the destination handler 461 * 462 * @param what 463 * @param arg1 464 */ sendMessage(int what, int arg1)465 public void sendMessage(int what, int arg1) { 466 Message msg = Message.obtain(); 467 msg.what = what; 468 msg.arg1 = arg1; 469 sendMessage(msg); 470 } 471 472 /** 473 * Send a message to the destination handler 474 * 475 * @param what 476 * @param arg1 477 * @param arg2 478 */ sendMessage(int what, int arg1, int arg2)479 public void sendMessage(int what, int arg1, int arg2) { 480 Message msg = Message.obtain(); 481 msg.what = what; 482 msg.arg1 = arg1; 483 msg.arg2 = arg2; 484 sendMessage(msg); 485 } 486 487 /** 488 * Send a message to the destination handler 489 * 490 * @param what 491 * @param arg1 492 * @param arg2 493 * @param obj 494 */ sendMessage(int what, int arg1, int arg2, Object obj)495 public void sendMessage(int what, int arg1, int arg2, Object obj) { 496 Message msg = Message.obtain(); 497 msg.what = what; 498 msg.arg1 = arg1; 499 msg.arg2 = arg2; 500 msg.obj = obj; 501 sendMessage(msg); 502 } 503 504 /** 505 * Send a message to the destination handler 506 * 507 * @param what 508 * @param obj 509 */ sendMessage(int what, Object obj)510 public void sendMessage(int what, Object obj) { 511 Message msg = Message.obtain(); 512 msg.what = what; 513 msg.obj = obj; 514 sendMessage(msg); 515 } 516 517 /** 518 * Reply to srcMsg sending dstMsg 519 * 520 * @param srcMsg 521 * @param dstMsg 522 */ replyToMessage(Message srcMsg, Message dstMsg)523 public void replyToMessage(Message srcMsg, Message dstMsg) { 524 try { 525 dstMsg.replyTo = mSrcMessenger; 526 srcMsg.replyTo.send(dstMsg); 527 } catch (RemoteException e) { 528 log("TODO: handle replyToMessage RemoteException" + e); 529 e.printStackTrace(); 530 } 531 } 532 533 /** 534 * Reply to srcMsg 535 * 536 * @param srcMsg 537 * @param what 538 */ replyToMessage(Message srcMsg, int what)539 public void replyToMessage(Message srcMsg, int what) { 540 Message msg = Message.obtain(); 541 msg.what = what; 542 replyToMessage(srcMsg, msg); 543 } 544 545 /** 546 * Reply to srcMsg 547 * 548 * @param srcMsg 549 * @param what 550 * @param arg1 551 */ replyToMessage(Message srcMsg, int what, int arg1)552 public void replyToMessage(Message srcMsg, int what, int arg1) { 553 Message msg = Message.obtain(); 554 msg.what = what; 555 msg.arg1 = arg1; 556 replyToMessage(srcMsg, msg); 557 } 558 559 /** 560 * Reply to srcMsg 561 * 562 * @param srcMsg 563 * @param what 564 * @param arg1 565 * @param arg2 566 */ replyToMessage(Message srcMsg, int what, int arg1, int arg2)567 public void replyToMessage(Message srcMsg, int what, int arg1, int arg2) { 568 Message msg = Message.obtain(); 569 msg.what = what; 570 msg.arg1 = arg1; 571 msg.arg2 = arg2; 572 replyToMessage(srcMsg, msg); 573 } 574 575 /** 576 * Reply to srcMsg 577 * 578 * @param srcMsg 579 * @param what 580 * @param arg1 581 * @param arg2 582 * @param obj 583 */ replyToMessage(Message srcMsg, int what, int arg1, int arg2, Object obj)584 public void replyToMessage(Message srcMsg, int what, int arg1, int arg2, Object obj) { 585 Message msg = Message.obtain(); 586 msg.what = what; 587 msg.arg1 = arg1; 588 msg.arg2 = arg2; 589 msg.obj = obj; 590 replyToMessage(srcMsg, msg); 591 } 592 593 /** 594 * Reply to srcMsg 595 * 596 * @param srcMsg 597 * @param what 598 * @param obj 599 */ replyToMessage(Message srcMsg, int what, Object obj)600 public void replyToMessage(Message srcMsg, int what, Object obj) { 601 Message msg = Message.obtain(); 602 msg.what = what; 603 msg.obj = obj; 604 replyToMessage(srcMsg, msg); 605 } 606 607 /** 608 * Send the Message synchronously. 609 * 610 * @param msg to send 611 * @return reply message or null if an error. 612 */ sendMessageSynchronously(Message msg)613 public Message sendMessageSynchronously(Message msg) { 614 Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg); 615 return resultMsg; 616 } 617 618 /** 619 * Send the Message synchronously. 620 * 621 * @param what 622 * @return reply message or null if an error. 623 */ sendMessageSynchronously(int what)624 public Message sendMessageSynchronously(int what) { 625 Message msg = Message.obtain(); 626 msg.what = what; 627 Message resultMsg = sendMessageSynchronously(msg); 628 return resultMsg; 629 } 630 631 /** 632 * Send the Message synchronously. 633 * 634 * @param what 635 * @param arg1 636 * @return reply message or null if an error. 637 */ sendMessageSynchronously(int what, int arg1)638 public Message sendMessageSynchronously(int what, int arg1) { 639 Message msg = Message.obtain(); 640 msg.what = what; 641 msg.arg1 = arg1; 642 Message resultMsg = sendMessageSynchronously(msg); 643 return resultMsg; 644 } 645 646 /** 647 * Send the Message synchronously. 648 * 649 * @param what 650 * @param arg1 651 * @param arg2 652 * @return reply message or null if an error. 653 */ sendMessageSynchronously(int what, int arg1, int arg2)654 public Message sendMessageSynchronously(int what, int arg1, int arg2) { 655 Message msg = Message.obtain(); 656 msg.what = what; 657 msg.arg1 = arg1; 658 msg.arg2 = arg2; 659 Message resultMsg = sendMessageSynchronously(msg); 660 return resultMsg; 661 } 662 663 /** 664 * Send the Message synchronously. 665 * 666 * @param what 667 * @param arg1 668 * @param arg2 669 * @param obj 670 * @return reply message or null if an error. 671 */ sendMessageSynchronously(int what, int arg1, int arg2, Object obj)672 public Message sendMessageSynchronously(int what, int arg1, int arg2, Object obj) { 673 Message msg = Message.obtain(); 674 msg.what = what; 675 msg.arg1 = arg1; 676 msg.arg2 = arg2; 677 msg.obj = obj; 678 Message resultMsg = sendMessageSynchronously(msg); 679 return resultMsg; 680 } 681 682 /** 683 * Send the Message synchronously. 684 * 685 * @param what 686 * @param obj 687 * @return reply message or null if an error. 688 */ sendMessageSynchronously(int what, Object obj)689 public Message sendMessageSynchronously(int what, Object obj) { 690 Message msg = Message.obtain(); 691 msg.what = what; 692 msg.obj = obj; 693 Message resultMsg = sendMessageSynchronously(msg); 694 return resultMsg; 695 } 696 697 /** 698 * Helper class to send messages synchronously 699 */ 700 private static class SyncMessenger { 701 /** A stack of SyncMessengers */ 702 private static Stack<SyncMessenger> sStack = new Stack<SyncMessenger>(); 703 /** A number of SyncMessengers created */ 704 private static int sCount = 0; 705 /** The handler thread */ 706 private HandlerThread mHandlerThread; 707 /** The handler that will receive the result */ 708 private SyncHandler mHandler; 709 /** The messenger used to send the message */ 710 private Messenger mMessenger; 711 712 /** private constructor */ SyncMessenger()713 private SyncMessenger() { 714 } 715 716 /** Synchronous Handler class */ 717 private class SyncHandler extends Handler { 718 /** The object used to wait/notify */ 719 private Object mLockObject = new Object(); 720 /** The resulting message */ 721 private Message mResultMsg; 722 723 /** Constructor */ SyncHandler(Looper looper)724 private SyncHandler(Looper looper) { 725 super(looper); 726 } 727 728 /** Handle of the reply message */ 729 @Override handleMessage(Message msg)730 public void handleMessage(Message msg) { 731 mResultMsg = Message.obtain(); 732 mResultMsg.copyFrom(msg); 733 synchronized(mLockObject) { 734 mLockObject.notify(); 735 } 736 } 737 } 738 739 /** 740 * @return the SyncMessenger 741 */ obtain()742 private static SyncMessenger obtain() { 743 SyncMessenger sm; 744 synchronized (sStack) { 745 if (sStack.isEmpty()) { 746 sm = new SyncMessenger(); 747 sm.mHandlerThread = new HandlerThread("SyncHandler-" + sCount++); 748 sm.mHandlerThread.start(); 749 sm.mHandler = sm.new SyncHandler(sm.mHandlerThread.getLooper()); 750 sm.mMessenger = new Messenger(sm.mHandler); 751 } else { 752 sm = sStack.pop(); 753 } 754 } 755 return sm; 756 } 757 758 /** 759 * Recycle this object 760 */ recycle()761 private void recycle() { 762 synchronized (sStack) { 763 sStack.push(this); 764 } 765 } 766 767 /** 768 * Send a message synchronously. 769 * 770 * @param msg to send 771 * @return result message or null if an error occurs 772 */ sendMessageSynchronously(Messenger dstMessenger, Message msg)773 private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) { 774 SyncMessenger sm = SyncMessenger.obtain(); 775 try { 776 if (dstMessenger != null && msg != null) { 777 msg.replyTo = sm.mMessenger; 778 synchronized (sm.mHandler.mLockObject) { 779 dstMessenger.send(msg); 780 sm.mHandler.mLockObject.wait(); 781 } 782 } else { 783 sm.mHandler.mResultMsg = null; 784 } 785 } catch (InterruptedException e) { 786 sm.mHandler.mResultMsg = null; 787 } catch (RemoteException e) { 788 sm.mHandler.mResultMsg = null; 789 } 790 Message resultMsg = sm.mHandler.mResultMsg; 791 sm.recycle(); 792 return resultMsg; 793 } 794 } 795 796 /** 797 * Reply to the src handler that we're half connected. 798 * see: CMD_CHANNEL_HALF_CONNECTED for message contents 799 * 800 * @param status to be stored in msg.arg1 801 */ replyHalfConnected(int status)802 private void replyHalfConnected(int status) { 803 Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED); 804 msg.arg1 = status; 805 msg.obj = this; 806 msg.replyTo = mDstMessenger; 807 mSrcHandler.sendMessage(msg); 808 } 809 810 /** 811 * Reply to the src handler that we are disconnected 812 * see: CMD_CHANNEL_DISCONNECTED for message contents 813 * 814 * @param status to be stored in msg.arg1 815 */ replyDisconnected(int status)816 private void replyDisconnected(int status) { 817 Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED); 818 msg.arg1 = status; 819 msg.obj = this; 820 msg.replyTo = mDstMessenger; 821 mSrcHandler.sendMessage(msg); 822 } 823 824 825 /** 826 * ServiceConnection to receive call backs. 827 */ 828 class AsyncChannelConnection implements ServiceConnection { AsyncChannelConnection()829 AsyncChannelConnection() { 830 } 831 832 @Override onServiceConnected(ComponentName className, IBinder service)833 public void onServiceConnected(ComponentName className, IBinder service) { 834 mDstMessenger = new Messenger(service); 835 replyHalfConnected(STATUS_SUCCESSFUL); 836 } 837 838 @Override onServiceDisconnected(ComponentName className)839 public void onServiceDisconnected(ComponentName className) { 840 replyDisconnected(STATUS_SUCCESSFUL); 841 } 842 } 843 844 /** 845 * Log the string. 846 * 847 * @param s 848 */ log(String s)849 private static void log(String s) { 850 Slog.d(TAG, s); 851 } 852 } 853