/*
 * Copyright (C) 2021 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

//! compsvc is a service to run compilation tasks in a PVM upon request. It is able to set up
//! file descriptors backed by authfs (via authfs_service) and pass the file descriptors to the
//! actual compiler.

use anyhow::{bail, Context, Result};
use log::{error, info};
use rustutils::system_properties;
use std::default::Default;
use std::fs::read_dir;
use std::iter::zip;
use std::path::{Path, PathBuf};
use std::sync::RwLock;

use crate::artifact_signer::ArtifactSigner;
use crate::compilation::odrefresh;
use crate::compos_key;
use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::{
    IAuthFsService, AUTHFS_SERVICE_SOCKET_NAME,
};
use binder::{BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, Strong};
use compos_aidl_interface::aidl::com::android::compos::ICompOsService::{
    BnCompOsService, ICompOsService, OdrefreshArgs::OdrefreshArgs,
};
use compos_common::binder::to_binder_result;
use compos_common::odrefresh::{is_system_property_interesting, ODREFRESH_PATH};
use rpcbinder::RpcSession;

/// Constructs a binder object that implements ICompOsService.
pub fn new_binder() -> Result<Strong<dyn ICompOsService>> {
    let service = CompOsService {
        odrefresh_path: PathBuf::from(ODREFRESH_PATH),
        initialized: RwLock::new(None),
    };
    Ok(BnCompOsService::new_binder(service, BinderFeatures::default()))
}

struct CompOsService {
    odrefresh_path: PathBuf,

    /// A locked protected tri-state.
    ///  * None: uninitialized
    ///  * Some(true): initialized successfully
    ///  * Some(false): failed to initialize
    initialized: RwLock<Option<bool>>,
}

impl Interface for CompOsService {}

impl ICompOsService for CompOsService {
    fn initializeSystemProperties(&self, names: &[String], values: &[String]) -> BinderResult<()> {
        let mut initialized = self.initialized.write().unwrap();
        if initialized.is_some() {
            return Err(Status::new_exception_str(
                ExceptionCode::ILLEGAL_STATE,
                Some(format!("Already initialized: {:?}", initialized)),
            ));
        }
        *initialized = Some(false);

        if names.len() != values.len() {
            return Err(Status::new_exception_str(
                ExceptionCode::ILLEGAL_ARGUMENT,
                Some(format!(
                    "Received inconsistent number of keys ({}) and values ({})",
                    names.len(),
                    values.len()
                )),
            ));
        }
        for (name, value) in zip(names, values) {
            if !is_system_property_interesting(name) {
                return Err(Status::new_exception_str(
                    ExceptionCode::ILLEGAL_ARGUMENT,
                    Some(format!("Received invalid system property {}", &name)),
                ));
            }
            let result = system_properties::write(name, value);
            if result.is_err() {
                error!("Failed to setprop {}", &name);
                return to_binder_result(result);
            }
        }
        *initialized = Some(true);
        Ok(())
    }

    fn odrefresh(&self, args: &OdrefreshArgs) -> BinderResult<i8> {
        let initialized = *self.initialized.read().unwrap();
        if !initialized.unwrap_or(false) {
            return Err(Status::new_exception_str(
                ExceptionCode::ILLEGAL_STATE,
                Some("Service has not been initialized"),
            ));
        }

        to_binder_result(self.do_odrefresh(args))
    }

    fn getPublicKey(&self) -> BinderResult<Vec<u8>> {
        to_binder_result(compos_key::get_public_key())
    }

    fn getAttestationChain(&self) -> BinderResult<Vec<u8>> {
        to_binder_result(compos_key::get_attestation_chain())
    }

    fn quit(&self) -> BinderResult<()> {
        // When our process exits, Microdroid will shut down the VM.
        info!("Received quit request, exiting");
        std::process::exit(0);
    }
}

impl CompOsService {
    fn do_odrefresh(&self, args: &OdrefreshArgs) -> Result<i8> {
        log::debug!("Prepare to connect to {}", AUTHFS_SERVICE_SOCKET_NAME);
        let authfs_service: Strong<dyn IAuthFsService> = RpcSession::new()
            .setup_unix_domain_client(AUTHFS_SERVICE_SOCKET_NAME)
            .with_context(|| format!("Failed to connect to {}", AUTHFS_SERVICE_SOCKET_NAME))?;
        let exit_code = odrefresh(&self.odrefresh_path, args, authfs_service, |output_dir| {
            // authfs only shows us the files we created, so it's ok to just sign everything
            // under the output directory.
            let mut artifact_signer = ArtifactSigner::new(&output_dir);
            add_artifacts(&output_dir, &mut artifact_signer)?;

            artifact_signer.write_info_and_signature(&output_dir.join("compos.info"))
        })
        .context("odrefresh failed")?;
        Ok(exit_code as i8)
    }
}

fn add_artifacts(target_dir: &Path, artifact_signer: &mut ArtifactSigner) -> Result<()> {
    for entry in
        read_dir(target_dir).with_context(|| format!("Traversing {}", target_dir.display()))?
    {
        let entry = entry?;
        let file_type = entry.file_type()?;
        if file_type.is_dir() {
            add_artifacts(&entry.path(), artifact_signer)?;
        } else if file_type.is_file() {
            artifact_signer.add_artifact(&entry.path())?;
        } else {
            // authfs shouldn't create anything else, but just in case
            bail!("Unexpected file type in artifacts: {:?}", entry);
        }
    }
    Ok(())
}
