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