binder_rust/
binder.rs

1use crate::{
2    parcel::Parcel
3};
4
5use nix::{
6    fcntl::{
7        OFlag,
8        open,
9    },
10    ioctl_readwrite,
11    ioctl_write_int,
12    ioctl_write_ptr,
13    sys::{
14        mman::{
15            MapFlags,
16            mmap,
17            ProtFlags,
18        },
19        stat::Mode,
20    },
21    unistd::close,
22};
23
24use std::{convert::TryFrom, ffi::c_void, mem::size_of, ops::BitOr, os::unix::io::RawFd, ptr, slice};
25
26use num_traits::FromPrimitive;
27
28
29/// The binder device name
30const DEVICE: &str = "/dev/binder";
31
32/// The default maximum number of threads to support
33const DEFAULT_MAX_BINDER_THREADS: u32 = 15;
34
35const PAGE_SIZE: usize = 0x1000;
36const BINDER_VM_SIZE: usize =  (1 * 1024 * 1024) - PAGE_SIZE * 2;
37
38
39macro_rules! pack_chars {
40    ($c1:expr, $c2:expr, $c3:expr, $c4:expr) => {
41        (((($c1 as u32) << 24)) | ((($c2 as u32) << 16)) | ((($c3 as u32) << 8)) | ($c4 as u32))
42    };
43}
44
45const BINDER_TYPE_LARGE: u8 = 0x85;
46
47const TF_BINDER: u32 = pack_chars!(b's', b'b', b'*', BINDER_TYPE_LARGE);
48const TF_WEAKBINDER: u32 = pack_chars!(b'w', b'b', b'*', BINDER_TYPE_LARGE);
49const TF_HANDLE: u32 = pack_chars!(b's', b'h', b'*', BINDER_TYPE_LARGE);
50const TF_WEAKHANDLE: u32 = pack_chars!(b'w', b'h', b'*', BINDER_TYPE_LARGE);
51const TF_FD: u32 = pack_chars!(b'f', b'd', b'*', BINDER_TYPE_LARGE);
52const TF_FDA: u32 = pack_chars!(b'f', b'd', b'a', BINDER_TYPE_LARGE);
53const TF_PTR: u32 = pack_chars!(b'p', b't', b'*', BINDER_TYPE_LARGE);
54
55#[repr(u32)]
56#[derive(Debug, Hash, Clone, Copy, PartialEq, FromPrimitive)]
57pub enum BinderType {
58    Binder = TF_BINDER,
59    WeakBinder = TF_WEAKBINDER,
60    Handle = TF_HANDLE,
61    WeakHandle = TF_WEAKHANDLE,
62    Fd = TF_FD,
63    Fda = TF_FDA,
64    Ptr = TF_PTR,
65}
66
67
68#[repr(C)]
69#[derive(Debug)]
70pub struct BinderFlatObject {
71    pub(crate) binder_type: BinderType,
72    flags: u32,
73    pub(crate) handle: *const c_void,
74    cookie: *const c_void,
75}
76
77impl BinderFlatObject {
78    pub fn new(binder_type: BinderType, handle: usize, cookie: usize, flags: u32) -> Self {
79        Self {
80            binder_type,
81            flags,
82            handle: handle as *const c_void,
83            cookie: cookie as *const c_void,
84        }
85
86    }
87
88    pub fn handle(&self) -> *const c_void {
89        self.handle
90    }
91
92    pub fn cookie(&self) -> *const c_void {
93        self.cookie
94    }
95}
96
97const PING_TRANSCATION: u32 = pack_chars!(b'_', b'P',b'N',b'G');
98const DUMP_TRANSACTION: u32 = pack_chars!(b'_', b'D', b'M', b'P');
99const SHELL_COMMAND_TRANSACTION: u32 = pack_chars!(b'_', b'C', b'M', b'D');
100const INTERFACE_TRANSACTION: u32 = pack_chars!(b'_', b'N', b'T', b'F');
101const SYSPROPS_TRANSACTION: u32 = pack_chars!(b'_', b'S', b'P', b'R');
102const EXTENSION_TRANSACTION: u32 = pack_chars!(b'_', b'E', b'X', b'T');
103const DEBUG_PID_TRANSACTION: u32 = pack_chars!(b'_', b'P', b'I', b'D');
104const TWEET_TRANSACTION: u32 = pack_chars!(b'_', b'T', b'W', b'T');
105const LIKE_TRANSACTION: u32 = pack_chars!(b'_', b'L', b'I', b'K');
106
107#[repr(u32)]
108#[derive(Debug, FromPrimitive)]
109pub enum Transaction {
110    FirstCall = 1,
111    LastCall = 0xffffff,
112    Ping = PING_TRANSCATION,
113    Dump = DUMP_TRANSACTION,
114    ShellCommand = SHELL_COMMAND_TRANSACTION,
115    Interface = INTERFACE_TRANSACTION,
116    Sysprops = SYSPROPS_TRANSACTION,
117    Extension = EXTENSION_TRANSACTION,
118    DebugPid = DEBUG_PID_TRANSACTION,
119    Tweet = TWEET_TRANSACTION,
120    Like = LIKE_TRANSACTION,
121}
122
123/// A structure representing the binder version
124#[repr(C)]
125pub struct BinderVersion {
126    protocol_version: i32,
127}
128
129
130#[repr(C)]
131pub struct BinderWriteRead {
132    write_size: usize,
133    write_consumed: usize,
134    write_buffer: *const c_void,
135    read_size: usize,
136    read_consumed: usize,
137    read_buffer: *mut c_void,
138}
139
140impl BinderWriteRead {
141    pub fn write_size (&self) -> usize {
142        self.write_size
143    }
144    pub fn write_consumed (&self) -> usize {
145        self.write_consumed
146    }
147    pub fn read_size (&self) -> usize {
148        self.read_size
149    }
150    pub fn read_consumed (&self) -> usize {
151        self.read_consumed
152    }
153    pub fn write_buffer (&self) -> *const c_void {
154
155        self.write_buffer
156    }
157    pub fn read_buffer (&self) -> *mut c_void {
158        self.read_buffer
159    }
160}
161#[repr(C)]
162pub(crate) struct BinderTransactionDataData {
163}
164#[repr(C)]
165#[derive(Debug)]
166pub struct BinderTransactionData {
167    target: u32,
168    cookie: u64,
169    code: u32,
170    flags: u32,
171    sender_pid: u32,
172    sender_euid: u32,
173    data_size: u64,
174    offset_size: u64,
175    data: *mut u8,
176    offsets: *mut usize,
177}
178
179impl BinderTransactionData {
180    pub fn code(&self) -> u32 {
181        self.code
182    }
183    pub fn cookie(&self) -> u64 {
184        self.cookie
185    }
186
187    pub fn target(&self) -> u32 {
188        self.target
189    }
190
191    pub fn flags(&self) -> TransactionFlags {
192        TransactionFlags::from_bits(self.flags).unwrap()
193    }
194
195    pub unsafe fn raw_data(&self) -> &[u8] {
196        std::slice::from_raw_parts(self.data, self.data_size as usize)
197    }
198
199    pub fn parcel(&self) -> Parcel {
200        unsafe { Parcel::from_slice(self.raw_data()) }
201    }
202}
203
204enum Result {
205    InvalidOperation,
206    NoError,
207}
208
209ioctl_readwrite!(binder_write_read, b'b', 1, BinderWriteRead);
210ioctl_write_ptr!(binder_set_max_threads, b'b', 5, u32);
211ioctl_readwrite!(binder_read_version, b'b', 9, BinderVersion);
212
213bitflags! {
214    pub struct TransactionFlags: u32 {
215        const OneWay = 1;
216        const CollectNotedAppOps = 2;
217        const RootObject = 4;
218        const StatusCode = 8;
219        const AcceptFds = 0x10;
220        const ClearBuf = 0x20;
221    }
222}
223
224macro_rules! _iow {
225    ($c1:expr, $c2:expr, $c3:expr) => {
226        (((0x40 << 24)) | ((($c3 as u32) << 16)) | ((($c1 as u32) << 8)) | ($c2 as u32))
227    };
228}
229
230macro_rules! _ior {
231    ($c1:expr, $c2:expr, $c3:expr) => {
232        (((0x80 << 24)) | ((($c3 as u32) << 16)) | ((($c1 as u32) << 8)) | ($c2 as u32))
233    };
234}
235
236macro_rules! _io {
237    ($c1:expr, $c2:expr) => {
238        (((($c1 as u32) << 8)) | ($c2 as u32))
239    };
240}
241
242const BC_TRANSACTION: u32 = _iow!(b'c', 0, 0x40);
243const BC_REPLY: u32 = _iow!(b'c', 1, 0x40);
244const BC_ACQUIRE_RESULT: u32 = _iow!(b'c', 2, 0x4);
245const BC_FREE_BUFFER: u32 = _iow!(b'c', 3, 0x8);
246const BC_INCREFS: u32 = _iow!(b'c', 4, 0x4);
247const BC_ACQUIRE: u32 = _iow!(b'c', 5, 0x4);
248const BC_RELEASE: u32 = _iow!(b'c', 6, 0x4);
249const BC_DECREFS: u32 = _iow!(b'c', 7, 0x4);
250const BC_INCREFS_DONE: u32 = _iow!(b'c', 8, 0x10);
251const BC_ACQUIRE_DONE: u32 = _iow!(b'c', 9, 0x10);
252const BC_ATTEMPT_ACQUIRE: u32 = _iow!(b'c', 10, 0x10);
253const BC_REGISTER_LOOPER: u32 = 25355;
254const BC_ENTER_LOOPER: u32 = 25356;
255const BC_EXIT_LOOPER: u32 = 25357;
256const BC_REQUEST_DEATH_NOTIFICATION: u32 = _iow!(b'c', 14, 0x10);
257const BC_CLEAR_DEATH_NOTIFICATION: u32 = _iow!(b'c', 15, 0x10);
258const BC_DEAD_BINDER_DONE: u32 = _iow!(b'c', 16, 0x8);
259
260#[repr(u32)]
261#[derive(Debug, FromPrimitive)]
262pub enum BinderDriverCommandProtocol {
263    Transaction = BC_TRANSACTION,
264    Reply = BC_REPLY,
265    AcquireResult = BC_ACQUIRE_RESULT,
266    FreeBuffer = BC_FREE_BUFFER,
267    IncRefs = BC_INCREFS,
268    Acquire = BC_ACQUIRE,
269    Release = BC_RELEASE,
270    DecRefs = BC_DECREFS,
271    IncRefsDone = BC_INCREFS_DONE,
272    AcquireDone = BC_ACQUIRE_DONE,
273    AttemptAcquire = BC_ATTEMPT_ACQUIRE,
274    RegisterLooper = BC_REGISTER_LOOPER,
275    EnterLooper = BC_ENTER_LOOPER,
276    ExitLooper = BC_EXIT_LOOPER,
277    RequestDeathNotification = BC_REQUEST_DEATH_NOTIFICATION,
278    ClearDeathNotification = BC_CLEAR_DEATH_NOTIFICATION,
279    DeadBinderDone = BC_DEAD_BINDER_DONE,
280}
281
282impl From<u32> for BinderDriverCommandProtocol {
283    fn from(int: u32) -> Self {
284        BinderDriverCommandProtocol::from_u32(int).unwrap()
285    }
286}
287
288const BR_ERROR: u32 = _ior!(b'r', 0, 4);
289const BR_OK: u32 = _ior!(b'r', 1, 0);
290const BR_TRANSACTION: u32 = _ior!(b'r', 2, 0x40);
291const BR_REPLY: u32 = _ior!(b'r', 3, 0x40);
292const BR_ACQUIRE_RESULT: u32 = _ior!(b'r', 4, 0x4);
293const BR_DEAD_REPLY: u32 = _io!(b'r', 5);
294const BR_TRANSACTION_COMPLETE: u32 = _io!(b'r', 6);
295const BR_INCREFS: u32 = _ior!(b'r', 7, 0x10);
296const BR_ACQUIRE: u32 = _ior!(b'r', 8, 0x10);
297const BR_RELEASE: u32 = _ior!(b'r', 9, 0x10);
298const BR_DECREFS: u32 = _ior!(b'r', 10, 0x10);
299const BR_ATTEMPT_ACQUIRE: u32 = _ior!(b'r', 11, 0x10);
300const BR_NOOP: u32 = _io!(b'r', 12);
301const BR_SPAWN_LOOPER: u32 = _io!(b'r', 13);
302const BR_FINISHED: u32 = _io!(b'r', 14);
303const BR_DEAD_BINDER: u32 = _ior!(b'r', 15, 0x8);
304const BR_CLEAR_DEATH_NOTIFICATION_DONE: u32 = _ior!(b'r', 16, 0x10);
305const BR_FAILED_REPLY: u32 = _io!(b'r', 17);
306
307#[repr(u32)]
308#[derive(Debug, FromPrimitive, ToPrimitive)]
309pub enum BinderDriverReturnProtocol {
310    Error = BR_ERROR,
311    Ok = BR_OK,
312    Transaction = BR_TRANSACTION,
313    Reply = BR_REPLY,
314    AcquireResult = BR_ACQUIRE_RESULT,
315    DeadReply = BR_DEAD_REPLY,
316    TransactionComplete = BR_TRANSACTION_COMPLETE,
317    IncRefs = BR_INCREFS,
318    Acquire = BR_ACQUIRE,
319    Release = BR_RELEASE,
320    DecRefs = BR_DECREFS,
321    AttemptAcquire = BR_ATTEMPT_ACQUIRE,
322    Noop = BR_NOOP,
323    SpawnLooper = BR_SPAWN_LOOPER,
324    Finished = BR_FINISHED,
325    DeadBinder = BR_DEAD_BINDER,
326    ClearDeathNotification = BR_CLEAR_DEATH_NOTIFICATION_DONE,
327    FailedReply = BR_FAILED_REPLY,
328}
329
330impl From<u32> for BinderDriverReturnProtocol {
331    fn from(int: u32) -> Self {
332        BinderDriverReturnProtocol::from_u32(int).unwrap()
333    }
334}
335
336/// Structure representing an open Binder interface.
337pub struct Binder {
338    fd: RawFd,
339    mem: *const c_void,
340    pending_out_data: Parcel,
341}
342
343impl Binder {
344    pub fn new() -> Self {
345        let mut flags = OFlag::empty();
346        flags.set(OFlag::O_RDWR, true);
347        flags.set(OFlag::O_CLOEXEC, true);
348
349        let fd = open(DEVICE, flags, Mode::empty()).expect("Failed to open binder device");
350
351        let mut binder_version = BinderVersion { protocol_version: 0 };
352        unsafe {
353            binder_read_version(fd, &mut binder_version).expect("Failed to read binder version");
354        }
355
356        let mut flags = MapFlags::empty();
357        flags.set(MapFlags::MAP_PRIVATE, true);
358        flags.set(MapFlags::MAP_NORESERVE, true);
359        let mapping_address = unsafe { mmap(ptr::null_mut(), BINDER_VM_SIZE, ProtFlags::PROT_READ, flags, fd, 0) }.expect("Failed to map the binder file");
360
361        let binder = Self {
362            fd,
363            mem: mapping_address as *const _,
364            pending_out_data: Parcel::empty(),
365        };
366
367        unsafe {
368            binder_set_max_threads(fd, &DEFAULT_MAX_BINDER_THREADS).expect("Failed to set max threads");
369        }
370
371
372        binder
373    }
374
375    /// Tell binder that we are entering the looper
376    pub fn enter_looper(&self) {
377        let mut parcel_out = Parcel::empty();
378
379        parcel_out.write_i32(BinderDriverCommandProtocol::EnterLooper as i32);
380
381        self.write_read(&parcel_out, false);
382    }
383
384    /// Tell binder that we are exiting the looper
385    fn exit_looper(&self) {
386        let mut parcel_out = Parcel::empty();
387
388        parcel_out.write_i32(BinderDriverCommandProtocol::ExitLooper as i32);
389
390        self.write_read(&parcel_out, false);
391    }
392
393    /// Increment the server side reference count of the given handle. Note that this request is
394    /// queued and only actually perfomed with the next outgoing transaction.
395    pub fn add_ref(&mut self, handle: i32) {
396        self.pending_out_data.write_u32(BinderDriverCommandProtocol::IncRefs as u32);
397        self.pending_out_data.write_i32(handle);
398    }
399
400    /// Decrement the server side reference count of the given handle. Note that this request is
401    /// queued and only actually perfomed with the next outgoing transaction.
402    pub fn dec_ref(&mut self, handle: i32) {
403        self.pending_out_data.write_u32(BinderDriverCommandProtocol::DecRefs as u32);
404        self.pending_out_data.write_i32(handle);
405    }
406
407    /// Acquire the server side resource for the given handle. Note that this request is
408    /// queued and only actually perfomed with the next outgoing transaction.
409    pub fn acquire(&mut self, handle: i32) {
410        self.pending_out_data.write_u32(BinderDriverCommandProtocol::Acquire as u32);
411        self.pending_out_data.write_i32(handle);
412    }
413
414    /// Release the server side resource for the given handle. Note that this request is
415    /// queued and only actually perfomed with the next outgoing transaction.
416    pub fn release(&mut self, handle: i32) {
417        self.pending_out_data.write_u32(BinderDriverCommandProtocol::Release as u32);
418        self.pending_out_data.write_i32(handle);
419    }
420
421    pub fn transact(&mut self, handle: i32, code: u32, flags: TransactionFlags, data: &mut Parcel) -> (Option<BinderTransactionData>, Parcel) {
422
423        self.pending_out_data.write_i32(BinderDriverCommandProtocol::Transaction as i32);
424
425        let transaction_data_out = BinderTransactionData {
426            target: handle as u32,
427            code,
428            flags: (TransactionFlags::AcceptFds | flags).bits,
429            cookie: 0,
430            sender_pid: 0,
431            sender_euid: 0,
432            data_size: data.len() as u64,
433            offset_size: (data.offsets_len() * size_of::<usize>()) as u64,
434            data: if data.len() != 0 { data.as_mut_ptr() } else { 0 as *mut u8 },
435            offsets: if data.offsets_len() != 0 { data.offsets().as_mut_ptr() } else { 0 as *mut usize },
436        };
437        self.pending_out_data.write_transaction_data(&transaction_data_out);
438
439        self.do_write_read(&mut Parcel::empty())
440    }
441
442    pub fn reply(&mut self, data: &mut Parcel, flags: TransactionFlags) -> (Option<BinderTransactionData>, Parcel) {
443
444        self.pending_out_data.write_i32(BinderDriverCommandProtocol::Reply as i32);
445
446        let transaction_data_out = BinderTransactionData {
447            target: 0xffffffff,
448            code: 0,
449            flags: flags.bits,
450            cookie: 0,
451            sender_pid: 0,
452            sender_euid: 0,
453            data_size: data.len() as u64,
454            offset_size: (data.offsets_len() * size_of::<usize>()) as u64,
455            data: if data.len() != 0 { data.as_mut_ptr() } else { 0 as *mut u8 },
456            offsets: if data.offsets_len() != 0 { data.offsets().as_mut_ptr() } else { 0 as *mut usize },
457        };
458        self.pending_out_data.write_transaction_data(&transaction_data_out);
459
460        self.do_write_read(&mut Parcel::empty())
461    }
462
463    pub fn do_write_read(&mut self, parcel_out: &mut Parcel) -> (Option<BinderTransactionData>, Parcel) {
464        self.pending_out_data.append_parcel(parcel_out);
465        let mut parcel_in = self.write_read(&self.pending_out_data, true);
466        self.pending_out_data.reset();
467
468        self.proccess_incoming(&mut parcel_in)
469    }
470
471    fn proccess_incoming(&mut self, parcel_in: &mut Parcel) -> (Option<BinderTransactionData>, Parcel) {
472        let mut acquire_result = Result::NoError;
473
474        while parcel_in.has_unread_data() {
475            let cmd_u32 = parcel_in.read_u32();
476            let cmd_option = BinderDriverReturnProtocol::from_u32(cmd_u32);
477            match cmd_option {
478                Some(cmd) => match cmd {
479                    BinderDriverReturnProtocol::TransactionComplete => {},
480                    BinderDriverReturnProtocol::DeadReply => {
481                        panic!("Got a DEAD_REPLY");
482                    },
483                    BinderDriverReturnProtocol::FailedReply => {
484                        panic!("Transaction failed");
485                    },
486                    BinderDriverReturnProtocol::IncRefs => {
487                    },
488                    BinderDriverReturnProtocol::Acquire => {
489                    },
490                    BinderDriverReturnProtocol::AcquireResult => {
491                        let result = parcel_in.read_i32();
492                        acquire_result = if result == 0 {
493                            Result::InvalidOperation
494                        } else {
495                            Result::NoError
496                        };
497                    },
498                    BinderDriverReturnProtocol::Reply | BinderDriverReturnProtocol::Transaction => {
499                        let transaction_data_in = parcel_in.read_transaction_data();
500                        let parcel = Parcel::from_data_and_offsets(
501                                transaction_data_in.data,
502                                transaction_data_in.data_size as usize,
503                                transaction_data_in.offsets,
504                                transaction_data_in.offset_size as usize / size_of::<usize>()
505                            );
506                        return (
507                            Some(transaction_data_in),
508                            parcel,
509                        );
510                    },
511                    BinderDriverReturnProtocol::Error => {
512                        println!("Got an error {}", parcel_in.read_i32());
513                    },
514                    BinderDriverReturnProtocol::Noop => {
515                    },
516                    BinderDriverReturnProtocol::SpawnLooper => {
517                    },
518                    _  => {}
519
520                },
521                None => {},
522            }
523        }
524
525        (None, Parcel::empty())
526    }
527    /// Perform a low-level binder write/read operation
528    fn write_read(&self, data_out: &Parcel, with_read: bool) -> Parcel {
529        let mut data_in = [0u8; 32 * 8];
530
531        let mut write_read_struct = BinderWriteRead {
532            write_size: data_out.len(),
533            write_buffer: data_out.as_ptr() as *const c_void,
534            write_consumed: 0,
535            read_size: if with_read { data_in.len() } else { 0 },
536            read_buffer: data_in.as_mut_ptr() as *mut c_void,
537            read_consumed: 0,
538        };
539
540        unsafe {
541            binder_write_read(self.fd, &mut write_read_struct).expect("Failed to perform write_read");
542        }
543        Parcel::from_slice(&data_in[..write_read_struct.read_consumed])
544
545    }
546
547}
548
549/// Implement Drop for Binder, so that we can clean up resources
550impl Drop for Binder {
551    fn drop(&mut self) {
552        //TODO: do we need to unmap?
553
554        self.exit_looper();
555
556        close(self.fd);
557    }
558}