diff options
3 files changed, 944 insertions, 0 deletions
diff --git a/core/java/com/android/internal/util/AsyncChannel.java b/core/java/com/android/internal/util/AsyncChannel.java new file mode 100644 index 000000000000..15b929054699 --- /dev/null +++ b/core/java/com/android/internal/util/AsyncChannel.java @@ -0,0 +1,778 @@ +/** + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.HandlerThread; +import android.os.IBinder; +import android.os.Looper; +import android.os.Message; +import android.os.Messenger; +import android.os.RemoteException; +import android.util.Slog; + +import java.util.Stack; + +/** + * An asynchronous channel between two handlers. + * + * The handlers maybe in the same process or in another process. There + * are two protocol styles that can be used with an AysncChannel. The + * first is a simple request/reply protocol where the server does + * not need to know which client is issuing the request. + * + * In a simple request/reply protocol the client/source sends requests to the + * server/destination. And the server uses the replyToMessage methods. + * In this usage model there is no need for the destination to + * use the connect methods. The typical sequence of operations is: + * + * 1) Client calls AsyncChannel#connect + * 2) Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel + + * 3) Client calls AsyncChannel#sendMessage(msgX) + * 4) Server receives and processes msgX + * 5) Server optionally calls AsyncChannel#replyToMessage(msgY) + * and if sent Client receives and processes msgY + * 6) Loop to step 3 until done + * + * 7) When done Client calls {@link AsyncChannel#disconnect(int)} + * 8) Client receives CMD_CHANNEL_DISCONNECTED from AsyncChannel + * + * A second usage model is where the server/destination needs to know + * which client it's connected too. For example the server needs to + * send unsolicited messages back to the client. Or the server keeps + * different state for each client. In this model the server will also + * use the connect methods. The typical sequence of operation is: + * + * 1) Client calls AsyncChannel#connect + * 2) Client receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel + * 3) Client calls AsyncChannel#sendMessage(CMD_CHANNEL_FULL_CONNECTION) + * 4) Server receives CMD_CHANNEL_FULL_CONNECTION + * 5) Server calls AsyncChannel#connect + * 6) Server receives CMD_CHANNEL_HALF_CONNECTED from AsyncChannel + * 7) Server sends AsyncChannel#sendMessage(CMD_CHANNEL_FULLY_CONNECTED) + * 8) Client receives CMD_CHANNEL_FULLY_CONNECTED + * + * 9) Client/Server uses AsyncChannel#sendMessage/replyToMessage + * to communicate and perform work + * 10) Loop to step 9 until done + * + * 11) When done Client/Server calls {@link AsyncChannel#disconnect(int)} + * 12) Client/Server receives CMD_CHANNEL_DISCONNECTED from AsyncChannel + */ +public class AsyncChannel { + /** Log tag */ + private static final String TAG = "AsyncChannel"; + + /** Enable to turn on debugging */ + private static final boolean DBG = false; + + /** + * Command sent when the channel is half connected. Half connected + * means that the channel can be used to send commends to the destination + * but the destination is unaware that the channel exists. The first + * command sent to the destination is typically CMD_CHANNEL_FULL_CONNECTION if + * it is desired to establish a long term connection, but any command maybe + * sent. + * + * msg.arg1 == 0 : STATUS_SUCCESSFUL + * 1 : STATUS_BINDING_UNSUCCESSFUL + * msg.arg2 == token parameter + * msg.replyTo == dstMessenger if successful + */ + public static final int CMD_CHANNEL_HALF_CONNECTED = -1; + + /** + * Command typically sent when after receiving the CMD_CHANNEL_HALF_CONNECTED. + * This is used to initiate a long term connection with the destination and + * typically the destination will reply with CMD_CHANNEL_FULLY_CONNECTED. + * + * msg.replyTo = srcMessenger. + */ + public static final int CMD_CHANNEL_FULL_CONNECTION = -2; + + /** + * Command typically sent after the destination receives a CMD_CHANNEL_FULL_CONNECTION. + * This signifies the acceptance or rejection of the channel by the sender. + * + * msg.arg1 == 0 : Accept connection + * : All other values signify the destination rejected the connection + * and {@link AsyncChannel#disconnect(int)} would typically be called. + */ + public static final int CMD_CHANNEL_FULLY_CONNECTED = -3; + + /** + * Command sent when one side or the other wishes to disconnect. The sender + * may or may not be able to receive a reply depending upon the protocol and + * the state of the connection. The receiver should call {@link AsyncChannel#disconnect(int)} + * to close its side of the channel and it will receive a CMD_CHANNEL_DISCONNECTED + * when the channel is closed. + * + * msg.replyTo = messenger that is disconnecting + */ + public static final int CMD_CHANNEL_DISCONNECT = -4; + + /** + * Command sent when the channel becomes disconnected. This is sent when the + * channel is forcibly disconnected by the system or as a reply to CMD_CHANNEL_DISCONNECT. + * + * msg.arg1 == 0 : STATUS_SUCCESSFUL + * : All other values signify failure and the channel state is indeterminate + * msg.arg2 == token parameter + * msg.replyTo = messenger disconnecting or null if it was never connected. + */ + public static final int CMD_CHANNEL_DISCONNECTED = -5; + + /** Successful status always 0, !0 is an unsuccessful status */ + public static final int STATUS_SUCCESSFUL = 0; + + /** Error attempting to bind on a connect */ + public static final int STATUS_BINDING_UNSUCCESSFUL = 1; + + /** Service connection */ + private AsyncChannelConnection mConnection; + + /** Context for source */ + private Context mSrcContext; + + /** Handler for source */ + private Handler mSrcHandler; + + /** Messenger for source */ + private Messenger mSrcMessenger; + + /** Messenger for destination */ + private Messenger mDstMessenger; + + /** + * AsyncChannel constructor + */ + public AsyncChannel() { + } + + /** + * Connect handler to named package/class. + * + * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. + * + * @param srcContext is the context of the source + * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED + * messages + * @param dstPackageName is the destination package name + * @param dstClassName is the fully qualified class name (i.e. contains + * package name) + * @param token unique id for this connection + */ + private void connectSrcHandlerToPackage( + Context srcContext, Handler srcHandler, String dstPackageName, String dstClassName, + int token) { + if (DBG) log("connect srcHandler to dst Package & class E"); + + mConnection = new AsyncChannelConnection(token); + + /* Initialize the source information */ + mSrcContext = srcContext; + mSrcHandler = srcHandler; + mSrcMessenger = new Messenger(srcHandler); + + /* + * Initialize destination information to null they will + * be initialized when the AsyncChannelConnection#onServiceConnected + * is called + */ + mDstMessenger = null; + + /* Send intent to create the connection */ + Intent intent = new Intent(Intent.ACTION_MAIN); + intent.setClassName(dstPackageName, dstClassName); + boolean result = srcContext.bindService(intent, mConnection, Context.BIND_AUTO_CREATE); + if (!result) { + replyHalfConnected(STATUS_BINDING_UNSUCCESSFUL, token); + } + + if (DBG) log("connect srcHandler to dst Package & class X result=" + result); + } + + /** + * Connect handler to named package/class. + * + * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. + * msg.arg1 = status + * msg.arg2 = token + * + * @param srcContext is the context of the source + * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED + * messages + * @param dstPackageName is the destination package name + * @param dstClassName is the fully qualified class name (i.e. contains + * package name) + * @param token returned in msg.arg2 + */ + public void connect(Context srcContext, Handler srcHandler, String dstPackageName, + String dstClassName, int token) { + if (DBG) log("connect srcHandler to dst Package & class E"); + + final class ConnectAsync implements Runnable { + Context mSrcCtx; + Handler mSrcHdlr; + String mDstPackageName; + String mDstClassName; + int mToken; + + ConnectAsync(Context srcContext, Handler srcHandler, String dstPackageName, + String dstClassName, int token) { + mSrcCtx = srcContext; + mSrcHdlr = srcHandler; + mDstPackageName = dstPackageName; + mDstClassName = dstClassName; + mToken = token; + } + + @Override + public void run() { + connectSrcHandlerToPackage(mSrcCtx, mSrcHdlr, mDstPackageName, mDstClassName, + mToken); + } + } + + ConnectAsync ca = new ConnectAsync(srcContext, srcHandler, dstPackageName, dstClassName, + token); + new Thread(ca).start(); + + if (DBG) log("connect srcHandler to dst Package & class X"); + } + + /** + * Connect handler to a class + * + * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. + * msg.arg1 = status + * msg.arg2 = token + * + * @param srcContext + * @param srcHandler + * @param klass is the class to send messages to. + * @param token returned in msg.arg2 + */ + public void connect(Context srcContext, Handler srcHandler, Class<?> klass, int token) { + connect(srcContext, srcHandler, klass.getPackage().getName(), klass.getName(), token); + } + + /** + * Connect handler and messenger. + * + * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. + * msg.arg1 = status + * msg.arg2 = token + * + * @param srcContext + * @param srcHandler + * @param dstMessenger + * @param token returned in msg.arg2 + */ + public void connect(Context srcContext, Handler srcHandler, Messenger dstMessenger, int token) { + if (DBG) log("connect srcHandler to the dstMessenger E"); + + // Initialize source fields + mSrcContext = srcContext; + mSrcHandler = srcHandler; + mSrcMessenger = new Messenger(mSrcHandler); + + // Initialize destination fields + mDstMessenger = dstMessenger; + + if (DBG) log("tell source we are half connected"); + + // Tell source we are half connected + replyHalfConnected(STATUS_SUCCESSFUL, token); + + if (DBG) log("connect srcHandler to the dstMessenger X"); + } + + /** + * Connect two local Handlers. + * + * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcHandler when complete. + * msg.arg1 = status + * msg.arg2 = token + * + * @param srcContext is the context of the source + * @param srcHandler is the hander to receive CONNECTED & DISCONNECTED + * messages + * @param dstHandler is the hander to send messages to. + * @param token returned in msg.arg2 + */ + public void connect(Context srcContext, Handler srcHandler, Handler dstHandler, int token) { + connect(srcContext, srcHandler, new Messenger(dstHandler), token); + } + + /** + * Connect service and messenger. + * + * Sends a CMD_CHANNEL_HALF_CONNECTED message to srcAsyncService when complete. + * msg.arg1 = status + * msg.arg2 = token + * + * @param srcAsyncService + * @param dstMessenger + * @param token returned in msg.arg2 + */ + public void connect(AsyncService srcAsyncService, Messenger dstMessenger, int token) { + connect(srcAsyncService, srcAsyncService.getHandler(), dstMessenger, token); + } + + /** + * To close the connection call when handler receives CMD_CHANNEL_DISCONNECTED + */ + public void disconnected() { + mSrcHandler = null; + mSrcMessenger = null; + mDstMessenger = null; + mConnection = null; + } + + /** + * Disconnect + */ + public void disconnect(int token) { + if (mConnection != null) { + mConnection.setToken(token); + mSrcContext.unbindService(mConnection); + } + if (mSrcHandler != null) { + Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED); + msg.arg1 = STATUS_SUCCESSFUL; + msg.arg2 = token; + msg.replyTo = mDstMessenger; + mSrcHandler.sendMessage(msg); + } + } + + /** + * Send a message to the destination handler. + * + * @param msg + */ + public void sendMessage(Message msg) { + msg.replyTo = mSrcMessenger; + try { + mDstMessenger.send(msg); + } catch (RemoteException e) { + log("TODO: handle sendMessage RemoteException" + e); + } + } + + /** + * Send a message to the destination handler + * + * @param what + */ + public void sendMessage(int what) { + Message msg = Message.obtain(); + msg.what = what; + sendMessage(msg); + } + + /** + * Send a message to the destination handler + * + * @param what + * @param arg1 + */ + public void sendMessage(int what, int arg1) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + sendMessage(msg); + } + + /** + * Send a message to the destination handler + * + * @param what + * @param arg1 + * @param arg2 + */ + public void sendMessage(int what, int arg1, int arg2) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + msg.arg2 = arg2; + sendMessage(msg); + } + + /** + * Send a message to the destination handler + * + * @param what + * @param arg1 + * @param arg2 + * @param obj + */ + public void sendMessage(int what, int arg1, int arg2, Object obj) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + msg.arg2 = arg2; + msg.obj = obj; + sendMessage(msg); + } + + /** + * Send a message to the destination handler + * + * @param what + * @param obj + */ + public void sendMessage(int what, Object obj) { + Message msg = Message.obtain(); + msg.what = what; + msg.obj = obj; + sendMessage(msg); + } + + /** + * Reply to srcMsg sending dstMsg + * + * @param srcMsg + * @param dstMsg + */ + public void replyToMessage(Message srcMsg, Message dstMsg) { + try { + srcMsg.replyTo.send(dstMsg); + } catch (RemoteException e) { + log("TODO: handle replyToMessage RemoteException" + e); + e.printStackTrace(); + } + } + + /** + * Reply to srcMsg + * + * @param srcMsg + * @param what + */ + public void replyToMessage(Message srcMsg, int what) { + Message msg = Message.obtain(); + msg.what = what; + replyToMessage(srcMsg, msg); + } + + /** + * Reply to srcMsg + * + * @param srcMsg + * @param what + * @param arg1 + */ + public void replyToMessage(Message srcMsg, int what, int arg1) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + replyToMessage(srcMsg, msg); + } + + /** + * Reply to srcMsg + * + * @param srcMsg + * @param what + * @param arg1 + * @param arg2 + */ + public void replyToMessage(Message srcMsg, int what, int arg1, int arg2) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + msg.arg2 = arg2; + replyToMessage(srcMsg, msg); + } + + /** + * Reply to srcMsg + * + * @param srcMsg + * @param what + * @param arg1 + * @param arg2 + * @param obj + */ + public void replyToMessage(Message srcMsg, int what, int arg1, int arg2, Object obj) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + msg.arg2 = arg2; + msg.obj = obj; + replyToMessage(srcMsg, msg); + } + + /** + * Reply to srcMsg + * + * @param srcMsg + * @param what + * @param obj + */ + public void replyToMessage(Message srcMsg, int what, Object obj) { + Message msg = Message.obtain(); + msg.what = what; + msg.obj = obj; + replyToMessage(srcMsg, msg); + } + + /** + * Send the Message synchronously. + * + * @param msg to send + * @return reply message or null if an error. + */ + public Message sendMessageSynchronously(Message msg) { + Message resultMsg = SyncMessenger.sendMessageSynchronously(mDstMessenger, msg); + return resultMsg; + } + + /** + * Send the Message synchronously. + * + * @param what + * @return reply message or null if an error. + */ + public Message sendMessageSynchronously(int what) { + Message msg = Message.obtain(); + msg.what = what; + Message resultMsg = sendMessageSynchronously(msg); + return resultMsg; + } + + /** + * Send the Message synchronously. + * + * @param what + * @param arg1 + * @return reply message or null if an error. + */ + public Message sendMessageSynchronously(int what, int arg1) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + Message resultMsg = sendMessageSynchronously(msg); + return resultMsg; + } + + /** + * Send the Message synchronously. + * + * @param what + * @param arg1 + * @param arg2 + * @return reply message or null if an error. + */ + public Message sendMessageSynchronously(int what, int arg1, int arg2) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + msg.arg2 = arg2; + Message resultMsg = sendMessageSynchronously(msg); + return resultMsg; + } + + /** + * Send the Message synchronously. + * + * @param what + * @param arg1 + * @param arg2 + * @param obj + * @return reply message or null if an error. + */ + public Message sendMessageSynchronously(int what, int arg1, int arg2, Object obj) { + Message msg = Message.obtain(); + msg.what = what; + msg.arg1 = arg1; + msg.arg2 = arg2; + msg.obj = obj; + Message resultMsg = sendMessageSynchronously(msg); + return resultMsg; + } + + /** + * Send the Message synchronously. + * + * @param what + * @param obj + * @return reply message or null if an error. + */ + public Message sendMessageSynchronously(int what, Object obj) { + Message msg = Message.obtain(); + msg.what = what; + msg.obj = obj; + Message resultMsg = sendMessageSynchronously(msg); + return resultMsg; + } + + /** + * Helper class to send messages synchronously + */ + private static class SyncMessenger { + /** A stack of SyncMessengers */ + private static Stack<SyncMessenger> sStack = new Stack<SyncMessenger>(); + /** A number of SyncMessengers created */ + private static int sCount = 0; + /** The handler thread */ + private HandlerThread mHandlerThread; + /** The handler that will receive the result */ + private SyncHandler mHandler; + /** The messenger used to send the message */ + private Messenger mMessenger; + + /** private constructor */ + private SyncMessenger() { + } + + /** Synchronous Handler class */ + private class SyncHandler extends Handler { + /** The object used to wait/notify */ + private Object mLockObject = new Object(); + /** The resulting message */ + private Message mResultMsg; + + /** Constructor */ + private SyncHandler(Looper looper) { + super(looper); + } + + /** Handle of the reply message */ + @Override + public void handleMessage(Message msg) { + mResultMsg = Message.obtain(); + mResultMsg.copyFrom(msg); + synchronized(mLockObject) { + mLockObject.notify(); + } + } + } + + /** + * @return the SyncMessenger + */ + private static SyncMessenger obtain() { + SyncMessenger sm; + synchronized (sStack) { + if (sStack.isEmpty()) { + sm = new SyncMessenger(); + sm.mHandlerThread = new HandlerThread("SyncHandler-" + sCount++); + sm.mHandlerThread.start(); + sm.mHandler = sm.new SyncHandler(sm.mHandlerThread.getLooper()); + sm.mMessenger = new Messenger(sm.mHandler); + } else { + sm = sStack.pop(); + } + } + return sm; + } + + /** + * Recycle this object + */ + private void recycle() { + synchronized (sStack) { + sStack.push(this); + } + } + + /** + * Send a message synchronously. + * + * @param msg to send + * @return result message or null if an error occurs + */ + private static Message sendMessageSynchronously(Messenger dstMessenger, Message msg) { + SyncMessenger sm = SyncMessenger.obtain(); + try { + msg.replyTo = sm.mMessenger; + dstMessenger.send(msg); + synchronized (sm.mHandler.mLockObject) { + sm.mHandler.mLockObject.wait(); + } + } catch (InterruptedException e) { + sm.mHandler.mResultMsg = null; + } catch (RemoteException e) { + sm.mHandler.mResultMsg = null; + } + Message resultMsg = sm.mHandler.mResultMsg; + sm.recycle(); + return resultMsg; + } + } + + /** + * Reply to the src handler that we're half connected. + * + * @param status to be stored in msg.arg1 + */ + private void replyHalfConnected(int status, int token) { + Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_HALF_CONNECTED); + msg.arg1 = status; + msg.arg2 = token; + msg.replyTo = mDstMessenger; + mSrcHandler.sendMessage(msg); + } + + /** + * ServiceConnection to receive call backs. + */ + class AsyncChannelConnection implements ServiceConnection { + private int mToken; + + AsyncChannelConnection(int token) { + mToken = token; + } + + /** + * @param token + */ + public void setToken(int token) { + mToken = token; + } + + public void onServiceConnected(ComponentName className, IBinder service) { + mDstMessenger = new Messenger(service); + replyHalfConnected(STATUS_SUCCESSFUL, mToken); + } + + public void onServiceDisconnected(ComponentName className) { + Message msg = mSrcHandler.obtainMessage(CMD_CHANNEL_DISCONNECTED); + msg.arg1 = STATUS_SUCCESSFUL; + msg.arg2 = mToken; + msg.replyTo = mDstMessenger; + mSrcHandler.sendMessage(msg); + } + } + + /** + * Log the string. + * + * @param s + */ + private static void log(String s) { + Slog.d(TAG, s); + } +} diff --git a/core/java/com/android/internal/util/AsyncService.java b/core/java/com/android/internal/util/AsyncService.java new file mode 100644 index 000000000000..54d3c4260bc6 --- /dev/null +++ b/core/java/com/android/internal/util/AsyncService.java @@ -0,0 +1,128 @@ +/** + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.internal.util; + +import android.app.Service; +import android.content.Intent; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.os.Messenger; +import android.util.Slog; + +/** + * A service that receives Intents and IBinder transactions + * as messages via an AsyncChannel. + * <p> + * The Start Intent arrives as CMD_ASYNC_SERVICE_ON_START_INTENT with msg.arg1 = flags, + * msg.arg2 = startId, and msg.obj = intent. + * <p> + */ +abstract public class AsyncService extends Service { + private static final String TAG = "AsyncService"; + + protected static final boolean DBG = true; + + /** The command sent when a onStartCommand is invoked */ + public static final int CMD_ASYNC_SERVICE_ON_START_INTENT = IBinder.LAST_CALL_TRANSACTION; + + /** The command sent when a onDestroy is invoked */ + public static final int CMD_ASYNC_SERVICE_DESTROY = IBinder.LAST_CALL_TRANSACTION + 1; + + /** Messenger transport */ + protected Messenger mMessenger; + + /** Message Handler that will receive messages */ + Handler mHandler; + + public static final class AsyncServiceInfo { + /** Message Handler that will receive messages */ + public Handler mHandler; + + /** + * The flags returned by onStartCommand on how to restart. + * For instance @see android.app.Service#START_STICKY + */ + public int mRestartFlags; + } + + AsyncServiceInfo mAsyncServiceInfo; + + /** + * Create the service's handler returning AsyncServiceInfo. + * + * @return AsyncServiceInfo + */ + abstract public AsyncServiceInfo createHandler(); + + /** + * Get the handler + */ + public Handler getHandler() { + return mHandler; + } + + /** + * onCreate + */ + @Override + public void onCreate() { + super.onCreate(); + mAsyncServiceInfo = createHandler(); + mHandler = mAsyncServiceInfo.mHandler; + mMessenger = new Messenger(mHandler); + } + + /** + * Sends the CMD_ASYNC_SERVICE_ON_START_INTENT message. + */ + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if (DBG) Slog.d(TAG, "onStartCommand"); + + Message msg = mHandler.obtainMessage(); + msg.what = CMD_ASYNC_SERVICE_ON_START_INTENT; + msg.arg1 = flags; + msg.arg2 = startId; + msg.obj = intent; + mHandler.sendMessage(msg); + + return mAsyncServiceInfo.mRestartFlags; + } + + /** + * Called when service is destroyed. After returning the + * service is dead an no more processing should be expected + * to occur. + */ + @Override + public void onDestroy() { + if (DBG) Slog.d(TAG, "onDestroy"); + + Message msg = mHandler.obtainMessage(); + msg.what = CMD_ASYNC_SERVICE_DESTROY; + mHandler.sendMessage(msg); + } + + /** + * Returns the Messenger's binder. + */ + @Override + public IBinder onBind(Intent intent) { + return mMessenger.getBinder(); + } +} diff --git a/core/tests/coretests/src/android/os/AsyncChannelTest.java b/core/tests/coretests/src/android/os/AsyncChannelTest.java new file mode 100644 index 000000000000..43c8290810c2 --- /dev/null +++ b/core/tests/coretests/src/android/os/AsyncChannelTest.java @@ -0,0 +1,38 @@ +/** + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.os; + +import android.test.suitebuilder.annotation.SmallTest; +import android.util.Log; + +import junit.framework.TestCase; + +/** + * Test for AsyncChannel. + */ +public class AsyncChannelTest extends TestCase { + private static final boolean DBG = true; + private static final boolean WAIT_FOR_DEBUGGER = true; + private static final String TAG = "AsyncChannelTest"; + + @SmallTest + public void test1() throws Exception { + if (WAIT_FOR_DEBUGGER) Debug.waitForDebugger(); + Log.d(TAG, "test1"); + assertTrue(1 == 1); + } +} |