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.IBinder; 25 import android.os.IInterface; 26 import android.os.RemoteCallbackList; 27 import android.os.RemoteException; 28 import android.test.AndroidTestCase; 29 30 public class RemoteCallbackListTest extends AndroidTestCase { 31 private static final String SERVICE_ACTION = "android.app.REMOTESERVICE"; 32 33 private ISecondary mSecondaryService = null; 34 // Lock object 35 private Sync mSync = new Sync(); 36 private Intent mIntent; 37 private Context mContext; 38 private ServiceConnection mSecondaryConnection; 39 40 @Override 41 protected void setUp() throws Exception { 42 super.setUp(); 43 mContext = getContext(); 44 mSecondaryConnection = new ServiceConnection() { 45 public void onServiceConnected(ComponentName className, IBinder service) { 46 mSecondaryService = ISecondary.Stub.asInterface(service); 47 synchronized (mSync) { 48 mSync.mIsConnected = true; 49 mSync.notify(); 50 } 51 } 52 53 public void onServiceDisconnected(ComponentName className) { 54 mSecondaryService = null; 55 synchronized (mSync) { 56 mSync.mIsDisConnected = true; 57 mSync.notify(); 58 } 59 } 60 }; 61 mIntent = new Intent(SERVICE_ACTION); 62 mIntent.setPackage(mContext.getPackageName()); 63 64 Intent secondaryIntent = new Intent(ISecondary.class.getName()); 65 secondaryIntent.setPackage(mContext.getPackageName()); 66 assertTrue(mContext.bindService(secondaryIntent, mSecondaryConnection, 67 Context.BIND_AUTO_CREATE)); 68 69 } 70 71 private static class Sync { 72 public boolean mIsConnected; 73 public boolean mIsDisConnected; 74 } 75 76 @Override 77 public void tearDown() throws Exception { 78 super.tearDown(); 79 if (mSecondaryConnection != null) { 80 mContext.unbindService(mSecondaryConnection); 81 } 82 if (mIntent != null) { 83 mContext.stopService(mIntent); 84 } 85 } 86 87 public void testRemoteCallbackList() throws Exception { 88 // Test constructor(default one). 89 MockRemoteCallbackList<IInterface> rc = new MockRemoteCallbackList<IInterface>(); 90 synchronized (mSync) { 91 if (!mSync.mIsConnected) { 92 mSync.wait(); 93 } 94 } 95 96 try { 97 rc.register(null); 98 fail("Should throw NullPointerException"); 99 } catch (NullPointerException e) { 100 // excepted 101 } 102 103 try { 104 rc.unregister(null); 105 fail("Should throw NullPointerException"); 106 } catch (NullPointerException e) { 107 // expected 108 } 109 110 int servicePid = mSecondaryService.getPid(); 111 // Test beginBroadcast, register, unregister. There is only one service binded. 112 assertTrue(rc.register(mSecondaryService)); 113 int index = rc.beginBroadcast(); 114 assertEquals(1, index); 115 IInterface actual = rc.getBroadcastItem(index - 1); 116 assertNotNull(actual); 117 assertSame(mSecondaryService, actual); 118 // Test finishBroadcast(Is it valid to use rc.getBroadcastItem after finishBroadcast) 119 rc.finishBroadcast(); 120 assertTrue(rc.unregister(mSecondaryService)); 121 122 rc.register(mSecondaryService); 123 rc.beginBroadcast(); 124 // Process killed. No need to call finishBroadcast, unregister 125 android.os.Process.killProcess(servicePid); 126 127 synchronized (mSync) { 128 if (!mSync.mIsDisConnected) { 129 mSync.wait(); 130 } 131 } 132 // sleep some time to wait for onCallbackDied called. 133 Thread.sleep(1000); 134 // Test onCallbackDied 135 assertTrue(rc.isOnCallbackDiedCalled); 136 } 137 138 public void testKill() { 139 MockRemoteCallbackList<IInterface> rc = new MockRemoteCallbackList<IInterface>(); 140 synchronized (mSync) { 141 if (!mSync.mIsConnected) { 142 try { 143 mSync.wait(); 144 } catch (InterruptedException e) { 145 fail("Throw InterruptedException: " + e.getMessage()); 146 } 147 } 148 } 149 150 rc.register(mSecondaryService); 151 rc.beginBroadcast(); 152 rc.finishBroadcast(); 153 rc.kill(); 154 // kill() should unregister the callback (beginBroadcast() 155 // should return 0) and not allow registering the service again. 156 assertEquals(0, rc.beginBroadcast()); 157 assertFalse(rc.register(mSecondaryService)); 158 } 159 160 private class MockRemoteCallbackList<E extends IInterface> extends RemoteCallbackList<E> { 161 public boolean isOnCallbackDiedCalled; 162 163 @Override 164 public void onCallbackDied(E callback) { 165 isOnCallbackDiedCalled = true; 166 super.onCallbackDied(callback); 167 } 168 } 169 } 170