• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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