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