Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 | /** |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 35 | * <p>An asynchronous channel between two handlers.</p> |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 36 | * |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 37 | * <p>The handlers maybe in the same process or in another process. There |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 40 | * not need to know which client is issuing the request.</p> |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 41 | * |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 42 | * <p>In a simple request/reply protocol the client/source sends requests to the |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 43 | * server/destination. And the server uses the replyToMessage methods. |
| 44 | * In this usage model there is no need for the destination to |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 45 | * use the connect methods. The typical sequence of operations is:</p> |
| 46 | *<ol> |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 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> |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 51 | * <li><code>comm-loop:</code></li> |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 52 | * <li>Client calls AsyncChannel#sendMessage</li> |
| 53 | * <li>Server processes messages and optionally replies using AsyncChannel#replyToMessage |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 54 | * <li>Loop to <code>comm-loop</code> until done</li> |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 55 | * <li>When done Client calls {@link AsyncChannel#disconnect}</li> |
| 56 | * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li> |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 57 | *</ol> |
| 58 | *<br/> |
| 59 | * <p>A second usage model is where the server/destination needs to know |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 63 | * use the connect methods. The typical sequence of operation is:</p> |
| 64 | *<ol> |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 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> |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 70 | * <li>Server receives CMD_CHANNEL_FULL_CONNECTION</li> |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 71 | * <li>Server calls AsyncChannel#connected</li> |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 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> |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 78 | * <li>When done Client/Server calls {@link AsyncChannel#disconnect}</li> |
Wink Saville | 33c54e3 | 2010-11-15 10:50:34 -0800 | [diff] [blame] | 79 | * <li>Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel</li> |
| 80 | *</ol> |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 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. |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 | |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 93 | private static final int BASE = Protocol.BASE_SYSTEM_ASYNC_CHANNEL; |
| 94 | |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 105 | * msg.obj == the AsyncChannel |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 106 | * msg.replyTo == dstMessenger if successful |
| 107 | */ |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 108 | public static final int CMD_CHANNEL_HALF_CONNECTED = BASE + 0; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 | */ |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 117 | public static final int CMD_CHANNEL_FULL_CONNECTION = BASE + 1; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 125 | * and {@link AsyncChannel#disconnect} would typically be called. |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 126 | */ |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 127 | public static final int CMD_CHANNEL_FULLY_CONNECTED = BASE + 2; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 132 | * the state of the connection. The receiver should call {@link AsyncChannel#disconnect} |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 | */ |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 138 | public static final int CMD_CHANNEL_DISCONNECT = BASE + 3; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 145 | * 1 : STATUS_BINDING_UNSUCCESSFUL |
| 146 | * 2 : STATUS_SEND_UNSUCCESSFUL |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 147 | * : All other values signify failure and the channel state is indeterminate |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 148 | * msg.obj == the AsyncChannel |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 149 | * msg.replyTo = messenger disconnecting or null if it was never connected. |
| 150 | */ |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 151 | public static final int CMD_CHANNEL_DISCONNECTED = BASE + 4; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 152 | |
Wink Saville | 01ce0ce | 2012-04-18 21:42:44 -0700 | [diff] [blame] | 153 | private static final int CMD_TO_STRING_COUNT = CMD_CHANNEL_DISCONNECTED - BASE + 1; |
Wink Saville | 583eaaa | 2012-04-13 16:11:20 -0700 | [diff] [blame] | 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 | } |
| 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 Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 | |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 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 | |
Vairavan Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 183 | /** Error indicating abnormal termination of destination messenger */ |
| 184 | public static final int STATUS_REMOTE_DISCONNECTION = 4; |
| 185 | |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 | |
Vairavan Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 201 | /** Death Monitor for destination messenger */ |
| 202 | private DeathMonitor mDeathMonitor; |
| 203 | |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 204 | /** |
| 205 | * AsyncChannel constructor |
| 206 | */ |
| 207 | public AsyncChannel() { |
| 208 | } |
| 209 | |
| 210 | /** |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 211 | * Connect handler to named package/class synchronously. |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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) |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 219 | * |
| 220 | * @return STATUS_SUCCESSFUL on success any other value is an error. |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 221 | */ |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 222 | public int connectSrcHandlerToPackageSync( |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 223 | Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName) { |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 224 | if (DBG) log("connect srcHandler to dst Package & class E"); |
| 225 | |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 226 | mConnection = new AsyncChannelConnection(); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 244 | if (DBG) log("connect srcHandler to dst Package & class X result=" + result); |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 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 | */ |
| 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 Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 306 | * msg.obj = the AsyncChannel |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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) |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 314 | */ |
| 315 | public void connect(Context srcContext, Handler srcHandler, String dstPackageName, |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 316 | String dstClassName) { |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 324 | |
| 325 | ConnectAsync(Context srcContext, Handler srcHandler, String dstPackageName, |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 326 | String dstClassName) { |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 327 | mSrcCtx = srcContext; |
| 328 | mSrcHdlr = srcHandler; |
| 329 | mDstPackageName = dstPackageName; |
| 330 | mDstClassName = dstClassName; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 331 | } |
| 332 | |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 333 | @Override |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 334 | public void run() { |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 335 | int result = connectSrcHandlerToPackageSync(mSrcCtx, mSrcHdlr, mDstPackageName, |
| 336 | mDstClassName); |
| 337 | replyHalfConnected(result); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 338 | } |
| 339 | } |
| 340 | |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 341 | ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 352 | * msg.obj = the AsyncChannel |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 353 | * |
| 354 | * @param srcContext |
| 355 | * @param srcHandler |
| 356 | * @param klass is the class to send messages to. |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 357 | */ |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 358 | public void connect(Context srcContext, Handler srcHandler, Class<?> klass) { |
| 359 | connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName()); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 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 |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 367 | * msg.obj = the AsyncChannel |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 368 | * |
| 369 | * @param srcContext |
| 370 | * @param srcHandler |
| 371 | * @param dstMessenger |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 372 | */ |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 373 | public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger) { |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 374 | if (DBG) log("connect srcHandler to the dstMessenger E"); |
| 375 | |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 376 | // We are connected |
| 377 | connected(srcContext, srcHandler, dstMessenger); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 378 | |
| 379 | // Tell source we are half connected |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 380 | replyHalfConnected(STATUS_SUCCESSFUL); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 381 | |
| 382 | if (DBG) log("connect srcHandler to the dstMessenger X"); |
| 383 | } |
| 384 | |
| 385 | /** |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 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. |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 390 | * |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 391 | * @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 Wang | 19c4883 | 2016-03-28 12:50:52 -0700 | [diff] [blame] | 405 | linkToDeathMonitor(); |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 406 | if (DBG) log("connected srcHandler to the dstMessenger X"); |
| 407 | } |
| 408 | |
| 409 | /** |
| 410 | * Connect two local Handlers. |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 411 | * |
| 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 Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 416 | */ |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 417 | public void connect(Context srcContext, Handler srcHandler, Handler dstHandler) { |
| 418 | connect(srcContext, srcHandler, new Messenger(dstHandler)); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 419 | } |
| 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 Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 426 | * msg.obj = the AsyncChannel |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 427 | * |
| 428 | * @param srcAsyncService |
| 429 | * @param dstMessenger |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 430 | */ |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 431 | public void connect(AsyncService srcAsyncService, Messenger dstMessenger) { |
| 432 | connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 433 | } |
| 434 | |
| 435 | /** |
| 436 | * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED |
| 437 | */ |
| 438 | public void disconnected() { |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 439 | mSrcContext = null; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 440 | mSrcHandler = null; |
| 441 | mSrcMessenger = null; |
| 442 | mDstMessenger = null; |
Vairavan Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 443 | mDeathMonitor = null; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 444 | mConnection = null; |
| 445 | } |
| 446 | |
| 447 | /** |
| 448 | * Disconnect |
| 449 | */ |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 450 | public void disconnect() { |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 451 | if ((mConnection != null) && (mSrcContext != null)) { |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 452 | mSrcContext.unbindService(mConnection); |
Robert Greenwalt | b7fbb9b | 2014-05-07 23:56:50 -0700 | [diff] [blame] | 453 | mConnection = null; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 454 | } |
Wink Saville | f3110df | 2012-05-27 22:12:07 -0700 | [diff] [blame] | 455 | 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 Jensen | d0d4205 | 2015-05-07 10:44:32 -0400 | [diff] [blame] | 465 | replyDisconnected(STATUS_SUCCESSFUL); |
| 466 | mSrcHandler = null; |
Vairavan Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 467 | // Unlink only when bindService isn't used |
| 468 | if (mConnection == null && mDstMessenger != null && mDeathMonitor!= null) { |
| 469 | mDstMessenger.getBinder().unlinkToDeath(mDeathMonitor, 0); |
Robert Greenwalt | b7fbb9b | 2014-05-07 23:56:50 -0700 | [diff] [blame] | 470 | mDeathMonitor = null; |
Vairavan Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 471 | } |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 472 | } |
| 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 Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 484 | replyDisconnected(STATUS_SEND_UNSUCCESSFUL); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 485 | } |
| 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 Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 565 | dstMsg.replyTo = mSrcMessenger; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 566 | 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 Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 816 | 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 Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 824 | } |
| 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 Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 838 | * see: CMD_CHANNEL_HALF_CONNECTED for message contents |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 839 | * |
| 840 | * @param status to be stored in msg.arg1 |
| 841 | */ |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 842 | private void replyHalfConnected(int status) { |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 843 | Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED); |
| 844 | msg.arg1 = status; |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 845 | msg.obj = this; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 846 | msg.replyTo = mDstMessenger; |
Wei Wang | 19c4883 | 2016-03-28 12:50:52 -0700 | [diff] [blame] | 847 | if (!linkToDeathMonitor()) { |
| 848 | // Override status to indicate failure |
| 849 | msg.arg1 = STATUS_BINDING_UNSUCCESSFUL; |
| 850 | } |
Vairavan Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 851 | |
Wei Wang | 19c4883 | 2016-03-28 12:50:52 -0700 | [diff] [blame] | 852 | 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 Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 862 | mDeathMonitor = new DeathMonitor(); |
| 863 | try { |
| 864 | mDstMessenger.getBinder().linkToDeath(mDeathMonitor, 0); |
| 865 | } catch (RemoteException e) { |
| 866 | mDeathMonitor = null; |
Wei Wang | 19c4883 | 2016-03-28 12:50:52 -0700 | [diff] [blame] | 867 | return false; |
Vairavan Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 868 | } |
| 869 | } |
Wei Wang | 19c4883 | 2016-03-28 12:50:52 -0700 | [diff] [blame] | 870 | return true; |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 871 | } |
| 872 | |
| 873 | /** |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 874 | * 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 Jensen | d0d4205 | 2015-05-07 10:44:32 -0400 | [diff] [blame] | 880 | // Can't reply if already disconnected. Avoid NullPointerException. |
| 881 | if (mSrcHandler == null) return; |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 882 | 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 Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 891 | * ServiceConnection to receive call backs. |
| 892 | */ |
| 893 | class AsyncChannelConnection implements ServiceConnection { |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 894 | AsyncChannelConnection() { |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 895 | } |
| 896 | |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 897 | @Override |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 898 | public void onServiceConnected(ComponentName className, IBinder service) { |
| 899 | mDstMessenger = new Messenger(service); |
Wink Saville | cfce303 | 2010-12-01 23:20:25 -0800 | [diff] [blame] | 900 | replyHalfConnected(STATUS_SUCCESSFUL); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 901 | } |
| 902 | |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 903 | @Override |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 904 | public void onServiceDisconnected(ComponentName className) { |
Wink Saville | 0246bbc | 2011-05-02 10:44:56 -0700 | [diff] [blame] | 905 | replyDisconnected(STATUS_SUCCESSFUL); |
Wink Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 906 | } |
| 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 Srinivasan | ba059bf | 2012-08-01 00:38:08 -0700 | [diff] [blame] | 917 | |
| 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 Saville | d20a5d6 | 2010-10-20 15:17:28 -0700 | [diff] [blame] | 928 | } |