Assorted refactoring

Mostly removing duplication. Also added a comment as suggested by
Andrew.

Bug: 161471326
Test: composd_cmd async-odrefresh

Change-Id: I7da83cb825de7b4fd2267b1e496808a423544c16
diff --git a/compos/common/Android.bp b/compos/common/Android.bp
index 7c61d94..39e7c0a 100644
--- a/compos/common/Android.bp
+++ b/compos/common/Android.bp
@@ -11,6 +11,7 @@
         "android.system.virtualizationservice-rust",
         "compos_aidl_interface-rust",
         "libanyhow",
+        "libbinder_common",
         "libbinder_rpc_unstable_bindgen",
         "libbinder_rs",
         "liblog_rust",
diff --git a/compos/common/binder.rs b/compos/common/binder.rs
new file mode 100644
index 0000000..6bd3957
--- /dev/null
+++ b/compos/common/binder.rs
@@ -0,0 +1,34 @@
+/*
+ * Copyright 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.
+ */
+
+//! Helper for converting Error types to what Binder expects
+
+use anyhow::Result;
+use binder::public_api::{ExceptionCode, Result as BinderResult};
+use binder_common::new_binder_exception;
+use log::warn;
+use std::fmt::Debug;
+
+/// Convert a Result<T, E> to BinderResult<T> to allow it to be returned from a binder RPC,
+/// preserving the content as far as possible.
+/// Also log the error if there is one.
+pub fn to_binder_result<T, E: Debug>(result: Result<T, E>) -> BinderResult<T> {
+    result.map_err(|e| {
+        let message = format!("{:?}", e);
+        warn!("Returning binder error: {}", &message);
+        new_binder_exception(ExceptionCode::SERVICE_SPECIFIC, message)
+    })
+}
diff --git a/compos/common/lib.rs b/compos/common/lib.rs
index 5c28379..6e397a2 100644
--- a/compos/common/lib.rs
+++ b/compos/common/lib.rs
@@ -16,6 +16,7 @@
 
 //! Common items used by CompOS server and/or clients
 
+pub mod binder;
 pub mod compos_client;
 pub mod odrefresh;
 pub mod timeouts;
diff --git a/compos/common/odrefresh.rs b/compos/common/odrefresh.rs
index 7838b69..7fe6ed5 100644
--- a/compos/common/odrefresh.rs
+++ b/compos/common/odrefresh.rs
@@ -16,12 +16,15 @@
 
 //! Helpers for running odrefresh
 
+use anyhow::{anyhow, Result};
 use num_derive::FromPrimitive;
 use num_traits::FromPrimitive;
 
 /// The path to the odrefresh binary
 pub const ODREFRESH_PATH: &str = "/apex/com.android.art/bin/odrefresh";
 
+// The highest "standard" exit code defined in sysexits.h (as EX__MAX); odrefresh error codes
+// start above here to avoid clashing.
 // TODO: What if this changes?
 const EX_MAX: i8 = 78;
 
@@ -30,7 +33,7 @@
 #[repr(i8)]
 pub enum ExitCode {
     /// No compilation required, all artifacts look good
-    Okay = 0i8,
+    Okay = 0,
     /// Compilation required
     CompilationRequired = EX_MAX + 1,
     /// New artifacts successfully generated
@@ -43,7 +46,8 @@
 
 impl ExitCode {
     /// Map an integer to the corresponding ExitCode enum, if there is one
-    pub fn from_i32(exit_code: i32) -> Option<Self> {
+    pub fn from_i32(exit_code: i32) -> Result<Self> {
         FromPrimitive::from_i32(exit_code)
+            .ok_or_else(|| anyhow!("Unexpected odrefresh exit code: {}", exit_code))
     }
 }