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