Home | History | Annotate | Download | only in cts
      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
     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
    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 
    142         public MockServiceConnection(final boolean isDisconnect, final boolean setReporter) {
    143             mIsDisconnect = isDisconnect;
    144             mSetReporter = setReporter;
    145             mIsMonitorEnable = !setReporter;
    146         }
    147 
    148         void setMonitor(boolean v) {
    149             mIsMonitorEnable = v;
    150         }
    151 
    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 
    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 
    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 
    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 
    336     public void testFlushPendingCommands() {
    337         Binder.flushPendingCommands();
    338     }
    339 
    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 
    378     public void testClearCallingIdentity() {
    379         long token = Binder.clearCallingIdentity();
    380         assertTrue(token > 0);
    381         Binder.restoreCallingIdentity(token);
    382     }
    383 
    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 {
    396          public void binderDied() {
    397 
    398          }
    399     }
    400 
    401     private static class MockIInterface implements IInterface {
    402         public IBinder asBinder() {
    403             return new Binder();
    404         }
    405     }
    406 
    407     private static class MockBinder extends Binder {
    408         @Override
    409         public void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
    410             super.dump(fd, fout, args);
    411         }
    412     }
    413 
    414 }
    415