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