1 /*
2  * Copyright (C) 2021 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 //! Implementation of IIsolatedCompilationService, called from system server when compilation is
18 //! desired.
19 
20 use crate::instance_manager::InstanceManager;
21 use crate::odrefresh_task::OdrefreshTask;
22 use android_system_composd::aidl::android::system::composd::{
23     ICompilationTask::{BnCompilationTask, ICompilationTask},
24     ICompilationTaskCallback::ICompilationTaskCallback,
25     IIsolatedCompilationService::{
26         ApexSource::ApexSource, BnIsolatedCompilationService, IIsolatedCompilationService,
27     },
28 };
29 use anyhow::{Context, Result};
30 use binder::{self, BinderFeatures, ExceptionCode, Interface, Status, Strong, ThreadState};
31 use compos_aidl_interface::aidl::com::android::compos::ICompOsService::CompilationMode::CompilationMode;
32 use compos_common::binder::to_binder_result;
33 use compos_common::odrefresh::{PENDING_ARTIFACTS_SUBDIR, TEST_ARTIFACTS_SUBDIR};
34 use rustutils::{users::AID_ROOT, users::AID_SYSTEM};
35 use std::sync::Arc;
36 
37 pub struct IsolatedCompilationService {
38     instance_manager: Arc<InstanceManager>,
39 }
40 
new_binder( instance_manager: Arc<InstanceManager>, ) -> Strong<dyn IIsolatedCompilationService>41 pub fn new_binder(
42     instance_manager: Arc<InstanceManager>,
43 ) -> Strong<dyn IIsolatedCompilationService> {
44     let service = IsolatedCompilationService { instance_manager };
45     BnIsolatedCompilationService::new_binder(service, BinderFeatures::default())
46 }
47 
48 impl Interface for IsolatedCompilationService {}
49 
50 impl IIsolatedCompilationService for IsolatedCompilationService {
startStagedApexCompile( &self, callback: &Strong<dyn ICompilationTaskCallback>, ) -> binder::Result<Strong<dyn ICompilationTask>>51     fn startStagedApexCompile(
52         &self,
53         callback: &Strong<dyn ICompilationTaskCallback>,
54     ) -> binder::Result<Strong<dyn ICompilationTask>> {
55         check_permissions()?;
56         to_binder_result(self.do_start_staged_apex_compile(callback))
57     }
58 
startTestCompile( &self, apex_source: ApexSource, callback: &Strong<dyn ICompilationTaskCallback>, os: &str, ) -> binder::Result<Strong<dyn ICompilationTask>>59     fn startTestCompile(
60         &self,
61         apex_source: ApexSource,
62         callback: &Strong<dyn ICompilationTaskCallback>,
63         os: &str,
64     ) -> binder::Result<Strong<dyn ICompilationTask>> {
65         check_permissions()?;
66         let prefer_staged = match apex_source {
67             ApexSource::NoStaged => false,
68             ApexSource::PreferStaged => true,
69             _ => unreachable!("Invalid ApexSource {:?}", apex_source),
70         };
71         to_binder_result(self.do_start_test_compile(prefer_staged, callback, os))
72     }
73 }
74 
75 impl IsolatedCompilationService {
do_start_staged_apex_compile( &self, callback: &Strong<dyn ICompilationTaskCallback>, ) -> Result<Strong<dyn ICompilationTask>>76     fn do_start_staged_apex_compile(
77         &self,
78         callback: &Strong<dyn ICompilationTaskCallback>,
79     ) -> Result<Strong<dyn ICompilationTask>> {
80         let comp_os = self.instance_manager.start_current_instance().context("Starting CompOS")?;
81 
82         let target_dir_name = PENDING_ARTIFACTS_SUBDIR.to_owned();
83         let task = OdrefreshTask::start(
84             comp_os,
85             CompilationMode::NORMAL_COMPILE,
86             target_dir_name,
87             callback,
88         )?;
89 
90         Ok(BnCompilationTask::new_binder(task, BinderFeatures::default()))
91     }
92 
do_start_test_compile( &self, prefer_staged: bool, callback: &Strong<dyn ICompilationTaskCallback>, os: &str, ) -> Result<Strong<dyn ICompilationTask>>93     fn do_start_test_compile(
94         &self,
95         prefer_staged: bool,
96         callback: &Strong<dyn ICompilationTaskCallback>,
97         os: &str,
98     ) -> Result<Strong<dyn ICompilationTask>> {
99         let comp_os = self
100             .instance_manager
101             .start_test_instance(prefer_staged, os)
102             .context("Starting CompOS")?;
103 
104         let target_dir_name = TEST_ARTIFACTS_SUBDIR.to_owned();
105         let task = OdrefreshTask::start(
106             comp_os,
107             CompilationMode::TEST_COMPILE,
108             target_dir_name,
109             callback,
110         )?;
111 
112         Ok(BnCompilationTask::new_binder(task, BinderFeatures::default()))
113     }
114 }
115 
check_permissions() -> binder::Result<()>116 fn check_permissions() -> binder::Result<()> {
117     let calling_uid = ThreadState::get_calling_uid();
118     // This should only be called by system server, or root while testing
119     if calling_uid != AID_SYSTEM && calling_uid != AID_ROOT {
120         Err(Status::new_exception(ExceptionCode::SECURITY, None))
121     } else {
122         Ok(())
123     }
124 }
125