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