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