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.util.Log;
20 import android.util.Slog;
21 import com.android.internal.util.FastPrintWriter;
22 import libcore.io.IoUtils;
23 
24 import java.io.FileDescriptor;
25 import java.io.FileOutputStream;
26 import java.io.IOException;
27 import java.io.PrintWriter;
28 import java.lang.ref.WeakReference;
29 import java.lang.reflect.Modifier;
30 
31 /**
32  * Base class for a remotable object, the core part of a lightweight
33  * remote procedure call mechanism defined by {@link IBinder}.
34  * This class is an implementation of IBinder that provides
35  * standard local implementation of such an object.
36  *
37  * <p>Most developers will not implement this class directly, instead using the
38  * <a href="{@docRoot}guide/components/aidl.html">aidl</a> tool to describe the desired
39  * interface, having it generate the appropriate Binder subclass.  You can,
40  * however, derive directly from Binder to implement your own custom RPC
41  * protocol or simply instantiate a raw Binder object directly to use as a
42  * token that can be shared across processes.
43  *
44  * <p>This class is just a basic IPC primitive; it has no impact on an application's
45  * lifecycle, and is valid only as long as the process that created it continues to run.
46  * To use this correctly, you must be doing so within the context of a top-level
47  * application component (a {@link android.app.Service}, {@link android.app.Activity},
48  * or {@link android.content.ContentProvider}) that lets the system know your process
49  * should remain running.</p>
50  *
51  * <p>You must keep in mind the situations in which your process
52  * could go away, and thus require that you later re-create a new Binder and re-attach
53  * it when the process starts again.  For example, if you are using this within an
54  * {@link android.app.Activity}, your activity's process may be killed any time the
55  * activity is not started; if the activity is later re-created you will need to
56  * create a new Binder and hand it back to the correct place again; you need to be
57  * aware that your process may be started for another reason (for example to receive
58  * a broadcast) that will not involve re-creating the activity and thus run its code
59  * to create a new Binder.</p>
60  *
61  * @see IBinder
62  */
63 public class Binder implements IBinder {
64     /*
65      * Set this flag to true to detect anonymous, local or member classes
66      * that extend this Binder class and that are not static. These kind
67      * of classes can potentially create leaks.
68      */
69     private static final boolean FIND_POTENTIAL_LEAKS = false;
70     private static final boolean CHECK_PARCEL_SIZE = false;
71     static final String TAG = "Binder";
72 
73     /** @hide */
74     public static boolean LOG_RUNTIME_EXCEPTION = false; // DO NOT SUBMIT WITH TRUE
75 
76     /**
77      * Control whether dump() calls are allowed.
78      */
79     private static String sDumpDisabled = null;
80 
81     /**
82      * Global transaction tracker instance for this process.
83      */
84     private static TransactionTracker sTransactionTracker = null;
85 
86     // Transaction tracking code.
87 
88     /**
89      * Flag indicating whether we should be tracing transact calls.
90      *
91      */
92     private static boolean sTracingEnabled = false;
93 
94     /**
95      * Enable Binder IPC tracing.
96      *
97      * @hide
98      */
enableTracing()99     public static void  enableTracing() {
100         sTracingEnabled = true;
101     };
102 
103     /**
104      * Disable Binder IPC tracing.
105      *
106      * @hide
107      */
disableTracing()108     public static void  disableTracing() {
109         sTracingEnabled = false;
110     }
111 
112     /**
113      * Check if binder transaction tracing is enabled.
114      *
115      * @hide
116      */
isTracingEnabled()117     public static boolean isTracingEnabled() {
118         return sTracingEnabled;
119     }
120 
121     /**
122      * Get the binder transaction tracker for this process.
123      *
124      * @hide
125      */
getTransactionTracker()126     public synchronized static TransactionTracker getTransactionTracker() {
127         if (sTransactionTracker == null)
128             sTransactionTracker = new TransactionTracker();
129         return sTransactionTracker;
130     }
131 
132     /* mObject is used by native code, do not remove or rename */
133     private long mObject;
134     private IInterface mOwner;
135     private String mDescriptor;
136 
137     /**
138      * Return the ID of the process that sent you the current transaction
139      * that is being processed.  This pid can be used with higher-level
140      * system services to determine its identity and check permissions.
141      * If the current thread is not currently executing an incoming transaction,
142      * then its own pid is returned.
143      */
getCallingPid()144     public static final native int getCallingPid();
145 
146     /**
147      * Return the Linux uid assigned to the process that sent you the
148      * current transaction that is being processed.  This uid can be used with
149      * higher-level system services to determine its identity and check
150      * permissions.  If the current thread is not currently executing an
151      * incoming transaction, then its own uid is returned.
152      */
getCallingUid()153     public static final native int getCallingUid();
154 
155     /**
156      * Return the UserHandle assigned to the process that sent you the
157      * current transaction that is being processed.  This is the user
158      * of the caller.  It is distinct from {@link #getCallingUid()} in that a
159      * particular user will have multiple distinct apps running under it each
160      * with their own uid.  If the current thread is not currently executing an
161      * incoming transaction, then its own UserHandle is returned.
162      */
getCallingUserHandle()163     public static final UserHandle getCallingUserHandle() {
164         return UserHandle.of(UserHandle.getUserId(getCallingUid()));
165     }
166 
167     /**
168      * Reset the identity of the incoming IPC on the current thread.  This can
169      * be useful if, while handling an incoming call, you will be calling
170      * on interfaces of other objects that may be local to your process and
171      * need to do permission checks on the calls coming into them (so they
172      * will check the permission of your own local process, and not whatever
173      * process originally called you).
174      *
175      * @return Returns an opaque token that can be used to restore the
176      * original calling identity by passing it to
177      * {@link #restoreCallingIdentity(long)}.
178      *
179      * @see #getCallingPid()
180      * @see #getCallingUid()
181      * @see #restoreCallingIdentity(long)
182      */
clearCallingIdentity()183     public static final native long clearCallingIdentity();
184 
185     /**
186      * Restore the identity of the incoming IPC on the current thread
187      * back to a previously identity that was returned by {@link
188      * #clearCallingIdentity}.
189      *
190      * @param token The opaque token that was previously returned by
191      * {@link #clearCallingIdentity}.
192      *
193      * @see #clearCallingIdentity
194      */
restoreCallingIdentity(long token)195     public static final native void restoreCallingIdentity(long token);
196 
197     /**
198      * Sets the native thread-local StrictMode policy mask.
199      *
200      * <p>The StrictMode settings are kept in two places: a Java-level
201      * threadlocal for libcore/Dalvik, and a native threadlocal (set
202      * here) for propagation via Binder calls.  This is a little
203      * unfortunate, but necessary to break otherwise more unfortunate
204      * dependencies either of Dalvik on Android, or Android
205      * native-only code on Dalvik.
206      *
207      * @see StrictMode
208      * @hide
209      */
setThreadStrictModePolicy(int policyMask)210     public static final native void setThreadStrictModePolicy(int policyMask);
211 
212     /**
213      * Gets the current native thread-local StrictMode policy mask.
214      *
215      * @see #setThreadStrictModePolicy
216      * @hide
217      */
getThreadStrictModePolicy()218     public static final native int getThreadStrictModePolicy();
219 
220     /**
221      * Flush any Binder commands pending in the current thread to the kernel
222      * driver.  This can be
223      * useful to call before performing an operation that may block for a long
224      * time, to ensure that any pending object references have been released
225      * in order to prevent the process from holding on to objects longer than
226      * it needs to.
227      */
flushPendingCommands()228     public static final native void flushPendingCommands();
229 
230     /**
231      * Add the calling thread to the IPC thread pool.  This function does
232      * not return until the current process is exiting.
233      */
joinThreadPool()234     public static final native void joinThreadPool();
235 
236     /**
237      * Returns true if the specified interface is a proxy.
238      * @hide
239      */
isProxy(IInterface iface)240     public static final boolean isProxy(IInterface iface) {
241         return iface.asBinder() != iface;
242     }
243 
244     /**
245      * Call blocks until the number of executing binder threads is less
246      * than the maximum number of binder threads allowed for this process.
247      * @hide
248      */
blockUntilThreadAvailable()249     public static final native void blockUntilThreadAvailable();
250 
251     /**
252      * Default constructor initializes the object.
253      */
Binder()254     public Binder() {
255         init();
256 
257         if (FIND_POTENTIAL_LEAKS) {
258             final Class<? extends Binder> klass = getClass();
259             if ((klass.isAnonymousClass() || klass.isMemberClass() || klass.isLocalClass()) &&
260                     (klass.getModifiers() & Modifier.STATIC) == 0) {
261                 Log.w(TAG, "The following Binder class should be static or leaks might occur: " +
262                     klass.getCanonicalName());
263             }
264         }
265     }
266 
267     /**
268      * Convenience method for associating a specific interface with the Binder.
269      * After calling, queryLocalInterface() will be implemented for you
270      * to return the given owner IInterface when the corresponding
271      * descriptor is requested.
272      */
attachInterface(IInterface owner, String descriptor)273     public void attachInterface(IInterface owner, String descriptor) {
274         mOwner = owner;
275         mDescriptor = descriptor;
276     }
277 
278     /**
279      * Default implementation returns an empty interface name.
280      */
getInterfaceDescriptor()281     public String getInterfaceDescriptor() {
282         return mDescriptor;
283     }
284 
285     /**
286      * Default implementation always returns true -- if you got here,
287      * the object is alive.
288      */
pingBinder()289     public boolean pingBinder() {
290         return true;
291     }
292 
293     /**
294      * {@inheritDoc}
295      *
296      * Note that if you're calling on a local binder, this always returns true
297      * because your process is alive if you're calling it.
298      */
isBinderAlive()299     public boolean isBinderAlive() {
300         return true;
301     }
302 
303     /**
304      * Use information supplied to attachInterface() to return the
305      * associated IInterface if it matches the requested
306      * descriptor.
307      */
queryLocalInterface(String descriptor)308     public IInterface queryLocalInterface(String descriptor) {
309         if (mDescriptor.equals(descriptor)) {
310             return mOwner;
311         }
312         return null;
313     }
314 
315     /**
316      * Control disabling of dump calls in this process.  This is used by the system
317      * process watchdog to disable incoming dump calls while it has detecting the system
318      * is hung and is reporting that back to the activity controller.  This is to
319      * prevent the controller from getting hung up on bug reports at this point.
320      * @hide
321      *
322      * @param msg The message to show instead of the dump; if null, dumps are
323      * re-enabled.
324      */
setDumpDisabled(String msg)325     public static void setDumpDisabled(String msg) {
326         synchronized (Binder.class) {
327             sDumpDisabled = msg;
328         }
329     }
330 
331     /**
332      * Default implementation is a stub that returns false.  You will want
333      * to override this to do the appropriate unmarshalling of transactions.
334      *
335      * <p>If you want to call this, call transact().
336      */
onTransact(int code, Parcel data, Parcel reply, int flags)337     protected boolean onTransact(int code, Parcel data, Parcel reply,
338             int flags) throws RemoteException {
339         if (code == INTERFACE_TRANSACTION) {
340             reply.writeString(getInterfaceDescriptor());
341             return true;
342         } else if (code == DUMP_TRANSACTION) {
343             ParcelFileDescriptor fd = data.readFileDescriptor();
344             String[] args = data.readStringArray();
345             if (fd != null) {
346                 try {
347                     dump(fd.getFileDescriptor(), args);
348                 } finally {
349                     IoUtils.closeQuietly(fd);
350                 }
351             }
352             // Write the StrictMode header.
353             if (reply != null) {
354                 reply.writeNoException();
355             } else {
356                 StrictMode.clearGatheredViolations();
357             }
358             return true;
359         } else if (code == SHELL_COMMAND_TRANSACTION) {
360             ParcelFileDescriptor in = data.readFileDescriptor();
361             ParcelFileDescriptor out = data.readFileDescriptor();
362             ParcelFileDescriptor err = data.readFileDescriptor();
363             String[] args = data.readStringArray();
364             ResultReceiver resultReceiver = ResultReceiver.CREATOR.createFromParcel(data);
365             try {
366                 if (out != null) {
367                     shellCommand(in != null ? in.getFileDescriptor() : null,
368                             out.getFileDescriptor(),
369                             err != null ? err.getFileDescriptor() : out.getFileDescriptor(),
370                             args, resultReceiver);
371                 }
372             } finally {
373                 IoUtils.closeQuietly(in);
374                 IoUtils.closeQuietly(out);
375                 IoUtils.closeQuietly(err);
376                 // Write the StrictMode header.
377                 if (reply != null) {
378                     reply.writeNoException();
379                 } else {
380                     StrictMode.clearGatheredViolations();
381                 }
382             }
383             return true;
384         }
385         return false;
386     }
387 
388     /**
389      * Implemented to call the more convenient version
390      * {@link #dump(FileDescriptor, PrintWriter, String[])}.
391      */
dump(FileDescriptor fd, String[] args)392     public void dump(FileDescriptor fd, String[] args) {
393         FileOutputStream fout = new FileOutputStream(fd);
394         PrintWriter pw = new FastPrintWriter(fout);
395         try {
396             doDump(fd, pw, args);
397         } finally {
398             pw.flush();
399         }
400     }
401 
doDump(FileDescriptor fd, PrintWriter pw, String[] args)402     void doDump(FileDescriptor fd, PrintWriter pw, String[] args) {
403         final String disabled;
404         synchronized (Binder.class) {
405             disabled = sDumpDisabled;
406         }
407         if (disabled == null) {
408             try {
409                 dump(fd, pw, args);
410             } catch (SecurityException e) {
411                 pw.println("Security exception: " + e.getMessage());
412                 throw e;
413             } catch (Throwable e) {
414                 // Unlike usual calls, in this case if an exception gets thrown
415                 // back to us we want to print it back in to the dump data, since
416                 // that is where the caller expects all interesting information to
417                 // go.
418                 pw.println();
419                 pw.println("Exception occurred while dumping:");
420                 e.printStackTrace(pw);
421             }
422         } else {
423             pw.println(sDumpDisabled);
424         }
425     }
426 
427     /**
428      * Like {@link #dump(FileDescriptor, String[])}, but ensures the target
429      * executes asynchronously.
430      */
dumpAsync(final FileDescriptor fd, final String[] args)431     public void dumpAsync(final FileDescriptor fd, final String[] args) {
432         final FileOutputStream fout = new FileOutputStream(fd);
433         final PrintWriter pw = new FastPrintWriter(fout);
434         Thread thr = new Thread("Binder.dumpAsync") {
435             public void run() {
436                 try {
437                     dump(fd, pw, args);
438                 } finally {
439                     pw.flush();
440                 }
441             }
442         };
443         thr.start();
444     }
445 
446     /**
447      * Print the object's state into the given stream.
448      *
449      * @param fd The raw file descriptor that the dump is being sent to.
450      * @param fout The file to which you should dump your state.  This will be
451      * closed for you after you return.
452      * @param args additional arguments to the dump request.
453      */
dump(FileDescriptor fd, PrintWriter fout, String[] args)454     protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
455     }
456 
457     /**
458      * @param in The raw file descriptor that an input data stream can be read from.
459      * @param out The raw file descriptor that normal command messages should be written to.
460      * @param err The raw file descriptor that command error messages should be written to.
461      * @param args Command-line arguments.
462      * @param resultReceiver Called when the command has finished executing, with the result code.
463      * @throws RemoteException
464      * @hide
465      */
shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ResultReceiver resultReceiver)466     public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
467             String[] args, ResultReceiver resultReceiver) throws RemoteException {
468         onShellCommand(in, out, err, args, resultReceiver);
469     }
470 
471     /**
472      * Handle a call to {@link #shellCommand}.  The default implementation simply prints
473      * an error message.  Override and replace with your own.
474      * <p class="caution">Note: no permission checking is done before calling this method; you must
475      * apply any security checks as appropriate for the command being executed.
476      * Consider using {@link ShellCommand} to help in the implementation.</p>
477      * @hide
478      */
onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ResultReceiver resultReceiver)479     public void onShellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
480             String[] args, ResultReceiver resultReceiver) throws RemoteException {
481         FileOutputStream fout = new FileOutputStream(err != null ? err : out);
482         PrintWriter pw = new FastPrintWriter(fout);
483         pw.println("No shell command implementation.");
484         pw.flush();
485         resultReceiver.send(0, null);
486     }
487 
488     /**
489      * Default implementation rewinds the parcels and calls onTransact.  On
490      * the remote side, transact calls into the binder to do the IPC.
491      */
transact(int code, Parcel data, Parcel reply, int flags)492     public final boolean transact(int code, Parcel data, Parcel reply,
493             int flags) throws RemoteException {
494         if (false) Log.v("Binder", "Transact: " + code + " to " + this);
495 
496         if (data != null) {
497             data.setDataPosition(0);
498         }
499         boolean r = onTransact(code, data, reply, flags);
500         if (reply != null) {
501             reply.setDataPosition(0);
502         }
503         return r;
504     }
505 
506     /**
507      * Local implementation is a no-op.
508      */
linkToDeath(DeathRecipient recipient, int flags)509     public void linkToDeath(DeathRecipient recipient, int flags) {
510     }
511 
512     /**
513      * Local implementation is a no-op.
514      */
unlinkToDeath(DeathRecipient recipient, int flags)515     public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
516         return true;
517     }
518 
finalize()519     protected void finalize() throws Throwable {
520         try {
521             destroy();
522         } finally {
523             super.finalize();
524         }
525     }
526 
checkParcel(IBinder obj, int code, Parcel parcel, String msg)527     static void checkParcel(IBinder obj, int code, Parcel parcel, String msg) {
528         if (CHECK_PARCEL_SIZE && parcel.dataSize() >= 800*1024) {
529             // Trying to send > 800k, this is way too much
530             StringBuilder sb = new StringBuilder();
531             sb.append(msg);
532             sb.append(": on ");
533             sb.append(obj);
534             sb.append(" calling ");
535             sb.append(code);
536             sb.append(" size ");
537             sb.append(parcel.dataSize());
538             sb.append(" (data: ");
539             parcel.setDataPosition(0);
540             sb.append(parcel.readInt());
541             sb.append(", ");
542             sb.append(parcel.readInt());
543             sb.append(", ");
544             sb.append(parcel.readInt());
545             sb.append(")");
546             Slog.wtfStack(TAG, sb.toString());
547         }
548     }
549 
init()550     private native final void init();
destroy()551     private native final void destroy();
552 
553     // Entry point from android_util_Binder.cpp's onTransact
execTransact(int code, long dataObj, long replyObj, int flags)554     private boolean execTransact(int code, long dataObj, long replyObj,
555             int flags) {
556         Parcel data = Parcel.obtain(dataObj);
557         Parcel reply = Parcel.obtain(replyObj);
558         // theoretically, we should call transact, which will call onTransact,
559         // but all that does is rewind it, and we just got these from an IPC,
560         // so we'll just call it directly.
561         boolean res;
562         // Log any exceptions as warnings, don't silently suppress them.
563         // If the call was FLAG_ONEWAY then these exceptions disappear into the ether.
564         try {
565             res = onTransact(code, data, reply, flags);
566         } catch (RemoteException|RuntimeException e) {
567             if (LOG_RUNTIME_EXCEPTION) {
568                 Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
569             }
570             if ((flags & FLAG_ONEWAY) != 0) {
571                 if (e instanceof RemoteException) {
572                     Log.w(TAG, "Binder call failed.", e);
573                 } else {
574                     Log.w(TAG, "Caught a RuntimeException from the binder stub implementation.", e);
575                 }
576             } else {
577                 reply.setDataPosition(0);
578                 reply.writeException(e);
579             }
580             res = true;
581         } catch (OutOfMemoryError e) {
582             // Unconditionally log this, since this is generally unrecoverable.
583             Log.e(TAG, "Caught an OutOfMemoryError from the binder stub implementation.", e);
584             RuntimeException re = new RuntimeException("Out of memory", e);
585             reply.setDataPosition(0);
586             reply.writeException(re);
587             res = true;
588         }
589         checkParcel(this, code, reply, "Unreasonably large binder reply buffer");
590         reply.recycle();
591         data.recycle();
592 
593         // Just in case -- we are done with the IPC, so there should be no more strict
594         // mode violations that have gathered for this thread.  Either they have been
595         // parceled and are now in transport off to the caller, or we are returning back
596         // to the main transaction loop to wait for another incoming transaction.  Either
597         // way, strict mode begone!
598         StrictMode.clearGatheredViolations();
599 
600         return res;
601     }
602 }
603 
604 final class BinderProxy implements IBinder {
pingBinder()605     public native boolean pingBinder();
isBinderAlive()606     public native boolean isBinderAlive();
607 
queryLocalInterface(String descriptor)608     public IInterface queryLocalInterface(String descriptor) {
609         return null;
610     }
611 
transact(int code, Parcel data, Parcel reply, int flags)612     public boolean transact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
613         Binder.checkParcel(this, code, data, "Unreasonably large binder buffer");
614         if (Binder.isTracingEnabled()) { Binder.getTransactionTracker().addTrace(); }
615         return transactNative(code, data, reply, flags);
616     }
617 
getInterfaceDescriptor()618     public native String getInterfaceDescriptor() throws RemoteException;
transactNative(int code, Parcel data, Parcel reply, int flags)619     public native boolean transactNative(int code, Parcel data, Parcel reply,
620             int flags) throws RemoteException;
linkToDeath(DeathRecipient recipient, int flags)621     public native void linkToDeath(DeathRecipient recipient, int flags)
622             throws RemoteException;
unlinkToDeath(DeathRecipient recipient, int flags)623     public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
624 
dump(FileDescriptor fd, String[] args)625     public void dump(FileDescriptor fd, String[] args) throws RemoteException {
626         Parcel data = Parcel.obtain();
627         Parcel reply = Parcel.obtain();
628         data.writeFileDescriptor(fd);
629         data.writeStringArray(args);
630         try {
631             transact(DUMP_TRANSACTION, data, reply, 0);
632             reply.readException();
633         } finally {
634             data.recycle();
635             reply.recycle();
636         }
637     }
638 
dumpAsync(FileDescriptor fd, String[] args)639     public void dumpAsync(FileDescriptor fd, String[] args) throws RemoteException {
640         Parcel data = Parcel.obtain();
641         Parcel reply = Parcel.obtain();
642         data.writeFileDescriptor(fd);
643         data.writeStringArray(args);
644         try {
645             transact(DUMP_TRANSACTION, data, reply, FLAG_ONEWAY);
646         } finally {
647             data.recycle();
648             reply.recycle();
649         }
650     }
651 
shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err, String[] args, ResultReceiver resultReceiver)652     public void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,
653             String[] args, ResultReceiver resultReceiver) throws RemoteException {
654         Parcel data = Parcel.obtain();
655         Parcel reply = Parcel.obtain();
656         data.writeFileDescriptor(in);
657         data.writeFileDescriptor(out);
658         data.writeFileDescriptor(err);
659         data.writeStringArray(args);
660         resultReceiver.writeToParcel(data, 0);
661         try {
662             transact(SHELL_COMMAND_TRANSACTION, data, reply, 0);
663             reply.readException();
664         } finally {
665             data.recycle();
666             reply.recycle();
667         }
668     }
669 
BinderProxy()670     BinderProxy() {
671         mSelf = new WeakReference(this);
672     }
673 
674     @Override
finalize()675     protected void finalize() throws Throwable {
676         try {
677             destroy();
678         } finally {
679             super.finalize();
680         }
681     }
682 
destroy()683     private native final void destroy();
684 
sendDeathNotice(DeathRecipient recipient)685     private static final void sendDeathNotice(DeathRecipient recipient) {
686         if (false) Log.v("JavaBinder", "sendDeathNotice to " + recipient);
687         try {
688             recipient.binderDied();
689         }
690         catch (RuntimeException exc) {
691             Log.w("BinderNative", "Uncaught exception from death notification",
692                     exc);
693         }
694     }
695 
696     final private WeakReference mSelf;
697     private long mObject;
698     private long mOrgue;
699 }
700