Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Conversation

viswajith-g
Copy link
Contributor

Pull Request Overview

This pr introduces an uninstall(ShortId, app_version) function to the dynamic process loader.

The uninstall operation supports two cases:

  1. The application is currently enabled (i.e., running as a process)
  2. The application is installed but disabled (i.e., present in storage, but not loaded as a process)

The uninstall procedure involves three steps:

  1. Locate the Binary

    • Scan the storage to find a binary that matches the ShortId and app_version values
  2. Terminate if Running
    If the binary corresponds to a currently running process:

    • Terminate the process
    • Remove it from the process array

If the binary is not enabled, this step does nothing.

  1. Remove and Pad
    • Erase the binary from flash, and write a padding app in its place

Testing Strategy

This pull request was tested by running a blink app on an nRF52840dk and then using a helper app to uninstall it.

TODO or Help Wanted

N/A

Documentation Updated

  • Updated the relevant files in /docs, or no updates are required.

Formatting

  • Ran make prepush.

@viswajith-g
Copy link
Contributor Author

I implemented a helper that iterates over loaded processes to detect and remove any matching instance in the kernel. I did not want to the async loader to track these additional states

Comment on lines +313 to +315
kernel_data
.schedule_upcall(upcall::UNINSTALL_DONE, (into_statuscode(result), 0, 0))
.ok();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
kernel_data
.schedule_upcall(upcall::UNINSTALL_DONE, (into_statuscode(result), 0, 0))
.ok();
let _ = kernel_data
.schedule_upcall(upcall::UNINSTALL_DONE, (into_statuscode(result), 0, 0));

Comment on lines +92 to +93
/// Call to uninstall an app with given ShortId and app version.
fn uninstall(&self, short_id: usize, app_version: usize) -> Result<(), ErrorCode>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why isn't this short_id: ShortId using the actual type?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't have "install" so maybe we shouldn't have "uninstall" in this trait. What about "remove" or "erase"? I think the arguments make sense because it is the only general way to identify a unique app binary.

The comment should be more specific about what this operation has to do exactly.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because I wanted to keep all this within the dynamic_binary_storage capsule. It can be changed to app_loader.

Hm. Essentially we aim to terminate the process and then erase. Which is two operations. Hence, the name uninstall for this function.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But why would the trait responsible for storing an app also be expected to track the state of the app, possibly terminate, and do whatever else is required? I would expect the implementor to just have to worry about how apps are stored.

Comment on lines +317 to +328
/// Terminate a process if it exists, and remove it from ProcessArray.
pub(crate) fn reclaim_app_memory(&self, shortid: process::ShortId) {
for slot in self.processes.iter() {
if let Some(process) = slot.get() {
if process.short_app_id() == shortid {
process.terminate(None);
slot.proc.set(None);
break;
}
}
}
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree this reclaims the slot in the processes array, but the app memory is still effectively lost isn't it?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, the memory is lost because of how the SequentialProcessLoadingMachine is implemented. We need to scan RAM for new memory availability similar to scan_flash_for_binaries().

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, I just pushed a commit which fixes this. It is very inelegant, but it scans for memory regions just before process creation and passes the slice of app_memory much like we do with flash.

ram_reclaim

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In the iteration before this change, the memory region shrinks, so uninstalling the app and reinstalling it still placed the new memory region at 0x20016000.

Comment on lines 133 to 135

/// Credential to vaildate if the app needs to be loaded
pub valid_app: bool,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of duplicating this information, we can just call self.header.enabled() if we need to know this

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, makes sense

Comment on lines -165 to -176
// If this is an app but it isn't enabled, then we can return an error.
if !tbf_header.enabled() {
if config::CONFIG.debug_load_processes {
debug!(
"Process not enabled flash={:#010X}-{:#010X} process={:?}",
app_flash.as_ptr() as usize,
app_flash.as_ptr() as usize + app_flash.len() - 1,
tbf_header.get_package_name().unwrap_or("(no name)")
);
}
return Err(ProcessBinaryError::NotEnabledProcess);
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this no longer an error?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Because if this errors out, we don't get the process binary object to compute the ShortId from.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think that's fine, but the error variant needs to be removed entirely.

@bradjc
Copy link
Contributor

bradjc commented Jul 29, 2025

I think that adding a dynamic RAM slice approach needs to be its own PR. There is a lot going on in that change and it really needs independent scrutiny. My initial thought is I think the size of the memory region has to remain in ProcessStandard::create(). The caller can pass in multiple candidate slices, but we won't know the actual size until ProcessStandard::create() is able to compute it. Although even that is tricky, because the MPU has to be able to protect the region. This might require more thought.

@bradjc bradjc changed the title app_loader: add uninstall functionailty app_loader: add uninstall functionality Jul 29, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants