composd: prepare staging directory w/ libartpalette-system

Output files are staged until they are fully generated, then move to the
final location. The staging directory has a different SELinux context to
prevent misuse, and should change when it's moved to the final
directory.

This change makes composd to follow the same setup, using libartpalette.
As a result, the output are no longer stored in CompOS's own apexdata
(which was not intentional).

This change does not use bindgen, which seems have some difficulty to
bridge `const char**` correctly. Neither cxx, since it doesn't seem to
simplify the (already simple) call.

Bug: 205750213
Test: See odrefresh produces output in the staging directory

Change-Id: Ifc97b31a98052a31209556449d1642089a8c0e2e
diff --git a/compos/composd/native/Android.bp b/compos/composd/native/Android.bp
index ad0afd9..135f4d4 100644
--- a/compos/composd/native/Android.bp
+++ b/compos/composd/native/Android.bp
@@ -7,12 +7,17 @@
     crate_name: "composd_native",
     srcs: ["lib.rs"],
     rustlibs: [
+        "libanyhow",
         "libcxx",
+        "liblibc",
     ],
     static_libs: [
         "libcomposd_native_cpp",
     ],
-    shared_libs: ["libcrypto"],
+    shared_libs: [
+        "libartpalette-system",
+        "libcrypto",
+    ],
     apex_available: ["com.android.compos"],
 }
 
diff --git a/compos/composd/native/lib.rs b/compos/composd/native/lib.rs
index ace9600..cbec7fd 100644
--- a/compos/composd/native/lib.rs
+++ b/compos/composd/native/lib.rs
@@ -12,12 +12,13 @@
 // See the License for the specific language governing permissions and
 // limitations under the License.
 
-//! Bindings native helpers for composd.
+//! Native helpers for composd.
 
-pub use ffi::*;
+pub use art::*;
+pub use crypto::*;
 
 #[cxx::bridge]
-mod ffi {
+mod crypto {
     /// Contains either a key or a reason why the key could not be extracted.
     struct KeyResult {
         /// The extracted key. If empty, the attempt to extract the key failed.
@@ -36,3 +37,38 @@
         fn extract_rsa_public_key(der_certificate: &[u8]) -> KeyResult;
     }
 }
+
+mod art {
+    use anyhow::{anyhow, Result};
+    use libc::c_char;
+    use std::ffi::{CStr, OsStr};
+    use std::io::Error;
+    use std::os::unix::ffi::OsStrExt;
+    use std::path::Path;
+    use std::ptr::null;
+
+    // From libartpalette(-system)
+    extern "C" {
+        fn PaletteCreateOdrefreshStagingDirectory(out_staging_dir: *mut *const c_char) -> i32;
+    }
+    const PALETTE_STATUS_OK: i32 = 0;
+    const PALETTE_STATUS_CHECK_ERRNO: i32 = 1;
+
+    /// Creates and returns the staging directory for odrefresh.
+    pub fn palette_create_odrefresh_staging_directory() -> Result<&'static Path> {
+        let mut staging_dir: *const c_char = null();
+        // SAFETY: The C function always returns a non-null C string (after created the directory).
+        let status = unsafe { PaletteCreateOdrefreshStagingDirectory(&mut staging_dir) };
+        match status {
+            PALETTE_STATUS_OK => {
+                // SAFETY: The previously returned `*const c_char` should point to a legitimate C
+                // string.
+                let cstr = unsafe { CStr::from_ptr(staging_dir) };
+                let path = OsStr::from_bytes(cstr.to_bytes()).as_ref();
+                Ok(path)
+            }
+            PALETTE_STATUS_CHECK_ERRNO => Err(anyhow!(Error::last_os_error().to_string())),
+            _ => Err(anyhow!("Failed with palette status {}", status)),
+        }
+    }
+}
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
index b126710..a2898a2 100644
--- a/compos/composd/src/service.rs
+++ b/compos/composd/src/service.rs
@@ -20,7 +20,6 @@
 use crate::compilation_task::CompilationTask;
 use crate::fd_server_helper::FdServerConfig;
 use crate::instance_manager::InstanceManager;
-use crate::instance_starter::CompOsInstance;
 use crate::util::to_binder_result;
 use android_system_composd::aidl::android::system::composd::{
     ICompilationTask::{BnCompilationTask, ICompilationTask},
@@ -31,12 +30,11 @@
     self, BinderFeatures, ExceptionCode, Interface, Status, Strong, ThreadState,
 };
 use anyhow::{Context, Result};
-use compos_common::COMPOS_DATA_ROOT;
 use rustutils::{system_properties, users::AID_ROOT, users::AID_SYSTEM};
-use std::fs::{create_dir, File, OpenOptions};
+use std::fs::{File, OpenOptions};
 use std::os::unix::fs::OpenOptionsExt;
 use std::os::unix::io::AsRawFd;
-use std::path::{Path, PathBuf};
+use std::path::Path;
 use std::sync::Arc;
 
 pub struct IsolatedCompilationService {
@@ -100,19 +98,12 @@
     }
 
     fn do_odrefresh_for_test(&self) -> Result<i8> {
-        let mut staging_dir_path = PathBuf::from(COMPOS_DATA_ROOT);
-        staging_dir_path.push("test-artifacts");
-        to_binder_result(create_dir(&staging_dir_path))?;
-
         let compos = self
             .instance_manager
             .start_test_instance()
             .context("Starting CompOS for odrefresh test")?;
-        self.do_odrefresh(compos, &staging_dir_path)
-    }
 
-    fn do_odrefresh(&self, compos: Arc<CompOsInstance>, staging_dir_path: &Path) -> Result<i8> {
-        let output_dir = open_dir(staging_dir_path)?;
+        let output_dir = open_dir(composd_native::palette_create_odrefresh_staging_directory()?)?;
         let system_dir = open_dir(Path::new("/system"))?;
 
         // Spawn a fd_server to serve the FDs.