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 import java.io.ByteArrayOutputStream;
20 import java.io.FileDescriptor;
21 import java.io.PrintWriter;
22 
23 import android.content.ComponentName;
24 import android.content.Intent;
25 import android.content.ServiceConnection;
26 import android.os.Binder;
27 import android.os.IBinder;
28 import android.os.IInterface;
29 import android.os.Parcel;
30 import android.os.Process;
31 import android.os.RemoteException;
32 
33 public class BinderTest extends ActivityTestsBase {
34     private static final String DESCRIPTOR_GOOGLE = "google";
35     private static final String DESCRIPTOR_ANDROID = "android";
36     // states of mStartState
37     private static final int STATE_START_1 = 0;
38     private static final int STATE_START_2 = 1;
39     private static final int STATE_UNBIND = 2;
40     private static final int STATE_DESTROY = 3;
41     private static final int STATE_REBIND = 4;
42     private static final int STATE_UNBIND_ONLY = 5;
43     private static final int DELAY_MSEC = 5000;
44     private MockBinder mBinder;
45     private Binder mStartReceiver;
46     private int mStartState;
47     private Intent mService;
48 
49     @Override
setUp()50     protected void setUp() throws Exception {
51         super.setUp();
52         mService = new Intent(
53                 LocalService.SERVICE_LOCAL, null /*uri*/, mContext, LocalService.class);
54         mBinder = new MockBinder();
55         mStartReceiver = new Binder() {
56             @Override
57             protected boolean onTransact(int code, Parcel data, Parcel reply, int flags)
58                              throws RemoteException {
59                 switch (code) {
60                     case LocalService.STARTED_CODE:
61                         data.enforceInterface(LocalService.SERVICE_LOCAL);
62                         int count = data.readInt();
63 
64                         switch (mStartState) {
65                             case STATE_START_1:
66                                 if (count == 1) {
67                                     finishGood();
68                                 } else {
69                                     finishBad("onStart() again on an object when it "
70                                             + "should have been the first time");
71                                 }
72                                 break;
73                             case STATE_START_2:
74                                 if (count == 2) {
75                                     finishGood();
76                                 } else {
77                                     finishBad("onStart() the first time on an object when it "
78                                             + "should have been the second time");
79                                 }
80                                 break;
81                             default:
82                                 finishBad("onStart() was called when not expected (state="
83                                         + mStartState + ")");
84                         }
85                         return true;
86                     case LocalService.DESTROYED_CODE:
87                         data.enforceInterface(LocalService.SERVICE_LOCAL);
88                         if (mStartState == STATE_DESTROY) {
89                             finishGood();
90                         } else {
91                             finishBad("onDestroy() was called when not expected (state="
92                                     + mStartState + ")");
93                         }
94                         return true;
95                     case LocalService.UNBIND_CODE:
96                         data.enforceInterface(LocalService.SERVICE_LOCAL);
97                         switch (mStartState) {
98                             case STATE_UNBIND:
99                                 mStartState = STATE_DESTROY;
100                                 break;
101                             case STATE_UNBIND_ONLY:
102                                 finishGood();
103                                 break;
104                             default:
105                                 finishBad("onUnbind() was called when not expected (state="
106                                         + mStartState + ")");
107                         }
108                         return true;
109                     case LocalService.REBIND_CODE:
110                         data.enforceInterface(LocalService.SERVICE_LOCAL);
111                         if (mStartState == STATE_REBIND) {
112                             finishGood();
113                         } else {
114                             finishBad("onRebind() was called when not expected (state="
115                                     + mStartState + ")");
116                         }
117                         return true;
118                     default:
119                         return super.onTransact(code, data, reply, flags);
120                 }
121             }
122         };
123 
124     }
125 
126     @Override
tearDown()127     protected void tearDown() throws Exception {
128         super.tearDown();
129         mContext.stopService(mService);
130     }
131 
132     // Mock ServiceConnection
133     public class MockServiceConnection implements ServiceConnection {
134         private final boolean mIsDisconnect;
135         private final boolean mSetReporter;
136         private boolean mIsMonitorEnable;
137         private int mCount;
138 
MockServiceConnection(final boolean isDisconnect, final boolean setReporter)139         public MockServiceConnection(final boolean isDisconnect, final boolean setReporter) {
140             mIsDisconnect = isDisconnect;
141             mSetReporter = setReporter;
142             mIsMonitorEnable = !setReporter;
143         }
144 
setMonitor(boolean v)145         void setMonitor(boolean v) {
146             mIsMonitorEnable = v;
147         }
148 
onServiceConnected(ComponentName name, IBinder service)149         public void onServiceConnected(ComponentName name, IBinder service) {
150             if (mSetReporter) {
151                 Parcel data = Parcel.obtain();
152                 data.writeInterfaceToken(LocalService.SERVICE_LOCAL);
153                 data.writeStrongBinder(mStartReceiver);
154 
155                 try {
156                     service.transact(LocalService.SET_REPORTER_CODE, data, null, 0);
157                 } catch (RemoteException e) {
158                     finishBad("DeadObjectException when sending reporting object");
159                 }
160 
161                 data.recycle();
162             }
163 
164             if (mIsMonitorEnable) {
165                 mCount++;
166 
167                 if (mStartState == STATE_START_1) {
168                     if (mCount == 1) {
169                         finishGood();
170                     } else {
171                         finishBad("onServiceConnected() again on an object when it "
172                                 + "should have been the first time");
173                     }
174                 } else if (mStartState == STATE_START_2) {
175                     if (mCount == 2) {
176                         finishGood();
177                     } else {
178                         finishBad("onServiceConnected() the first time on an object "
179                                 + "when it should have been the second time");
180                     }
181                 } else {
182                     finishBad("onServiceConnected() called unexpectedly");
183                 }
184             }
185         }
186 
onServiceDisconnected(ComponentName name)187         public void onServiceDisconnected(ComponentName name) {
188             if (mIsMonitorEnable) {
189                 if (mStartState == STATE_DESTROY) {
190                     if (mIsDisconnect) {
191                         finishGood();
192                     } else {
193                         finishBad("onServiceDisconnected() when it shouldn't have been");
194                     }
195                 } else {
196                     finishBad("onServiceDisconnected() called unexpectedly");
197                 }
198             }
199         }
200     }
201 
testTransact()202     public void testTransact() {
203         MockServiceConnection conn1 = new MockServiceConnection(true, false);
204         MockServiceConnection conn2 = new MockServiceConnection(false, false);
205         boolean success = false;
206 
207         try {
208             // Expect to see the TestConnection connected.
209             mStartState = STATE_START_1;
210             getContext().bindService(mService, conn1, 0);
211             getContext().startService(mService);
212             waitForResultOrThrow(DELAY_MSEC, "existing connection to receive service");
213 
214             // Expect to see the second TestConnection connected.
215             getContext().bindService(mService, conn2, 0);
216             waitForResultOrThrow(DELAY_MSEC, "new connection to receive service");
217 
218             getContext().unbindService(conn2);
219             success = true;
220         } finally {
221             if (!success) {
222                 try {
223                 getContext().stopService(mService);
224                 getContext().unbindService(conn1);
225                 getContext().unbindService(conn2);
226                 } catch (SecurityException e) {
227                     fail(e.getMessage());
228                 }
229             }
230         }
231 
232         // Expect to see the TestConnection disconnected.
233         mStartState = STATE_DESTROY;
234         getContext().stopService(mService);
235         waitForResultOrThrow(DELAY_MSEC, "the existing connection to lose service");
236 
237         getContext().unbindService(conn1);
238 
239         conn1 = new MockServiceConnection(true, true);
240         success = false;
241 
242         try {
243             // Expect to see the TestConnection connected.
244             conn1.setMonitor(true);
245             mStartState = STATE_START_1;
246             getContext().bindService(mService, conn1, 0);
247             getContext().startService(mService);
248             waitForResultOrThrow(DELAY_MSEC, "the existing connection to receive service");
249 
250             success = true;
251         } finally {
252             if (!success) {
253                 try {
254                     getContext().stopService(mService);
255                     getContext().unbindService(conn1);
256                 } catch (Exception e) {
257                     fail(e.getMessage());
258                 }
259             }
260         }
261 
262         // Expect to see the service unbind and then destroyed.
263         conn1.setMonitor(false);
264         mStartState = STATE_UNBIND;
265         getContext().stopService(mService);
266         waitForResultOrThrow(DELAY_MSEC, "the existing connection to lose service");
267 
268         getContext().unbindService(conn1);
269 
270         conn1 = new MockServiceConnection(true, true);
271         success = false;
272 
273         try {
274             // Expect to see the TestConnection connected.
275             conn1.setMonitor(true);
276             mStartState = STATE_START_1;
277             getContext().bindService(mService, conn1, 0);
278             getContext().startService(mService);
279             waitForResultOrThrow(DELAY_MSEC, "existing connection to receive service");
280 
281             success = true;
282         } finally {
283             if (!success) {
284                 try {
285                     getContext().stopService(mService);
286                     getContext().unbindService(conn1);
287                 } catch (Exception e) {
288                     fail(e.getMessage());
289                 }
290             }
291         }
292 
293         // Expect to see the service unbind but not destroyed.
294         conn1.setMonitor(false);
295         mStartState = STATE_UNBIND_ONLY;
296         getContext().unbindService(conn1);
297         waitForResultOrThrow(DELAY_MSEC, "existing connection to unbind service");
298 
299         // Expect to see the service rebound.
300         mStartState = STATE_REBIND;
301         getContext().bindService(mService, conn1, 0);
302         waitForResultOrThrow(DELAY_MSEC, "existing connection to rebind service");
303 
304         // Expect to see the service unbind and then destroyed.
305         mStartState = STATE_UNBIND;
306         getContext().stopService(mService);
307         waitForResultOrThrow(DELAY_MSEC, "existing connection to lose service");
308 
309         getContext().unbindService(conn1);
310     }
311 
testSimpleMethods()312     public void testSimpleMethods() {
313         new Binder();
314 
315         assertEquals(Process.myPid(), Binder.getCallingPid());
316         assertEquals(Process.myUid(), Binder.getCallingUid());
317 
318         final String[] dumpArgs = new String[]{"one", "two", "three"};
319         mBinder.dump(new FileDescriptor(),
320                 new PrintWriter(new ByteArrayOutputStream()),
321                 dumpArgs);
322 
323         mBinder.dump(new FileDescriptor(), dumpArgs);
324         assertTrue(mBinder.isBinderAlive());
325 
326         mBinder.linkToDeath(new MockDeathRecipient(), 0);
327 
328         assertTrue(mBinder.unlinkToDeath(new MockDeathRecipient(), 0));
329 
330         assertTrue(mBinder.pingBinder());
331     }
332 
testFlushPendingCommands()333     public void testFlushPendingCommands() {
334         Binder.flushPendingCommands();
335     }
336 
testJoinThreadPool()337     public void testJoinThreadPool() {
338         //from java doc this function won't be return until the current process is exiting.
339         //so not suitable to test it in unit test
340     }
341 
testClearCallingIdentity()342     public void testClearCallingIdentity() {
343         long token = Binder.clearCallingIdentity();
344         assertTrue(token > 0);
345         Binder.restoreCallingIdentity(token);
346     }
347 
testInterfaceRelatedMethods()348     public void testInterfaceRelatedMethods() {
349         assertNull(mBinder.getInterfaceDescriptor());
350         mBinder.attachInterface(new MockIInterface(), DESCRIPTOR_GOOGLE);
351         assertEquals(DESCRIPTOR_GOOGLE, mBinder.getInterfaceDescriptor());
352 
353         mBinder.attachInterface(new MockIInterface(), DESCRIPTOR_ANDROID);
354         assertNull(mBinder.queryLocalInterface(DESCRIPTOR_GOOGLE));
355         mBinder.attachInterface(new MockIInterface(), DESCRIPTOR_GOOGLE);
356         assertNotNull(mBinder.queryLocalInterface(DESCRIPTOR_GOOGLE));
357     }
358 
359     private static class MockDeathRecipient implements IBinder.DeathRecipient {
binderDied()360          public void binderDied() {
361 
362          }
363     }
364 
365     private static class MockIInterface implements IInterface {
asBinder()366         public IBinder asBinder() {
367             return new Binder();
368         }
369     }
370 
371     private static class MockBinder extends Binder {
372         @Override
dump(FileDescriptor fd, PrintWriter fout, String[] args)373         public void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
374             super.dump(fd, fout, args);
375         }
376     }
377 
378 }
379