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