diff --git a/flutter/lib/common.dart b/flutter/lib/common.dart
index 74ed28d01..eda1ed4e7 100644
--- a/flutter/lib/common.dart
+++ b/flutter/lib/common.dart
@@ -306,7 +306,7 @@ class PermissionManager {
     if (!permissions.contains(type))
       return Future.error("Wrong permission!$type");
 
-    FFI.invokeMethod("request_permission", type);
+    gFFI.invokeMethod("request_permission", type);
     if (type == "ignore_battery_optimizations") {
       return Future.value(false);
     }
diff --git a/flutter/lib/mobile/pages/remote_page.dart b/flutter/lib/mobile/pages/remote_page.dart
index 203f76e3f..23900ef07 100644
--- a/flutter/lib/mobile/pages/remote_page.dart
+++ b/flutter/lib/mobile/pages/remote_page.dart
@@ -516,10 +516,10 @@ class _RemotePageState extends State<RemotePage> {
         },
         onLongPress: () {
           if (touchMode) {
-            FFI.cursorModel
+            gFFI.cursorModel
                 .move(_cacheLongPressPosition.dx, _cacheLongPressPosition.dy);
           }
-          FFI.tap(MouseButtons.right);
+          gFFI.tap(MouseButtons.right);
         },
         onDoubleFinerTap: (d) {
           if (!touchMode) {
@@ -546,13 +546,13 @@ class _RemotePageState extends State<RemotePage> {
             gFFI.cursorModel.move(d.localPosition.dx, d.localPosition.dy);
             gFFI.sendMouse('down', MouseButtons.left);
           } else {
-            final cursorX = FFI.cursorModel.x;
-            final cursorY = FFI.cursorModel.y;
+            final cursorX = gFFI.cursorModel.x;
+            final cursorY = gFFI.cursorModel.y;
             final visible =
-                FFI.cursorModel.getVisibleRect().inflate(1); // extend edges
+                gFFI.cursorModel.getVisibleRect().inflate(1); // extend edges
             final size = MediaQueryData.fromWindow(ui.window).size;
             if (!visible.contains(Offset(cursorX, cursorY))) {
-              FFI.cursorModel.move(size.width / 2, size.height / 2);
+              gFFI.cursorModel.move(size.width / 2, size.height / 2);
             }
           }
         },
diff --git a/flutter/lib/mobile/pages/settings_page.dart b/flutter/lib/mobile/pages/settings_page.dart
index 477659a58..53583479f 100644
--- a/flutter/lib/mobile/pages/settings_page.dart
+++ b/flutter/lib/mobile/pages/settings_page.dart
@@ -1,9 +1,4 @@
 import 'dart:async';
-
-import 'package:settings_ui/settings_ui.dart';
-import 'package:flutter/material.dart';
-import 'package:url_launcher/url_launcher.dart';
-import 'package:provider/provider.dart';
 import 'dart:convert';
 
 import 'package:flutter/material.dart';
@@ -75,7 +70,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
   Widget build(BuildContext context) {
     Provider.of<FfiModel>(context);
     final username = getUsername();
-    final enableAbr = FFI.getByName("option", "enable-abr") != 'N';
+    final enableAbr = gFFI.getByName("option", "enable-abr") != 'N';
     final enhancementsTiles = [
       SettingsTile.switchTile(
         title: Text(translate('Adaptive Bitrate') + '(beta)'),
@@ -87,7 +82,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
           if (!v) {
             msg["value"] = "N";
           }
-          FFI.setByName("option", json.encode(msg));
+          gFFI.setByName("option", json.encode(msg));
           setState(() {});
         },
       )
diff --git a/flutter/lib/mobile/widgets/dialog.dart b/flutter/lib/mobile/widgets/dialog.dart
index 7d1711390..3ab0489a9 100644
--- a/flutter/lib/mobile/widgets/dialog.dart
+++ b/flutter/lib/mobile/widgets/dialog.dart
@@ -23,7 +23,7 @@ void showError({Duration duration = SEC1}) {
 }
 
 void setPermanentPasswordDialog() {
-  final pw = FFI.getByName("permanent_password");
+  final pw = gFFI.getByName("permanent_password");
   final p0 = TextEditingController(text: pw);
   final p1 = TextEditingController(text: pw);
   var validateLength = false;
@@ -105,7 +105,7 @@ void setPermanentPasswordDialog() {
 
 void setTemporaryPasswordLengthDialog() {
   List<String> lengths = ['6', '8', '10'];
-  String length = FFI.getByName('option', 'temporary-password-length');
+  String length = gFFI.getByName('option', 'temporary-password-length');
   var index = lengths.indexOf(length);
   if (index < 0) index = 0;
   length = lengths[index];
@@ -119,8 +119,8 @@ void setTemporaryPasswordLengthDialog() {
       Map<String, String> msg = Map()
         ..["name"] = "temporary-password-length"
         ..["value"] = newValue;
-      FFI.setByName("option", jsonEncode(msg));
-      FFI.setByName("temporary_password");
+      gFFI.setByName("option", jsonEncode(msg));
+      gFFI.setByName("temporary_password");
       Future.delayed(Duration(milliseconds: 200), () {
         close();
         showSuccess();
diff --git a/flutter/lib/models/server_model.dart b/flutter/lib/models/server_model.dart
index e1703f51f..9b5909a90 100644
--- a/flutter/lib/models/server_model.dart
+++ b/flutter/lib/models/server_model.dart
@@ -126,8 +126,9 @@ class ServerModel with ChangeNotifier {
 
   updatePasswordModel() {
     var update = false;
-    final temporaryPassword = FFI.getByName("temporary_password");
-    final verificationMethod = FFI.getByName("option", "verification-method");
+    final temporaryPassword = gFFI.getByName("temporary_password");
+    print("tempo passwd: ${temporaryPassword}");
+    final verificationMethod = gFFI.getByName("option", "verification-method");
     if (_serverPasswd.text != temporaryPassword) {
       _serverPasswd.text = temporaryPassword;
       update = true;
@@ -286,7 +287,7 @@ class ServerModel with ChangeNotifier {
     const maxCount = 10;
     while (count < maxCount) {
       await Future.delayed(Duration(seconds: 1));
-      final id = parent.target?.getByName("server_id");
+      final id = parent.target?.getByName("server_id") ?? "";
       if (id.isEmpty) {
         continue;
       } else {
diff --git a/libs/hbb_common/src/config.rs b/libs/hbb_common/src/config.rs
index 7349e2873..33c46e7ae 100644
--- a/libs/hbb_common/src/config.rs
+++ b/libs/hbb_common/src/config.rs
@@ -1,15 +1,3 @@
-use crate::{
-    log,
-    password_security::{
-        decrypt_str_or_original, decrypt_vec_or_original, encrypt_str_or_original,
-        encrypt_vec_or_original,
-    },
-};
-use anyhow::Result;
-use directories_next::ProjectDirs;
-use rand::Rng;
-use serde_derive::{Deserialize, Serialize};
-use sodiumoxide::crypto::sign;
 use std::{
     collections::HashMap,
     fs,
@@ -19,6 +7,20 @@ use std::{
     time::SystemTime,
 };
 
+use anyhow::Result;
+use directories_next::ProjectDirs;
+use rand::Rng;
+use serde_derive::{Deserialize, Serialize};
+use sodiumoxide::crypto::sign;
+
+use crate::{
+    log,
+    password_security::{
+        decrypt_str_or_original, decrypt_vec_or_original, encrypt_str_or_original,
+        encrypt_vec_or_original,
+    },
+};
+
 pub const RENDEZVOUS_TIMEOUT: u64 = 12_000;
 pub const CONNECT_TIMEOUT: u64 = 18_000;
 pub const REG_INTERVAL: i64 = 12_000;
@@ -48,16 +50,10 @@ lazy_static::lazy_static! {
     pub static ref APP_NAME: Arc<RwLock<String>> = Arc::new(RwLock::new("RustDesk".to_owned()));
     static ref KEY_PAIR: Arc<Mutex<Option<(Vec<u8>, Vec<u8>)>>> = Default::default();
 }
-#[cfg(target_os = "android")]
-lazy_static::lazy_static! {
-    pub static ref APP_DIR: Arc<RwLock<String>> = Arc::new(RwLock::new("/data/user/0/com.carriez.flutter_hbb/app_flutter".to_owned()));
-}
-#[cfg(target_os = "ios")]
-lazy_static::lazy_static! {
-    pub static ref APP_DIR: Arc<RwLock<String>> = Default::default();
-}
+
 // #[cfg(any(target_os = "android", target_os = "ios"))]
 lazy_static::lazy_static! {
+    pub static ref APP_DIR: Arc<RwLock<String>> = Default::default();
     pub static ref APP_HOME_DIR: Arc<RwLock<String>> = Default::default();
 }
 const CHARS: &'static [char] = &[
diff --git a/src/client.rs b/src/client.rs
index 5d117e709..478d81ce8 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -12,11 +12,6 @@ use cpal::{
     Device, Host, StreamConfig,
 };
 use magnum_opus::{Channels::*, Decoder as AudioDecoder};
-use scrap::{
-    codec::{Decoder, DecoderCfg},
-    VpxDecoderConfig, VpxVideoCodecId,
-};
-
 use sha2::{Digest, Sha256};
 use uuid::Uuid;
 
@@ -38,14 +33,18 @@ use hbb_common::{
     AddrMangle, ResultType, Stream,
 };
 pub use helper::LatencyController;
-use scrap::{Decoder, Image, VideoCodecId};
+pub use helper::*;
+use scrap::Image;
+use scrap::{
+    codec::{Decoder, DecoderCfg},
+    VpxDecoderConfig, VpxVideoCodecId,
+};
 
 pub use super::lang::*;
 
 pub mod file_trait;
 pub mod helper;
 
-pub use helper::*;
 pub const SEC30: Duration = Duration::from_secs(30);
 
 /// Client of the remote desktop.
@@ -784,25 +783,25 @@ impl VideoHandler {
     }
 
     /// Handle a VP9S frame.
-    pub fn handle_vp9s(&mut self, vp9s: &VP9s) -> ResultType<bool> {
-        let mut last_frame = Image::new();
-        for vp9 in vp9s.frames.iter() {
-            for frame in self.decoder.decode(&vp9.data)? {
-                drop(last_frame);
-                last_frame = frame;
-            }
-        }
-        for frame in self.decoder.flush()? {
-            drop(last_frame);
-            last_frame = frame;
-        }
-        if last_frame.is_null() {
-            Ok(false)
-        } else {
-            last_frame.rgb(1, true, &mut self.rgb);
-            Ok(true)
-        }
-    }
+    // pub fn handle_vp9s(&mut self, vp9s: &VP9s) -> ResultType<bool> {
+    //     let mut last_frame = Image::new();
+    //     for vp9 in vp9s.frames.iter() {
+    //         for frame in self.decoder.decode(&vp9.data)? {
+    //             drop(last_frame);
+    //             last_frame = frame;
+    //         }
+    //     }
+    //     for frame in self.decoder.flush()? {
+    //         drop(last_frame);
+    //         last_frame = frame;
+    //     }
+    //     if last_frame.is_null() {
+    //         Ok(false)
+    //     } else {
+    //         last_frame.rgb(1, true, &mut self.rgb);
+    //         Ok(true)
+    //     }
+    // }
 
     /// Reset the decoder.
     pub fn reset(&mut self) {
diff --git a/src/common.rs b/src/common.rs
index f375ac46c..d2d1922ec 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -11,8 +11,8 @@ use hbb_common::{
     config::{self, Config, COMPRESS_LEVEL, RENDEZVOUS_TIMEOUT},
     get_version_number, log,
     message_proto::*,
-    protobuf::Message as _,
     protobuf::Enum,
+    protobuf::Message as _,
     rendezvous_proto::*,
     sleep, socket_client, tokio, ResultType,
 };
@@ -51,7 +51,7 @@ pub fn create_clipboard_msg(content: String) -> Message {
     let mut msg = Message::new();
     msg.set_clipboard(Clipboard {
         compress,
-        content:content.into(),
+        content: content.into(),
         ..Default::default()
     });
     msg
diff --git a/src/flutter_ffi.rs b/src/flutter_ffi.rs
index afbe35ec8..f1aeabfcc 100644
--- a/src/flutter_ffi.rs
+++ b/src/flutter_ffi.rs
@@ -7,7 +7,7 @@ use std::{
 use flutter_rust_bridge::{StreamSink, SyncReturn, ZeroCopyBuffer};
 use serde_json::{json, Number, Value};
 
-use hbb_common::ResultType;
+use hbb_common::{ResultType, password_security};
 use hbb_common::{
     config::{self, Config, LocalConfig, PeerConfig, ONLINE},
     fs, log,
@@ -24,7 +24,8 @@ use crate::ui_interface::{
     get_async_job_status, get_connect_status, get_fav, get_id, get_lan_peers, get_license,
     get_local_option, get_options, get_peer, get_peer_option, get_socks, get_sound_inputs,
     get_uuid, get_version, has_rendezvous_service, is_ok_change_id, post_request, set_local_option,
-    set_options, set_peer_option, set_socks, store_fav, test_if_valid_server, using_public_server,
+    set_options, set_peer_option, set_socks, store_fav, temporary_password, test_if_valid_server,
+    using_public_server,
 };
 
 fn initialize(app_dir: &str) {
@@ -581,8 +582,8 @@ unsafe extern "C" fn get_by_name(name: *const c_char, arg: *const c_char) -> *co
             "server_id" => {
                 res = ui_interface::get_id();
             }
-            "server_password" => {
-                res = Config::get_password();
+            "temporary_password" => {
+                res = password_security::temporary_password();
             }
             "connect_statue" => {
                 res = ONLINE
@@ -627,7 +628,7 @@ unsafe extern "C" fn get_by_name(name: *const c_char, arg: *const c_char) -> *co
                 }
             }
             "uuid" => {
-                res = base64::encode(crate::get_uuid());
+                res = base64::encode(get_uuid());
             }
             _ => {
                 log::error!("Unknown name of get_by_name: {}", name);
@@ -942,13 +943,13 @@ unsafe extern "C" fn set_by_name(name: *const c_char, value: *const c_char) {
                 //     }
                 // }
                 // Server Side
-                "update_password" => {
-                    if value.is_empty() {
-                        Config::set_password(&Config::get_auto_password());
-                    } else {
-                        Config::set_password(value);
-                    }
-                }
+                // "update_password" => {
+                //     if value.is_empty() {
+                //         Config::set_password(&Config::get_auto_password());
+                //     } else {
+                //         Config::set_password(value);
+                //     }
+                // }
                 #[cfg(target_os = "android")]
                 "chat_server_mode" => {
                     if let Ok(m) = serde_json::from_str::<HashMap<String, Value>>(value) {
diff --git a/src/ipc.rs b/src/ipc.rs
index c95a045fe..99670890e 100644
--- a/src/ipc.rs
+++ b/src/ipc.rs
@@ -1,9 +1,8 @@
-use crate::rendezvous_mediator::RendezvousMediator;
-use bytes::Bytes;
 use std::{collections::HashMap, sync::atomic::Ordering};
 #[cfg(not(windows))]
 use std::{fs::File, io::prelude::*};
 
+use bytes::Bytes;
 use parity_tokio_ipc::{
     Connection as Conn, ConnectionClient as ConnClient, Endpoint, Incoming, SecurityAttributes,
 };
diff --git a/src/rendezvous_mediator.rs b/src/rendezvous_mediator.rs
index 9f3674d36..6e38bff21 100644
--- a/src/rendezvous_mediator.rs
+++ b/src/rendezvous_mediator.rs
@@ -1,21 +1,4 @@
-use crate::server::{check_zombie, new as new_server, ServerPtr};
-use hbb_common::{
-    allow_err,
-    anyhow::bail,
-    config::{Config, REG_INTERVAL, RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT},
-    futures::future::join_all,
-    log,
-    protobuf::Message as _,
-    rendezvous_proto::*,
-    sleep, socket_client,
-    tcp::FramedStream,
-    tokio::{
-        self, select,
-        time::{interval, Duration},
-    },
-    udp::FramedSocket,
-    AddrMangle, IntoTargetAddr, ResultType, TargetAddr,
-};
+use std::collections::HashMap;
 use std::{
     net::SocketAddr,
     sync::{
@@ -24,8 +7,31 @@ use std::{
     },
     time::Instant,
 };
+
 use uuid::Uuid;
 
+use hbb_common::config::DiscoveryPeer;
+use hbb_common::tcp::FramedStream;
+use hbb_common::{
+    allow_err,
+    anyhow::bail,
+    config,
+    config::{Config, REG_INTERVAL, RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT},
+    futures::future::join_all,
+    log,
+    protobuf::Message as _,
+    rendezvous_proto::*,
+    sleep, socket_client,
+    tokio::{
+        self, select,
+        time::{interval, Duration},
+    },
+    udp::FramedSocket,
+    AddrMangle, IntoTargetAddr, ResultType, TargetAddr,
+};
+
+use crate::server::{check_zombie, new as new_server, ServerPtr};
+
 type Message = RendezvousMessage;
 
 lazy_static::lazy_static! {
@@ -354,7 +360,14 @@ impl RendezvousMediator {
         {
             let uuid = Uuid::new_v4().to_string();
             return self
-                .create_relay(ph.socket_addr.into(), relay_server, uuid, server, true, true)
+                .create_relay(
+                    ph.socket_addr.into(),
+                    relay_server,
+                    uuid,
+                    server,
+                    true,
+                    true,
+                )
                 .await;
         }
         let peer_addr = AddrMangle::decode(&ph.socket_addr);
@@ -568,7 +581,7 @@ fn lan_discovery() -> ResultType<()> {
         if let Ok((len, addr)) = socket.recv_from(&mut buf) {
             if let Ok(msg_in) = Message::parse_from_bytes(&buf[0..len]) {
                 match msg_in.union {
-                    Some(rendezvous_message::Union::peer_discovery(p)) => {
+                    Some(rendezvous_message::Union::PeerDiscovery(p)) => {
                         if p.cmd == "ping" {
                             let mut msg_out = Message::new();
                             let peer = PeerDiscovery {
@@ -616,11 +629,22 @@ pub fn discover() -> ResultType<()> {
         if let Ok((len, _)) = socket.recv_from(&mut buf) {
             if let Ok(msg_in) = Message::parse_from_bytes(&buf[0..len]) {
                 match msg_in.union {
-                    Some(rendezvous_message::Union::peer_discovery(p)) => {
+                    Some(rendezvous_message::Union::PeerDiscovery(p)) => {
                         last_recv_time = Instant::now();
                         if p.cmd == "pong" {
                             if p.mac != mac {
-                                peers.push((p.id, p.username, p.hostname, p.platform));
+                                let dp = DiscoveryPeer {
+                                    id: "".to_string(),
+                                    ip_mac: HashMap::from([
+                                        // TODO: addr ip
+                                        (addr.ip().to_string(), p.mac.clone()),
+                                    ]),
+                                    username: p.username,
+                                    hostname: p.hostname,
+                                    platform: p.platform,
+                                    online: true,
+                                };
+                                peers.push(dp);
                             }
                         }
                     }
@@ -629,7 +653,7 @@ pub fn discover() -> ResultType<()> {
             }
         }
         if last_write_time.elapsed().as_millis() > 300 && last_write_n != peers.len() {
-            config::LanPeers::store(serde_json::to_string(&peers)?);
+            config::LanPeers::store(&peers);
             last_write_time = Instant::now();
             last_write_n = peers.len();
         }
@@ -638,7 +662,7 @@ pub fn discover() -> ResultType<()> {
         }
     }
     log::info!("discover ping done");
-    config::LanPeers::store(serde_json::to_string(&peers)?);
+    config::LanPeers::store(&peers);
     Ok(())
 }
 
@@ -678,7 +702,7 @@ pub async fn query_online_states<F: FnOnce(Vec<String>, Vec<String>)>(ids: Vec<S
 }
 
 async fn create_online_stream() -> ResultType<FramedStream> {
-    let rendezvous_server = crate::get_rendezvous_server(1_000).await;
+    let (mut rendezvous_server, servers, contained) = crate::get_rendezvous_server(1_000).await;
     let tmp: Vec<&str> = rendezvous_server.split(":").collect();
     if tmp.len() != 2 {
         bail!("Invalid server address: {}", rendezvous_server);
@@ -722,7 +746,7 @@ async fn query_online_states_(
             Some(Ok(bytes)) => {
                 if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) {
                     match msg_in.union {
-                        Some(rendezvous_message::Union::online_response(online_response)) => {
+                        Some(rendezvous_message::Union::OnlineResponse(online_response)) => {
                             let states = online_response.states;
                             let mut onlines = Vec::new();
                             let mut offlines = Vec::new();
diff --git a/src/ui.rs b/src/ui.rs
index 52e605bc8..c2bc8cbc3 100644
--- a/src/ui.rs
+++ b/src/ui.rs
@@ -1,25 +1,12 @@
 use std::{
     collections::HashMap,
     iter::FromIterator,
+    process::Child,
     sync::{Arc, Mutex},
 };
 
 use sciter::Value;
 
-use hbb_common::{allow_err, config::PeerConfig, log};
-
-use crate::ui_interface::*;
-
-mod cm;
-#[cfg(feature = "inline")]
-mod inline;
-#[cfg(target_os = "macos")]
-mod macos;
-pub mod remote;
-#[cfg(target_os = "windows")]
-pub mod win_privacy;
-use crate::common::SOFTWARE_UPDATE_URL;
-use crate::ipc;
 use hbb_common::{
     allow_err,
     config::{self, Config, LocalConfig, PeerConfig, RENDEZVOUS_PORT, RENDEZVOUS_TIMEOUT},
@@ -31,13 +18,33 @@ use hbb_common::{
     tcp::FramedStream,
     tokio::{self, sync::mpsc, time},
 };
-use sciter::Value;
-use std::{
-    collections::HashMap,
-    iter::FromIterator,
-    process::Child,
-    sync::{Arc, Mutex},
+
+use crate::common::{get_app_name, SOFTWARE_UPDATE_URL};
+use crate::ui_interface::{
+    check_mouse_time, closing, create_shortcut, current_is_wayland, fix_login_wayland,
+    forget_password, get_api_server, get_async_job_status, get_connect_status, get_error, get_fav,
+    get_icon, get_lan_peers, get_license, get_local_option, get_mouse_time, get_new_version,
+    get_option, get_options, get_peer, get_peer_option, get_recent_sessions, get_remote_id,
+    get_size, get_socks, get_software_ext, get_software_store_path, get_software_update_url,
+    get_uuid, get_version, goto_install, has_rendezvous_service, install_me, install_path,
+    is_can_screen_recording, is_installed, is_installed_daemon, is_installed_lower_version,
+    is_login_wayland, is_ok_change_id, is_process_trusted, is_rdp_service_open, is_share_rdp,
+    is_xfce, modify_default_login, new_remote, open_url, peer_has_password, permanent_password,
+    post_request, recent_sessions_updated, remove_peer, run_without_install, set_local_option,
+    set_option, set_options, set_peer_option, set_remote_id, set_share_rdp, set_socks,
+    show_run_without_install, store_fav, t, temporary_password, test_if_valid_server, update_me,
+    update_temporary_password, using_public_server,
 };
+use crate::{discover, ipc};
+
+mod cm;
+#[cfg(feature = "inline")]
+mod inline;
+#[cfg(target_os = "macos")]
+mod macos;
+pub mod remote;
+#[cfg(target_os = "windows")]
+pub mod win_privacy;
 
 type Message = RendezvousMessage;
 
@@ -79,7 +86,7 @@ pub fn start(args: &mut [String]) {
     }
     #[cfg(windows)]
     if args.len() > 0 && args[0] == "--tray" {
-        let options = OPTIONS.clone();
+        let options = check_connect_status(false).1;
         crate::tray::start_tray(options);
         return;
     }
@@ -105,8 +112,8 @@ pub fn start(args: &mut [String]) {
         args[1] = id;
     }
     if args.is_empty() {
-        let cloned = CHILDS.clone();
-        std::thread::spawn(move || check_zombie(cloned));
+        let child: Childs = Default::default();
+        std::thread::spawn(move || check_zombie(child));
         crate::common::check_software_update();
         frame.event_handler(UI {});
         frame.sciter_handler(UIHostHandler {});
@@ -177,45 +184,24 @@ pub fn start(args: &mut [String]) {
 struct UI {}
 
 impl UI {
-    fn new(childs: Childs) -> Self {
-        let res = check_connect_status(true);
-        Self(childs, res.0, res.1, Default::default(), res.2, res.3)
-    }
-
-    fn recent_sessions_updated(&mut self) -> bool {
-        let mut lock = self.0.lock().unwrap();
-        if lock.0 {
-            lock.0 = false;
-            true
-        } else {
-            false
-        }
     fn recent_sessions_updated(&self) -> bool {
         recent_sessions_updated()
     }
 
     fn get_id(&self) -> String {
-        get_id()
-    }
-
-    fn get_password(&mut self) -> String {
-        get_password()
+        ipc::get_id()
     }
 
     fn temporary_password(&mut self) -> String {
-        self.5.lock().unwrap().clone()
+        temporary_password()
     }
 
     fn update_temporary_password(&self) {
-        allow_err!(ipc::update_temporary_password());
-    }
-
-    fn update_password(&mut self, password: String) {
-        update_password(password)
+        update_temporary_password()
     }
 
     fn permanent_password(&self) -> String {
-        ipc::get_permanent_password()
+        permanent_password()
     }
 
     fn set_permanent_password(&self, password: String) {
@@ -507,7 +493,7 @@ impl UI {
     }
 
     fn discover(&self) {
-        discover()
+        discover();
     }
 
     fn get_lan_peers(&self) -> String {
@@ -523,7 +509,8 @@ impl UI {
     }
 
     fn change_id(&self, id: String) {
-        change_id(id)
+        let old_id = self.get_id();
+        change_id(id, old_id);
     }
 
     fn post_request(&self, url: String, body: String, header: String) {
diff --git a/src/ui_interface.rs b/src/ui_interface.rs
index 86b4e9e9a..a3643d5c9 100644
--- a/src/ui_interface.rs
+++ b/src/ui_interface.rs
@@ -14,7 +14,7 @@ use hbb_common::{
     rendezvous_proto::*,
     sleep,
     tcp::FramedStream,
-    tokio::{self, sync::mpsc, time},
+    tokio::{self, sync::mpsc, time}, password_security,
 };
 
 use crate::common::SOFTWARE_UPDATE_URL;
@@ -31,6 +31,7 @@ lazy_static::lazy_static! {
     pub static ref OPTIONS : Arc<Mutex<HashMap<String, String>>> = Arc::new(Mutex::new(Config::get_options()));
     pub static ref ASYNC_JOB_STATUS : Arc<Mutex<String>> = Default::default();
     pub static ref SENDER : Mutex<mpsc::UnboundedSender<ipc::Data>> = Mutex::new(check_connect_status(true));
+    pub static ref TEMPORARY_PASSWD : Arc<Mutex<String>> = Arc::new(Mutex::new("".to_owned()));
 }
 
 pub fn recent_sessions_updated() -> bool {
@@ -47,18 +48,6 @@ pub fn get_id() -> String {
     ipc::get_id()
 }
 
-pub fn get_password() -> String {
-    ipc::get_password()
-}
-
-pub fn update_password(password: String) {
-    if password.is_empty() {
-        allow_err!(ipc::set_password(Config::get_auto_password()));
-    } else {
-        allow_err!(ipc::set_password(password));
-    }
-}
-
 pub fn get_remote_id() -> String {
     LocalConfig::get_remote_id()
 }
@@ -369,6 +358,18 @@ pub fn get_connect_status() -> Status {
     res
 }
 
+pub fn update_temporary_password() {
+    allow_err!(ipc::update_temporary_password());
+}
+
+pub fn permanent_password() -> String {
+    ipc::get_permanent_password()
+}
+
+pub fn temporary_password() -> String {
+    password_security::temporary_password()
+}
+
 pub fn get_peer(id: String) -> PeerConfig {
     PeerConfig::load(&id)
 }
@@ -542,11 +543,11 @@ pub fn discover() {
 }
 
 pub fn get_lan_peers() -> String {
-    config::LanPeers::load().peers
+    serde_json::to_string(&config::LanPeers::load().peers).unwrap_or_default()
 }
 
 pub fn get_uuid() -> String {
-    base64::encode(crate::get_uuid())
+    base64::encode(hbb_common::get_uuid())
 }
 
 #[cfg(not(any(target_os = "android", target_os = "ios", feature = "cli")))]
@@ -762,7 +763,7 @@ async fn check_id(
             if let Some(Ok(bytes)) = socket.next_timeout(3_000).await {
                 if let Ok(msg_in) = RendezvousMessage::parse_from_bytes(&bytes) {
                     match msg_in.union {
-                        Some(rendezvous_message::Union::register_pk_response(rpr)) => {
+                        Some(rendezvous_message::Union::RegisterPkResponse(rpr)) => {
                             match rpr.result.enum_value_or_default() {
                                 register_pk_response::Result::OK => {
                                     ok = true;