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