-
-
Notifications
You must be signed in to change notification settings - Fork 779
Uninstall previous version when installing an app #4530
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Uninstall previous version when installing an app #4530
Conversation
Now that I think about it a bit, we moved the padding app writing from Do we hold the requesting entity responsible for the correctness of the app? I need some thoughts on the flow here. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To the question of in-place updating versus two-phase, I don't know that the low-level kernel components should necessarily have an opinion on that.
My view is that uninstall
should do what it says on the tin, i.e., just uninstall the specified app. Similarly install
can be used to install a new version of an app. Higher layers can build an A/B update service on top of these two primitives.
A separate interface, which is likely also useful, is a replace
interface (or overwrite
or update-in-place
; name could be bikeshed). This is obviously a higher-risk primitive, but may be necessary for e.g. cases where there isn't enough storage to hold two versions of an app simultaneously.
I view uninstall
and replace
as two completely separate operations, however.
I think we should start with support for the simpler case: plain uninstall
support. Get that solid. Then we can implement replace
next.
// We are in the wrong mode of operation. Ideally we should never reach | ||
// here, but this error exists as a failsafe. The capsule should send | ||
// a busy error out to the userland app. | ||
Err(ErrorCode::INVAL) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Err(ErrorCode::INVAL) | |
Err(ErrorCode::FAIL) |
Probably better matches this case?
// This means the app is disabled, and does not have to be | ||
// loaded | ||
if !process_binary.valid_app { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// This means the app is disabled, and does not have to be | |
// loaded | |
if !process_binary.valid_app { | |
if !process_binary.header.enabled() { |
|
||
/// Credential to vaildate if the app needs to be loaded | ||
pub valid_app: bool, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/// Credential to vaildate if the app needs to be loaded | |
pub valid_app: bool, |
You shouldn't need a separate variable here I don't think, can just do header.enabled()
// a flag to let process loaders know if this is an app to make a process out of, | ||
// or if it is a disabled app that is stored in the storage, but otherwise not used | ||
let valid_app: bool = tbf_header.enabled(); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// a flag to let process loaders know if this is an app to make a process out of, | |
// or if it is a disabled app that is stored in the storage, but otherwise not used | |
let valid_app: bool = tbf_header.enabled(); |
footers: footer_region, | ||
flash: app_flash, | ||
credential: OptionalCell::empty(), | ||
valid_app, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
valid_app, |
These are valid reviews, however this pr is blocked by #4528 and will be rebased on that. These changes have already been made on that pr. The uninstall functionality by itself is a separate pr, the one linked before. There is some discussions on RAM reclamation and such on that pr. This is just a wishlist item of how i view apps to be a single entity that are upgraded in version when a new app is installed instead of having multiple versions run (given the constrained environment), but that can be discussed further later. |
Pull Request Overview
The reason I built this PR is because we deal with limited resources. At any point, one app only needs one binary and one process. We already have the memory taken care of via
check_if_blocked_by()
. However, we cannot simply deny apps to write new versions of themselves. On the other hand, I think it is also bad for apps to have binaries with various versions and deny storage to other apps.So, this pull request adds a feature where when a new binary is being installed, the kernel will look for a previous version of the same app in the storage. If it finds one, the kernel then terminates the process (if active) and erases the previous version binary. If there is no previous version on device, the new version gets installed like it always does.
This PR builds on top of #4528 and is blocked by said PR.
Eventually, I want to build something that performs defragmentation (if that's even possible), so we have neat spaces for new apps.
Testing Strategy
This pull request was tested by installing a blink app with version 0. Then we use the dynamic app load helper app to install a blink app with version 2. We observe that the old version is uninstalled completely before the new version is loaded.
TODO or Help Wanted
I guess I was wondering if it made more sense to move the erase part to after successfully loading the new process instead. Actually, I think that makes the most sense, I will update the PR according to that.
Documentation Updated
/docs
, or no updates are required.Formatting
make prepush
.