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 static org.junit.Assert.assertEquals; 20 import static org.junit.Assert.assertFalse; 21 import static org.junit.Assert.assertNotNull; 22 import static org.junit.Assert.assertNull; 23 import static org.junit.Assert.assertThrows; 24 import static org.junit.Assert.assertTrue; 25 import static org.junit.Assert.fail; 26 27 import android.os.Binder; 28 import android.os.IBinder; 29 import android.os.IInterface; 30 import android.os.ParcelFileDescriptor; 31 import android.os.Process; 32 import android.os.WorkSource; 33 import android.platform.test.annotations.AppModeSdkSandbox; 34 import android.platform.test.annotations.IgnoreUnderRavenwood; 35 import android.platform.test.ravenwood.RavenwoodRule; 36 37 import org.junit.Before; 38 import org.junit.Rule; 39 import org.junit.Test; 40 41 import java.io.ByteArrayOutputStream; 42 import java.io.FileDescriptor; 43 import java.io.PrintWriter; 44 import java.util.Arrays; 45 import java.util.concurrent.CountDownLatch; 46 import java.util.concurrent.TimeUnit; 47 48 @AppModeSdkSandbox(reason = "Allow test in the SDK sandbox (does not prevent other modes).") 49 public class BinderTest { 50 @Rule public RavenwoodRule mRavenwood = new RavenwoodRule.Builder().setProcessApp().build(); 51 52 private static final String DESCRIPTOR_GOOGLE = "google"; 53 private static final String DESCRIPTOR_ANDROID = "android"; 54 private MockBinder mBinder; 55 56 @Before setUp()57 public void setUp() throws Exception { 58 mBinder = new MockBinder(); 59 } 60 61 @Test testSimpleMethods()62 public void testSimpleMethods() { 63 new Binder(); 64 65 assertEquals(Process.myPid(), Binder.getCallingPid()); 66 assertEquals(Process.myUid(), Binder.getCallingUid()); 67 68 assertTrue(mBinder.isBinderAlive()); 69 70 mBinder.linkToDeath(new MockDeathRecipient(), 0); 71 72 assertTrue(mBinder.unlinkToDeath(new MockDeathRecipient(), 0)); 73 74 assertTrue(mBinder.pingBinder()); 75 76 assertTrue(IBinder.getSuggestedMaxIpcSizeBytes() > 0); 77 } 78 79 @Test 80 @IgnoreUnderRavenwood testDump()81 public void testDump() { 82 final String[] dumpArgs = new String[]{"one", "two", "three"}; 83 mBinder.dump(new FileDescriptor(), 84 new PrintWriter(new ByteArrayOutputStream()), 85 dumpArgs); 86 87 mBinder.dump(new FileDescriptor(), dumpArgs); 88 } 89 90 @Test 91 @IgnoreUnderRavenwood testHandleShellCommand()92 public void testHandleShellCommand() throws Exception { 93 String[] cmdArgs = new String[]{"4", "8", "15", "16", "23", "42"}; 94 95 mBinder.handleShellCommand(ParcelFileDescriptor.dup(FileDescriptor.in), 96 ParcelFileDescriptor.dup(FileDescriptor.out), 97 ParcelFileDescriptor.dup(FileDescriptor.err), cmdArgs); 98 } 99 100 @Test testFlushPendingCommands()101 public void testFlushPendingCommands() { 102 Binder.flushPendingCommands(); 103 } 104 105 @Test 106 @IgnoreUnderRavenwood(reason = "Requires kernel support") testJoinThreadPool()107 public void testJoinThreadPool() { 108 final CountDownLatch waitLatch = new CountDownLatch(1); 109 final CountDownLatch alertLatch = new CountDownLatch(1); 110 Thread joinThread = new Thread("JoinThreadPool-Thread") { 111 @Override 112 public void run() { 113 waitLatch.countDown(); 114 Binder.joinThreadPool(); 115 // Should not reach here. Let the main thread know. 116 alertLatch.countDown(); 117 } 118 }; 119 joinThread.setDaemon(true); 120 joinThread.start(); 121 try { 122 assertTrue(waitLatch.await(10, TimeUnit.SECONDS)); 123 } catch (InterruptedException e) { 124 fail("InterruptedException"); 125 } 126 try { 127 // This waits a small amount of time, hoping that if joinThreadPool 128 // fails, it fails fast. 129 assertFalse(alertLatch.await(3, TimeUnit.SECONDS)); 130 } catch (InterruptedException e) { 131 fail("InterruptedException"); 132 } 133 // Confirm that the thread is actually in joinThreadPool. 134 StackTraceElement stack[] = joinThread.getStackTrace(); 135 boolean found = false; 136 for (StackTraceElement elem : stack) { 137 if (elem.toString().contains("Binder.joinThreadPool")) { 138 found = true; 139 break; 140 } 141 } 142 assertTrue(Arrays.toString(stack), found); 143 } 144 145 @Test testClearCallingIdentity()146 public void testClearCallingIdentity() { 147 long token = Binder.clearCallingIdentity(); 148 assertTrue(token > 0); 149 Binder.restoreCallingIdentity(token); 150 } 151 152 @Test testGetCallingUidOrThrow_throws()153 public void testGetCallingUidOrThrow_throws() throws Exception { 154 assertThrows(IllegalStateException.class, () -> Binder.getCallingUidOrThrow()); 155 } 156 157 @Test testGetCallingUidOrThrow_insideClearRestoreCallingIdentity_doesNotThrow()158 public void testGetCallingUidOrThrow_insideClearRestoreCallingIdentity_doesNotThrow() 159 throws Exception { 160 long token = Binder.clearCallingIdentity(); 161 try { 162 Binder.getCallingUidOrThrow(); 163 } finally { 164 Binder.restoreCallingIdentity(token); 165 } 166 } 167 168 @Test testGetCallingUidOrThrow_afterClearRestoreCallingIdentity_throws()169 public void testGetCallingUidOrThrow_afterClearRestoreCallingIdentity_throws() 170 throws Exception { 171 long token = Binder.clearCallingIdentity(); 172 try { 173 Binder.getCallingUidOrThrow(); 174 } finally { 175 Binder.restoreCallingIdentity(token); 176 } 177 // if a token is properly cleared and restored, a subsequent call should throw 178 assertThrows(IllegalStateException.class, () -> Binder.getCallingUidOrThrow()); 179 } 180 181 @Test testGetCallingUidOrThrow_multipleClearsAreRestoredCorrectly_throws()182 public void testGetCallingUidOrThrow_multipleClearsAreRestoredCorrectly_throws() 183 throws Exception { 184 long outerToken = Binder.clearCallingIdentity(); 185 long innerToken = Binder.clearCallingIdentity(); 186 try { 187 Binder.getCallingUidOrThrow(); 188 } finally { 189 Binder.restoreCallingIdentity(innerToken); 190 Binder.restoreCallingIdentity(outerToken); 191 } 192 // if multiple tokens are cleared and restored in the proper order, 193 // a subsequent call should throw 194 assertThrows(IllegalStateException.class, () -> Binder.getCallingUidOrThrow()); 195 } 196 197 @Test testGetCallingUidOrThrow_onlyOutermostClearIsRestored_throws()198 public void testGetCallingUidOrThrow_onlyOutermostClearIsRestored_throws() throws Exception { 199 long outerToken = Binder.clearCallingIdentity(); 200 long innerToken = Binder.clearCallingIdentity(); 201 try { 202 Binder.getCallingUidOrThrow(); 203 } finally { 204 Binder.restoreCallingIdentity(outerToken); 205 } 206 // if multiple tokens are cleared, and only the outermost token is restored, 207 // a subsequent call should throw 208 assertThrows(IllegalStateException.class, () -> Binder.getCallingUidOrThrow()); 209 } 210 211 @Test testGetCallingUidOrThrow_multipleClearsAreRestoredIncorrectly_doesNotThrow()212 public void testGetCallingUidOrThrow_multipleClearsAreRestoredIncorrectly_doesNotThrow() 213 throws Exception { 214 long outerToken = Binder.clearCallingIdentity(); 215 long innerToken = Binder.clearCallingIdentity(); 216 try { 217 Binder.getCallingUidOrThrow(); 218 } finally { 219 Binder.restoreCallingIdentity(outerToken); 220 Binder.restoreCallingIdentity(innerToken); 221 } 222 // if multiple tokens are restored incorrectly, 223 // a subsequent call will not throw 224 Binder.getCallingUidOrThrow(); 225 } 226 227 @Test testGetCallingUidOrThrow_duplicateClearsAreStoredInSameVariable_doesNotThrow()228 public void testGetCallingUidOrThrow_duplicateClearsAreStoredInSameVariable_doesNotThrow() 229 throws Exception { 230 long token = Binder.clearCallingIdentity(); 231 token = Binder.clearCallingIdentity(); 232 try { 233 Binder.getCallingUidOrThrow(); 234 } finally { 235 Binder.restoreCallingIdentity(token); 236 } 237 // if the same variable is used for multiple clears, a subsequent call will not throw 238 Binder.getCallingUidOrThrow(); 239 } 240 241 @Test 242 @IgnoreUnderRavenwood(blockedBy = WorkSource.class) testClearCallingWorkSource()243 public void testClearCallingWorkSource() { 244 final long token = Binder.clearCallingWorkSource(); 245 Binder.restoreCallingWorkSource(token); 246 } 247 248 @Test 249 @IgnoreUnderRavenwood(blockedBy = WorkSource.class) testSetCallingWorkSourceUid()250 public void testSetCallingWorkSourceUid() { 251 final int otherUid = android.os.Process.myUid() + 1; 252 assertFalse(Binder.getCallingWorkSourceUid() == otherUid); 253 254 final long token = Binder.setCallingWorkSourceUid(otherUid); 255 assertTrue(Binder.getCallingWorkSourceUid() == otherUid); 256 Binder.restoreCallingWorkSource(token); 257 258 assertFalse(Binder.getCallingWorkSourceUid() == otherUid); 259 } 260 261 @Test testInterfaceRelatedMethods()262 public void testInterfaceRelatedMethods() { 263 assertNull(mBinder.getInterfaceDescriptor()); 264 mBinder.attachInterface(new MockIInterface(), DESCRIPTOR_GOOGLE); 265 assertEquals(DESCRIPTOR_GOOGLE, mBinder.getInterfaceDescriptor()); 266 267 mBinder.attachInterface(new MockIInterface(), DESCRIPTOR_ANDROID); 268 assertNull(mBinder.queryLocalInterface(DESCRIPTOR_GOOGLE)); 269 mBinder.attachInterface(new MockIInterface(), DESCRIPTOR_GOOGLE); 270 assertNotNull(mBinder.queryLocalInterface(DESCRIPTOR_GOOGLE)); 271 } 272 273 private static class MockDeathRecipient implements IBinder.DeathRecipient { binderDied()274 public void binderDied() { 275 276 } 277 } 278 279 private static class MockIInterface implements IInterface { asBinder()280 public IBinder asBinder() { 281 return new Binder(); 282 } 283 } 284 285 private static class MockBinder extends Binder { 286 @Override dump(FileDescriptor fd, PrintWriter fout, String[] args)287 public void dump(FileDescriptor fd, PrintWriter fout, String[] args) { 288 super.dump(fd, fout, args); 289 } 290 } 291 292 } 293