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