@@ -222,23 +222,67 @@ func (d *Driver) Transact(
222222 readBuffer : uint64 (uintptr (unsafe .Pointer (& readBuf [0 ]))),
223223 }
224224
225- _ , _ , errno := unix .Syscall (
226- unix .SYS_IOCTL ,
227- uintptr (d .fd ),
228- binderWriteReadIoctl ,
229- uintptr (unsafe .Pointer (& bwr )),
230- )
231- if errno != 0 {
232- return nil , & aidlerrors.BinderError {Op : "ioctl(BINDER_WRITE_READ)" , Err : errno }
225+ for {
226+ _ , _ , errno := unix .Syscall (
227+ unix .SYS_IOCTL ,
228+ uintptr (d .fd ),
229+ binderWriteReadIoctl ,
230+ uintptr (unsafe .Pointer (& bwr )),
231+ )
232+ switch errno {
233+ case 0 :
234+ // Success — proceed to parse.
235+ case unix .EINTR :
236+ // Retry on interrupted system call.
237+ // Reset write buffer (already consumed) but keep read buffer.
238+ bwr .writeSize = 0
239+ continue
240+ default :
241+ return nil , & aidlerrors.BinderError {Op : "ioctl(BINDER_WRITE_READ)" , Err : errno }
242+ }
243+ break
233244 }
234245
235- // Parse the read buffer for BR codes.
236- reply , err := d .parseReadBuffer (ctx , readBuf [:bwr .readConsumed ])
237- if err != nil {
238- return nil , err
239- }
246+ // Parse the read buffer for BR codes. The kernel may split
247+ // BR_TRANSACTION_COMPLETE and BR_REPLY across separate ioctl reads —
248+ // if we got TC but no reply yet, read again to wait for BR_REPLY.
249+ isOneway := flags & binder .FlagOneway != 0
250+ for {
251+ reply , err := d .parseReadBuffer (ctx , readBuf [:bwr .readConsumed ])
252+ if err != nil {
253+ return nil , err
254+ }
240255
241- return reply , nil
256+ // If we got a non-empty reply, or this is a oneway transaction
257+ // (which never gets BR_REPLY), return immediately.
258+ if reply .Len () > 0 || isOneway {
259+ return reply , nil
260+ }
261+
262+ // Empty reply on a non-oneway transaction means the kernel sent
263+ // BR_TRANSACTION_COMPLETE but BR_REPLY hasn't arrived yet.
264+ // Issue a read-only ioctl to wait for it.
265+ logger .Debugf (ctx , "Transact: got BR_TRANSACTION_COMPLETE without BR_REPLY, reading again" )
266+ bwr .writeSize = 0
267+ bwr .writeConsumed = 0
268+ bwr .readConsumed = 0
269+ for {
270+ _ , _ , errno := unix .Syscall (
271+ unix .SYS_IOCTL ,
272+ uintptr (d .fd ),
273+ binderWriteReadIoctl ,
274+ uintptr (unsafe .Pointer (& bwr )),
275+ )
276+ switch errno {
277+ case 0 :
278+ case unix .EINTR :
279+ continue
280+ default :
281+ return nil , & aidlerrors.BinderError {Op : "ioctl(BINDER_WRITE_READ/read)" , Err : errno }
282+ }
283+ break
284+ }
285+ }
242286}
243287
244288// parseReadBuffer processes BR_* codes from the read buffer and returns the reply parcel.
@@ -496,17 +540,24 @@ func (d *Driver) writeCommand(
496540 writeBuffer : uint64 (uintptr (unsafe .Pointer (& writeBuf [0 ]))),
497541 }
498542
499- _ , _ , errno := unix .Syscall (
500- unix .SYS_IOCTL ,
501- uintptr (d .fd ),
502- binderWriteReadIoctl ,
503- uintptr (unsafe .Pointer (& bwr )),
504- )
505- if errno != 0 {
506- return & aidlerrors.BinderError {Op : "ioctl(BINDER_WRITE_READ)" , Err : errno }
543+ for {
544+ _ , _ , errno := unix .Syscall (
545+ unix .SYS_IOCTL ,
546+ uintptr (d .fd ),
547+ binderWriteReadIoctl ,
548+ uintptr (unsafe .Pointer (& bwr )),
549+ )
550+ switch errno {
551+ case 0 :
552+ return nil
553+ case unix .EINTR :
554+ // Retry on interrupted system call — the command was not
555+ // processed and must be resent.
556+ continue
557+ default :
558+ return & aidlerrors.BinderError {Op : "ioctl(BINDER_WRITE_READ)" , Err : errno }
559+ }
507560 }
508-
509- return nil
510561}
511562
512563// copyStructToBytes copies a struct's raw memory into a byte slice.
0 commit comments