Home | History | Annotate | Download | only in os
      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      */
     99     public static void  enableTracing() {
    100         sTracingEnabled = true;
    101     };
    102 
    103     /**
    104      * Disable Binder IPC tracing.
    105      *
    106      * @hide
    107      */
    108     public static void  disableTracing() {
    109         sTracingEnabled = false;
    110     }
    111 
    112     /**
    113      * Check if binder transaction tracing is enabled.
    114      *
    115      * @hide
    116      */
    117     public static boolean isTracingEnabled() {
    118         return sTracingEnabled;
    119     }
    120 
    121     /**
    122      * Get the binder transaction tracker for this process.
    123      *
    124      * @hide
    125      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    234     public static final native void joinThreadPool();
    235 
    236     /**
    237      * Returns true if the specified interface is a proxy.
    238      * @hide
    239      */
    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      */
    249     public static final native void blockUntilThreadAvailable();
    250 
    251     /**
    252      * Default constructor initializes the object.
    253      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    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 
    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      */
    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      */
    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      */
    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      */
    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      */
    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      */
    509     public void linkToDeath(DeathRecipient recipient, int flags) {
    510     }
    511 
    512     /**
    513      * Local implementation is a no-op.
    514      */
    515     public boolean unlinkToDeath(DeathRecipient recipient, int flags) {
    516         return true;
    517     }
    518 
    519     protected void finalize() throws Throwable {
    520         try {
    521             destroy();
    522         } finally {
    523             super.finalize();
    524         }
    525     }
    526 
    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 
    550     private native final void init();
    551     private native final void destroy();
    552 
    553     // Entry point from android_util_Binder.cpp's onTransact
    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 {
    605     public native boolean pingBinder();
    606     public native boolean isBinderAlive();
    607 
    608     public IInterface queryLocalInterface(String descriptor) {
    609         return null;
    610     }
    611 
    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 
    618     public native String getInterfaceDescriptor() throws RemoteException;
    619     public native boolean transactNative(int code, Parcel data, Parcel reply,
    620             int flags) throws RemoteException;
    621     public native void linkToDeath(DeathRecipient recipient, int flags)
    622             throws RemoteException;
    623     public native boolean unlinkToDeath(DeathRecipient recipient, int flags);
    624 
    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 
    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 
    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 
    670     BinderProxy() {
    671         mSelf = new WeakReference(this);
    672     }
    673 
    674     @Override
    675     protected void finalize() throws Throwable {
    676         try {
    677             destroy();
    678         } finally {
    679             super.finalize();
    680         }
    681     }
    682 
    683     private native final void destroy();
    684 
    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