1 /* 2 * Copyright (C) 2008 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 android.os.cts; 18 19 20 import android.content.ComponentName; 21 import android.content.Context; 22 import android.content.Intent; 23 import android.content.ServiceConnection; 24 import android.os.Handler; 25 import android.os.HandlerThread; 26 import android.os.IBinder; 27 import android.os.IInterface; 28 import android.os.Looper; 29 import android.os.Message; 30 import android.os.Messenger; 31 import android.os.Parcel; 32 import android.os.RemoteException; 33 import android.os.ResultReceiver; 34 import android.test.AndroidTestCase; 35 36 import java.io.FileDescriptor; 37 38 public class MessengerTest extends AndroidTestCase { 39 40 private Messenger mMessenger; 41 private Message mMessage; 42 private boolean mResult; 43 private Messenger mServiceMessenger; 44 private static final int MSG_ARG1 = 100; 45 private static final int MSG_ARG2 = 1000; 46 private static final int WHAT = 2008; 47 private Handler mHandler = new Handler(Looper.getMainLooper()) { 48 @Override 49 public boolean sendMessageAtTime(Message msg, long uptimeMillis) { 50 mResult = true; 51 mMessage = msg; 52 return super.sendMessageAtTime(msg, uptimeMillis); 53 } 54 }; 55 56 private final IBinder mIBinder = new IBinder() { 57 58 public String getInterfaceDescriptor() throws RemoteException { 59 return null; 60 } 61 62 public boolean isBinderAlive() { 63 return false; 64 } 65 66 public void linkToDeath(DeathRecipient recipient, int flags) throws RemoteException { 67 } 68 69 public boolean pingBinder() { 70 return false; 71 } 72 73 public IInterface queryLocalInterface(String descriptor) { 74 return null; 75 } 76 77 public boolean transact(int code, Parcel data, Parcel reply, int flags) 78 throws RemoteException { 79 return false; 80 } 81 82 public boolean unlinkToDeath(DeathRecipient recipient, int flags) { 83 return false; 84 } 85 86 public void dump(FileDescriptor fd, String[] args) throws RemoteException { 87 } 88 89 public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException { 90 } 91 92 @Override 93 public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 94 String[] args, ResultReceiver resultReceiver) { 95 } 96 97 }; 98 99 // Create another messenger to send msg. 100 private ServiceConnection mConnection = new ServiceConnection() { 101 public void onServiceConnected(ComponentName name, IBinder service) { 102 synchronized (MessengerTest.this) { 103 mServiceMessenger = new Messenger(service); 104 MessengerTest.this.notifyAll(); 105 } 106 } 107 108 public void onServiceDisconnected(ComponentName name) { 109 mServiceMessenger = null; 110 } 111 }; 112 113 @Override setUp()114 protected void setUp() throws Exception { 115 116 super.setUp(); 117 mMessenger = new Messenger(mHandler); 118 getContext().bindService(new Intent(mContext, MessengerService.class), mConnection, 119 Context.BIND_AUTO_CREATE); 120 synchronized (this) { 121 while (mServiceMessenger == null) { 122 wait(); 123 } 124 } 125 } 126 127 @Override tearDown()128 protected void tearDown() throws Exception { 129 super.tearDown(); 130 getContext().unbindService(mConnection); 131 } 132 testConstructorAndEquals()133 public void testConstructorAndEquals() { 134 Messenger messenger = new Messenger(mHandler); 135 Messenger objMessenger = new Messenger(mHandler); 136 assertTrue(messenger.equals(objMessenger)); 137 messenger = new Messenger(mIBinder); 138 assertFalse(messenger.equals(objMessenger)); 139 } 140 testSend()141 public void testSend() throws RemoteException, InterruptedException { 142 // messenger used by its own thread. 143 Message message = Message.obtain(mHandler, WHAT, MSG_ARG1, MSG_ARG2); 144 mMessenger.send(message); 145 assertTrue(mResult); 146 assertNotNull(mMessage); 147 assertEquals(mMessage.what, message.what); 148 assertEquals(mMessage.arg1, message.arg1); 149 assertEquals(mMessage.arg2, message.arg2); 150 151 // Used in other process. If the sent msg does not equal to expected, it will throw failure 152 // and the test will fail 153 (new MessengerTestHelper()).doTest(1000, 50); 154 } 155 testHashCode()156 public void testHashCode() { 157 assertEquals(mMessenger.getBinder().hashCode(), mMessenger.hashCode()); 158 } 159 testGetBinder()160 public void testGetBinder() { 161 Messenger messenger = new Messenger(mIBinder); 162 assertSame(mIBinder, messenger.getBinder()); 163 assertNotNull(mMessenger.getBinder()); 164 } 165 testWriteToParcel()166 public void testWriteToParcel() { 167 Parcel parcel = Parcel.obtain(); 168 mMessenger.writeToParcel(parcel, 0); 169 parcel.setDataPosition(0); 170 Messenger messenger = Messenger.CREATOR.createFromParcel(parcel); 171 assertTrue(messenger.equals(mMessenger)); 172 parcel.recycle(); 173 } 174 testDescribeContents()175 public void testDescribeContents() { 176 assertEquals(0, mMessenger.describeContents()); 177 } 178 testWriteMessengerOrNullToParcel()179 public void testWriteMessengerOrNullToParcel() { 180 Parcel parcelWithMessenger = Parcel.obtain(); 181 Messenger.writeMessengerOrNullToParcel(mMessenger, parcelWithMessenger); 182 parcelWithMessenger.setDataPosition(0); 183 Messenger messenger = Messenger.readMessengerOrNullFromParcel(parcelWithMessenger); 184 assertNotNull(messenger); 185 assertTrue(messenger.equals(mMessenger)); 186 parcelWithMessenger.recycle(); 187 188 Parcel parcelWithNull = Parcel.obtain(); 189 Messenger.writeMessengerOrNullToParcel(null, parcelWithNull); 190 parcelWithNull.setDataPosition(0); 191 messenger = Messenger.readMessengerOrNullFromParcel(parcelWithNull); 192 assertNull(messenger); 193 parcelWithNull.recycle(); 194 } 195 196 /** 197 * This helper class is used for test of MessengerTest. Mainly on control of the message looper. 198 */ 199 private class MessengerTestHelper { 200 private boolean mDone = false; 201 private boolean mSuccess = false; 202 private RuntimeException mFailure = null; 203 private Looper mLooper; 204 205 private Handler mTestHandler; 206 private Messenger mTestMessenger; 207 init()208 public void init() { 209 synchronized (MessengerTest.this) { 210 mTestHandler = new Handler() { 211 public void handleMessage(Message msg) { 212 MessengerTestHelper.this.handleMessage(msg); 213 } 214 }; 215 mTestMessenger = new Messenger(mTestHandler); 216 try { 217 MessengerTestHelper.this.executeTest(); 218 } catch (RemoteException e) { 219 fail(e.getMessage()); 220 } 221 } 222 } 223 MessengerTestHelper()224 public MessengerTestHelper() { 225 } 226 executeTest()227 public void executeTest() throws RemoteException { 228 Message msg = Message.obtain(); 229 msg.arg1 = MSG_ARG1; 230 msg.arg2 = MSG_ARG2; 231 msg.replyTo = mTestMessenger; 232 // Use another messenger to send msg. 233 mServiceMessenger.send(msg); 234 } 235 236 /** 237 * This method is used to check if the message sent by another messenger is correctly 238 * handled by this thread. If not equals to expected, there will be a failure thrown. 239 */ handleMessage(Message msg)240 public void handleMessage(Message msg) { 241 if (msg.arg1 != MSG_ARG1) { 242 failure(new RuntimeException("Message.arg1 is not " + MSG_ARG1 + ", it's " 243 + msg.arg1)); 244 return; 245 } 246 if (msg.arg2 != MSG_ARG2) { 247 failure(new RuntimeException("Message.arg2 is not " + MSG_ARG2 + ", it's " 248 + msg.arg2)); 249 return; 250 } 251 if (!mTestMessenger.equals(msg.replyTo)) { 252 failure(new RuntimeException("Message.replyTo is not me, it's " + msg.replyTo)); 253 return; 254 } 255 success(); 256 } 257 doTest(long timeout, long interval)258 public void doTest(long timeout, long interval) throws InterruptedException { 259 (new LooperThread()).start(); 260 261 synchronized (this) { 262 long now = System.currentTimeMillis(); 263 long endTime = now + timeout; 264 // wait and frequently check if mDone is set. 265 while (!mDone && now < endTime) { 266 wait(interval); 267 now = System.currentTimeMillis(); 268 } 269 } 270 271 mLooper.quit(); 272 273 if (!mDone) { 274 throw new RuntimeException("test timed out"); 275 } 276 if (!mSuccess) { 277 throw mFailure; 278 } 279 } 280 getLooper()281 public Looper getLooper() { 282 return mLooper; 283 } 284 success()285 public void success() { 286 synchronized (this) { 287 mSuccess = true; 288 quit(); 289 } 290 } 291 failure(RuntimeException failure)292 public void failure(RuntimeException failure) { 293 synchronized (this) { 294 mSuccess = false; 295 mFailure = failure; 296 quit(); 297 } 298 } 299 300 class LooperThread extends HandlerThread { 301 LooperThread()302 public LooperThread() { 303 super("MessengerLooperThread"); 304 } 305 onLooperPrepared()306 public void onLooperPrepared() { 307 init(); 308 mLooper = getLooper(); 309 } 310 311 @Override run()312 public void run() { 313 super.run(); 314 synchronized (MessengerTestHelper.this) { 315 mDone = true; 316 if (!mSuccess && mFailure == null) { 317 mFailure = new RuntimeException("no failure exception set"); 318 } 319 MessengerTestHelper.this.notifyAll(); 320 } 321 } 322 } 323 quit()324 private void quit() { 325 synchronized (this) { 326 mDone = true; 327 notifyAll(); 328 } 329 } 330 } 331 } 332