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