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