private static int PatchReadTransaction(Thread current, Pointer marshaledBufferStart, ref binder_transaction_data tr)
        {
            if (tr.data_size != 0)
                tr.data_buffer += current.Parent.binderVMStart.Value.ToUInt32();

            if (tr.offsets_size != 0)
                tr.data_offsets += current.Parent.binderVMStart.Value.ToUInt32();

            if (GainingWindowFocus(current, tr))
                Globals.SecurityManager.OnActiveProcessChanged(current.Parent);

            for (var off_ptr = tr.data_offsets; off_ptr < tr.data_offsets + tr.offsets_size; off_ptr += 4)
            {
                var fp = new flat_binder_object();
                int off;
                if (off_ptr.Read(current, out off) != 0)
                {
                    Arch.Console.Write("Can't get offset");
                    return -1;
                }

                var fp_ptr = tr.data_buffer + off;
                if (fp_ptr.Read(current, out fp) != 0)
                {
                    Arch.Console.Write("Read fp failed, ptr:");
                    Arch.Console.Write(fp_ptr.Value.ToInt32());
                    Arch.Console.WriteLine();
                    return -1;
                }

                //Arch.Console.Write("off_ptr:");
                //Arch.Console.Write(tr->data_offsets.Value.ToUInt32());
                //Arch.Console.Write(" Off end:");
                //Arch.Console.Write((tr->data_offsets + tr->offsets_size).Value.ToUInt32());
                //Arch.Console.WriteLine();

                switch (fp.type)
                {
                    case BinderINode.BINDER_TYPE_FD:
                        {
                            var proc = current.Parent;
                            var linux_fd = fp.binderOrHandle.Value.ToInt32();

                            GenericINode inode;
                            if (IsScreenSharingTransaction(current, ref tr))
                                inode = new ScreenBufferINode(linux_fd, proc.helperPid);
                            else
                                inode = new BinderSharedINode(linux_fd, proc.helperPid);

                            int fd = proc.GetUnusedFd();
                            proc.InstallFd(fd, new File(proc, inode, FileSystem.O_RDWR, 0));
                            // Patch the data structure
                            (fp_ptr + flat_binder_object.OFFSET_OF_HANDLE).Write(current, fd);
                        }
                        break;

                    case BinderINode.BINDER_TYPE_HANDLE:
                        // sliently ignore it (it seems safe)
                        break;

                    default:
                        Arch.Console.Write("BinderINode::PatchReadTransaction ignoring ");
                        Arch.Console.Write(fp.type);
                        Arch.Console.WriteLine();
                        break;
                }
            }

            return 0;
        }
        private static int PatchReadTransaction(Thread current, Pointer marshaledBufferStart, ref binder_transaction_data tr)
        {
            Contract.Requires(current.Parent != null);

            if (tr.data_size != 0)
            {
                tr.data_buffer += current.Parent.binderVMStart.Value.ToUInt32();
            }

            if (tr.offsets_size != 0)
            {
                tr.data_offsets += current.Parent.binderVMStart.Value.ToUInt32();
            }

            if (GainingWindowFocus(current, tr))
            {
                Globals.SecurityManager.OnActiveProcessChanged(current.Parent);
            }

            for (var off_ptr = tr.data_offsets; off_ptr < tr.data_offsets + tr.offsets_size; off_ptr += 4)
            {
                var fp = new flat_binder_object();
                int off;
                if (off_ptr.Read(current, out off) != 0)
                {
                    Arch.Console.Write("Can't get offset");
                    return(-1);
                }

                var fp_ptr = tr.data_buffer + off;
                if (fp_ptr.Read(current, out fp) != 0)
                {
                    Arch.Console.Write("Read fp failed, ptr:");
                    Arch.Console.Write(fp_ptr.Value.ToInt32());
                    Arch.Console.WriteLine();
                    return(-1);
                }

                //Arch.Console.Write("off_ptr:");
                //Arch.Console.Write(tr->data_offsets.Value.ToUInt32());
                //Arch.Console.Write(" Off end:");
                //Arch.Console.Write((tr->data_offsets + tr->offsets_size).Value.ToUInt32());
                //Arch.Console.WriteLine();

                switch (fp.type)
                {
                case BinderINode.BINDER_TYPE_FD:
                {
                    var proc     = current.Parent;
                    var linux_fd = fp.binderOrHandle.Value.ToInt32();

                    GenericINode inode;
                    if (IsScreenSharingTransaction(current, ref tr))
                    {
                        inode = new ScreenBufferINode(linux_fd, proc.helperPid);
                    }
                    else
                    {
                        inode = new BinderSharedINode(linux_fd, proc.helperPid);
                    }

                    int fd = proc.GetUnusedFd();
                    proc.InstallFd(fd, new File(proc, inode, FileSystem.O_RDWR, 0));
                    // Patch the data structure
                    (fp_ptr + flat_binder_object.OFFSET_OF_HANDLE).Write(current, fd);
                }
                break;

                case BinderINode.BINDER_TYPE_HANDLE:
                    // sliently ignore it (it seems safe)
                    break;

                default:
                    Arch.Console.Write("BinderINode::PatchReadTransaction ignoring ");
                    Arch.Console.Write(fp.type);
                    Arch.Console.WriteLine();
                    break;
                }
            }

            return(0);
        }