[services] Introduce TeaclaveServiceLauncher to simplify app part of services
diff --git a/config/src/lib.rs b/config/src/lib.rs
index ddf03a3..60c5a70 100644
--- a/config/src/lib.rs
+++ b/config/src/lib.rs
@@ -23,7 +23,7 @@
 use serde::{Deserialize, Serialize};
 use std::path::PathBuf;
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 #[serde(rename_all = "snake_case")]
 pub(crate) enum ConfigSource {
     Path(PathBuf),
diff --git a/config/src/runtime.rs b/config/src/runtime.rs
index 1695359..d14dc58 100644
--- a/config/src/runtime.rs
+++ b/config/src/runtime.rs
@@ -31,7 +31,7 @@
 use std::string::String;
 use std::vec::Vec;
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct RuntimeConfig {
     pub api_endpoints: ApiEndpointsConfig,
     pub internal_endpoints: InternalEndpointsConfig,
@@ -40,13 +40,13 @@
     pub mount: MountConfig,
 }
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct ApiEndpointsConfig {
     pub frontend: ApiEndpoint,
     pub authentication: ApiEndpoint,
 }
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct InternalEndpointsConfig {
     pub access_control: InternalEndpoint,
     pub authentication: InternalEndpoint,
@@ -56,18 +56,18 @@
     pub scheduler: InternalEndpoint,
 }
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct ApiEndpoint {
     pub listen_address: net::SocketAddr,
 }
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct InternalEndpoint {
     pub listen_address: net::SocketAddr,
     pub advertised_address: String,
 }
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct AuditConfig {
     #[serde(rename(serialize = "enclave_info", deserialize = "enclave_info"))]
     enclave_info_source: ConfigSource,
@@ -79,7 +79,7 @@
     pub auditor_signatures_bytes: Vec<Vec<u8>>,
 }
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct AttestationServiceConfig {
     pub algorithm: String,
     pub url: String,
@@ -87,7 +87,7 @@
     pub spid: String,
 }
 
-#[derive(Debug, Serialize, Deserialize)]
+#[derive(Debug, Serialize, Deserialize, Clone)]
 pub struct MountConfig {
     pub fusion_base_dir: PathBuf,
 }
diff --git a/services/access_control/app/Cargo.toml b/services/access_control/app/Cargo.toml
index dd0a4de..395a7bb 100644
--- a/services/access_control/app/Cargo.toml
+++ b/services/access_control/app/Cargo.toml
@@ -8,14 +8,9 @@
 edition = "2018"
 
 [dependencies]
-log         = { version = "0.4.6" }
 env_logger  = { version = "0.7.1" }
 anyhow      = { version = "1.0.26" }
-signal-hook = { version = "0.1.13" }
 libc        = { version = "0.2.66" }
+signal-hook = { version = "0.1.13" }
 
-teaclave_binder            = { path = "../../../binder", features = ["app"] }
-teaclave_config            = { path = "../../../config" }
-teaclave_types             = { path = "../../../types" }
-
-sgx_types = { version = "1.1.2" }
+teaclave_service_app_utils = { path = "../../utils/service_app_utils" }
diff --git a/services/access_control/app/src/main.rs b/services/access_control/app/src/main.rs
index 56cc75c..d6e0127 100644
--- a/services/access_control/app/src/main.rs
+++ b/services/access_control/app/src/main.rs
@@ -18,70 +18,32 @@
 use anyhow::{Context, Result};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
-use teaclave_binder::proto::{ECallCommand, StartServiceInput, StartServiceOutput};
-use teaclave_binder::TeeBinder;
-use teaclave_config::RuntimeConfig;
-use teaclave_types::TeeServiceResult;
+use std::thread;
+use teaclave_service_app_utils::{register_signals, TeaclaveServiceLauncher};
 
 const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
 
-fn register_signals(term: Arc<AtomicBool>) -> Result<()> {
-    for signal in &[
-        signal_hook::SIGTERM,
-        signal_hook::SIGINT,
-        signal_hook::SIGHUP,
-    ] {
-        let term_ref = term.clone();
-        let thread = std::thread::current();
-        unsafe {
-            signal_hook::register(*signal, move || {
-                term_ref.store(true, Ordering::Relaxed);
-                thread.unpark();
-            })?;
-        }
-    }
-
-    Ok(())
-}
-
-fn start_enclave_service(tee: Arc<TeeBinder>, config: RuntimeConfig) {
-    let input = StartServiceInput::new(config);
-    let command = ECallCommand::StartService;
-    match tee.invoke::<StartServiceInput, TeeServiceResult<StartServiceOutput>>(command, input) {
-        Err(e) => {
-            eprintln!("TEE invocation error: {:?}", e);
-        }
-        Ok(Err(e)) => {
-            eprintln!("Service exit with error: {:?}", e);
-        }
-        _ => {
-            println!("Service successfully exit");
-        }
-    }
-
-    unsafe { libc::raise(signal_hook::SIGTERM) };
-}
-
 fn main() -> Result<()> {
     env_logger::init();
 
-    let tee = Arc::new(TeeBinder::new(PACKAGE_NAME).context("Failed to new the enclave.")?);
-    let config = teaclave_config::RuntimeConfig::from_toml("runtime.config.toml")
-        .context("Failed to load config file.")?;
-
-    let tee_ref = tee.clone();
-    std::thread::spawn(move || {
-        start_enclave_service(tee_ref, config);
+    let launcher = Arc::new(TeaclaveServiceLauncher::new(
+        PACKAGE_NAME,
+        "runtime.config.toml",
+    )?);
+    let launcher_ref = launcher.clone();
+    thread::spawn(move || {
+        let _ = launcher_ref.start();
+        unsafe { libc::raise(signal_hook::SIGTERM) }
     });
 
     let term = Arc::new(AtomicBool::new(false));
     register_signals(term.clone()).context("Failed to register signal handler")?;
 
     while !term.load(Ordering::Relaxed) {
-        std::thread::park();
+        thread::park();
     }
 
-    tee.finalize();
+    launcher.finalize();
 
     Ok(())
 }
diff --git a/services/authentication/app/Cargo.toml b/services/authentication/app/Cargo.toml
index 2d05a52..d215e38 100644
--- a/services/authentication/app/Cargo.toml
+++ b/services/authentication/app/Cargo.toml
@@ -8,14 +8,9 @@
 edition = "2018"
 
 [dependencies]
-log         = { version = "0.4.6" }
 env_logger  = { version = "0.7.1" }
 anyhow      = { version = "1.0.26" }
-signal-hook = { version = "0.1.13" }
 libc        = { version = "0.2.66" }
+signal-hook = { version = "0.1.13" }
 
-teaclave_binder            = { path = "../../../binder", features = ["app"] }
-teaclave_config            = { path = "../../../config" }
-teaclave_types             = { path = "../../../types" }
-
-sgx_types = { version = "1.1.2" }
+teaclave_service_app_utils = { path = "../../utils/service_app_utils" }
diff --git a/services/authentication/app/src/main.rs b/services/authentication/app/src/main.rs
index 56cc75c..d6e0127 100644
--- a/services/authentication/app/src/main.rs
+++ b/services/authentication/app/src/main.rs
@@ -18,70 +18,32 @@
 use anyhow::{Context, Result};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
-use teaclave_binder::proto::{ECallCommand, StartServiceInput, StartServiceOutput};
-use teaclave_binder::TeeBinder;
-use teaclave_config::RuntimeConfig;
-use teaclave_types::TeeServiceResult;
+use std::thread;
+use teaclave_service_app_utils::{register_signals, TeaclaveServiceLauncher};
 
 const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
 
-fn register_signals(term: Arc<AtomicBool>) -> Result<()> {
-    for signal in &[
-        signal_hook::SIGTERM,
-        signal_hook::SIGINT,
-        signal_hook::SIGHUP,
-    ] {
-        let term_ref = term.clone();
-        let thread = std::thread::current();
-        unsafe {
-            signal_hook::register(*signal, move || {
-                term_ref.store(true, Ordering::Relaxed);
-                thread.unpark();
-            })?;
-        }
-    }
-
-    Ok(())
-}
-
-fn start_enclave_service(tee: Arc<TeeBinder>, config: RuntimeConfig) {
-    let input = StartServiceInput::new(config);
-    let command = ECallCommand::StartService;
-    match tee.invoke::<StartServiceInput, TeeServiceResult<StartServiceOutput>>(command, input) {
-        Err(e) => {
-            eprintln!("TEE invocation error: {:?}", e);
-        }
-        Ok(Err(e)) => {
-            eprintln!("Service exit with error: {:?}", e);
-        }
-        _ => {
-            println!("Service successfully exit");
-        }
-    }
-
-    unsafe { libc::raise(signal_hook::SIGTERM) };
-}
-
 fn main() -> Result<()> {
     env_logger::init();
 
-    let tee = Arc::new(TeeBinder::new(PACKAGE_NAME).context("Failed to new the enclave.")?);
-    let config = teaclave_config::RuntimeConfig::from_toml("runtime.config.toml")
-        .context("Failed to load config file.")?;
-
-    let tee_ref = tee.clone();
-    std::thread::spawn(move || {
-        start_enclave_service(tee_ref, config);
+    let launcher = Arc::new(TeaclaveServiceLauncher::new(
+        PACKAGE_NAME,
+        "runtime.config.toml",
+    )?);
+    let launcher_ref = launcher.clone();
+    thread::spawn(move || {
+        let _ = launcher_ref.start();
+        unsafe { libc::raise(signal_hook::SIGTERM) }
     });
 
     let term = Arc::new(AtomicBool::new(false));
     register_signals(term.clone()).context("Failed to register signal handler")?;
 
     while !term.load(Ordering::Relaxed) {
-        std::thread::park();
+        thread::park();
     }
 
-    tee.finalize();
+    launcher.finalize();
 
     Ok(())
 }
diff --git a/services/execution/app/Cargo.toml b/services/execution/app/Cargo.toml
index 6416814..48deaac 100644
--- a/services/execution/app/Cargo.toml
+++ b/services/execution/app/Cargo.toml
@@ -8,15 +8,10 @@
 edition = "2018"
 
 [dependencies]
-log         = { version = "0.4.6" }
 env_logger  = { version = "0.7.1" }
 anyhow      = { version = "1.0.26" }
-signal-hook = { version = "0.1.13" }
 libc        = { version = "0.2.66" }
+signal-hook = { version = "0.1.13" }
 
-teaclave_binder            = { path = "../../../binder", features = ["app"] }
-teaclave_config            = { path = "../../../config" }
-teaclave_types             = { path = "../../../types" }
 teaclave_file_agent        = { path = "../../../file_agent" }
-
-sgx_types = { version = "1.1.2" }
+teaclave_service_app_utils = { path = "../../utils/service_app_utils" }
diff --git a/services/execution/app/src/main.rs b/services/execution/app/src/main.rs
index 0fd7b3c..4e5799b 100644
--- a/services/execution/app/src/main.rs
+++ b/services/execution/app/src/main.rs
@@ -18,72 +18,35 @@
 use anyhow::{Context, Result};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
-use teaclave_binder::proto::{ECallCommand, StartServiceInput, StartServiceOutput};
-use teaclave_binder::TeeBinder;
-use teaclave_config::RuntimeConfig;
-use teaclave_types::TeeServiceResult;
+use std::thread;
+use teaclave_service_app_utils::{register_signals, TeaclaveServiceLauncher};
 
-const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
-
+// Use to import ocall
 pub use teaclave_file_agent::ocall_handle_file_request;
 
-fn register_signals(term: Arc<AtomicBool>) -> Result<()> {
-    for signal in &[
-        signal_hook::SIGTERM,
-        signal_hook::SIGINT,
-        signal_hook::SIGHUP,
-    ] {
-        let term_ref = term.clone();
-        let thread = std::thread::current();
-        unsafe {
-            signal_hook::register(*signal, move || {
-                term_ref.store(true, Ordering::Relaxed);
-                thread.unpark();
-            })?;
-        }
-    }
-
-    Ok(())
-}
-
-fn start_enclave_service(tee: Arc<TeeBinder>, config: RuntimeConfig) {
-    let input = StartServiceInput::new(config);
-    let command = ECallCommand::StartService;
-    match tee.invoke::<StartServiceInput, TeeServiceResult<StartServiceOutput>>(command, input) {
-        Err(e) => {
-            eprintln!("TEE invocation error: {:?}", e);
-        }
-        Ok(Err(e)) => {
-            eprintln!("Service exit with error: {:?}", e);
-        }
-        _ => {
-            println!("Service successfully exit");
-        }
-    }
-
-    unsafe { libc::raise(signal_hook::SIGTERM) };
-}
+const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
 
 fn main() -> Result<()> {
     env_logger::init();
 
-    let tee = Arc::new(TeeBinder::new(PACKAGE_NAME).context("Failed to new the enclave.")?);
-    let config = teaclave_config::RuntimeConfig::from_toml("runtime.config.toml")
-        .context("Failed to load config file.")?;
-
-    let tee_ref = tee.clone();
-    std::thread::spawn(move || {
-        start_enclave_service(tee_ref, config);
+    let launcher = Arc::new(TeaclaveServiceLauncher::new(
+        PACKAGE_NAME,
+        "runtime.config.toml",
+    )?);
+    let launcher_ref = launcher.clone();
+    thread::spawn(move || {
+        let _ = launcher_ref.start();
+        unsafe { libc::raise(signal_hook::SIGTERM) }
     });
 
     let term = Arc::new(AtomicBool::new(false));
     register_signals(term.clone()).context("Failed to register signal handler")?;
 
     while !term.load(Ordering::Relaxed) {
-        std::thread::park();
+        thread::park();
     }
 
-    tee.finalize();
+    launcher.finalize();
 
     Ok(())
 }
diff --git a/services/frontend/app/Cargo.toml b/services/frontend/app/Cargo.toml
index d5182c8..de0e909 100644
--- a/services/frontend/app/Cargo.toml
+++ b/services/frontend/app/Cargo.toml
@@ -8,14 +8,9 @@
 edition = "2018"
 
 [dependencies]
-log         = { version = "0.4.6" }
 env_logger  = { version = "0.7.1" }
 anyhow      = { version = "1.0.26" }
-signal-hook = { version = "0.1.13" }
 libc        = { version = "0.2.66" }
+signal-hook = { version = "0.1.13" }
 
-teaclave_binder            = { path = "../../../binder", features = ["app"] }
-teaclave_config            = { path = "../../../config" }
-teaclave_types             = { path = "../../../types" }
-
-sgx_types = { version = "1.1.2" }
+teaclave_service_app_utils = { path = "../../utils/service_app_utils" }
diff --git a/services/frontend/app/src/main.rs b/services/frontend/app/src/main.rs
index 56cc75c..d6e0127 100644
--- a/services/frontend/app/src/main.rs
+++ b/services/frontend/app/src/main.rs
@@ -18,70 +18,32 @@
 use anyhow::{Context, Result};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
-use teaclave_binder::proto::{ECallCommand, StartServiceInput, StartServiceOutput};
-use teaclave_binder::TeeBinder;
-use teaclave_config::RuntimeConfig;
-use teaclave_types::TeeServiceResult;
+use std::thread;
+use teaclave_service_app_utils::{register_signals, TeaclaveServiceLauncher};
 
 const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
 
-fn register_signals(term: Arc<AtomicBool>) -> Result<()> {
-    for signal in &[
-        signal_hook::SIGTERM,
-        signal_hook::SIGINT,
-        signal_hook::SIGHUP,
-    ] {
-        let term_ref = term.clone();
-        let thread = std::thread::current();
-        unsafe {
-            signal_hook::register(*signal, move || {
-                term_ref.store(true, Ordering::Relaxed);
-                thread.unpark();
-            })?;
-        }
-    }
-
-    Ok(())
-}
-
-fn start_enclave_service(tee: Arc<TeeBinder>, config: RuntimeConfig) {
-    let input = StartServiceInput::new(config);
-    let command = ECallCommand::StartService;
-    match tee.invoke::<StartServiceInput, TeeServiceResult<StartServiceOutput>>(command, input) {
-        Err(e) => {
-            eprintln!("TEE invocation error: {:?}", e);
-        }
-        Ok(Err(e)) => {
-            eprintln!("Service exit with error: {:?}", e);
-        }
-        _ => {
-            println!("Service successfully exit");
-        }
-    }
-
-    unsafe { libc::raise(signal_hook::SIGTERM) };
-}
-
 fn main() -> Result<()> {
     env_logger::init();
 
-    let tee = Arc::new(TeeBinder::new(PACKAGE_NAME).context("Failed to new the enclave.")?);
-    let config = teaclave_config::RuntimeConfig::from_toml("runtime.config.toml")
-        .context("Failed to load config file.")?;
-
-    let tee_ref = tee.clone();
-    std::thread::spawn(move || {
-        start_enclave_service(tee_ref, config);
+    let launcher = Arc::new(TeaclaveServiceLauncher::new(
+        PACKAGE_NAME,
+        "runtime.config.toml",
+    )?);
+    let launcher_ref = launcher.clone();
+    thread::spawn(move || {
+        let _ = launcher_ref.start();
+        unsafe { libc::raise(signal_hook::SIGTERM) }
     });
 
     let term = Arc::new(AtomicBool::new(false));
     register_signals(term.clone()).context("Failed to register signal handler")?;
 
     while !term.load(Ordering::Relaxed) {
-        std::thread::park();
+        thread::park();
     }
 
-    tee.finalize();
+    launcher.finalize();
 
     Ok(())
 }
diff --git a/services/management/app/Cargo.toml b/services/management/app/Cargo.toml
index 969d1c1..0d7533f 100644
--- a/services/management/app/Cargo.toml
+++ b/services/management/app/Cargo.toml
@@ -8,14 +8,9 @@
 edition = "2018"
 
 [dependencies]
-log         = { version = "0.4.6" }
 env_logger  = { version = "0.7.1" }
 anyhow      = { version = "1.0.26" }
-signal-hook = { version = "0.1.13" }
 libc        = { version = "0.2.66" }
+signal-hook = { version = "0.1.13" }
 
-teaclave_binder            = { path = "../../../binder", features = ["app"] }
-teaclave_config            = { path = "../../../config" }
-teaclave_types             = { path = "../../../types" }
-
-sgx_types = { version = "1.1.2" }
+teaclave_service_app_utils = { path = "../../utils/service_app_utils" }
diff --git a/services/management/app/src/main.rs b/services/management/app/src/main.rs
index 56cc75c..d6e0127 100644
--- a/services/management/app/src/main.rs
+++ b/services/management/app/src/main.rs
@@ -18,70 +18,32 @@
 use anyhow::{Context, Result};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
-use teaclave_binder::proto::{ECallCommand, StartServiceInput, StartServiceOutput};
-use teaclave_binder::TeeBinder;
-use teaclave_config::RuntimeConfig;
-use teaclave_types::TeeServiceResult;
+use std::thread;
+use teaclave_service_app_utils::{register_signals, TeaclaveServiceLauncher};
 
 const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
 
-fn register_signals(term: Arc<AtomicBool>) -> Result<()> {
-    for signal in &[
-        signal_hook::SIGTERM,
-        signal_hook::SIGINT,
-        signal_hook::SIGHUP,
-    ] {
-        let term_ref = term.clone();
-        let thread = std::thread::current();
-        unsafe {
-            signal_hook::register(*signal, move || {
-                term_ref.store(true, Ordering::Relaxed);
-                thread.unpark();
-            })?;
-        }
-    }
-
-    Ok(())
-}
-
-fn start_enclave_service(tee: Arc<TeeBinder>, config: RuntimeConfig) {
-    let input = StartServiceInput::new(config);
-    let command = ECallCommand::StartService;
-    match tee.invoke::<StartServiceInput, TeeServiceResult<StartServiceOutput>>(command, input) {
-        Err(e) => {
-            eprintln!("TEE invocation error: {:?}", e);
-        }
-        Ok(Err(e)) => {
-            eprintln!("Service exit with error: {:?}", e);
-        }
-        _ => {
-            println!("Service successfully exit");
-        }
-    }
-
-    unsafe { libc::raise(signal_hook::SIGTERM) };
-}
-
 fn main() -> Result<()> {
     env_logger::init();
 
-    let tee = Arc::new(TeeBinder::new(PACKAGE_NAME).context("Failed to new the enclave.")?);
-    let config = teaclave_config::RuntimeConfig::from_toml("runtime.config.toml")
-        .context("Failed to load config file.")?;
-
-    let tee_ref = tee.clone();
-    std::thread::spawn(move || {
-        start_enclave_service(tee_ref, config);
+    let launcher = Arc::new(TeaclaveServiceLauncher::new(
+        PACKAGE_NAME,
+        "runtime.config.toml",
+    )?);
+    let launcher_ref = launcher.clone();
+    thread::spawn(move || {
+        let _ = launcher_ref.start();
+        unsafe { libc::raise(signal_hook::SIGTERM) }
     });
 
     let term = Arc::new(AtomicBool::new(false));
     register_signals(term.clone()).context("Failed to register signal handler")?;
 
     while !term.load(Ordering::Relaxed) {
-        std::thread::park();
+        thread::park();
     }
 
-    tee.finalize();
+    launcher.finalize();
 
     Ok(())
 }
diff --git a/services/scheduler/app/Cargo.toml b/services/scheduler/app/Cargo.toml
index 86bdd7b..4f53190 100644
--- a/services/scheduler/app/Cargo.toml
+++ b/services/scheduler/app/Cargo.toml
@@ -8,14 +8,9 @@
 edition = "2018"
 
 [dependencies]
-log         = { version = "0.4.6" }
 env_logger  = { version = "0.7.1" }
 anyhow      = { version = "1.0.26" }
-signal-hook = { version = "0.1.13" }
 libc        = { version = "0.2.66" }
+signal-hook = { version = "0.1.13" }
 
-teaclave_binder            = { path = "../../../binder", features = ["app"] }
-teaclave_config            = { path = "../../../config" }
-teaclave_types             = { path = "../../../types" }
-
-sgx_types = { version = "1.1.2" }
+teaclave_service_app_utils = { path = "../../utils/service_app_utils" }
diff --git a/services/scheduler/app/src/main.rs b/services/scheduler/app/src/main.rs
index 56cc75c..d6e0127 100644
--- a/services/scheduler/app/src/main.rs
+++ b/services/scheduler/app/src/main.rs
@@ -18,70 +18,32 @@
 use anyhow::{Context, Result};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
-use teaclave_binder::proto::{ECallCommand, StartServiceInput, StartServiceOutput};
-use teaclave_binder::TeeBinder;
-use teaclave_config::RuntimeConfig;
-use teaclave_types::TeeServiceResult;
+use std::thread;
+use teaclave_service_app_utils::{register_signals, TeaclaveServiceLauncher};
 
 const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
 
-fn register_signals(term: Arc<AtomicBool>) -> Result<()> {
-    for signal in &[
-        signal_hook::SIGTERM,
-        signal_hook::SIGINT,
-        signal_hook::SIGHUP,
-    ] {
-        let term_ref = term.clone();
-        let thread = std::thread::current();
-        unsafe {
-            signal_hook::register(*signal, move || {
-                term_ref.store(true, Ordering::Relaxed);
-                thread.unpark();
-            })?;
-        }
-    }
-
-    Ok(())
-}
-
-fn start_enclave_service(tee: Arc<TeeBinder>, config: RuntimeConfig) {
-    let input = StartServiceInput::new(config);
-    let command = ECallCommand::StartService;
-    match tee.invoke::<StartServiceInput, TeeServiceResult<StartServiceOutput>>(command, input) {
-        Err(e) => {
-            eprintln!("TEE invocation error: {:?}", e);
-        }
-        Ok(Err(e)) => {
-            eprintln!("Service exit with error: {:?}", e);
-        }
-        _ => {
-            println!("Service successfully exit");
-        }
-    }
-
-    unsafe { libc::raise(signal_hook::SIGTERM) };
-}
-
 fn main() -> Result<()> {
     env_logger::init();
 
-    let tee = Arc::new(TeeBinder::new(PACKAGE_NAME).context("Failed to new the enclave.")?);
-    let config = teaclave_config::RuntimeConfig::from_toml("runtime.config.toml")
-        .context("Failed to load config file.")?;
-
-    let tee_ref = tee.clone();
-    std::thread::spawn(move || {
-        start_enclave_service(tee_ref, config);
+    let launcher = Arc::new(TeaclaveServiceLauncher::new(
+        PACKAGE_NAME,
+        "runtime.config.toml",
+    )?);
+    let launcher_ref = launcher.clone();
+    thread::spawn(move || {
+        let _ = launcher_ref.start();
+        unsafe { libc::raise(signal_hook::SIGTERM) }
     });
 
     let term = Arc::new(AtomicBool::new(false));
     register_signals(term.clone()).context("Failed to register signal handler")?;
 
     while !term.load(Ordering::Relaxed) {
-        std::thread::park();
+        thread::park();
     }
 
-    tee.finalize();
+    launcher.finalize();
 
     Ok(())
 }
diff --git a/services/storage/app/Cargo.toml b/services/storage/app/Cargo.toml
index 92ef92b..389cdd2 100644
--- a/services/storage/app/Cargo.toml
+++ b/services/storage/app/Cargo.toml
@@ -8,14 +8,9 @@
 edition = "2018"
 
 [dependencies]
-log         = { version = "0.4.6" }
 env_logger  = { version = "0.7.1" }
 anyhow      = { version = "1.0.26" }
-signal-hook = { version = "0.1.13" }
 libc        = { version = "0.2.66" }
+signal-hook = { version = "0.1.13" }
 
-teaclave_binder            = { path = "../../../binder", features = ["app"] }
-teaclave_config            = { path = "../../../config" }
-teaclave_types             = { path = "../../../types" }
-
-sgx_types = { version = "1.1.2" }
+teaclave_service_app_utils = { path = "../../utils/service_app_utils" }
diff --git a/services/storage/app/src/main.rs b/services/storage/app/src/main.rs
index 56cc75c..d6e0127 100644
--- a/services/storage/app/src/main.rs
+++ b/services/storage/app/src/main.rs
@@ -18,70 +18,32 @@
 use anyhow::{Context, Result};
 use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
-use teaclave_binder::proto::{ECallCommand, StartServiceInput, StartServiceOutput};
-use teaclave_binder::TeeBinder;
-use teaclave_config::RuntimeConfig;
-use teaclave_types::TeeServiceResult;
+use std::thread;
+use teaclave_service_app_utils::{register_signals, TeaclaveServiceLauncher};
 
 const PACKAGE_NAME: &str = env!("CARGO_PKG_NAME");
 
-fn register_signals(term: Arc<AtomicBool>) -> Result<()> {
-    for signal in &[
-        signal_hook::SIGTERM,
-        signal_hook::SIGINT,
-        signal_hook::SIGHUP,
-    ] {
-        let term_ref = term.clone();
-        let thread = std::thread::current();
-        unsafe {
-            signal_hook::register(*signal, move || {
-                term_ref.store(true, Ordering::Relaxed);
-                thread.unpark();
-            })?;
-        }
-    }
-
-    Ok(())
-}
-
-fn start_enclave_service(tee: Arc<TeeBinder>, config: RuntimeConfig) {
-    let input = StartServiceInput::new(config);
-    let command = ECallCommand::StartService;
-    match tee.invoke::<StartServiceInput, TeeServiceResult<StartServiceOutput>>(command, input) {
-        Err(e) => {
-            eprintln!("TEE invocation error: {:?}", e);
-        }
-        Ok(Err(e)) => {
-            eprintln!("Service exit with error: {:?}", e);
-        }
-        _ => {
-            println!("Service successfully exit");
-        }
-    }
-
-    unsafe { libc::raise(signal_hook::SIGTERM) };
-}
-
 fn main() -> Result<()> {
     env_logger::init();
 
-    let tee = Arc::new(TeeBinder::new(PACKAGE_NAME).context("Failed to new the enclave.")?);
-    let config = teaclave_config::RuntimeConfig::from_toml("runtime.config.toml")
-        .context("Failed to load config file.")?;
-
-    let tee_ref = tee.clone();
-    std::thread::spawn(move || {
-        start_enclave_service(tee_ref, config);
+    let launcher = Arc::new(TeaclaveServiceLauncher::new(
+        PACKAGE_NAME,
+        "runtime.config.toml",
+    )?);
+    let launcher_ref = launcher.clone();
+    thread::spawn(move || {
+        let _ = launcher_ref.start();
+        unsafe { libc::raise(signal_hook::SIGTERM) }
     });
 
     let term = Arc::new(AtomicBool::new(false));
     register_signals(term.clone()).context("Failed to register signal handler")?;
 
     while !term.load(Ordering::Relaxed) {
-        std::thread::park();
+        thread::park();
     }
 
-    tee.finalize();
+    launcher.finalize();
 
     Ok(())
 }
diff --git a/services/utils/service_app_utils/Cargo.toml b/services/utils/service_app_utils/Cargo.toml
index ac02241..26e6f20 100644
--- a/services/utils/service_app_utils/Cargo.toml
+++ b/services/utils/service_app_utils/Cargo.toml
@@ -12,5 +12,9 @@
 env_logger = { version = "0.7.1" }
 anyhow     = { version = "1.0.26" }
 log        = { version = "0.4.6" }
+libc        = { version = "0.2.66" }
+signal-hook = { version = "0.1.13" }
 
-teaclave_binder = { path = "../../../binder" }
+teaclave_binder = { path = "../../../binder", features = ["app"] }
+teaclave_config = { path = "../../../config" }
+teaclave_types = { path = "../../../types" }
diff --git a/services/utils/service_app_utils/src/lib.rs b/services/utils/service_app_utils/src/lib.rs
index b9024b8..a5297af 100644
--- a/services/utils/service_app_utils/src/lib.rs
+++ b/services/utils/service_app_utils/src/lib.rs
@@ -15,17 +15,61 @@
 // specific language governing permissions and limitations
 // under the License.
 
-use anyhow::Result;
-use log::{error, info};
+use anyhow::{bail, Context, Result};
+use std::path::Path;
+use std::sync::atomic::{AtomicBool, Ordering};
 use std::sync::Arc;
+use teaclave_binder::proto::{ECallCommand, StartServiceInput, StartServiceOutput};
 use teaclave_binder::TeeBinder;
+use teaclave_config::RuntimeConfig;
+use teaclave_types::TeeServiceResult;
 
-pub struct ServiceEnclaveBuilder;
+pub struct TeaclaveServiceLauncher {
+    tee: TeeBinder,
+    config: RuntimeConfig,
+}
 
-impl ServiceEnclaveBuilder {
-    pub fn init_tee_binder(enclave_name: &str) -> Result<TeeBinder> {
-        env_logger::init();
-
-        TeeBinder::new(enclave_name, 1)
+impl TeaclaveServiceLauncher {
+    pub fn new<P: AsRef<Path>>(package_name: &str, config_path: P) -> Result<Self> {
+        let config = RuntimeConfig::from_toml(config_path.as_ref())
+            .context("Failed to load config file.")?;
+        let tee = TeeBinder::new(package_name).context("Failed to new the enclave.")?;
+        Ok(Self { tee, config })
     }
+
+    pub fn start(&self) -> Result<String> {
+        let input = StartServiceInput::new(self.config.clone());
+        let command = ECallCommand::StartService;
+        match self
+            .tee
+            .invoke::<StartServiceInput, TeeServiceResult<StartServiceOutput>>(command, input)
+        {
+            Err(e) => bail!("TEE invocation error: {:?}", e),
+            Ok(Err(e)) => bail!("Service exit with error: {:?}", e),
+            _ => Ok(String::from("Service successfully exit")),
+        }
+    }
+
+    pub fn finalize(&self) {
+        self.tee.finalize();
+    }
+}
+
+pub fn register_signals(term: Arc<AtomicBool>) -> Result<()> {
+    for signal in &[
+        signal_hook::SIGTERM,
+        signal_hook::SIGINT,
+        signal_hook::SIGHUP,
+    ] {
+        let term_ref = term.clone();
+        let thread = std::thread::current();
+        unsafe {
+            signal_hook::register(*signal, move || {
+                term_ref.store(true, Ordering::Relaxed);
+                thread.unpark();
+            })?;
+        }
+    }
+
+    Ok(())
 }