1 /* 2 * Copyright (C) 2006 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; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.util.Log; 22 import android.util.SparseIntArray; 23 24 import com.android.internal.annotations.GuardedBy; 25 import com.android.internal.os.BinderInternal; 26 27 import libcore.util.NativeAllocationRegistry; 28 29 import java.io.FileDescriptor; 30 import java.lang.ref.WeakReference; 31 import java.util.ArrayList; 32 import java.util.Arrays; 33 import java.util.HashMap; 34 import java.util.Map; 35 36 /** 37 * Java proxy for a native IBinder object. 38 * Allocated and constructed by the native javaObjectforIBinder function. Never allocated 39 * directly from Java code. 40 * 41 * @hide 42 */ 43 public final class BinderProxy implements IBinder { 44 // See android_util_Binder.cpp for the native half of this. 45 46 // Assume the process-wide default value when created 47 volatile boolean mWarnOnBlocking = Binder.sWarnOnBlocking; 48 49 private static volatile Binder.ProxyTransactListener sTransactListener = null; 50 51 /** 52 * @see {@link Binder#setProxyTransactListener(listener)}. 53 */ setTransactListener(@ullable Binder.ProxyTransactListener listener)54 public static void setTransactListener(@Nullable Binder.ProxyTransactListener listener) { 55 sTransactListener = listener; 56 } 57 58 /* 59 * Map from longs to BinderProxy, retaining only a WeakReference to the BinderProxies. 60 * We roll our own only because we need to lazily remove WeakReferences during accesses 61 * to avoid accumulating junk WeakReference objects. WeakHashMap isn't easily usable 62 * because we want weak values, not keys. 63 * Our hash table is never resized, but the number of entries is unlimited; 64 * performance degrades as occupancy increases significantly past MAIN_INDEX_SIZE. 65 * Not thread-safe. Client ensures there's a single access at a time. 66 */ 67 private static final class ProxyMap { 68 private static final int LOG_MAIN_INDEX_SIZE = 8; 69 private static final int MAIN_INDEX_SIZE = 1 << LOG_MAIN_INDEX_SIZE; 70 private static final int MAIN_INDEX_MASK = MAIN_INDEX_SIZE - 1; 71 // Debuggable builds will throw an AssertionError if the number of map entries exceeds: 72 private static final int CRASH_AT_SIZE = 20_000; 73 74 /** 75 * We next warn when we exceed this bucket size. 76 */ 77 private int mWarnBucketSize = 20; 78 79 /** 80 * Increment mWarnBucketSize by WARN_INCREMENT each time we warn. 81 */ 82 private static final int WARN_INCREMENT = 10; 83 84 /** 85 * Hash function tailored to native pointers. 86 * Returns a value < MAIN_INDEX_SIZE. 87 */ hash(long arg)88 private static int hash(long arg) { 89 return ((int) ((arg >> 2) ^ (arg >> (2 + LOG_MAIN_INDEX_SIZE)))) & MAIN_INDEX_MASK; 90 } 91 92 /** 93 * Return the total number of pairs in the map. 94 */ size()95 private int size() { 96 int size = 0; 97 for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) { 98 if (a != null) { 99 size += a.size(); 100 } 101 } 102 return size; 103 } 104 105 /** 106 * Return the total number of pairs in the map containing values that have 107 * not been cleared. More expensive than the above size function. 108 */ unclearedSize()109 private int unclearedSize() { 110 int size = 0; 111 for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) { 112 if (a != null) { 113 for (WeakReference<BinderProxy> ref : a) { 114 if (ref.get() != null) { 115 ++size; 116 } 117 } 118 } 119 } 120 return size; 121 } 122 123 /** 124 * Remove ith entry from the hash bucket indicated by hash. 125 */ remove(int hash, int index)126 private void remove(int hash, int index) { 127 Long[] keyArray = mMainIndexKeys[hash]; 128 ArrayList<WeakReference<BinderProxy>> valueArray = mMainIndexValues[hash]; 129 int size = valueArray.size(); // KeyArray may have extra elements. 130 // Move last entry into empty slot, and truncate at end. 131 if (index != size - 1) { 132 keyArray[index] = keyArray[size - 1]; 133 valueArray.set(index, valueArray.get(size - 1)); 134 } 135 valueArray.remove(size - 1); 136 // Just leave key array entry; it's unused. We only trust the valueArray size. 137 } 138 139 /** 140 * Look up the supplied key. If we have a non-cleared entry for it, return it. 141 */ get(long key)142 BinderProxy get(long key) { 143 int myHash = hash(key); 144 Long[] keyArray = mMainIndexKeys[myHash]; 145 if (keyArray == null) { 146 return null; 147 } 148 ArrayList<WeakReference<BinderProxy>> valueArray = mMainIndexValues[myHash]; 149 int bucketSize = valueArray.size(); 150 for (int i = 0; i < bucketSize; ++i) { 151 long foundKey = keyArray[i]; 152 if (key == foundKey) { 153 WeakReference<BinderProxy> wr = valueArray.get(i); 154 BinderProxy bp = wr.get(); 155 if (bp != null) { 156 return bp; 157 } else { 158 remove(myHash, i); 159 return null; 160 } 161 } 162 } 163 return null; 164 } 165 166 private int mRandom; // A counter used to generate a "random" index. World's 2nd worst RNG. 167 168 /** 169 * Add the key-value pair to the map. 170 * Requires that the indicated key is not already in the map. 171 */ set(long key, @NonNull BinderProxy value)172 void set(long key, @NonNull BinderProxy value) { 173 int myHash = hash(key); 174 ArrayList<WeakReference<BinderProxy>> valueArray = mMainIndexValues[myHash]; 175 if (valueArray == null) { 176 valueArray = mMainIndexValues[myHash] = new ArrayList<>(); 177 mMainIndexKeys[myHash] = new Long[1]; 178 } 179 int size = valueArray.size(); 180 WeakReference<BinderProxy> newWr = new WeakReference<>(value); 181 // First look for a cleared reference. 182 // This ensures that ArrayList size is bounded by the maximum occupancy of 183 // that bucket. 184 for (int i = 0; i < size; ++i) { 185 if (valueArray.get(i).get() == null) { 186 valueArray.set(i, newWr); 187 Long[] keyArray = mMainIndexKeys[myHash]; 188 keyArray[i] = key; 189 if (i < size - 1) { 190 // "Randomly" check one of the remaining entries in [i+1, size), so that 191 // needlessly long buckets are eventually pruned. 192 int rnd = Math.floorMod(++mRandom, size - (i + 1)); 193 if (valueArray.get(i + 1 + rnd).get() == null) { 194 remove(myHash, i + 1 + rnd); 195 } 196 } 197 return; 198 } 199 } 200 valueArray.add(size, newWr); 201 Long[] keyArray = mMainIndexKeys[myHash]; 202 if (keyArray.length == size) { 203 // size >= 1, since we initially allocated one element 204 Long[] newArray = new Long[size + size / 2 + 2]; 205 System.arraycopy(keyArray, 0, newArray, 0, size); 206 newArray[size] = key; 207 mMainIndexKeys[myHash] = newArray; 208 } else { 209 keyArray[size] = key; 210 } 211 if (size >= mWarnBucketSize) { 212 final int totalSize = size(); 213 Log.v(Binder.TAG, "BinderProxy map growth! bucket size = " + size 214 + " total = " + totalSize); 215 mWarnBucketSize += WARN_INCREMENT; 216 if (Build.IS_DEBUGGABLE && totalSize >= CRASH_AT_SIZE) { 217 // Use the number of uncleared entries to determine whether we should 218 // really report a histogram and crash. We don't want to fundamentally 219 // change behavior for a debuggable process, so we GC only if we are 220 // about to crash. 221 final int totalUnclearedSize = unclearedSize(); 222 if (totalUnclearedSize >= CRASH_AT_SIZE) { 223 dumpProxyInterfaceCounts(); 224 dumpPerUidProxyCounts(); 225 Runtime.getRuntime().gc(); 226 throw new AssertionError("Binder ProxyMap has too many entries: " 227 + totalSize + " (total), " + totalUnclearedSize + " (uncleared), " 228 + unclearedSize() + " (uncleared after GC). BinderProxy leak?"); 229 } else if (totalSize > 3 * totalUnclearedSize / 2) { 230 Log.v(Binder.TAG, "BinderProxy map has many cleared entries: " 231 + (totalSize - totalUnclearedSize) + " of " + totalSize 232 + " are cleared"); 233 } 234 } 235 } 236 } 237 getSortedInterfaceCounts(int maxToReturn)238 private InterfaceCount[] getSortedInterfaceCounts(int maxToReturn) { 239 if (maxToReturn < 0) { 240 throw new IllegalArgumentException("negative interface count"); 241 } 242 243 Map<String, Integer> counts = new HashMap<>(); 244 for (ArrayList<WeakReference<BinderProxy>> a : mMainIndexValues) { 245 if (a != null) { 246 for (WeakReference<BinderProxy> weakRef : a) { 247 BinderProxy bp = weakRef.get(); 248 String key; 249 if (bp == null) { 250 key = "<cleared weak-ref>"; 251 } else { 252 try { 253 key = bp.getInterfaceDescriptor(); 254 if ((key == null || key.isEmpty()) && !bp.isBinderAlive()) { 255 key = "<proxy to dead node>"; 256 } 257 } catch (Throwable t) { 258 key = "<exception during getDescriptor>"; 259 } 260 } 261 Integer i = counts.get(key); 262 if (i == null) { 263 counts.put(key, 1); 264 } else { 265 counts.put(key, i + 1); 266 } 267 } 268 } 269 } 270 Map.Entry<String, Integer>[] sorted = counts.entrySet().toArray( 271 new Map.Entry[counts.size()]); 272 273 Arrays.sort(sorted, (Map.Entry<String, Integer> a, Map.Entry<String, Integer> b) 274 -> b.getValue().compareTo(a.getValue())); 275 276 int returnCount = Math.min(maxToReturn, sorted.length); 277 InterfaceCount[] ifaceCounts = new InterfaceCount[returnCount]; 278 for (int i = 0; i < returnCount; i++) { 279 ifaceCounts[i] = new InterfaceCount(sorted[i].getKey(), sorted[i].getValue()); 280 } 281 return ifaceCounts; 282 } 283 284 static final int MAX_NUM_INTERFACES_TO_DUMP = 10; 285 286 /** 287 * Dump a histogram to the logcat. Used to diagnose abnormally large proxy maps. 288 */ dumpProxyInterfaceCounts()289 private void dumpProxyInterfaceCounts() { 290 final InterfaceCount[] sorted = getSortedInterfaceCounts(MAX_NUM_INTERFACES_TO_DUMP); 291 292 Log.v(Binder.TAG, "BinderProxy descriptor histogram " 293 + "(top " + Integer.toString(MAX_NUM_INTERFACES_TO_DUMP) + "):"); 294 for (int i = 0; i < sorted.length; i++) { 295 Log.v(Binder.TAG, " #" + (i + 1) + ": " + sorted[i]); 296 } 297 } 298 299 /** 300 * Dump per uid binder proxy counts to the logcat. 301 */ dumpPerUidProxyCounts()302 private void dumpPerUidProxyCounts() { 303 SparseIntArray counts = BinderInternal.nGetBinderProxyPerUidCounts(); 304 if (counts.size() == 0) return; 305 Log.d(Binder.TAG, "Per Uid Binder Proxy Counts:"); 306 for (int i = 0; i < counts.size(); i++) { 307 final int uid = counts.keyAt(i); 308 final int binderCount = counts.valueAt(i); 309 Log.d(Binder.TAG, "UID : " + uid + " count = " + binderCount); 310 } 311 } 312 313 // Corresponding ArrayLists in the following two arrays always have the same size. 314 // They contain no empty entries. However WeakReferences in the values ArrayLists 315 // may have been cleared. 316 317 // mMainIndexKeys[i][j] corresponds to mMainIndexValues[i].get(j) . 318 // The values ArrayList has the proper size(), the corresponding keys array 319 // is always at least the same size, but may be larger. 320 // If either a particular keys array, or the corresponding values ArrayList 321 // are null, then they both are. 322 private final Long[][] mMainIndexKeys = new Long[MAIN_INDEX_SIZE][]; 323 private final ArrayList<WeakReference<BinderProxy>>[] mMainIndexValues = 324 new ArrayList[MAIN_INDEX_SIZE]; 325 } 326 327 @GuardedBy("sProxyMap") 328 private static final ProxyMap sProxyMap = new ProxyMap(); 329 330 /** 331 * Simple pair-value class to store number of binder proxy interfaces live in this process. 332 */ 333 public static final class InterfaceCount { 334 private final String mInterfaceName; 335 private final int mCount; 336 InterfaceCount(String interfaceName, int count)337 InterfaceCount(String interfaceName, int count) { 338 mInterfaceName = interfaceName; 339 mCount = count; 340 } 341 342 @Override toString()343 public String toString() { 344 return mInterfaceName + " x" + Integer.toString(mCount); 345 } 346 } 347 348 /** 349 * Get a sorted array with entries mapping proxy interface names to the number 350 * of live proxies with those names. 351 * 352 * @param num maximum number of proxy interface counts to return. Use 353 * Integer.MAX_VALUE to retrieve all 354 * @hide 355 */ getSortedInterfaceCounts(int num)356 public static InterfaceCount[] getSortedInterfaceCounts(int num) { 357 synchronized (sProxyMap) { 358 return sProxyMap.getSortedInterfaceCounts(num); 359 } 360 } 361 362 /** 363 * Returns the number of binder proxies held in this process. 364 * @return number of binder proxies in this process 365 */ getProxyCount()366 public static int getProxyCount() { 367 synchronized (sProxyMap) { 368 return sProxyMap.size(); 369 } 370 } 371 372 /** 373 * Dump proxy debug information. 374 * 375 * @hide 376 */ dumpProxyDebugInfo()377 public static void dumpProxyDebugInfo() { 378 if (Build.IS_DEBUGGABLE) { 379 synchronized (sProxyMap) { 380 sProxyMap.dumpProxyInterfaceCounts(); 381 sProxyMap.dumpPerUidProxyCounts(); 382 } 383 } 384 } 385 386 /** 387 * Return a BinderProxy for IBinder. 388 * If we previously returned a BinderProxy bp for the same iBinder, and bp is still 389 * in use, then we return the same bp. 390 * 391 * @param nativeData C++ pointer to (possibly still empty) BinderProxyNativeData. 392 * Takes ownership of nativeData iff <result>.mNativeData == nativeData, or if 393 * we exit via an exception. If neither applies, it's the callers responsibility to 394 * recycle nativeData. 395 * @param iBinder C++ pointer to IBinder. Does not take ownership of referenced object. 396 */ getInstance(long nativeData, long iBinder)397 private static BinderProxy getInstance(long nativeData, long iBinder) { 398 BinderProxy result; 399 synchronized (sProxyMap) { 400 try { 401 result = sProxyMap.get(iBinder); 402 if (result != null) { 403 return result; 404 } 405 result = new BinderProxy(nativeData); 406 } catch (Throwable e) { 407 // We're throwing an exception (probably OOME); don't drop nativeData. 408 NativeAllocationRegistry.applyFreeFunction(NoImagePreloadHolder.sNativeFinalizer, 409 nativeData); 410 throw e; 411 } 412 NoImagePreloadHolder.sRegistry.registerNativeAllocation(result, nativeData); 413 // The registry now owns nativeData, even if registration threw an exception. 414 sProxyMap.set(iBinder, result); 415 } 416 return result; 417 } 418 BinderProxy(long nativeData)419 private BinderProxy(long nativeData) { 420 mNativeData = nativeData; 421 } 422 423 /** 424 * Guestimate of native memory associated with a BinderProxy. 425 * This includes the underlying IBinder, associated DeathRecipientList, and KeyedVector 426 * that points back to us. We guess high since it includes a GlobalRef, which 427 * may be in short supply. 428 */ 429 private static final int NATIVE_ALLOCATION_SIZE = 1000; 430 431 // Use a Holder to allow static initialization of BinderProxy in the boot image, and 432 // to avoid some initialization ordering issues. 433 private static class NoImagePreloadHolder { 434 public static final long sNativeFinalizer = getNativeFinalizer(); 435 public static final NativeAllocationRegistry sRegistry = new NativeAllocationRegistry( 436 BinderProxy.class.getClassLoader(), sNativeFinalizer, NATIVE_ALLOCATION_SIZE); 437 } 438 439 /** 440 * @return false if the hosting process is gone, otherwise whatever the remote returns 441 */ pingBinder()442 public native boolean pingBinder(); 443 444 /** 445 * @return false if the hosting process is gone 446 */ isBinderAlive()447 public native boolean isBinderAlive(); 448 449 /** 450 * Retrieve a local interface - always null in case of a proxy 451 */ queryLocalInterface(String descriptor)452 public IInterface queryLocalInterface(String descriptor) { 453 return null; 454 } 455 456 /** 457 * Perform a binder transaction on a proxy. 458 * 459 * @param code The action to perform. This should 460 * be a number between {@link #FIRST_CALL_TRANSACTION} and 461 * {@link #LAST_CALL_TRANSACTION}. 462 * @param data Marshalled data to send to the target. Must not be null. 463 * If you are not sending any data, you must create an empty Parcel 464 * that is given here. 465 * @param reply Marshalled data to be received from the target. May be 466 * null if you are not interested in the return value. 467 * @param flags Additional operation flags. Either 0 for a normal 468 * RPC, or {@link #FLAG_ONEWAY} for a one-way RPC. 469 * 470 * @return 471 * @throws RemoteException 472 */ transact(int code, Parcel data, Parcel reply, int flags)473 public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException { 474 Binder.checkParcel(this, code, data, "Unreasonably large binder buffer"); 475 476 if (mWarnOnBlocking && ((flags & FLAG_ONEWAY) == 0)) { 477 // For now, avoid spamming the log by disabling after we've logged 478 // about this interface at least once 479 mWarnOnBlocking = false; 480 Log.w(Binder.TAG, "Outgoing transactions from this process must be FLAG_ONEWAY", 481 new Throwable()); 482 } 483 484 final boolean tracingEnabled = Binder.isTracingEnabled(); 485 if (tracingEnabled) { 486 final Throwable tr = new Throwable(); 487 Binder.getTransactionTracker().addTrace(tr); 488 StackTraceElement stackTraceElement = tr.getStackTrace()[1]; 489 Trace.traceBegin(Trace.TRACE_TAG_ALWAYS, 490 stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName()); 491 } 492 493 // Make sure the listener won't change while processing a transaction. 494 final Binder.ProxyTransactListener transactListener = sTransactListener; 495 Object session = null; 496 497 if (transactListener != null) { 498 final int origWorkSourceUid = Binder.getCallingWorkSourceUid(); 499 session = transactListener.onTransactStarted(this, code); 500 501 // Allow the listener to update the work source uid. We need to update the request 502 // header if the uid is updated. 503 final int updatedWorkSourceUid = Binder.getCallingWorkSourceUid(); 504 if (origWorkSourceUid != updatedWorkSourceUid) { 505 data.replaceCallingWorkSourceUid(updatedWorkSourceUid); 506 } 507 } 508 509 try { 510 return transactNative(code, data, reply, flags); 511 } finally { 512 if (transactListener != null) { 513 transactListener.onTransactEnded(session); 514 } 515 516 if (tracingEnabled) { 517 Trace.traceEnd(Trace.TRACE_TAG_ALWAYS); 518 } 519 } 520 } 521 522 /* Returns the native free function */ getNativeFinalizer()523 private static native long getNativeFinalizer(); 524 /** 525 * See {@link IBinder#getInterfaceDescriptor()} 526 */ getInterfaceDescriptor()527 public native String getInterfaceDescriptor() throws RemoteException; 528 529 /** 530 * Native implementation of transact() for proxies 531 */ transactNative(int code, Parcel data, Parcel reply, int flags)532 public native boolean transactNative(int code, Parcel data, Parcel reply, 533 int flags) throws RemoteException; 534 /** 535 * See {@link IBinder#linkToDeath(DeathRecipient, int)} 536 */ linkToDeath(DeathRecipient recipient, int flags)537 public native void linkToDeath(DeathRecipient recipient, int flags) 538 throws RemoteException; 539 /** 540 * See {@link IBinder#unlinkToDeath} 541 */ unlinkToDeath(DeathRecipient recipient, int flags)542 public native boolean unlinkToDeath(DeathRecipient recipient, int flags); 543 544 /** 545 * Perform a dump on the remote object 546 * 547 * @param fd The raw file descriptor that the dump is being sent to. 548 * @param args additional arguments to the dump request. 549 * @throws RemoteException 550 */ dump(FileDescriptor fd, String[] args)551 public void dump(FileDescriptor fd, String[] args) throws RemoteException { 552 Parcel data = Parcel.obtain(); 553 Parcel reply = Parcel.obtain(); 554 data.writeFileDescriptor(fd); 555 data.writeStringArray(args); 556 try { 557 transact(DUMP_TRANSACTION, data, reply, 0); 558 reply.readException(); 559 } finally { 560 data.recycle(); 561 reply.recycle(); 562 } 563 } 564 565 /** 566 * Perform an asynchronous dump on the remote object 567 * 568 * @param fd The raw file descriptor that the dump is being sent to. 569 * @param args additional arguments to the dump request. 570 * @throws RemoteException 571 */ dumpAsync(FileDescriptor fd, String[] args)572 public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException { 573 Parcel data = Parcel.obtain(); 574 Parcel reply = Parcel.obtain(); 575 data.writeFileDescriptor(fd); 576 data.writeStringArray(args); 577 try { 578 transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY); 579 } finally { 580 data.recycle(); 581 reply.recycle(); 582 } 583 } 584 585 /** 586 * See {@link IBinder#shellCommand(FileDescriptor, FileDescriptor, FileDescriptor, 587 * String[], ShellCallback, ResultReceiver)} 588 * 589 * @param in The raw file descriptor that an input data stream can be read from. 590 * @param out The raw file descriptor that normal command messages should be written to. 591 * @param err The raw file descriptor that command error messages should be written to. 592 * @param args Command-line arguments. 593 * @param callback Optional callback to the caller's shell to perform operations in it. 594 * @param resultReceiver Called when the command has finished executing, with the result code. 595 * @throws RemoteException 596 */ shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ShellCallback callback, ResultReceiver resultReceiver)597 public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, 598 String[] args, ShellCallback callback, 599 ResultReceiver resultReceiver) throws RemoteException { 600 Parcel data = Parcel.obtain(); 601 Parcel reply = Parcel.obtain(); 602 data.writeFileDescriptor(in); 603 data.writeFileDescriptor(out); 604 data.writeFileDescriptor(err); 605 data.writeStringArray(args); 606 ShellCallback.writeToParcel(callback, data); 607 resultReceiver.writeToParcel(data, 0); 608 try { 609 transact(SHELL_COMMAND_TRANSACTION, data, reply, 0); 610 reply.readException(); 611 } finally { 612 data.recycle(); 613 reply.recycle(); 614 } 615 } 616 sendDeathNotice(DeathRecipient recipient)617 private static void sendDeathNotice(DeathRecipient recipient) { 618 if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient); 619 try { 620 recipient.binderDied(); 621 } catch (RuntimeException exc) { 622 Log.w("BinderNative", "Uncaught exception from death notification", 623 exc); 624 } 625 } 626 627 /** 628 * C++ pointer to BinderProxyNativeData. That consists of strong pointers to the 629 * native IBinder object, and a DeathRecipientList. 630 */ 631 private final long mNativeData; 632 } 633