binaryninja/
background_task.rs

1// Copyright 2021-2026 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/// An RAII guard for [`BackgroundTask`] to finish the task when dropped.
28pub struct OwnedBackgroundTaskGuard {
29    pub(crate) task: Ref<BackgroundTask>,
30}
31
32impl OwnedBackgroundTaskGuard {
33    pub fn cancel(&self) {
34        self.task.cancel();
35    }
36
37    pub fn is_cancelled(&self) -> bool {
38        self.task.is_cancelled()
39    }
40
41    pub fn set_progress_text(&self, text: &str) {
42        self.task.set_progress_text(text);
43    }
44}
45
46impl Drop for OwnedBackgroundTaskGuard {
47    fn drop(&mut self) {
48        self.task.finish();
49    }
50}
51
52/// A [`BackgroundTask`] does not actually execute any code, only act as a handler, primarily to query
53/// the status of the task, and to cancel the task.
54///
55/// If you are looking to execute code in the background, consider using rusts threading API, or if you
56/// want the core to execute the task on a worker thread, instead use the [`crate::worker_thread`] API.
57///
58/// NOTE: If you do not call [`BackgroundTask::finish`] or [`BackgroundTask::cancel`], the task will
59/// persist even _after_ it has been dropped, use [`OwnedBackgroundTaskGuard`] to ensure the task is
60/// finished, see [`BackgroundTask::enter`] for usage.
61#[derive(PartialEq, Eq, Hash)]
62pub struct BackgroundTask {
63    pub(crate) handle: *mut BNBackgroundTask,
64}
65
66impl BackgroundTask {
67    pub(crate) unsafe fn from_raw(handle: *mut BNBackgroundTask) -> Self {
68        debug_assert!(!handle.is_null());
69
70        Self { handle }
71    }
72
73    /// Begin the [`BackgroundTask`], you must manually finish the task by calling [`BackgroundTask::finish`].
74    ///
75    /// If you wish to automatically finish the task when leaving the scope, use [`BackgroundTask::enter`].
76    pub fn new(initial_text: &str, can_cancel: bool) -> Ref<Self> {
77        let text = initial_text.to_cstr();
78        let handle = unsafe { BNBeginBackgroundTask(text.as_ptr(), can_cancel) };
79        // We should always be returned a valid task.
80        assert!(!handle.is_null());
81        unsafe { Ref::new(Self { handle }) }
82    }
83
84    /// Creates a [`OwnedBackgroundTaskGuard`] that is responsible for finishing the background task
85    /// once dropped. Because the status of a task does not dictate the underlying objects' lifetime,
86    /// this can be safely done without requiring exclusive ownership.
87    pub fn enter(&self) -> OwnedBackgroundTaskGuard {
88        OwnedBackgroundTaskGuard {
89            task: self.to_owned(),
90        }
91    }
92
93    pub fn can_cancel(&self) -> bool {
94        unsafe { BNCanCancelBackgroundTask(self.handle) }
95    }
96
97    pub fn is_cancelled(&self) -> bool {
98        unsafe { BNIsBackgroundTaskCancelled(self.handle) }
99    }
100
101    pub fn cancel(&self) {
102        unsafe { BNCancelBackgroundTask(self.handle) }
103    }
104
105    pub fn is_finished(&self) -> bool {
106        unsafe { BNIsBackgroundTaskFinished(self.handle) }
107    }
108
109    pub fn finish(&self) {
110        unsafe { BNFinishBackgroundTask(self.handle) }
111    }
112
113    pub fn progress_text(&self) -> String {
114        unsafe { BnString::into_string(BNGetBackgroundTaskProgressText(self.handle)) }
115    }
116
117    pub fn set_progress_text(&self, text: &str) {
118        let progress_text = text.to_cstr();
119        unsafe { BNSetBackgroundTaskProgressText(self.handle, progress_text.as_ptr()) }
120    }
121
122    pub fn running_tasks() -> Array<BackgroundTask> {
123        unsafe {
124            let mut count = 0;
125            let handles = BNGetRunningBackgroundTasks(&mut count);
126            Array::new(handles, count, ())
127        }
128    }
129}
130
131impl Debug for BackgroundTask {
132    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
133        f.debug_struct("BackgroundTask")
134            .field("progress_text", &self.progress_text())
135            .field("can_cancel", &self.can_cancel())
136            .field("is_cancelled", &self.is_cancelled())
137            .field("is_finished", &self.is_finished())
138            .finish()
139    }
140}
141
142unsafe impl RefCountable for BackgroundTask {
143    unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
144        Ref::new(Self {
145            handle: BNNewBackgroundTaskReference(handle.handle),
146        })
147    }
148
149    unsafe fn dec_ref(handle: &Self) {
150        BNFreeBackgroundTask(handle.handle);
151    }
152}
153
154impl CoreArrayProvider for BackgroundTask {
155    type Raw = *mut BNBackgroundTask;
156    type Context = ();
157    type Wrapped<'a> = Guard<'a, BackgroundTask>;
158}
159
160unsafe impl CoreArrayProviderInner for BackgroundTask {
161    unsafe fn free(raw: *mut *mut BNBackgroundTask, count: usize, _context: &()) {
162        BNFreeBackgroundTaskList(raw, count);
163    }
164    unsafe fn wrap_raw<'a>(raw: &'a *mut BNBackgroundTask, context: &'a ()) -> Self::Wrapped<'a> {
165        Guard::new(BackgroundTask::from_raw(*raw), context)
166    }
167}
168
169impl ToOwned for BackgroundTask {
170    type Owned = Ref<Self>;
171
172    fn to_owned(&self) -> Self::Owned {
173        unsafe { RefCountable::inc_ref(self) }
174    }
175}
176
177unsafe impl Send for BackgroundTask {}
178unsafe impl Sync for BackgroundTask {}