Skip to main content
KeyOS API Reference

app_manager/
lib.rs

1// SPDX-FileCopyrightText: 2025 Foundation Devices, Inc. <hello@foundation.xyz>
2// SPDX-License-Identifier: GPL-3.0-or-later
3pub use error::*;
4pub use messages::*;
5
6pub mod error;
7pub mod messages;
8
9use server::{CheckedConn, CheckedPermissions, MessageAllowed};
10use xous::{AppId, PID};
11
12#[macro_export]
13macro_rules! use_api {
14    () => {
15        mod app_manager_permissions {
16            use app_manager::messages::*;
17            #[derive(Clone, Default, server::Permissions)]
18            #[server_name = "os/app-manager"]
19            pub struct AppManagerPermissions;
20        }
21        type AppManagerApi = app_manager::AppManagerApi<app_manager_permissions::AppManagerPermissions>;
22    };
23}
24
25#[derive(Clone, Default)]
26pub struct AppManagerApi<P: CheckedPermissions>(pub(crate) CheckedConn<P>);
27
28impl<P: CheckedPermissions> AppManagerApi<P> {
29    pub fn launch_app_blocking(&self, app_id: &AppId) -> Result<PID, AppManagerError>
30    where
31        P: MessageAllowed<LaunchAppBlocking>,
32    {
33        self.0
34            .try_send_blocking_scalar(LaunchAppBlocking(*app_id))
35            .map_err(|_| AppManagerError::InternalError)?
36    }
37
38    pub fn launch_app(&self, app_id: &AppId) -> Result<(), xous::Error>
39    where
40        P: MessageAllowed<LaunchApp>,
41    {
42        self.0.try_send_scalar(LaunchApp(*app_id))?;
43        Ok(())
44    }
45
46    pub fn refresh_installed_apps(&self) -> Result<(), AppManagerError>
47    where
48        P: MessageAllowed<RefreshInstalledApps>,
49    {
50        self.0.try_send_blocking_scalar(RefreshInstalledApps).map_err(|_| AppManagerError::InternalError)?
51    }
52
53    pub fn app_name_by_app_id(&self, id: &AppId, locale: &str) -> Option<String>
54    where
55        P: MessageAllowed<GetAppName>,
56    {
57        self.0.send_blocking_archive(GetAppName::new_by_app_id(id, locale))
58    }
59
60    pub fn app_name_by_pid(&self, pid: PID, locale: &str) -> Option<String>
61    where
62        P: MessageAllowed<GetAppName>,
63    {
64        self.0.send_blocking_archive(GetAppName::new_by_pid(pid, locale))
65    }
66
67    pub fn get_qr_match_rules(&self) -> Vec<AppQrMatchRules>
68    where
69        P: MessageAllowed<GetQrMatchRules>,
70    {
71        self.0.send_blocking_archive(GetQrMatchRules)
72    }
73
74    /// List installed apps, optionally narrowed by `filter`. Pass `AppFilter::default()`
75    /// for everything, `AppFilter::third_party_only()` for sideloaded apps, etc.
76    pub fn list_apps(&self, locale: &str, filter: AppFilter) -> Vec<InstalledAppInfo>
77    where
78        P: MessageAllowed<ListApps>,
79    {
80        self.0.send_blocking_archive(ListApps { locale: locale.to_string(), filter })
81    }
82
83    pub fn get_app_icon(&self, app_id: &str) -> Option<Vec<u8>>
84    where
85        P: MessageAllowed<GetAppIcon>,
86    {
87        self.0.send_blocking_archive(GetAppIcon { app_id: app_id.to_string() })
88    }
89
90    pub fn set_app_permission_grant(
91        &self,
92        app_id: &str,
93        subgroup: &str,
94        decision: PermissionGrantDecision,
95    ) -> SetAppPermissionGrantResult
96    where
97        P: MessageAllowed<SetAppPermissionGrant>,
98    {
99        self.0.send_blocking_archive(SetAppPermissionGrant {
100            app_id: app_id.to_string(),
101            subgroup: subgroup.to_string(),
102            decision,
103        })
104    }
105
106    pub fn get_permission_request_info(
107        &self,
108        sender_app_id: [u8; 16],
109        server_sid: [u32; 4],
110        message_id: usize,
111        locale: &str,
112    ) -> PermissionRequestInfoResult
113    where
114        P: MessageAllowed<GetPermissionRequestInfo>,
115    {
116        self.0.send_blocking_archive(GetPermissionRequestInfo {
117            sender_app_id,
118            server_sid,
119            message_id,
120            locale: locale.to_string(),
121        })
122    }
123
124    pub fn get_third_party_certificates(&self) -> Vec<ThirdPartyCertificateInfo>
125    where
126        P: MessageAllowed<GetThirdPartyCertificates>,
127    {
128        self.0.send_blocking_archive(GetThirdPartyCertificates)
129    }
130
131    pub fn import_third_party_certificate(
132        &self,
133        certificate_pem: Vec<u8>,
134    ) -> Result<ImportThirdPartyCertificateResult, xous::Error>
135    where
136        P: MessageAllowed<ImportThirdPartyCertificate>,
137    {
138        self.0.try_send_blocking_archive(ImportThirdPartyCertificate { certificate_pem })
139    }
140
141    pub fn remove_third_party_certificate(
142        &self,
143        public_key: impl Into<String>,
144        locale: &str,
145    ) -> Result<RemoveThirdPartyCertificateResult, xous::Error>
146    where
147        P: MessageAllowed<RemoveThirdPartyCertificate>,
148    {
149        self.0.try_send_blocking_archive(RemoveThirdPartyCertificate {
150            public_key: public_key.into(),
151            locale: locale.to_string(),
152        })
153    }
154
155    pub fn remove_installed_app(&self, app_id: &AppId) -> Result<RemoveInstalledAppResult, xous::Error>
156    where
157        P: MessageAllowed<RemoveInstalledApp>,
158    {
159        self.0.try_send_blocking_archive(RemoveInstalledApp { app_id: *app_id })
160    }
161
162    /// Subscribe the calling server to app lifecycle events (launch/crash).
163    ///
164    /// The subscriber must implement `server::ArchiveEventHandler<AppEvent>`.
165    pub fn server_subscribe_app_events<S>(&self, context: &mut server::ServerContext<S>)
166    where
167        P: 'static,
168        P: MessageAllowed<SubscribeAppEvents>,
169        S: server::Server + server::ArchiveEventHandler<AppEvent>,
170    {
171        self.0.subscribe_archive_infallible(SubscribeAppEvents, context)
172    }
173}
174
175pub fn decode_app_id_str(id: &str) -> anyhow::Result<AppId> {
176    Ok(AppId(app_manifest::parse_app_id_bytes(id)?))
177}