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