Extract a library for common binder-related things

Initially this just unifies the various copies of we have of
new_binder_exception(), and adds a variation for service-specific
errors. (I thought this would help me solve my problem with missing
error info, but it turns out I was wrong.) I'm intending to move more
things here though to facilitate reuse.

Bug: 186126194
Test: atest -p
Change-Id: I82187903b55c4cd64307065761e1e03c4e6012f4
diff --git a/authfs/fd_server/Android.bp b/authfs/fd_server/Android.bp
index 8ddbf69..327df0d 100644
--- a/authfs/fd_server/Android.bp
+++ b/authfs/fd_server/Android.bp
@@ -9,6 +9,7 @@
         "authfs_aidl_interface-rust",
         "libandroid_logger",
         "libanyhow",
+        "libbinder_common",
         "libbinder_rpc_unstable_bindgen",
         "libbinder_rs",
         "libclap",
diff --git a/authfs/fd_server/src/main.rs b/authfs/fd_server/src/main.rs
index 7e551a3..12f013c 100644
--- a/authfs/fd_server/src/main.rs
+++ b/authfs/fd_server/src/main.rs
@@ -30,7 +30,6 @@
 use std::cmp::min;
 use std::collections::BTreeMap;
 use std::convert::TryInto;
-use std::ffi::CString;
 use std::fs::File;
 use std::io;
 use std::os::unix::fs::FileExt;
@@ -43,13 +42,10 @@
 use authfs_aidl_interface::binder::{
     BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, StatusCode, Strong,
 };
+use binder_common::new_binder_exception;
 
 const RPC_SERVICE_PORT: u32 = 3264; // TODO: support dynamic port for multiple fd_server instances
 
-fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
-    Status::new_exception(exception, CString::new(message.as_ref()).as_deref().ok())
-}
-
 fn validate_and_cast_offset(offset: i64) -> Result<u64, Status> {
     offset.try_into().map_err(|_| {
         new_binder_exception(ExceptionCode::ILLEGAL_ARGUMENT, format!("Invalid offset: {}", offset))
diff --git a/authfs/service/Android.bp b/authfs/service/Android.bp
index 943db35..6c32c67 100644
--- a/authfs/service/Android.bp
+++ b/authfs/service/Android.bp
@@ -12,6 +12,7 @@
         "authfs_aidl_interface-rust",
         "libandroid_logger",
         "libanyhow",
+        "libbinder_common",
         "libbinder_rs",
         "liblibc",
         "liblog_rust",
diff --git a/authfs/service/src/authfs.rs b/authfs/service/src/authfs.rs
index f41a3a6..5601738 100644
--- a/authfs/service/src/authfs.rs
+++ b/authfs/service/src/authfs.rs
@@ -26,7 +26,6 @@
 use std::thread::sleep;
 use std::time::{Duration, Instant};
 
-use crate::common::new_binder_exception;
 use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFs::{BnAuthFs, IAuthFs};
 use authfs_aidl_interface::aidl::com::android::virt::fs::{
     AuthFsConfig::AuthFsConfig, InputFdAnnotation::InputFdAnnotation,
@@ -35,6 +34,7 @@
 use authfs_aidl_interface::binder::{
     self, BinderFeatures, ExceptionCode, Interface, ParcelFileDescriptor, Strong,
 };
+use binder_common::new_binder_exception;
 
 const AUTHFS_BIN: &str = "/system/bin/authfs";
 const AUTHFS_SETUP_POLL_INTERVAL_MS: Duration = Duration::from_millis(50);
diff --git a/authfs/service/src/common.rs b/authfs/service/src/common.rs
deleted file mode 100644
index 00efe9e..0000000
--- a/authfs/service/src/common.rs
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * 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.
- */
-
-use std::ffi::CString;
-
-use authfs_aidl_interface::binder::{ExceptionCode, Status};
-
-/// Helper function to create a binder exception.
-pub fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
-    Status::new_exception(exception, CString::new(message.as_ref()).as_deref().ok())
-}
diff --git a/authfs/service/src/main.rs b/authfs/service/src/main.rs
index e426734..af8c7f9 100644
--- a/authfs/service/src/main.rs
+++ b/authfs/service/src/main.rs
@@ -21,7 +21,6 @@
 //! is able to retrieve "remote file descriptors".
 
 mod authfs;
-mod common;
 
 use anyhow::{bail, Context, Result};
 use log::*;
@@ -29,7 +28,6 @@
 use std::fs::{create_dir, read_dir, remove_dir_all, remove_file};
 use std::sync::atomic::{AtomicUsize, Ordering};
 
-use crate::common::new_binder_exception;
 use authfs_aidl_interface::aidl::com::android::virt::fs::AuthFsConfig::AuthFsConfig;
 use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFs::IAuthFs;
 use authfs_aidl_interface::aidl::com::android::virt::fs::IAuthFsService::{
@@ -38,6 +36,7 @@
 use authfs_aidl_interface::binder::{
     self, add_service, BinderFeatures, ExceptionCode, Interface, ProcessState, Strong,
 };
+use binder_common::new_binder_exception;
 
 const SERVICE_NAME: &str = "authfs_service";
 const SERVICE_ROOT: &str = "/data/misc/authfs";
diff --git a/binder_common/Android.bp b/binder_common/Android.bp
new file mode 100644
index 0000000..789a891
--- /dev/null
+++ b/binder_common/Android.bp
@@ -0,0 +1,17 @@
+package {
+    default_applicable_licenses: ["Android-Apache-2.0"],
+}
+
+rust_library {
+    name: "libbinder_common",
+    crate_name: "binder_common",
+    srcs: ["lib.rs"],
+    edition: "2018",
+    rustlibs: [
+        "libbinder_rs",
+    ],
+    apex_available: [
+        "com.android.compos",
+        "com.android.virt",
+    ],
+}
diff --git a/binder_common/lib.rs b/binder_common/lib.rs
new file mode 100644
index 0000000..54cb80e
--- /dev/null
+++ b/binder_common/lib.rs
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+
+//! Common items useful for binder clients and/or servers.
+
+use binder::public_api::{ExceptionCode, Status};
+use std::ffi::CString;
+
+/// Constructs a new Binder error `Status` with the given `ExceptionCode` and message.
+pub fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
+    match exception {
+        ExceptionCode::SERVICE_SPECIFIC => new_binder_service_specific_error(-1, message),
+        _ => Status::new_exception(exception, to_cstring(message).as_deref()),
+    }
+}
+
+/// Constructs a Binder `Status` representing a service-specific exception with the given code and
+/// message.
+pub fn new_binder_service_specific_error<T: AsRef<str>>(code: i32, message: T) -> Status {
+    Status::new_service_specific_error(code, to_cstring(message).as_deref())
+}
+
+fn to_cstring<T: AsRef<str>>(message: T) -> Option<CString> {
+    CString::new(message.as_ref()).ok()
+}
diff --git a/compos/Android.bp b/compos/Android.bp
index 2cc5131..b1e5f89 100644
--- a/compos/Android.bp
+++ b/compos/Android.bp
@@ -40,6 +40,7 @@
         "compos_aidl_interface-rust",
         "libandroid_logger",
         "libanyhow",
+        "libbinder_common",
         "libbinder_rpc_unstable_bindgen",
         "libbinder_rs",
         "libclap",
diff --git a/compos/composd/Android.bp b/compos/composd/Android.bp
index 0a25f05..9887483 100644
--- a/compos/composd/Android.bp
+++ b/compos/composd/Android.bp
@@ -13,6 +13,7 @@
         "compos_aidl_interface-rust",
         "libandroid_logger",
         "libanyhow",
+        "libbinder_common",
         "libbinder_rs",
         "libcompos_common",
         "libcomposd_native_rust",
diff --git a/compos/composd/src/service.rs b/compos/composd/src/service.rs
index fadca6c..2a67a27 100644
--- a/compos/composd/src/service.rs
+++ b/compos/composd/src/service.rs
@@ -22,13 +22,13 @@
 use android_system_composd::aidl::android::system::composd::IIsolatedCompilationService::{
     BnIsolatedCompilationService, IIsolatedCompilationService,
 };
-use android_system_composd::binder::{self, BinderFeatures, Interface, Status, Strong};
+use android_system_composd::binder::{self, BinderFeatures, Interface, Strong};
 use anyhow::{bail, Context, Result};
+use binder_common::new_binder_service_specific_error;
 use compos_aidl_interface::aidl::com::android::compos::{
     CompilationResult::CompilationResult, FdAnnotation::FdAnnotation,
 };
 use log::{error, info};
-use std::ffi::CString;
 
 pub struct IsolatedCompilationService {
     instance_manager: InstanceManager,
@@ -59,8 +59,9 @@
 
 fn to_binder_result<T>(result: Result<T>) -> binder::Result<T> {
     result.map_err(|e| {
-        error!("Returning binder error: {:#}", e);
-        Status::new_service_specific_error(-1, CString::new(format!("{:#}", e)).ok().as_deref())
+        let message = format!("{:?}", e);
+        error!("Returning binder error: {}", &message);
+        new_binder_service_specific_error(-1, message)
     })
 }
 
diff --git a/compos/src/compsvc.rs b/compos/src/compsvc.rs
index 55d9d64..954adf5 100644
--- a/compos/src/compsvc.rs
+++ b/compos/src/compsvc.rs
@@ -19,9 +19,9 @@
 //! actual compiler.
 
 use anyhow::Result;
+use binder_common::new_binder_exception;
 use log::warn;
 use std::default::Default;
-use std::ffi::CString;
 use std::path::PathBuf;
 use std::sync::{Arc, RwLock};
 
@@ -36,7 +36,7 @@
     ICompOsService::{BnCompOsService, ICompOsService},
 };
 use compos_aidl_interface::binder::{
-    BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Status, Strong,
+    BinderFeatures, ExceptionCode, Interface, Result as BinderResult, Strong,
 };
 
 const AUTHFS_SERVICE_NAME: &str = "authfs_service";
@@ -154,7 +154,3 @@
 fn get_authfs_service() -> BinderResult<Strong<dyn IAuthFsService>> {
     Ok(authfs_aidl_interface::binder::get_interface(AUTHFS_SERVICE_NAME)?)
 }
-
-fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
-    Status::new_exception(exception, CString::new(message.as_ref()).as_deref().ok())
-}
diff --git a/virtualizationservice/Android.bp b/virtualizationservice/Android.bp
index 54b32ec..443436d 100644
--- a/virtualizationservice/Android.bp
+++ b/virtualizationservice/Android.bp
@@ -25,6 +25,7 @@
         "android.os.permissions_aidl-rust",
         "libandroid_logger",
         "libanyhow",
+        "libbinder_common",
         "libbinder_rpc_unstable_bindgen",
         "libbinder_rs",
         "libcommand_fds",
diff --git a/virtualizationservice/src/aidl.rs b/virtualizationservice/src/aidl.rs
index 6679da6..76c3a16 100644
--- a/virtualizationservice/src/aidl.rs
+++ b/virtualizationservice/src/aidl.rs
@@ -19,6 +19,7 @@
 use crate::payload::add_microdroid_images;
 use crate::{Cid, FIRST_GUEST_CID, SYSPROP_LAST_CID};
 
+use binder_common::new_binder_exception;
 use android_os_permissions_aidl::aidl::android::os::IPermissionController;
 use android_system_virtualizationservice::aidl::android::system::virtualizationservice::IVirtualMachine::{
     BnVirtualMachine, IVirtualMachine,
@@ -48,7 +49,6 @@
 use microdroid_payload_config::VmPayloadConfig;
 use rustutils::system_properties;
 use std::convert::TryInto;
-use std::ffi::CString;
 use std::fs::{File, OpenOptions, create_dir};
 use std::io::{Error, ErrorKind, Write};
 use std::num::NonZeroU32;
@@ -795,11 +795,6 @@
     ParcelFileDescriptor::new(f)
 }
 
-/// Constructs a new Binder error `Status` with the given `ExceptionCode` and message.
-fn new_binder_exception<T: AsRef<str>>(exception: ExceptionCode, message: T) -> Status {
-    Status::new_exception(exception, CString::new(message.as_ref()).ok().as_deref())
-}
-
 /// Simple utility for referencing Borrowed or Owned. Similar to std::borrow::Cow, but
 /// it doesn't require that T implements Clone.
 enum BorrowedOrOwned<'a, T> {