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