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