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