xref: /aosp_15_r20/system/apex/libs/libapexsupport/src/apexinfo.rs (revision 33f3758387333dbd2962d7edbd98681940d895da)
1*33f37583SAndroid Build Coastguard Worker /*
2*33f37583SAndroid Build Coastguard Worker  * Copyright (C) 2023 The Android Open Source Project
3*33f37583SAndroid Build Coastguard Worker  *
4*33f37583SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*33f37583SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*33f37583SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*33f37583SAndroid Build Coastguard Worker  *
8*33f37583SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*33f37583SAndroid Build Coastguard Worker  *
10*33f37583SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*33f37583SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*33f37583SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*33f37583SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*33f37583SAndroid Build Coastguard Worker  * limitations under the License.
15*33f37583SAndroid Build Coastguard Worker  */
16*33f37583SAndroid Build Coastguard Worker 
17*33f37583SAndroid Build Coastguard Worker //! Provides AApexInfo (name, version) from the calling process
18*33f37583SAndroid Build Coastguard Worker 
19*33f37583SAndroid Build Coastguard Worker use apex_manifest::apex_manifest::ApexManifest;
20*33f37583SAndroid Build Coastguard Worker use protobuf::Message;
21*33f37583SAndroid Build Coastguard Worker use std::env;
22*33f37583SAndroid Build Coastguard Worker use std::ffi::CString;
23*33f37583SAndroid Build Coastguard Worker use std::fs::File;
24*33f37583SAndroid Build Coastguard Worker use std::path::{Path, PathBuf};
25*33f37583SAndroid Build Coastguard Worker 
26*33f37583SAndroid Build Coastguard Worker #[derive(Debug)]
27*33f37583SAndroid Build Coastguard Worker pub enum AApexInfoError {
28*33f37583SAndroid Build Coastguard Worker     /// The executable's path is not from an APEX
29*33f37583SAndroid Build Coastguard Worker     PathNotFromApex(PathBuf),
30*33f37583SAndroid Build Coastguard Worker     /// Fail to get the current executable's path
31*33f37583SAndroid Build Coastguard Worker     ExePathUnavailable(std::io::Error),
32*33f37583SAndroid Build Coastguard Worker     /// Fail to read apex_manifest.pb from an APEX
33*33f37583SAndroid Build Coastguard Worker     InvalidApex(String),
34*33f37583SAndroid Build Coastguard Worker }
35*33f37583SAndroid Build Coastguard Worker 
36*33f37583SAndroid Build Coastguard Worker /// AApexInfo is used as an opaque object from FFI clients. This just wraps
37*33f37583SAndroid Build Coastguard Worker /// ApexManifest protobuf message.
38*33f37583SAndroid Build Coastguard Worker ///
39*33f37583SAndroid Build Coastguard Worker /// NOTE: that we don't want to provide too many details about APEX. It provides
40*33f37583SAndroid Build Coastguard Worker /// minimal information (for now, name and version) only for the APEX where the
41*33f37583SAndroid Build Coastguard Worker /// current process is loaded from.
42*33f37583SAndroid Build Coastguard Worker pub struct AApexInfo {
43*33f37583SAndroid Build Coastguard Worker     pub name: CString,
44*33f37583SAndroid Build Coastguard Worker     pub version: i64,
45*33f37583SAndroid Build Coastguard Worker }
46*33f37583SAndroid Build Coastguard Worker 
47*33f37583SAndroid Build Coastguard Worker impl AApexInfo {
48*33f37583SAndroid Build Coastguard Worker     /// Returns AApexInfo object when called by an executable from an APEX.
create() -> Result<Self, AApexInfoError>49*33f37583SAndroid Build Coastguard Worker     pub fn create() -> Result<Self, AApexInfoError> {
50*33f37583SAndroid Build Coastguard Worker         let exe_path = env::current_exe().map_err(AApexInfoError::ExePathUnavailable)?;
51*33f37583SAndroid Build Coastguard Worker         let manifest_path = get_apex_manifest_path(exe_path)?;
52*33f37583SAndroid Build Coastguard Worker         let manifest = parse_apex_manifest(manifest_path)?;
53*33f37583SAndroid Build Coastguard Worker         Ok(AApexInfo {
54*33f37583SAndroid Build Coastguard Worker             name: CString::new(manifest.name)
55*33f37583SAndroid Build Coastguard Worker                 .map_err(|err| AApexInfoError::InvalidApex(format!("{err:?}")))?,
56*33f37583SAndroid Build Coastguard Worker             version: manifest.version,
57*33f37583SAndroid Build Coastguard Worker         })
58*33f37583SAndroid Build Coastguard Worker     }
59*33f37583SAndroid Build Coastguard Worker }
60*33f37583SAndroid Build Coastguard Worker 
61*33f37583SAndroid Build Coastguard Worker /// Returns the apex_manifest.pb path when a given path belongs to an apex.
get_apex_manifest_path<P: AsRef<Path>>(path: P) -> Result<PathBuf, AApexInfoError>62*33f37583SAndroid Build Coastguard Worker fn get_apex_manifest_path<P: AsRef<Path>>(path: P) -> Result<PathBuf, AApexInfoError> {
63*33f37583SAndroid Build Coastguard Worker     let remain = path
64*33f37583SAndroid Build Coastguard Worker         .as_ref()
65*33f37583SAndroid Build Coastguard Worker         .strip_prefix("/apex")
66*33f37583SAndroid Build Coastguard Worker         .map_err(|_| AApexInfoError::PathNotFromApex(path.as_ref().to_owned()))?;
67*33f37583SAndroid Build Coastguard Worker     let apex_name = remain
68*33f37583SAndroid Build Coastguard Worker         .iter()
69*33f37583SAndroid Build Coastguard Worker         .next()
70*33f37583SAndroid Build Coastguard Worker         .ok_or_else(|| AApexInfoError::PathNotFromApex(path.as_ref().to_owned()))?;
71*33f37583SAndroid Build Coastguard Worker     Ok(Path::new("/apex").join(apex_name).join("apex_manifest.pb"))
72*33f37583SAndroid Build Coastguard Worker }
73*33f37583SAndroid Build Coastguard Worker 
74*33f37583SAndroid Build Coastguard Worker /// Parses the apex_manifest.pb protobuf message from a given path.
parse_apex_manifest<P: AsRef<Path>>(path: P) -> Result<ApexManifest, AApexInfoError>75*33f37583SAndroid Build Coastguard Worker fn parse_apex_manifest<P: AsRef<Path>>(path: P) -> Result<ApexManifest, AApexInfoError> {
76*33f37583SAndroid Build Coastguard Worker     let mut f = File::open(path).map_err(|err| AApexInfoError::InvalidApex(format!("{err:?}")))?;
77*33f37583SAndroid Build Coastguard Worker     Message::parse_from_reader(&mut f).map_err(|err| AApexInfoError::InvalidApex(format!("{err:?}")))
78*33f37583SAndroid Build Coastguard Worker }
79*33f37583SAndroid Build Coastguard Worker 
80*33f37583SAndroid Build Coastguard Worker #[cfg(test)]
81*33f37583SAndroid Build Coastguard Worker mod test {
82*33f37583SAndroid Build Coastguard Worker     use super::*;
83*33f37583SAndroid Build Coastguard Worker 
84*33f37583SAndroid Build Coastguard Worker     #[test]
test_get_apex_manifest_path()85*33f37583SAndroid Build Coastguard Worker     fn test_get_apex_manifest_path() {
86*33f37583SAndroid Build Coastguard Worker         assert_eq!(
87*33f37583SAndroid Build Coastguard Worker             get_apex_manifest_path("/apex/com.android.foo/bin/foo").unwrap(),
88*33f37583SAndroid Build Coastguard Worker             PathBuf::from("/apex/com.android.foo/apex_manifest.pb")
89*33f37583SAndroid Build Coastguard Worker         );
90*33f37583SAndroid Build Coastguard Worker         assert!(get_apex_manifest_path("/apex/").is_err());
91*33f37583SAndroid Build Coastguard Worker         assert!(get_apex_manifest_path("/apex").is_err());
92*33f37583SAndroid Build Coastguard Worker         assert!(get_apex_manifest_path("/com.android.foo/bin/foo").is_err());
93*33f37583SAndroid Build Coastguard Worker         assert!(get_apex_manifest_path("/system/apex/com.android.foo/bin/foo").is_err());
94*33f37583SAndroid Build Coastguard Worker     }
95*33f37583SAndroid Build Coastguard Worker }
96