binaryninja/
background_task.rs

1// Copyright 2021-2025 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Background tasks provide plugins the ability to inform the core of long-running background tasks.
16
17use binaryninjacore_sys::*;
18use std::fmt::Debug;
19
20use std::result;
21
22use crate::rc::*;
23use crate::string::*;
24
25pub type Result<R> = result::Result<R, ()>;
26
27/// A [`BackgroundTask`] does not actually execute any code, only act as a handler, primarily to query
28/// the status of the task, and to cancel the task.
29///
30/// If you are looking to execute code in the background consider using rusts threading API, or if you
31/// want the core to execute the task on a worker thread, use the [`crate::worker_thread`] API.
32///
33/// NOTE: If you do not call [`BackgroundTask::finish`] or [`BackgroundTask::cancel`] the task will
34/// persist even _after_ it has been dropped.
35#[derive(PartialEq, Eq, Hash)]
36pub struct BackgroundTask {
37    pub(crate) handle: *mut BNBackgroundTask,
38}
39
40impl BackgroundTask {
41    pub(crate) unsafe fn from_raw(handle: *mut BNBackgroundTask) -> Self {
42        debug_assert!(!handle.is_null());
43
44        Self { handle }
45    }
46
47    pub fn new(initial_text: &str, can_cancel: bool) -> Ref<Self> {
48        let text = initial_text.to_cstr();
49        let handle = unsafe { BNBeginBackgroundTask(text.as_ptr(), can_cancel) };
50        // We should always be returned a valid task.
51        assert!(!handle.is_null());
52        unsafe { Ref::new(Self { handle }) }
53    }
54
55    pub fn can_cancel(&self) -> bool {
56        unsafe { BNCanCancelBackgroundTask(self.handle) }
57    }
58
59    pub fn is_cancelled(&self) -> bool {
60        unsafe { BNIsBackgroundTaskCancelled(self.handle) }
61    }
62
63    pub fn cancel(&self) {
64        unsafe { BNCancelBackgroundTask(self.handle) }
65    }
66
67    pub fn is_finished(&self) -> bool {
68        unsafe { BNIsBackgroundTaskFinished(self.handle) }
69    }
70
71    pub fn finish(&self) {
72        unsafe { BNFinishBackgroundTask(self.handle) }
73    }
74
75    pub fn progress_text(&self) -> String {
76        unsafe { BnString::into_string(BNGetBackgroundTaskProgressText(self.handle)) }
77    }
78
79    pub fn set_progress_text(&self, text: &str) {
80        let progress_text = text.to_cstr();
81        unsafe { BNSetBackgroundTaskProgressText(self.handle, progress_text.as_ptr()) }
82    }
83
84    pub fn running_tasks() -> Array<BackgroundTask> {
85        unsafe {
86            let mut count = 0;
87            let handles = BNGetRunningBackgroundTasks(&mut count);
88            Array::new(handles, count, ())
89        }
90    }
91}
92
93impl Debug for BackgroundTask {
94    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
95        f.debug_struct("BackgroundTask")
96            .field("progress_text", &self.progress_text())
97            .field("can_cancel", &self.can_cancel())
98            .field("is_cancelled", &self.is_cancelled())
99            .field("is_finished", &self.is_finished())
100            .finish()
101    }
102}
103
104unsafe impl RefCountable for BackgroundTask {
105    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
106        Ref::new(Self {
107            handle: BNNewBackgroundTaskReference(handle.handle),
108        })
109    }
110
111    unsafe fn dec_ref(handle: &Self) {
112        BNFreeBackgroundTask(handle.handle);
113    }
114}
115
116impl CoreArrayProvider for BackgroundTask {
117    type Raw = *mut BNBackgroundTask;
118    type Context = ();
119    type Wrapped<'a> = Guard<'a, BackgroundTask>;
120}
121
122unsafe impl CoreArrayProviderInner for BackgroundTask {
123    unsafe fn free(raw: *mut *mut BNBackgroundTask, count: usize, _context: &()) {
124        BNFreeBackgroundTaskList(raw, count);
125    }
126    unsafe fn wrap_raw<'a>(raw: &'a *mut BNBackgroundTask, context: &'a ()) -> Self::Wrapped<'a> {
127        Guard::new(BackgroundTask::from_raw(*raw), context)
128    }
129}
130
131impl ToOwned for BackgroundTask {
132    type Owned = Ref<Self>;
133
134    fn to_owned(&self) -> Self::Owned {
135        unsafe { RefCountable::inc_ref(self) }
136    }
137}
138
139unsafe impl Send for BackgroundTask {}
140unsafe impl Sync for BackgroundTask {}