FAILED BINDER TRANSACTION

1.异常Log Pattern


BroadcastQueue: Can't deliver broadcast to com.my.app (pid 8047). Crashing it.
ActivityManager: Killing 8047:com.my.demo/1000 (adj 0): scheduleCrash for 'can't deliver broadcast' failed
BroadcastQueue: Failure sending broadcast Intent { act=android.intent.action.BATTERY_CHANGED flg=0x60000010 (has extras) }
BroadcastQueue: android.os.DeadObjectException: Transaction failed on small parcel; remote process probably died
BroadcastQueue:     at android.os.BinderProxy.transactNative(Native Method)
BroadcastQueue:     at android.os.BinderProxy.transact(Binder.java:764)
BroadcastQueue:     at android.app.IApplicationThread$Stub$Proxy.scheduleRegisteredReceiver(IApplicationThread.java:1560)
BroadcastQueue:     at com.android.server.am.BroadcastQueue.performReceiveLocked(BroadcastQueue.java:491)
BroadcastQueue:     at com.android.server.am.BroadcastQueue.deliverToRegisteredReceiverLocked(BroadcastQueue.java:703)
BroadcastQueue:     at com.android.server.am.BroadcastQueue.processNextBroadcast(BroadcastQueue.java:858)
BroadcastQueue:     at com.android.server.am.BroadcastQueue$BroadcastHandler.handleMessage(BroadcastQueue.java:171)
BroadcastQueue:     at android.os.Handler.dispatchMessage(Handler.java:106)
BroadcastQueue:     at android.os.Looper.loop(Looper.java:164)
BroadcastQueue:     at android.os.HandlerThread.run(HandlerThread.java:65)
BroadcastQueue:     at com.android.server.ServiceThread.run(ServiceThread.java:46)

2.Crash的过程

出现两种情况
1.data parcel size大于2m 200×1024
2.异常 主要两种 deadobjectexception 调用的进程死掉了
另外为其他异常

@frameworks/base/core/jni/android_util_Binder.cpp
void signalExceptionForError(JNIEnv* env, jobject obj, status_t err,
        bool canThrowRemoteException, int parcelSize)
case FAILED_TRANSACTION: {
    ALOGE("!!! FAILED BINDER TRANSACTION !!!  (parcel size = %d)", parcelSize);
    if (canThrowRemoteException && parcelSize > 200*1024) {
        // bona fide large payload
        exceptionToThrow = "android/os/TransactionTooLargeException";
        snprintf(msg, sizeof(msg)-1, "data parcel size %d bytes", parcelSize);
    } else {
        // Heuristic: a payload smaller than this threshold "shouldn't" be too
        // big, so it's probably some other, more subtle problem.  In practice
        // it seems to always mean that the remote process died while the binder
        // transaction was already in flight.
        exceptionToThrow = (canThrowRemoteException)
                ? "android/os/DeadObjectException"
                : "java/lang/RuntimeException";
        snprintf(msg, sizeof(msg)-1,
                "Transaction failed on small parcel; remote process probably died");
    }
    jniThrowException(env, exceptionToThrow, msg);
} break;

//performReceiveLocked报错并且crash app
@BroadcastQueue.java
482    void performReceiveLocked(ProcessRecord app, IIntentReceiver receiver,
483            Intent intent, int resultCode, String data, Bundle extras,
484            boolean ordered, boolean sticky, int sendingUser) throws RemoteException {
485        // Send the intent to the receiver asynchronously using one-way binder calls.
486        if (app != null) {
487            if (app.thread != null) {
488                // If we have an app thread, do the call through that so it is
489                // correctly ordered with other one-way calls.
490                try {
491                    app.thread.scheduleRegisteredReceiver(receiver, intent, resultCode,
492                            data, extras, ordered, sticky, sendingUser, app.repProcState);
493                // TODO: Uncomment this when (b/28322359) is fixed and we aren't getting
494                // DeadObjectException when the process isn't actually dead.
495                //} catch (DeadObjectException ex) {
496                // Failed to call into the process.  It's dying so just let it die and move on.
497                //    throw ex;
498                } catch (RemoteException ex) {
499                    // Failed to call into the process. It's either dying or wedged. Kill it gently.
500                    synchronized (mService) {
501                        Slog.w(TAG, "Can't deliver broadcast to " + app.processName
502                                + " (pid " + app.pid + "). Crashing it.");  //here
503                        app.scheduleCrash("can't deliver broadcast");  //crash app
504                    }
505                    throw ex;
506                }
507            } else {
508                // Application has died. Receiver doesn't exist.
509                throw new RemoteException("app.thread must not be null");
510            }
511        } else {
512            receiver.performReceive(intent, resultCode, data, extras, ordered,
513                    sticky, sendingUser);
514        }
515    }

@frameworks/base/services/core/java/com/android/server/am/ProcessRecord.java
void scheduleCrash(String message) {
    // Checking killedbyAm should keep it from showing the crash dialog if the process
    // was already dead for a good / normal reason.
    if (!killedByAm) {
        if (thread != null) {
            if (pid == Process.myPid()) {
                Slog.w(TAG, "scheduleCrash: trying to crash system process!");
                return;
            }
            long ident = Binder.clearCallingIdentity();
            try {
                thread.scheduleCrash(message); //throw RemoteServiceException然后kill
            } catch (RemoteException e) {
                // If it's already dead our work is done. If it's wedged just kill it.
                // We won't get the crash dialog or the error reporting.
                kill("scheduleCrash for '" + message + "' failed", true);
            } finally {
                Binder.restoreCallingIdentity(ident);
            }
        }
    }
}

void kill(String reason, boolean noisy) {
    if (!killedByAm) {
        Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "kill");
        if (noisy) {
            Slog.i(TAG, "Killing " + toShortString() + " (adj " + setAdj + "): " + reason);
        }
        EventLog.writeEvent(EventLogTags.AM_KILL, userId, pid, processName, setAdj, reason);
        Process.killProcessQuiet(pid);
        ActivityManagerService.killProcessGroup(uid, pid);
        if (!persistent) {
            killed = true;
            killedByAm = true;
        }
        Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
    }
}

@frameworks/base/core/java/android/app/ActivityThread.java
public void scheduleCrash(String msg) {
    sendMessage(H.SCHEDULE_CRASH, msg);
}
1767                case SCHEDULE_CRASH:
1768                    throw new RemoteServiceException((String)msg.obj);

3.Binder错误信息kernel log

@binder.c
4067err_alloc_t_failed:
4068err_bad_call_stack:
4069err_empty_call_stack:
4070err_dead_binder:
4071err_invalid_target_handle:
...
4081	binder_debug(BINDER_DEBUG_FAILED_TRANSACTION,
4082	     "%d:%d transaction failed %d/%d, size %lld-%lld line %d\n",
4083	     proc->pid, thread->pid, return_error, return_error_param,
4084	     (u64)tr->data_size, (u64)tr->offsets_size,
4085	     return_error_line);

11-25 09:31:23.786059  1052  1052 I [128416.232769](6)[1052:ActivityManager]binder: 1025:1052 transaction failed 29201/-28, size 792-8 line 3781

那么问题来了,这个过程也是使用binder.
同样是systemserver向应用发送,为什么之前不成功,现在可以了,因为当时空间不够,后面可能够了

return_error --> 29201 --> BR_FAILED_REPLY 
return_error_param  --> 28 --> ENOSPC    /* No space left on device */
31#define    ENOSPC    28    /* No space left on device */

还有些错是parcel太大导致,这里是没有空间,可能注册广播太多,注销慢,或者逻辑错误,也可能是进程死了
还可以可能比如systemserver的线程都在做数据库之类的blocked

4.其他例子

https://ask.csdn.net/questions/682317

java.lang.RuntimeException: android.os.TransactionTooLargeException: data parcel size 3625220 bytes
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3982)
at android.os.Handler.handleCallback(Handler.java:761)
at android.os.Handler.dispatchMessage(Handler.java:98)
at android.os.Looper.loop(Looper.java:156)
at android.app.ActivityThread.main(ActivityThread.java:6523)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:942)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:832)
Caused by: android.os.TransactionTooLargeException: data parcel size 3625220 bytes
at android.os.BinderProxy.transactNative(Native Method)
at android.os.BinderProxy.transact(Binder.java:617)
at android.app.ActivityManagerProxy.activityStopped(ActivityManagerNative.java:3632)
at android.app.ActivityThread$StopInfo.run(ActivityThread.java:3974)

 

 

 

你可能感兴趣的:(Android,Binder)