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