summaryrefslogtreecommitdiff
path: root/0153-sandbox-sandbox-api-adapt-rust-interface.patch
diff options
context:
space:
mode:
Diffstat (limited to '0153-sandbox-sandbox-api-adapt-rust-interface.patch')
-rw-r--r--0153-sandbox-sandbox-api-adapt-rust-interface.patch4272
1 files changed, 4272 insertions, 0 deletions
diff --git a/0153-sandbox-sandbox-api-adapt-rust-interface.patch b/0153-sandbox-sandbox-api-adapt-rust-interface.patch
new file mode 100644
index 0000000..bacaa54
--- /dev/null
+++ b/0153-sandbox-sandbox-api-adapt-rust-interface.patch
@@ -0,0 +1,4272 @@
+From 32208449b2cf4de7b9c6b05b1bf58538f7f8640a Mon Sep 17 00:00:00 2001
+From: liuxu <liuxu156@huawei.com>
+Date: Thu, 21 Nov 2024 11:58:36 +0800
+Subject: [PATCH 153/156] sandbox: sandbox api adapt rust interface
+
+Signed-off-by: liuxu <liuxu156@huawei.com>
+---
+ cmake/options.cmake | 10 +-
+ cmake/protoc.cmake | 10 -
+ src/CMakeLists.txt | 4 +
+ .../sandbox/google/protobuf/any.proto | 155 ------
+ .../sandbox/google/protobuf/empty.proto | 52 --
+ .../sandbox/google/protobuf/timestamp.proto | 138 ------
+ src/api/services/sandbox/sandbox.proto | 204 --------
+ .../sandbox/sandbox/types/metrics.proto | 30 --
+ .../sandbox/sandbox/types/mount.proto | 43 --
+ .../sandbox/sandbox/types/platform.proto | 30 --
+ .../sandbox/sandbox/types/sandbox.proto | 54 --
+ src/daemon/common/cri/v1/v1_cri_helpers.cc | 3 +-
+ src/daemon/sandbox/CMakeLists.txt | 27 +-
+ .../sandbox/{controller => }/controller.h | 34 +-
+ src/daemon/sandbox/controller/CMakeLists.txt | 32 --
+ .../sandboxer/client/CMakeLists.txt | 20 -
+ .../sandboxer/client/grpc_async_wait_call.cc | 142 ------
+ .../sandboxer/client/grpc_async_wait_call.h | 94 ----
+ .../sandboxer/client/grpc_client_utils.cc | 36 --
+ .../sandboxer/client/grpc_client_utils.h | 23 -
+ .../sandboxer/client/grpc_sandboxer_client.cc | 337 -------------
+ .../client/grpc_sandboxer_monitor.cc | 314 ------------
+ .../sandboxer/client/grpc_sandboxer_monitor.h | 85 ----
+ .../{controller => }/controller_manager.cc | 3 -
+ .../{controller => }/controller_manager.h | 0
+ src/daemon/sandbox/sandbox.cc | 215 --------
+ src/daemon/sandbox/sandbox.h | 26 +-
+ src/daemon/sandbox/sandbox_manager.cc | 44 +-
+ src/daemon/sandbox/sandbox_ops.cc | 250 +++++++---
+ src/daemon/sandbox/sandbox_task.cc | 7 +-
+ src/daemon/sandbox/sandboxer/CMakeLists.txt | 15 +
+ .../controller}/CMakeLists.txt | 0
+ .../controller/client/CMakeLists.txt | 12 +
+ .../client/grpc_sandboxer_client.cc | 463 ++++++++++++++++++
+ .../client/grpc_sandboxer_client.h | 46 +-
+ .../controller}/sandboxer_controller.cc | 27 +-
+ .../controller}/sandboxer_controller.h | 9 +-
+ .../sandbox/sandboxer/sandboxer_sandbox.cc | 254 ++++++++++
+ .../sandbox/sandboxer/sandboxer_sandbox.h | 63 +++
+ src/daemon/sandbox/shim/CMakeLists.txt | 15 +
+ .../shim => shim/controller}/CMakeLists.txt | 0
+ .../controller}/shim_controller.cc | 19 +-
+ .../controller}/shim_controller.h | 12 +-
+ src/daemon/sandbox/shim/shim_sandbox.cc | 65 +++
+ src/daemon/sandbox/shim/shim_sandbox.h | 49 ++
+ 45 files changed, 1225 insertions(+), 2246 deletions(-)
+ delete mode 100644 src/api/services/sandbox/google/protobuf/any.proto
+ delete mode 100644 src/api/services/sandbox/google/protobuf/empty.proto
+ delete mode 100644 src/api/services/sandbox/google/protobuf/timestamp.proto
+ delete mode 100644 src/api/services/sandbox/sandbox.proto
+ delete mode 100644 src/api/services/sandbox/sandbox/types/metrics.proto
+ delete mode 100644 src/api/services/sandbox/sandbox/types/mount.proto
+ delete mode 100644 src/api/services/sandbox/sandbox/types/platform.proto
+ delete mode 100644 src/api/services/sandbox/sandbox/types/sandbox.proto
+ rename src/daemon/sandbox/{controller => }/controller.h (79%)
+ delete mode 100644 src/daemon/sandbox/controller/CMakeLists.txt
+ delete mode 100755 src/daemon/sandbox/controller/sandboxer/client/CMakeLists.txt
+ delete mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_async_wait_call.cc
+ delete mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_async_wait_call.h
+ delete mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_client_utils.cc
+ delete mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_client_utils.h
+ delete mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc
+ delete mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_monitor.cc
+ delete mode 100644 src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_monitor.h
+ rename src/daemon/sandbox/{controller => }/controller_manager.cc (98%)
+ rename src/daemon/sandbox/{controller => }/controller_manager.h (100%)
+ create mode 100755 src/daemon/sandbox/sandboxer/CMakeLists.txt
+ rename src/daemon/sandbox/{controller/sandboxer => sandboxer/controller}/CMakeLists.txt (100%)
+ create mode 100755 src/daemon/sandbox/sandboxer/controller/client/CMakeLists.txt
+ create mode 100644 src/daemon/sandbox/sandboxer/controller/client/grpc_sandboxer_client.cc
+ rename src/daemon/sandbox/{controller/sandboxer => sandboxer/controller}/client/grpc_sandboxer_client.h (54%)
+ rename src/daemon/sandbox/{controller/sandboxer => sandboxer/controller}/sandboxer_controller.cc (78%)
+ rename src/daemon/sandbox/{controller/sandboxer => sandboxer/controller}/sandboxer_controller.h (82%)
+ create mode 100644 src/daemon/sandbox/sandboxer/sandboxer_sandbox.cc
+ create mode 100644 src/daemon/sandbox/sandboxer/sandboxer_sandbox.h
+ create mode 100755 src/daemon/sandbox/shim/CMakeLists.txt
+ rename src/daemon/sandbox/{controller/shim => shim/controller}/CMakeLists.txt (100%)
+ rename src/daemon/sandbox/{controller/shim => shim/controller}/shim_controller.cc (97%)
+ rename src/daemon/sandbox/{controller/shim => shim/controller}/shim_controller.h (89%)
+ create mode 100644 src/daemon/sandbox/shim/shim_sandbox.cc
+ create mode 100644 src/daemon/sandbox/shim/shim_sandbox.h
+
+diff --git a/cmake/options.cmake b/cmake/options.cmake
+index 41177fe0..cee83ef2 100644
+--- a/cmake/options.cmake
++++ b/cmake/options.cmake
+@@ -53,9 +53,13 @@ endif()
+
+ option(ENABLE_SANDBOXER "Enable sandbox API" OFF)
+ if (ENABLE_SANDBOXER STREQUAL "ON")
+- add_definitions(-DENABLE_SANDBOXER)
+- set(ENABLE_SANDBOXER 1)
+- message("${Green}-- Enable sandbox API${ColourReset}")
++ if (ENABLE_CRI_API_V1)
++ add_definitions(-DENABLE_SANDBOXER)
++ set(ENABLE_SANDBOXER 1)
++ message("${Green}-- Enable sandbox API${ColourReset}")
++ else()
++ message("${Yellow}-- Can not enable sandboxer, sandboxer need enable CRI API V1 first ${ColourReset}")
++ endif()
+ endif()
+
+ option(ENABLE_OOM_MONITOR "Enable oom monitor" ON)
+diff --git a/cmake/protoc.cmake b/cmake/protoc.cmake
+index 6343fe3e..de337f25 100644
+--- a/cmake/protoc.cmake
++++ b/cmake/protoc.cmake
+@@ -66,13 +66,3 @@ if (GRPC_CONNECTOR)
+ PROTOC_GRPC_GEN(network ${NETWORK_PROTOS_OUT_PATH} ${PROTOS_PATH}/network/network.proto)
+ endif()
+ endif()
+-
+-if (ENABLE_CRI_API_V1 AND ENABLE_SANDBOXER)
+- execute_process(COMMAND mkdir -p ${SANDBOX_PROTOS_OUT_PATH})
+- PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/sandbox.proto)
+- PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/mount.proto)
+- PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/platform.proto)
+- PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox/types/metrics.proto)
+- PROTOC_CPP_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox.proto)
+- PROTOC_GRPC_GEN(sandbox ${SANDBOX_PROTOS_OUT_PATH} ${PROTOS_PATH}/sandbox/sandbox.proto)
+-endif()
+diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
+index 70a8ac91..6aab3f69 100644
+--- a/src/CMakeLists.txt
++++ b/src/CMakeLists.txt
+@@ -200,6 +200,10 @@ else()
+ set_target_properties(isulad PROPERTIES LINKER_LANGUAGE "C")
+ endif()
+
++if (ENABLE_SANDBOXER)
++ target_link_libraries(isulad isula_sandbox)
++endif()
++
+ target_link_libraries(isulad libisulad_tools libhttpclient -ldl)
+ if (ANDROID OR MUSL)
+ target_link_libraries(isulad ${LIBSSL_LIBRARY} ${LIBYAJL_LIBRARY})
+diff --git a/src/api/services/sandbox/google/protobuf/any.proto b/src/api/services/sandbox/google/protobuf/any.proto
+deleted file mode 100644
+index c9be8541..00000000
+--- a/src/api/services/sandbox/google/protobuf/any.proto
++++ /dev/null
+@@ -1,155 +0,0 @@
+-// Protocol Buffers - Google's data interchange format
+-// Copyright 2008 Google Inc. All rights reserved.
+-// https://developers.google.com/protocol-buffers/
+-//
+-// Redistribution and use in source and binary forms, with or without
+-// modification, are permitted provided that the following conditions are
+-// met:
+-//
+-// * Redistributions of source code must retain the above copyright
+-// notice, this list of conditions and the following disclaimer.
+-// * Redistributions in binary form must reproduce the above
+-// copyright notice, this list of conditions and the following disclaimer
+-// in the documentation and/or other materials provided with the
+-// distribution.
+-// * Neither the name of Google Inc. nor the names of its
+-// contributors may be used to endorse or promote products derived from
+-// this software without specific prior written permission.
+-//
+-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-
+-syntax = "proto3";
+-
+-package google.protobuf;
+-
+-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+-option go_package = "github.com/golang/protobuf/ptypes/any";
+-option java_package = "com.google.protobuf";
+-option java_outer_classname = "AnyProto";
+-option java_multiple_files = true;
+-option objc_class_prefix = "GPB";
+-
+-// `Any` contains an arbitrary serialized protocol buffer message along with a
+-// URL that describes the type of the serialized message.
+-//
+-// Protobuf library provides support to pack/unpack Any values in the form
+-// of utility functions or additional generated methods of the Any type.
+-//
+-// Example 1: Pack and unpack a message in C++.
+-//
+-// Foo foo = ...;
+-// Any any;
+-// any.PackFrom(foo);
+-// ...
+-// if (any.UnpackTo(&foo)) {
+-// ...
+-// }
+-//
+-// Example 2: Pack and unpack a message in Java.
+-//
+-// Foo foo = ...;
+-// Any any = Any.pack(foo);
+-// ...
+-// if (any.is(Foo.class)) {
+-// foo = any.unpack(Foo.class);
+-// }
+-//
+-// Example 3: Pack and unpack a message in Python.
+-//
+-// foo = Foo(...)
+-// any = Any()
+-// any.Pack(foo)
+-// ...
+-// if any.Is(Foo.DESCRIPTOR):
+-// any.Unpack(foo)
+-// ...
+-//
+-// Example 4: Pack and unpack a message in Go
+-//
+-// foo := &pb.Foo{...}
+-// any, err := ptypes.MarshalAny(foo)
+-// ...
+-// foo := &pb.Foo{}
+-// if err := ptypes.UnmarshalAny(any, foo); err != nil {
+-// ...
+-// }
+-//
+-// The pack methods provided by protobuf library will by default use
+-// 'type.googleapis.com/full.type.name' as the type URL and the unpack
+-// methods only use the fully qualified type name after the last '/'
+-// in the type URL, for example "foo.bar.com/x/y.z" will yield type
+-// name "y.z".
+-//
+-//
+-// JSON
+-// ====
+-// The JSON representation of an `Any` value uses the regular
+-// representation of the deserialized, embedded message, with an
+-// additional field `@type` which contains the type URL. Example:
+-//
+-// package google.profile;
+-// message Person {
+-// string first_name = 1;
+-// string last_name = 2;
+-// }
+-//
+-// {
+-// "@type": "type.googleapis.com/google.profile.Person",
+-// "firstName": <string>,
+-// "lastName": <string>
+-// }
+-//
+-// If the embedded message type is well-known and has a custom JSON
+-// representation, that representation will be embedded adding a field
+-// `value` which holds the custom JSON in addition to the `@type`
+-// field. Example (for message [google.protobuf.Duration][]):
+-//
+-// {
+-// "@type": "type.googleapis.com/google.protobuf.Duration",
+-// "value": "1.212s"
+-// }
+-//
+-message Any {
+- // A URL/resource name that uniquely identifies the type of the serialized
+- // protocol buffer message. This string must contain at least
+- // one "/" character. The last segment of the URL's path must represent
+- // the fully qualified name of the type (as in
+- // `path/google.protobuf.Duration`). The name should be in a canonical form
+- // (e.g., leading "." is not accepted).
+- //
+- // In practice, teams usually precompile into the binary all types that they
+- // expect it to use in the context of Any. However, for URLs which use the
+- // scheme `http`, `https`, or no scheme, one can optionally set up a type
+- // server that maps type URLs to message definitions as follows:
+- //
+- // * If no scheme is provided, `https` is assumed.
+- // * An HTTP GET on the URL must yield a [google.protobuf.Type][]
+- // value in binary format, or produce an error.
+- // * Applications are allowed to cache lookup results based on the
+- // URL, or have them precompiled into a binary to avoid any
+- // lookup. Therefore, binary compatibility needs to be preserved
+- // on changes to types. (Use versioned type names to manage
+- // breaking changes.)
+- //
+- // Note: this functionality is not currently available in the official
+- // protobuf release, and it is not used for type URLs beginning with
+- // type.googleapis.com.
+- //
+- // Schemes other than `http`, `https` (or the empty scheme) might be
+- // used with implementation specific semantics.
+- //
+- string type_url = 1;
+-
+- // Must be a valid serialized protocol buffer of the above specified type.
+- bytes value = 2;
+-}
+diff --git a/src/api/services/sandbox/google/protobuf/empty.proto b/src/api/services/sandbox/google/protobuf/empty.proto
+deleted file mode 100644
+index 03cacd23..00000000
+--- a/src/api/services/sandbox/google/protobuf/empty.proto
++++ /dev/null
+@@ -1,52 +0,0 @@
+-// Protocol Buffers - Google's data interchange format
+-// Copyright 2008 Google Inc. All rights reserved.
+-// https://developers.google.com/protocol-buffers/
+-//
+-// Redistribution and use in source and binary forms, with or without
+-// modification, are permitted provided that the following conditions are
+-// met:
+-//
+-// * Redistributions of source code must retain the above copyright
+-// notice, this list of conditions and the following disclaimer.
+-// * Redistributions in binary form must reproduce the above
+-// copyright notice, this list of conditions and the following disclaimer
+-// in the documentation and/or other materials provided with the
+-// distribution.
+-// * Neither the name of Google Inc. nor the names of its
+-// contributors may be used to endorse or promote products derived from
+-// this software without specific prior written permission.
+-//
+-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-
+-syntax = "proto3";
+-
+-package google.protobuf;
+-
+-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+-option go_package = "github.com/golang/protobuf/ptypes/empty";
+-option java_package = "com.google.protobuf";
+-option java_outer_classname = "EmptyProto";
+-option java_multiple_files = true;
+-option objc_class_prefix = "GPB";
+-option cc_enable_arenas = true;
+-
+-// A generic empty message that you can re-use to avoid defining duplicated
+-// empty messages in your APIs. A typical example is to use it as the request
+-// or the response type of an API method. For instance:
+-//
+-// service Foo {
+-// rpc Bar(google.protobuf.Empty) returns (google.protobuf.Empty);
+-// }
+-//
+-// The JSON representation for `Empty` is empty JSON object `{}`.
+-message Empty {}
+diff --git a/src/api/services/sandbox/google/protobuf/timestamp.proto b/src/api/services/sandbox/google/protobuf/timestamp.proto
+deleted file mode 100644
+index cd357864..00000000
+--- a/src/api/services/sandbox/google/protobuf/timestamp.proto
++++ /dev/null
+@@ -1,138 +0,0 @@
+-// Protocol Buffers - Google's data interchange format
+-// Copyright 2008 Google Inc. All rights reserved.
+-// https://developers.google.com/protocol-buffers/
+-//
+-// Redistribution and use in source and binary forms, with or without
+-// modification, are permitted provided that the following conditions are
+-// met:
+-//
+-// * Redistributions of source code must retain the above copyright
+-// notice, this list of conditions and the following disclaimer.
+-// * Redistributions in binary form must reproduce the above
+-// copyright notice, this list of conditions and the following disclaimer
+-// in the documentation and/or other materials provided with the
+-// distribution.
+-// * Neither the name of Google Inc. nor the names of its
+-// contributors may be used to endorse or promote products derived from
+-// this software without specific prior written permission.
+-//
+-// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+-// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+-// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+-// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+-// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+-// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+-// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+-// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+-// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+-// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+-
+-syntax = "proto3";
+-
+-package google.protobuf;
+-
+-option csharp_namespace = "Google.Protobuf.WellKnownTypes";
+-option cc_enable_arenas = true;
+-option go_package = "github.com/golang/protobuf/ptypes/timestamp";
+-option java_package = "com.google.protobuf";
+-option java_outer_classname = "TimestampProto";
+-option java_multiple_files = true;
+-option objc_class_prefix = "GPB";
+-
+-// A Timestamp represents a point in time independent of any time zone or local
+-// calendar, encoded as a count of seconds and fractions of seconds at
+-// nanosecond resolution. The count is relative to an epoch at UTC midnight on
+-// January 1, 1970, in the proleptic Gregorian calendar which extends the
+-// Gregorian calendar backwards to year one.
+-//
+-// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
+-// second table is needed for interpretation, using a [24-hour linear
+-// smear](https://developers.google.com/time/smear).
+-//
+-// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
+-// restricting to that range, we ensure that we can convert to and from [RFC
+-// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
+-//
+-// # Examples
+-//
+-// Example 1: Compute Timestamp from POSIX `time()`.
+-//
+-// Timestamp timestamp;
+-// timestamp.set_seconds(time(NULL));
+-// timestamp.set_nanos(0);
+-//
+-// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
+-//
+-// struct timeval tv;
+-// gettimeofday(&tv, NULL);
+-//
+-// Timestamp timestamp;
+-// timestamp.set_seconds(tv.tv_sec);
+-// timestamp.set_nanos(tv.tv_usec * 1000);
+-//
+-// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
+-//
+-// FILETIME ft;
+-// GetSystemTimeAsFileTime(&ft);
+-// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
+-//
+-// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
+-// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
+-// Timestamp timestamp;
+-// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
+-// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
+-//
+-// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
+-//
+-// long millis = System.currentTimeMillis();
+-//
+-// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
+-// .setNanos((int) ((millis % 1000) * 1000000)).build();
+-//
+-//
+-// Example 5: Compute Timestamp from current time in Python.
+-//
+-// timestamp = Timestamp()
+-// timestamp.GetCurrentTime()
+-//
+-// # JSON Mapping
+-//
+-// In JSON format, the Timestamp type is encoded as a string in the
+-// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
+-// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
+-// where {year} is always expressed using four digits while {month}, {day},
+-// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
+-// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
+-// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
+-// is required. A proto3 JSON serializer should always use UTC (as indicated by
+-// "Z") when printing the Timestamp type and a proto3 JSON parser should be
+-// able to accept both UTC and other timezones (as indicated by an offset).
+-//
+-// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
+-// 01:30 UTC on January 15, 2017.
+-//
+-// In JavaScript, one can convert a Date object to this format using the
+-// standard
+-// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
+-// method. In Python, a standard `datetime.datetime` object can be converted
+-// to this format using
+-// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
+-// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
+-// the Joda Time's [`ISODateTimeFormat.dateTime()`](
+-// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
+-// ) to obtain a formatter capable of generating timestamps in this format.
+-//
+-//
+-message Timestamp {
+- // Represents seconds of UTC time since Unix epoch
+- // 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
+- // 9999-12-31T23:59:59Z inclusive.
+- int64 seconds = 1;
+-
+- // Non-negative fractions of a second at nanosecond resolution. Negative
+- // second values with fractions must still have non-negative nanos values
+- // that count forward in time. Must be from 0 to 999,999,999
+- // inclusive.
+- int32 nanos = 2;
+-}
+diff --git a/src/api/services/sandbox/sandbox.proto b/src/api/services/sandbox/sandbox.proto
+deleted file mode 100644
+index dcc78444..00000000
+--- a/src/api/services/sandbox/sandbox.proto
++++ /dev/null
+@@ -1,204 +0,0 @@
+-/*
+- Copyright The containerd Authors.
+-
+- 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.
+-*/
+-
+-syntax = "proto3";
+-
+-// Sandbox is a v2 runtime extension that allows more complex execution environments for containers.
+-// This adds a notion of groups of containers that share same lifecycle and/or resources.
+-// A few good fits for sandbox can be:
+-// - A "pause" container in k8s, that acts as a parent process for child containers to hold network namespace.
+-// - (micro)VMs that launch a VM process and executes containers inside guest OS.
+-// containerd in this case remains implementation agnostic and delegates sandbox handling to runtimes.
+-// See proposal and discussion here: https://github.com/containerd/containerd/issues/4131
+-package containerd.services.sandbox.v1;
+-
+-import "google/protobuf/any.proto";
+-import "google/protobuf/timestamp.proto";
+-
+-import "sandbox/types/sandbox.proto";
+-import "sandbox/types/mount.proto";
+-import "sandbox/types/platform.proto";
+-import "sandbox/types/metrics.proto";
+-
+-option go_package = "github.com/containerd/containerd/api/services/sandbox/v1;sandbox";
+-
+-// Store provides a metadata storage interface for sandboxes. Similarly to `Containers`,
+-// sandbox object includes info required to start a new instance, but no runtime state.
+-// When running a new sandbox instance, store objects are used as base type to create from.
+-service Store {
+- rpc Create(StoreCreateRequest) returns (StoreCreateResponse);
+- rpc Update(StoreUpdateRequest) returns (StoreUpdateResponse);
+- rpc Delete(StoreDeleteRequest) returns (StoreDeleteResponse);
+- rpc List(StoreListRequest) returns (StoreListResponse);
+- rpc Get(StoreGetRequest) returns (StoreGetResponse);
+-}
+-
+-message StoreCreateRequest {
+- containerd.types.Sandbox sandbox = 1;
+-}
+-
+-message StoreCreateResponse {
+- containerd.types.Sandbox sandbox = 1;
+-}
+-
+-message StoreUpdateRequest {
+- containerd.types.Sandbox sandbox = 1;
+- repeated string fields = 2;
+-}
+-
+-message StoreUpdateResponse {
+- containerd.types.Sandbox sandbox = 1;
+-}
+-
+-message StoreDeleteRequest {
+- string sandbox_id = 1;
+-}
+-
+-message StoreDeleteResponse {}
+-
+-message StoreListRequest {
+- repeated string filters = 1;
+-}
+-
+-message StoreListResponse {
+- repeated containerd.types.Sandbox list = 1;
+-}
+-
+-message StoreGetRequest {
+- string sandbox_id = 1;
+-}
+-
+-message StoreGetResponse {
+- containerd.types.Sandbox sandbox = 1;
+-}
+-
+-// Controller is an interface to manage runtime sandbox instances.
+-service Controller {
+- rpc Create(ControllerCreateRequest) returns (ControllerCreateResponse);
+- rpc Start(ControllerStartRequest) returns (ControllerStartResponse);
+- rpc Platform(ControllerPlatformRequest) returns (ControllerPlatformResponse);
+- rpc Stop(ControllerStopRequest) returns (ControllerStopResponse);
+- rpc Wait(ControllerWaitRequest) returns (ControllerWaitResponse);
+- rpc Status(ControllerStatusRequest) returns (ControllerStatusResponse);
+- rpc Shutdown(ControllerShutdownRequest) returns (ControllerShutdownResponse);
+- rpc Metrics(ControllerMetricsRequest) returns (ControllerMetricsResponse);
+- rpc Update(ControllerUpdateRequest) returns (ControllerUpdateResponse);
+-}
+-
+-message ControllerCreateRequest {
+- string sandbox_id = 1;
+- repeated containerd.types.Mount rootfs = 2;
+- google.protobuf.Any options = 3;
+- string netns_path = 4;
+- map<string, string> annotations = 5;
+- containerd.types.Sandbox sandbox = 6;
+- string sandboxer = 10;
+-}
+-
+-message ControllerCreateResponse {
+- string sandbox_id = 1;
+-}
+-
+-message ControllerStartRequest {
+- string sandbox_id = 1;
+- string sandboxer = 10;
+-}
+-
+-message ControllerStartResponse {
+- string sandbox_id = 1;
+- uint32 pid = 2;
+- google.protobuf.Timestamp created_at = 3;
+- map<string, string> labels = 4;
+- // Address of the sandbox for containerd to connect,
+- // for calling Task or other APIs serving in the sandbox.
+- // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://<vsock cid>:<port>.
+- string address = 5;
+- uint32 version = 6;
+-}
+-
+-message ControllerPlatformRequest {
+- string sandbox_id = 1;
+- string sandboxer = 10;
+-}
+-
+-message ControllerPlatformResponse {
+- containerd.types.Platform platform = 1;
+-}
+-
+-message ControllerStopRequest {
+- string sandbox_id = 1;
+- uint32 timeout_secs = 2;
+- string sandboxer = 10;
+-}
+-
+-message ControllerStopResponse {}
+-
+-message ControllerWaitRequest {
+- string sandbox_id = 1;
+- string sandboxer = 10;
+-}
+-
+-message ControllerWaitResponse {
+- uint32 exit_status = 1;
+- google.protobuf.Timestamp exited_at = 2;
+-}
+-
+-message ControllerStatusRequest {
+- string sandbox_id = 1;
+- bool verbose = 2;
+- string sandboxer = 10;
+-}
+-
+-message ControllerStatusResponse {
+- string sandbox_id = 1;
+- uint32 pid = 2;
+- string state = 3;
+- map<string, string> info = 4;
+- google.protobuf.Timestamp created_at = 5;
+- google.protobuf.Timestamp exited_at = 6;
+- google.protobuf.Any extra = 7;
+- // Address of the sandbox for containerd to connect,
+- // for calling Task or other APIs serving in the sandbox.
+- // it is in the form of ttrpc+unix://path/to/uds or grpc+vsock://<vsock cid>:<port>.
+- string address = 8;
+- uint32 version = 9;
+-}
+-
+-message ControllerShutdownRequest {
+- string sandbox_id = 1;
+- string sandboxer = 10;
+-}
+-
+-message ControllerShutdownResponse {}
+-
+-message ControllerMetricsRequest {
+- string sandbox_id = 1;
+- string sandboxer = 10;
+-}
+-
+-message ControllerMetricsResponse {
+- types.Metric metrics = 1;
+-}
+-
+-message ControllerUpdateRequest {
+- string sandbox_id = 1;
+- string sandboxer = 2;
+- containerd.types.Sandbox sandbox = 3;
+- repeated string fields = 4;
+-}
+-
+-message ControllerUpdateResponse {
+-}
+\ No newline at end of file
+diff --git a/src/api/services/sandbox/sandbox/types/metrics.proto b/src/api/services/sandbox/sandbox/types/metrics.proto
+deleted file mode 100644
+index 61185939..00000000
+--- a/src/api/services/sandbox/sandbox/types/metrics.proto
++++ /dev/null
+@@ -1,30 +0,0 @@
+-/*
+- Copyright The containerd Authors.
+-
+- 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.
+-*/
+-
+-syntax = "proto3";
+-
+-package containerd.types;
+-
+-import "google/protobuf/any.proto";
+-import "google/protobuf/timestamp.proto";
+-
+-option go_package = "github.com/containerd/containerd/api/types;types";
+-
+-message Metric {
+- google.protobuf.Timestamp timestamp = 1;
+- string id = 2;
+- google.protobuf.Any data = 3;
+-}
+\ No newline at end of file
+diff --git a/src/api/services/sandbox/sandbox/types/mount.proto b/src/api/services/sandbox/sandbox/types/mount.proto
+deleted file mode 100644
+index 54e0a0cd..00000000
+--- a/src/api/services/sandbox/sandbox/types/mount.proto
++++ /dev/null
+@@ -1,43 +0,0 @@
+-/*
+- Copyright The containerd Authors.
+-
+- 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.
+-*/
+-
+-syntax = "proto3";
+-
+-package containerd.types;
+-
+-option go_package = "github.com/containerd/containerd/api/types;types";
+-
+-// Mount describes mounts for a container.
+-//
+-// This type is the lingua franca of ContainerD. All services provide mounts
+-// to be used with the container at creation time.
+-//
+-// The Mount type follows the structure of the mount syscall, including a type,
+-// source, target and options.
+-message Mount {
+- // Type defines the nature of the mount.
+- string type = 1;
+-
+- // Source specifies the name of the mount. Depending on mount type, this
+- // may be a volume name or a host path, or even ignored.
+- string source = 2;
+-
+- // Target path in container
+- string target = 3;
+-
+- // Options specifies zero or more fstab style mount options.
+- repeated string options = 4;
+-}
+diff --git a/src/api/services/sandbox/sandbox/types/platform.proto b/src/api/services/sandbox/sandbox/types/platform.proto
+deleted file mode 100644
+index 102e6e2b..00000000
+--- a/src/api/services/sandbox/sandbox/types/platform.proto
++++ /dev/null
+@@ -1,30 +0,0 @@
+-/*
+- Copyright The containerd Authors.
+-
+- 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.
+-*/
+-
+-syntax = "proto3";
+-
+-package containerd.types;
+-
+-option go_package = "github.com/containerd/containerd/api/types;types";
+-
+-// Platform follows the structure of the OCI platform specification, from
+-// descriptors.
+-message Platform {
+- string os = 1;
+- string architecture = 2;
+- string variant = 3;
+- string os_version = 4;
+-}
+\ No newline at end of file
+diff --git a/src/api/services/sandbox/sandbox/types/sandbox.proto b/src/api/services/sandbox/sandbox/types/sandbox.proto
+deleted file mode 100644
+index 6fe08d40..00000000
+--- a/src/api/services/sandbox/sandbox/types/sandbox.proto
++++ /dev/null
+@@ -1,54 +0,0 @@
+-/*
+- Copyright The containerd Authors.
+-
+- 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.
+-*/
+-
+-syntax = "proto3";
+-
+-package containerd.types;
+-
+-import "google/protobuf/any.proto";
+-import "google/protobuf/timestamp.proto";
+-
+-option go_package = "github.com/containerd/containerd/api/types;types";
+-
+-// Sandbox represents a sandbox metadata object that keeps all info required by controller to
+-// work with a particular instance.
+-message Sandbox {
+- // SandboxID is a unique instance identifier within namespace
+- string sandbox_id = 1;
+- message Runtime {
+- // Name is the name of the runtime.
+- string name = 1;
+- // Options specify additional runtime initialization options for the shim (this data will be available in StartShim).
+- // Typically this data expected to be runtime shim implementation specific.
+- google.protobuf.Any options = 2;
+- }
+- // Runtime specifies which runtime to use for executing this container.
+- Runtime runtime = 2;
+- // Spec is sandbox configuration (kin of OCI runtime spec), spec's data will be written to a config.json file in the
+- // bundle directory (similary to OCI spec).
+- google.protobuf.Any spec = 3;
+- // Labels provides an area to include arbitrary data on containers.
+- map<string, string> labels = 4;
+- // CreatedAt is the time the container was first created.
+- google.protobuf.Timestamp created_at = 5;
+- // UpdatedAt is the last time the container was mutated.
+- google.protobuf.Timestamp updated_at = 6;
+- // Extensions allow clients to provide optional blobs that can be handled by runtime.
+- map<string, google.protobuf.Any> extensions = 7;
+- // Sandboxer is the name of the sandbox controller who manages the sandbox.
+- string sandboxer = 10;
+-
+-}
+\ No newline at end of file
+diff --git a/src/daemon/common/cri/v1/v1_cri_helpers.cc b/src/daemon/common/cri/v1/v1_cri_helpers.cc
+index 31b6b137..dfe14ade 100644
+--- a/src/daemon/common/cri/v1/v1_cri_helpers.cc
++++ b/src/daemon/common/cri/v1/v1_cri_helpers.cc
+@@ -397,7 +397,7 @@ std::string CRISandboxerConvert(const std::string &runtime)
+ std::string sandboxer;
+ defs_map_string_object_sandboxer *criSandboxerList = nullptr;
+
+- if (runtime.empty() || runtime == DEFAULT_SANDBOXER_NAME) {
++ if (runtime.empty()) {
+ return DEFAULT_SANDBOXER_NAME;
+ }
+
+@@ -412,6 +412,7 @@ std::string CRISandboxerConvert(const std::string &runtime)
+ goto out;
+ }
+
++ sandboxer = DEFAULT_SANDBOXER_NAME;
+ criSandboxerList = args->json_confs->cri_sandboxers;
+ for (size_t i = 0; i < criSandboxerList->len; i++) {
+ if (criSandboxerList->keys[i] == nullptr || criSandboxerList->values[i] == nullptr ||
+diff --git a/src/daemon/sandbox/CMakeLists.txt b/src/daemon/sandbox/CMakeLists.txt
+index 7679ea68..2c31f243 100644
+--- a/src/daemon/sandbox/CMakeLists.txt
++++ b/src/daemon/sandbox/CMakeLists.txt
+@@ -1,15 +1,32 @@
+ # get current directory sources files
+
+ aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} sandbox_top_srcs)
+-add_subdirectory(controller)
+
+-set(SANDBOX_SRCS
++set(local_sandbox_top_srcs
+ ${sandbox_top_srcs}
+- ${SANDBOX_CONTROLLER_SRCS}
++ )
++set(local_sandbox_top_incs
++ ${CMAKE_CURRENT_SOURCE_DIR}
++ )
++
++if (ENABLE_CRI_API_V1 AND ENABLE_SANDBOXER)
++ add_subdirectory(sandboxer)
++ list (APPEND local_sandbox_top_srcs
++ ${SANDBOXER_SANDBOX_SRCS}
++ )
++ list (APPEND local_sandbox_top_incs
++ ${SANDBOXER_SANDBOX_INCS}
++ )
++endif()
++
++add_subdirectory(shim)
++set(SANDBOX_SRCS
++ ${local_sandbox_top_srcs}
++ ${SHIM_SANDBOX_SRCS}
+ PARENT_SCOPE
+ )
+ set(SANDBOX_INCS
+- ${CMAKE_CURRENT_SOURCE_DIR}
+- ${SANDBOX_CONTROLLER_INCS}
++ ${local_sandbox_top_incs}
++ ${SHIM_SANDBOX_INCS}
+ PARENT_SCOPE
+ )
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/controller/controller.h b/src/daemon/sandbox/controller.h
+similarity index 79%
+rename from src/daemon/sandbox/controller/controller.h
+rename to src/daemon/sandbox/controller.h
+index 60d2dee5..0975015a 100644
+--- a/src/daemon/sandbox/controller/controller.h
++++ b/src/daemon/sandbox/controller.h
+@@ -22,15 +22,19 @@
+ #include <grpc++/grpc++.h>
+ #include <stdint.h>
+
++#include <isula_libutils/sandbox_sandbox.h>
++
+ #include "errors.h"
+ #include "api_v1.pb.h"
+-#include "sandbox.pb.h"
++#include "utils_array.h"
+
+ namespace sandbox {
+
+ #define SANDBOX_READY_STATE_STR "SANDBOX_READY"
+ #define SANDBOX_NOTREADY_STATE_STR "SANDBOX_NOTREADY"
+
++const std::string SHIM_CONTROLLER_NAME = "shim";
++
+ struct ControllerMountInfo {
+ std::string source;
+ std::string destination;
+@@ -66,7 +70,7 @@ struct ControllerSandboxInfo {
+ uint32_t pid;
+ uint64_t createdAt;
+ std::string taskAddress;
+- std::string version;
++ uint32_t version;
+ google::protobuf::Map<std::string, std::string> labels;
+ };
+
+@@ -80,7 +84,7 @@ struct ControllerSandboxStatus {
+ uint32_t pid;
+ std::string state;
+ std::string taskAddress;
+- std::string version;
++ uint32_t version;
+ google::protobuf::Map<std::string, std::string> info;
+ uint64_t createdAt;
+ uint64_t exitedAt;
+@@ -95,20 +99,6 @@ struct ControllerStreamInfo {
+ bool terminal;
+ };
+
+-struct ControllerPrepareParams {
+- std::string containerId;
+- std::string execId;
+- std::unique_ptr<std::string> spec;
+- std::vector<std::unique_ptr<ControllerMountInfo>> rootfs;
+- std::unique_ptr<ControllerStreamInfo> streamInfo;
+-};
+-
+-struct ControllerUpdateResourcesParams {
+- std::string containerId;
+- std::unique_ptr<std::string> resources;
+- google::protobuf::Map<std::string, std::string> &annotations;
+-};
+-
+ class SandboxStatusCallback {
+ public:
+ virtual void OnSandboxReady() = 0;
+@@ -120,19 +110,13 @@ class Controller {
+ public:
+ virtual ~Controller() {};
+ virtual bool Init(Errors &error) = 0;
+- virtual void Destroy() = 0;
+ virtual bool Create(const std::string &sandboxId,
+ const ControllerCreateParams &params,
+ Errors &error) = 0;
+ virtual std::unique_ptr<ControllerSandboxInfo> Start(const std::string &sandboxId, Errors &error) = 0 ;
+ virtual std::unique_ptr<ControllerPlatformInfo> Platform(const std::string &sandboxId, Errors &error) = 0;
+- virtual bool Prepare(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields, Errors &error) = 0;
+- virtual bool Purge(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields, Errors &error) = 0;
+- virtual bool UpdateResources(const std::string &sandboxId,
+- const ControllerUpdateResourcesParams &params,
+- Errors &error) = 0;
++ virtual bool Update(sandbox_sandbox *apiSandbox,
++ string_array *fields, Errors &error) = 0;
+ virtual bool Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error) = 0;
+ virtual bool Wait(std::shared_ptr<SandboxStatusCallback> cb, const std::string &sandboxId, Errors &error) = 0;
+ virtual std::unique_ptr<ControllerSandboxStatus> Status(const std::string &sandboxId, bool verbose, Errors &error) = 0;
+diff --git a/src/daemon/sandbox/controller/CMakeLists.txt b/src/daemon/sandbox/controller/CMakeLists.txt
+deleted file mode 100644
+index 8764c05b..00000000
+--- a/src/daemon/sandbox/controller/CMakeLists.txt
++++ /dev/null
+@@ -1,32 +0,0 @@
+-# get current directory sources files
+-
+-aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} sandbox_controller_top_srcs)
+-
+-set(local_sandbox_controller_top_srcs
+- ${sandbox_controller_top_srcs}
+- )
+-set(local_sandbox_controller_top_incs
+- ${CMAKE_CURRENT_SOURCE_DIR}
+- )
+-
+-if (ENABLE_CRI_API_V1 AND ENABLE_SANDBOXER)
+- add_subdirectory(sandboxer)
+- list (APPEND local_sandbox_controller_top_srcs
+- ${CONTROLLER_SANDBOXER_SRCS}
+- )
+- list (APPEND local_sandbox_controller_top_incs
+- ${CONTROLLER_SANDBOXER_INCS}
+- )
+-endif()
+-
+-add_subdirectory(shim)
+-set(SANDBOX_CONTROLLER_SRCS
+- ${local_sandbox_controller_top_srcs}
+- ${CONTROLLER_SHIM_SRCS}
+- PARENT_SCOPE
+- )
+-set(SANDBOX_CONTROLLER_INCS
+- ${local_sandbox_controller_top_incs}
+- ${CONTROLLER_SHIM_INCS}
+- PARENT_SCOPE
+- )
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/CMakeLists.txt b/src/daemon/sandbox/controller/sandboxer/client/CMakeLists.txt
+deleted file mode 100755
+index 958ebaa5..00000000
+--- a/src/daemon/sandbox/controller/sandboxer/client/CMakeLists.txt
++++ /dev/null
+@@ -1,20 +0,0 @@
+-# get current directory sources files
+-aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} sandbox_controller_sandboxer_client_srcs)
+-aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox grpc_sandbox_api_srcs)
+-aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox/google/protobuf grpc_sandbox_google_protobuf_api_srcs)
+-aux_source_directory(${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox/sandbox/types sandbox_type_srcs)
+-
+-
+-set(CONTROLLER_SANDBOXER_CLIENT_SRCS
+- ${sandbox_controller_sandboxer_client_srcs}
+- ${grpc_sandbox_api_srcs}
+- ${grpc_sandbox_google_protobuf_api_srcs}
+- ${sandbox_type_srcs}
+- PARENT_SCOPE
+- )
+-
+-set(CONTROLLER_SANDBOXER_CLIENT_INCS
+- ${CMAKE_CURRENT_SOURCE_DIR}
+- ${CMAKE_BINARY_DIR}/grpc/src/api/services/sandbox
+- PARENT_SCOPE
+- )
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_async_wait_call.cc b/src/daemon/sandbox/controller/sandboxer/client/grpc_async_wait_call.cc
+deleted file mode 100644
+index c6f97da1..00000000
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_async_wait_call.cc
++++ /dev/null
+@@ -1,142 +0,0 @@
+-/******************************************************************************
+- * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
+- * iSulad licensed under the Mulan PSL v2.
+- * You can use this software according to the terms and conditions of the Mulan PSL v2.
+- * You may obtain a copy of Mulan PSL v2 at:
+- * http://license.coscl.org.cn/MulanPSL2
+- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+- * PURPOSE.
+- * See the Mulan PSL v2 for more details.
+- * Author: xuxuepeng
+- * Create: 2023-07-28
+- * Description: gRPC Async wait call object
+- ******************************************************************************/
+-
+-#include "grpc_async_wait_call.h"
+-
+-#include <grpc++/grpc++.h>
+-#include <isula_libutils/log.h>
+-
+-#include "grpc_client_utils.h"
+-
+-namespace sandbox {
+-
+-// Max retry counter. In monitor thread, we will check deferred calls every 200ms
+-// so if a call has retry counter for 1500, it means the call will be retried after 300 seconds
+-const int64_t MAX_RETRY_COUNTER = 1500; // 1500 * 200ms = 300s
+-
+-SandboxerAsyncWaitCall::SandboxerAsyncWaitCall(std::shared_ptr<SandboxStatusCallback> cb,
+- const std::string &sandboxId, const std::string &sandboxer)
+- : m_cb(cb), m_sandboxId(sandboxId), m_sandboxer(sandboxer)
+-{
+- m_status = grpc::Status::OK;
+- m_retryTimes = 0;
+- m_retryCounter = 0;
+- m_remove = false;
+-}
+-
+-auto SandboxerAsyncWaitCall::Call(containerd::services::sandbox::v1::Controller::StubInterface &stub,
+- grpc::CompletionQueue &cq) -> bool
+-{
+- containerd::services::sandbox::v1::ControllerWaitRequest request;
+- m_context = std::unique_ptr<grpc::ClientContext>(new grpc::ClientContext());
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(m_sandboxId);
+- m_responseReader = stub.PrepareAsyncWait(m_context.get(), request, &cq);
+- if (m_responseReader == nullptr) {
+- // Most likely the completion queue is shutdown
+- ERROR("Failed to prepare async wait request for sandboxer wait request, sandbox id: %s", m_sandboxId.c_str());
+- SandboxExitCallback(false, ControllerExitInfo());
+- return false;
+- }
+- m_responseReader->StartCall();
+- m_responseReader->Finish(&m_response, &m_status, (void *)this);
+- return true;
+-}
+-
+-auto SandboxerAsyncWaitCall::SandboxExitCallback(bool statusOK, const ControllerExitInfo &exitInfo) -> void
+-{
+- // If statusOK is false, it means something unexpected happened during async wait,
+- // the exitInfo is not valid, but we assume that the sandbox has exited.
+- if (!statusOK) {
+- ControllerExitInfo info;
+- auto currentTime = std::chrono::high_resolution_clock::now();
+- auto duration = currentTime.time_since_epoch();
+- info.exitedAt = std::chrono::duration_cast<std::chrono::nanoseconds>(duration).count();
+- info.exitStatus = -1;
+- m_cb->OnSandboxExit(info);
+- return;
+- }
+- m_cb->OnSandboxExit(exitInfo);
+-}
+-
+-auto SandboxerAsyncWaitCall::SandboxPendingCallback() -> void
+-{
+- m_cb->OnSandboxPending();
+-}
+-
+-auto SandboxerAsyncWaitCall::SandboxReadyCallback() -> void
+-{
+- m_cb->OnSandboxReady();
+-}
+-
+-auto SandboxerAsyncWaitCall::Timeout() -> bool
+-{
+- m_retryCounter--;
+- return m_retryCounter == 0;
+-}
+-
+-auto SandboxerAsyncWaitCall::GetSandboxId() -> const std::string &
+-{
+- return m_sandboxId;
+-}
+-
+-SandboxerAsyncWaitStatus SandboxerAsyncWaitCall::HandleResponse()
+-{
+- ControllerExitInfo exitInfo;
+- SandboxerAsyncWaitStatus waitStatus = SANDBOXER_ASYNC_WAIT_STATUS_ERROR;
+-
+- switch (m_status.error_code()) {
+- case grpc::StatusCode::UNAVAILABLE:
+- // If the status is unavailable, connection failed, we should retry
+- WARN("Sandboxer controller wait rpc server unavailable, error_code: %d: %s", m_status.error_code(),
+- m_status.error_message().c_str());
+- waitStatus = SANDBOXER_ASYNC_WAIT_STATUS_RETRY;
+- m_retryTimes++;
+- // If retried times is more than 10, we should retry every 300 seconds
+- if (m_retryTimes > 10) {
+- m_retryCounter = MAX_RETRY_COUNTER;
+- } else {
+- // Retry interval is 2 ^ retry times
+- m_retryCounter = 1 << m_retryTimes;
+- }
+- m_cb->OnSandboxPending();
+- break;
+- case grpc::StatusCode::OK:
+- exitInfo.exitedAt = TimestampToNanos(m_response.exited_at());
+- exitInfo.exitStatus = m_response.exit_status();
+- DEBUG("Sandboxer controller wait request success, sandbox id: %s, exit status: %d, exited at: %lu",
+- m_sandboxId.c_str(), exitInfo.exitStatus, exitInfo.exitedAt);
+- SandboxExitCallback(true, exitInfo);
+- waitStatus = SANDBOXER_ASYNC_WAIT_STATUS_OK;
+- break;
+- case grpc::StatusCode::NOT_FOUND:
+- // If the sandbox is not found, it has been deleted, we should return not found
+- WARN("The sandbox wait doesn't exist, sandbox id: %s, error_code: %d: %s",
+- m_sandboxId.c_str(), m_status.error_code(), m_status.error_message().c_str());
+- waitStatus = SANDBOXER_ASYNC_WAIT_STATUS_NOT_FOUND;
+- SandboxExitCallback(false, exitInfo);
+- break;
+- default:
+- // TODO: More error code should be handled
+- ERROR("Sandboxer controller wait request failed, error_code: %d: %s", m_status.error_code(),
+- m_status.error_message().c_str());
+- SandboxExitCallback(false, exitInfo);
+- break;
+- }
+-
+- return waitStatus;
+-}
+-
+-}; // namespace sandbox
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_async_wait_call.h b/src/daemon/sandbox/controller/sandboxer/client/grpc_async_wait_call.h
+deleted file mode 100644
+index 6e5a6756..00000000
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_async_wait_call.h
++++ /dev/null
+@@ -1,94 +0,0 @@
+-/******************************************************************************
+- * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
+- * iSulad licensed under the Mulan PSL v2.
+- * You can use this software according to the terms and conditions of the Mulan PSL v2.
+- * You may obtain a copy of Mulan PSL v2 at:
+- * http://license.coscl.org.cn/MulanPSL2
+- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+- * PURPOSE.
+- * See the Mulan PSL v2 for more details.
+- * Author: xuxuepeng
+- * Create: 2023-07-28
+- * Description: gRPC Async wait call object
+- ******************************************************************************/
+-
+-#ifndef DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_ASYNC_WAIT_CALL_H
+-#define DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_ASYNC_WAIT_CALL_H
+-
+-#include <string>
+-
+-#include "sandbox.pb.h"
+-#include "sandbox.grpc.pb.h"
+-
+-#include "controller.h"
+-
+-namespace sandbox {
+-
+-enum SandboxerAsyncWaitStatus {
+- SANDBOXER_ASYNC_WAIT_STATUS_OK = 0,
+- SANDBOXER_ASYNC_WAIT_STATUS_RETRY,
+- SANDBOXER_ASYNC_WAIT_STATUS_NOT_FOUND,
+- SANDBOXER_ASYNC_WAIT_STATUS_ERROR,
+-};
+-
+-/**
+- * SandboxerAsyncWaitCall is used to call the async wait method.
+- * It will be passed to completion queue to wait for the response.
+- * When the response is received, HandleResponse will be called.
+- */
+-class SandboxerAsyncWaitCall {
+-public:
+- SandboxerAsyncWaitCall(std::shared_ptr<SandboxStatusCallback> cb,
+- const std::string &sandboxId, const std::string &sandboxer);
+- virtual ~SandboxerAsyncWaitCall() = default;
+- auto Call(containerd::services::sandbox::v1::Controller::StubInterface &stub, grpc::CompletionQueue &cq) -> bool;
+- auto HandleResponse() -> SandboxerAsyncWaitStatus;
+- auto Timeout() -> bool;
+- void SandboxExitCallback(bool statusOK, const ControllerExitInfo &exitInfo);
+- void SandboxPendingCallback();
+- void SandboxReadyCallback();
+- auto GetSandboxId() -> const std::string &;
+- auto MarkRemove() -> void
+- {
+- m_remove = true;
+- }
+- auto ToRemove() -> bool
+- {
+- return m_remove;
+- }
+- auto ResetRetryTimes() -> void
+- {
+- m_retryTimes = 0;
+- }
+-
+-protected:
+- std::shared_ptr<containerd::services::sandbox::v1::Controller::StubInterface> m_stub;
+- std::shared_ptr<SandboxStatusCallback> m_cb;
+- std::string m_sandboxId;
+- std::string m_sandboxer;
+- std::unique_ptr<grpc::ClientAsyncResponseReaderInterface<containerd::services::sandbox::v1::ControllerWaitResponse>>
+- m_responseReader;
+- std::unique_ptr<grpc::ClientContext> m_context;
+- containerd::services::sandbox::v1::ControllerWaitResponse m_response;
+- grpc::Status m_status;
+- uint32_t m_retryTimes;
+- uint64_t m_retryCounter;
+- // The Call object will be deleted when it is unable to be enqueued to completion queue.
+- // However, since gRPC call happens in async function in Future object, there is potential race condition
+- // when deleting the call object:
+- // 1. Monitor thread cleanup future object first, which holding the reference to call object, and
+- // then AysncCompletionRpcThread received response for the call later, and delete the call object.
+- // It is OK in this case, since future release the call ownership, and the call object deleted later.
+- // 2. AsyncCompletionRpcThread received response for the call first, and delete the call object, and
+- // then Monitor thread cleanup future object later, which could cause use-after-free, since monitor
+- // thread will use the call to call the callback when cleaning the future object.
+- // So we need to mark the call object as removed, cleanup them together in Monitor thread after checking
+- // the future objects.
+- bool m_remove;
+-};
+-
+-
+-}; // namespace sandbox
+-
+-#endif // DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_ASYNC_WAIT_CALL_H
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_client_utils.cc b/src/daemon/sandbox/controller/sandboxer/client/grpc_client_utils.cc
+deleted file mode 100644
+index 2cc5a11e..00000000
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_client_utils.cc
++++ /dev/null
+@@ -1,36 +0,0 @@
+-/******************************************************************************
+- * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
+- * iSulad licensed under the Mulan PSL v2.
+- * You can use this software according to the terms and conditions of the Mulan PSL v2.
+- * You may obtain a copy of Mulan PSL v2 at:
+- * http://license.coscl.org.cn/MulanPSL2
+- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+- * PURPOSE.
+- * See the Mulan PSL v2 for more details.
+- * Author: xuxuepeng
+- * Create: 2023-07-28
+- * Description: grpc client utils functions
+- ******************************************************************************/
+-
+-#include "grpc_client_utils.h"
+-
+-const uint64_t SECOND_TO_NANOS = 1000000000;
+-const int64_t MAX_SECONDS_FOR_TIMESTAMP = 253402300799; // 9999-12-31T23:59:59Z
+-const int32_t MAX_NANOS_FOR_TIMESTAMP = 999999999;
+-
+-auto TimestampToNanos(const google::protobuf::Timestamp &timestamp) -> uint64_t
+-{
+- int64_t seconds = 0;
+- int32_t nanos = 0;
+-
+- seconds = timestamp.seconds();
+- seconds = seconds < 0 ? 0 : seconds;
+- seconds = seconds > MAX_SECONDS_FOR_TIMESTAMP ? MAX_SECONDS_FOR_TIMESTAMP : seconds;
+-
+- nanos = timestamp.nanos();
+- nanos = nanos < 0 ? 0 : nanos;
+- nanos = nanos > MAX_NANOS_FOR_TIMESTAMP ? MAX_NANOS_FOR_TIMESTAMP : nanos;
+-
+- return seconds * SECOND_TO_NANOS + nanos;
+-}
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_client_utils.h b/src/daemon/sandbox/controller/sandboxer/client/grpc_client_utils.h
+deleted file mode 100644
+index 105d33fc..00000000
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_client_utils.h
++++ /dev/null
+@@ -1,23 +0,0 @@
+-/******************************************************************************
+- * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
+- * iSulad licensed under the Mulan PSL v2.
+- * You can use this software according to the terms and conditions of the Mulan PSL v2.
+- * You may obtain a copy of Mulan PSL v2 at:
+- * http://license.coscl.org.cn/MulanPSL2
+- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+- * PURPOSE.
+- * See the Mulan PSL v2 for more details.
+- * Author: xuxuepeng
+- * Create: 2023-07-28
+- * Description: grpc client utils functions
+- ******************************************************************************/
+-
+-#ifndef DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_CLIENT_UTILS_H
+-#define DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_CLIENT_UTILS_H
+-
+-#include <google/protobuf/timestamp.pb.h>
+-
+-uint64_t TimestampToNanos(const google::protobuf::Timestamp &timestamp);
+-
+-#endif // DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_CLIENT_UTILS_H
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc
+deleted file mode 100644
+index e042ad45..00000000
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.cc
++++ /dev/null
+@@ -1,337 +0,0 @@
+-/******************************************************************************
+- * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
+- * iSulad licensed under the Mulan PSL v2.
+- * You can use this software according to the terms and conditions of the Mulan PSL v2.
+- * You may obtain a copy of Mulan PSL v2 at:
+- * http://license.coscl.org.cn/MulanPSL2
+- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+- * PURPOSE.
+- * See the Mulan PSL v2 for more details.
+- * Author: xuxuepeng
+- * Create: 2023-07-10
+- * Description: Sandboxer grpc client
+- ******************************************************************************/
+-
+-#include "grpc_sandboxer_client.h"
+-
+-#include <grpc++/grpc++.h>
+-#include <iostream>
+-#include <memory>
+-#include <string>
+-#include <random>
+-
+-#include "sandbox/types/platform.pb.h"
+-#include "sandbox.pb.h"
+-#include "sandbox.grpc.pb.h"
+-#include "utils.h"
+-#include "isula_libutils/log.h"
+-
+-#include "grpc_client_utils.h"
+-
+-namespace sandbox {
+-
+-SandboxerClient::SandboxerClient(const std::string &sandboxer, const std::string &address):
+- m_sandboxer(sandboxer), m_address(address)
+-{
+- std::string unixPrefix(UNIX_SOCKET_PREFIX);
+-
+- // Only support unix domain socket
+- if (m_address.compare(0, unixPrefix.length(), unixPrefix) != 0) {
+- m_address = unixPrefix + m_address;
+- }
+- m_channel = grpc::CreateChannel(m_address, grpc::InsecureChannelCredentials());
+- m_stub = containerd::services::sandbox::v1::Controller::NewStub(m_channel);
+- // Monitor shares the same channel with client and has its own stub
+- m_monitor = std::unique_ptr<SandboxerClientMonitor>(new SandboxerClientMonitor(m_channel, m_sandboxer));
+-}
+-
+-void SandboxerClient::InitMountInfo(Mount &mount, const ControllerMountInfo &mountInfo)
+-{
+- mount.set_type(mountInfo.type);
+- mount.set_source(mountInfo.source);
+- mount.set_target(mountInfo.destination);
+- for (const auto &option : mountInfo.options) {
+- mount.add_options(option);
+- }
+-}
+-
+-auto SandboxerClient::InitCreateRequest(containerd::services::sandbox::v1::ControllerCreateRequest &request,
+- const std::string &sandboxId,
+- const ControllerCreateParams &params) -> bool
+-{
+- if (params.config == nullptr) {
+- ERROR("Sandboxer controller create request failed, config is null");
+- return false;
+- }
+- request.mutable_options()->PackFrom(*params.config);
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+- for (const auto &entry : params.mounts) {
+- if (entry != nullptr) {
+- Mount* mount = request.add_rootfs();
+- InitMountInfo(*mount, *entry);
+- }
+- }
+- request.set_netns_path(params.netNSPath);
+- // The arg sandbox is useless for now
+- return true;
+-}
+-
+-void SandboxerClient::Init(Errors &error)
+-{
+- m_monitor->Start();
+-}
+-
+-void SandboxerClient::Destroy()
+-{
+- m_monitor->Stop();
+-}
+-
+-auto SandboxerClient::Create(const std::string &sandboxId, const ControllerCreateParams &params, Errors &error) -> bool
+-{
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::ControllerCreateRequest request;
+- containerd::services::sandbox::v1::ControllerCreateResponse response;
+- grpc::Status status;
+-
+- if (!InitCreateRequest(request, sandboxId, params)) {
+- error.SetError("Failed to init create request for sandboxer create request, sandbox id: " + sandboxId);
+- return false;
+- }
+-
+- status = m_stub->Create(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller create request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+- return true;
+-}
+-
+-void SandboxerClient::StartResponseToSandboxInfo(const containerd::services::sandbox::v1::ControllerStartResponse
+- &response,
+- ControllerSandboxInfo &sandboxInfo)
+-{
+- sandboxInfo.id = response.sandbox_id();
+- sandboxInfo.pid = response.pid();
+- sandboxInfo.createdAt = TimestampToNanos(response.created_at());
+- sandboxInfo.taskAddress = response.address();
+- sandboxInfo.version = response.version();
+- sandboxInfo.labels = response.labels();
+-}
+-
+-auto SandboxerClient::Start(const std::string &sandboxId, ControllerSandboxInfo &sandboxInfo, Errors &error) -> bool
+-{
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::ControllerStartRequest request;
+- containerd::services::sandbox::v1::ControllerStartResponse response;
+- grpc::Status status;
+-
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+-
+- status = m_stub->Start(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller start request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+- StartResponseToSandboxInfo(response, sandboxInfo);
+-
+- return true;
+-}
+-
+-void SandboxerClient::InitUpdateRequest(containerd::services::sandbox::v1::ControllerUpdateRequest &request,
+- containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields)
+-{
+- request.set_sandbox_id(apiSandbox.sandbox_id());
+- request.set_sandboxer(apiSandbox.sandboxer());
+- *(request.mutable_sandbox()) = apiSandbox;
+- *(request.mutable_fields()) = {fields.begin(), fields.end()};
+-}
+-
+-auto SandboxerClient::Prepare(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields, Errors &error) -> bool
+-{
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::ControllerUpdateRequest request;
+- containerd::services::sandbox::v1::ControllerUpdateResponse response;
+- grpc::Status status;
+-
+- InitUpdateRequest(request, apiSandbox, fields);
+-
+- status = m_stub->Update(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller prepare request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+- return true;
+-}
+-
+-auto SandboxerClient::Purge(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields, Errors &error) -> bool
+-{
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::ControllerUpdateRequest request;
+- containerd::services::sandbox::v1::ControllerUpdateResponse response;
+- grpc::Status status;
+-
+- InitUpdateRequest(request, apiSandbox, fields);
+-
+- status = m_stub->Update(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller purge request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+- return true;
+-}
+-
+-auto SandboxerClient::UpdateResources(const std::string &sandboxId, const ControllerUpdateResourcesParams &params,
+- Errors &error) -> bool
+-{
+- return true;
+-}
+-
+-void SandboxerClient::PlatformResponseToPlatformInfo(const containerd::services::sandbox::v1::ControllerPlatformResponse
+- &response,
+- ControllerPlatformInfo &platformInfo)
+-{
+- auto &platform = response.platform();
+- platformInfo.os = platform.os();
+- platformInfo.arch = platform.architecture();
+- platformInfo.variant = platform.variant();
+-}
+-
+-auto SandboxerClient::Platform(const std::string &sandboxId, ControllerPlatformInfo &platformInfo,
+- Errors &error) -> bool
+-{
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::ControllerPlatformRequest request;
+- containerd::services::sandbox::v1::ControllerPlatformResponse response;
+- grpc::Status status;
+-
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+-
+- status = m_stub->Platform(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller platform request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+- PlatformResponseToPlatformInfo(response, platformInfo);
+-
+- return true;
+-}
+-
+-auto SandboxerClient::Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error) -> bool
+-{
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::ControllerStopRequest request;
+- containerd::services::sandbox::v1::ControllerStopResponse response;
+- grpc::Status status;
+-
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+- request.set_timeout_secs(timeoutSecs);
+-
+- status = m_stub->Stop(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller stop request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+- return true;
+-}
+-
+-void SandboxerClient::StatusResponseToSandboxStatus(const containerd::services::sandbox::v1::ControllerStatusResponse
+- &response,
+- ControllerSandboxStatus &sandboxStatus)
+-{
+- sandboxStatus.id = response.sandbox_id();
+- sandboxStatus.pid = response.pid();
+- sandboxStatus.state = response.state();
+- sandboxStatus.taskAddress = response.address();
+- sandboxStatus.version = response.version();
+- sandboxStatus.info.insert(response.info().begin(), response.info().end());
+- sandboxStatus.createdAt = TimestampToNanos(response.created_at());
+- sandboxStatus.exitedAt = TimestampToNanos(response.exited_at());
+- sandboxStatus.extra = response.extra().value();
+-}
+-
+-auto SandboxerClient::Status(const std::string &sandboxId, bool verbose, ControllerSandboxStatus &sandboxStatus,
+- Errors &error) -> bool
+-{
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::ControllerStatusRequest request;
+- containerd::services::sandbox::v1::ControllerStatusResponse response;
+- grpc::Status status;
+-
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+- request.set_verbose(verbose);
+-
+- status = m_stub->Status(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller status request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+- StatusResponseToSandboxStatus(response, sandboxStatus);
+-
+- return true;
+-}
+-
+-auto SandboxerClient::Shutdown(const std::string &sandboxId, Errors &error) -> bool
+-{
+- grpc::ClientContext context;
+- containerd::services::sandbox::v1::ControllerShutdownRequest request;
+- containerd::services::sandbox::v1::ControllerShutdownResponse response;
+- grpc::Status status;
+-
+- request.set_sandboxer(m_sandboxer);
+- request.set_sandbox_id(sandboxId);
+-
+- status = m_stub->Shutdown(&context, request, &response);
+- if (!status.ok()) {
+- error.SetError(status.error_message());
+- ERROR("Sandboxer controller shutdown request failed, error_code: %d: %s", status.error_code(),
+- status.error_message().c_str());
+- return false;
+- }
+-
+- return true;
+-}
+-
+-auto SandboxerClient::Wait(std::shared_ptr<SandboxStatusCallback> cb, const std::string &sandboxId,
+- Errors &error) -> bool
+-{
+- if (m_monitor == nullptr) {
+- error.SetError("Cannot wait for sandbox, sandboxer client monitor is not initialized, "
+- "sandboxer: " + m_sandboxer);
+- return false;
+- }
+- SandboxerAsyncWaitCall *call = new SandboxerAsyncWaitCall(cb, sandboxId, m_sandboxer);
+- // Transfer ownership of call to monitor
+- return m_monitor->Monitor(call);
+-}
+-
+-} // namespace
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_monitor.cc b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_monitor.cc
+deleted file mode 100644
+index 485a0b23..00000000
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_monitor.cc
++++ /dev/null
+@@ -1,314 +0,0 @@
+-/******************************************************************************
+- * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
+- * iSulad licensed under the Mulan PSL v2.
+- * You can use this software according to the terms and conditions of the Mulan PSL v2.
+- * You may obtain a copy of Mulan PSL v2 at:
+- * http://license.coscl.org.cn/MulanPSL2
+- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+- * PURPOSE.
+- * See the Mulan PSL v2 for more details.
+- * Author: xuxuepeng
+- * Create: 2023-07-28
+- * Description: Sandboxer grpc client monitor
+- ******************************************************************************/
+-
+-#include "grpc_sandboxer_monitor.h"
+-
+-#include <random>
+-
+-#include "isula_libutils/log.h"
+-
+-namespace sandbox {
+-
+-const int64_t DEFERRED_QUEUE_CHECK_INTERVAL = 200; // milliseconds
+-
+-SandboxerClientMonitor::SandboxerClientMonitor(std::shared_ptr<grpc::Channel> channel, const std::string &sandboxer):
+- m_channel(channel), m_sandboxer(sandboxer), m_teardown(false)
+-{
+- m_stub = containerd::services::sandbox::v1::Controller::NewStub(m_channel);
+-}
+-
+-// Monitor will gain the ownership of the call object, and is responsible
+-// for deleting it
+-auto SandboxerClientMonitor::Monitor(SandboxerAsyncWaitCall *call) -> bool
+-{
+- if (call == nullptr) {
+- ERROR("Async wait call is null, failed to monitor.");
+- return false;
+- }
+-
+- if (m_teardown) {
+- ERROR("Monitor is already shutdown, failed to monitor sandbox, id: %s",
+- call->GetSandboxId().c_str());
+- delete call;
+- return false;
+- }
+-
+- // Try to monitor the call, if failed, we should delete it right way
+- if (!call->Call(*m_stub, m_cq)) {
+- // The failure is most likely due to the fact that the completion queue is shutdown
+- delete call;
+- return false;
+- }
+- // The call will be enqueued into completion queue, and the callback
+- // will be invoked when the response is ready
+- std::unique_lock<std::mutex> lock(m_callsMutex);
+- m_calls.push_back(call);
+- INFO("Start to monitor sandboxer wait call, sandbox id: %s",
+- call->GetSandboxId().c_str());
+- return true;
+-}
+-
+-void SandboxerClientMonitor::Start()
+-{
+- m_cqThread = std::thread(&SandboxerClientMonitor::AsyncCompleteRpcThread, this);
+- m_deferredThread = std::thread(&SandboxerClientMonitor::MonitorThread, this);
+-}
+-
+-void SandboxerClientMonitor::Stop()
+-{
+- // At the time of shutdown, the calls objects are in three states:
+- // 1. In the completion queue, waiting for the response
+- // 2. In the deferred queue, waiting for the dispatch
+- // 3. In the future queue, are about to get into completion queue
+- // We should cleanup all those objects
+- m_cq.Shutdown();
+- m_teardown = true;
+- // In case the deferred queue is empty, we should notify the condition variable
+- m_deferredCallsCond.notify_one();
+- INFO("Stopping sandboxer wait call monitor, sandboxer: %s", m_sandboxer.c_str());
+- // Wait until all the threads exit
+- m_cqThread.join();
+- m_deferredThread.join();
+-}
+-
+-auto SandboxerClientMonitor::IsAlive() -> bool
+-{
+- // GetState will retry the channel connection if channel is not active when the parameter is true.
+- // Monitor will keep retrying with wait call, so we dont have to let channel reconnect here, use false instead.
+- return m_channel->GetState(false) == GRPC_CHANNEL_READY;
+-}
+-
+-// When the call needs to be retried, we should put it into the deferred queue
+-void SandboxerClientMonitor::AddDeferredCall(SandboxerAsyncWaitCall *call)
+-{
+- std::unique_lock<std::mutex> lock(m_deferredCallsMutex);
+- m_deferredCalls.push_back(call);
+- m_deferredCallsCond.notify_one();
+-}
+-
+-// When the deferred queue and future queue are empty, we should wait for the condition signal
+-void SandboxerClientMonitor::WaitForDeferredCall()
+-{
+- std::unique_lock<std::mutex> lock(m_deferredCallsMutex);
+- // Check m_futures queue here as well just in case m_futures queue is
+- if (m_deferredCalls.empty() && m_futures.empty() && !m_teardown) {
+- m_deferredCallsCond.wait(lock);
+- }
+-}
+-
+-// Retry the call after a random sleep time
+-// There are two return values for the future:
+-// 1. bool: Indicate the call has been successfully retried and enqueued into completion queue
+-// 2. SandboxerAsyncWaitCall *: The call handled by the future
+-void SandboxerClientMonitor::InvokeDeferredCall(SandboxerAsyncWaitCall *call)
+-{
+- m_futures.push_back(std::async([this, call]() {
+- // Random sleep for 50 ~ 200 milliseconds to avoid thundering herd
+- std::random_device rd;
+- std::mt19937 gen(rd());
+- std::uniform_int_distribution<> dis(DEFERRED_QUEUE_CHECK_INTERVAL / 4, DEFERRED_QUEUE_CHECK_INTERVAL);
+- int sleepTime = dis(gen);
+- std::this_thread::sleep_for(std::chrono::milliseconds(sleepTime));
+-
+- if (this->m_teardown) {
+- // If the monitor is already shutdown, the call will be cleaned up
+- // by the cleanup function
+- return std::pair<bool, SandboxerAsyncWaitCall*>(false, nullptr);
+- }
+- if (!call->Call(*m_stub, m_cq)) {
+- return std::pair<bool, SandboxerAsyncWaitCall*>(false, call);
+- }
+- return std::pair<bool, SandboxerAsyncWaitCall*>(true, call);
+- }));
+-}
+-
+-// Iterate the calls that are timeout and retry them
+-void SandboxerClientMonitor::DispatchDeferredCalls()
+-{
+- std::unique_lock<std::mutex> lock(m_deferredCallsMutex);
+- if (m_teardown) {
+- // Stop dispatching deferred calls
+- return;
+- }
+- for (auto it = m_deferredCalls.begin(); it != m_deferredCalls.end();) {
+- auto &call = (*it);
+- if (call->Timeout()) {
+- // If the call is timeout, we should retry
+- InvokeDeferredCall(call);
+- it = m_deferredCalls.erase(it);
+- } else {
+- it++;
+- }
+- }
+-}
+-
+-// We use future to invoke the deferred call, when the future is ready, we should check the result
+-void SandboxerClientMonitor::CheckCompletedFutures()
+-{
+- for (auto it = m_futures.begin(); it != m_futures.end();) {
+- auto &future = (*it);
+- if (future.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+- auto result = future.get();
+- auto enqueued = result.first;
+- auto call = result.second;
+- if (!enqueued) {
+- if (call != nullptr) {
+- // Sandbox has been notified due to call failure in call->Call,
+- // so no need to notify again
+- call->MarkRemove();
+- }
+- } else {
+- // When the async wait is enqueued into completion queue,
+- // and wait does not return error, we have no feadback
+- // from the sandboxer, since async wait only return when
+- // sandbox exited or some errors happened.
+- // Therefore, one way to assume that the wait call suceeded
+- // is that check the client status. If the client goes alive,
+- // we assume the wait call succeeded.
+- if (IsAlive()) {
+- // The future is responsible to enqueue the call
+- // into completion queue. So there is still a chance
+- // that before we check future status here,
+- // the call in completion queue has already finished,
+- // and the callback has been invoked with OnSandboxPending
+- // or OnSandboxExit in the HandleResponse function.
+- // In this case, the OnSandboxReady will overwrite the
+- // status, but it is ok, because:
+- // 1. If OnSandboxPending has been invoked,
+- // retry will happen pretty soon, and the
+- // callback will be invoked again.
+- // 2. If OnSandboxExit has been invoked, the caller
+- // should check the sandbox status in the OnSandboxReady
+- // callback, and it will find out the sandbox has exited,
+- // and not set sandbox to ready status.
+- call->SandboxReadyCallback();
+- call->ResetRetryTimes();
+- }
+- }
+- it = m_futures.erase(it);
+- } else {
+- it++;
+- }
+- }
+-}
+-
+-void SandboxerClientMonitor::ClearDeferredCalls()
+-{
+- std::unique_lock<std::mutex> lock(m_deferredCallsMutex);
+- m_deferredCalls.clear();
+-}
+-
+-void SandboxerClientMonitor::ClearAllCalls()
+-{
+- std::unique_lock<std::mutex> lock(m_callsMutex);
+- for (auto &call : m_calls) {
+- delete call;
+- }
+- m_calls.clear();
+-}
+-
+-void SandboxerClientMonitor::Cleanup()
+-{
+- for (auto &future : m_futures) {
+- future.wait();
+- }
+- m_futures.clear();
+- ClearDeferredCalls();
+- ClearAllCalls();
+-}
+-
+-/**
+- * Thread for handling completion queue.
+- */
+-void SandboxerClientMonitor::AsyncCompleteRpcThread()
+-{
+- void *got_tag;
+- bool ok = false;
+- SandboxerAsyncWaitStatus waitStatus;
+- INFO("Start thread to monitor wait call completion queue for sandboxer, sandboxer: %s",
+- m_sandboxer.c_str());
+-
+- pthread_setname_np(pthread_self(), "SandboxerAsyncWaitThread");
+-
+- // Next only return false when the completion queue is shutdown and
+- // the queue is fully drained
+- while (m_cq.Next(&got_tag, &ok)) {
+- if (got_tag == nullptr || m_teardown) {
+- // The completion queue is shutdown
+- // The calls will be cleaned up by the cleanup function
+- break;
+- }
+- auto call = static_cast<SandboxerAsyncWaitCall *>(got_tag);
+- waitStatus = call->HandleResponse();
+- if (waitStatus == SANDBOXER_ASYNC_WAIT_STATUS_RETRY) {
+- AddDeferredCall(call);
+- continue;
+- }
+- // The reason for not deleting the call here is that
+- // while the call is being handled in this thread,
+- // the call object could still possibly be referenced in the future
+- // that has not been checked yet by the monitor thread. This could happen
+- // especially when the completion queue is shutdown.
+- call->MarkRemove();
+- // Should notify deferred thread to clean up the call
+- m_deferredCallsCond.notify_one();
+- }
+- INFO("Completion queue is shutdown, wait call monitor thread exit for sandboxer: %s",
+- m_sandboxer.c_str());
+-}
+-
+-/**
+- * Delete the calls that are marked to be removed.
+- */
+-void SandboxerClientMonitor::DeleteRemovedCalls()
+-{
+- std::unique_lock<std::mutex> lock(m_callsMutex);
+- for (auto it = m_calls.begin(); it != m_calls.end();) {
+- auto &call = (*it);
+- if (call->ToRemove()) {
+- delete call;
+- it = m_calls.erase(it);
+- } else {
+- it++;
+- }
+- }
+-}
+-
+-/**
+- * Thread for handling deferred retry calls and cleanup.
+- */
+-void SandboxerClientMonitor::MonitorThread()
+-{
+- INFO("Start wait call monitoring thread, sandboxer: %s",
+- m_sandboxer.c_str());
+- pthread_setname_np(pthread_self(), "SandboxerMonitorThread");
+- while (!m_teardown) {
+- // 1. Clean up futures that are ready
+- CheckCompletedFutures();
+- // 2. Delete the calls that are marked to be removed
+- DeleteRemovedCalls();
+- // 3. If deferred queue is empty, wait for the condition signal
+- WaitForDeferredCall();
+- // 4. We have deferred calls in the queue, deferred for 200 ms
+- std::this_thread::sleep_for(std::chrono::milliseconds(DEFERRED_QUEUE_CHECK_INTERVAL));
+- // 5. Dispatch the deferred calls
+- DispatchDeferredCalls();
+- }
+- // Cleanup the queue
+- Cleanup();
+- INFO("Start wait call monitoring thread, sandboxer: %s", m_sandboxer.c_str());
+-}
+-
+-} // namespace sandbox
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_monitor.h b/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_monitor.h
+deleted file mode 100644
+index b5740b44..00000000
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_monitor.h
++++ /dev/null
+@@ -1,85 +0,0 @@
+-/******************************************************************************
+- * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
+- * iSulad licensed under the Mulan PSL v2.
+- * You can use this software according to the terms and conditions of the Mulan PSL v2.
+- * You may obtain a copy of Mulan PSL v2 at:
+- * http://license.coscl.org.cn/MulanPSL2
+- * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
+- * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
+- * PURPOSE.
+- * See the Mulan PSL v2 for more details.
+- * Author: xuxuepeng
+- * Create: 2023-07-28
+- * Description: Sandboxer grpc client monitor
+- ******************************************************************************/
+-
+-#ifndef DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_SANDBOXER_MONITOR_H
+-#define DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_SANDBOXER_MONITOR_H
+-
+-#include <memory>
+-#include <string>
+-#include <thread>
+-#include <future>
+-
+-#include "grpc_async_wait_call.h"
+-
+-namespace sandbox {
+-
+-/**
+- * SandboxerClientMonitor is used to monitor the async wait call.
+- * It will start two threads, one for monitoring the completion queue,
+- * the other for retrying the async wait call.
+- * The lifecycle of SandboxerAsyncWaitCall object is managed in the following way:
+- * 1. When the async call first called, it will be directly passed into completion queue.
+- * 2. If the call status received from completion queue is SANDBOXER_ASYNC_WAIT_STATUS_RETRY,
+- * the call will be enqueued to m_deferredCalls, otherwise it will be deleted.
+- * 3. When the deferred duration is reached for the call, it will be retried, and passed to
+- * completion queue again.
+- */
+-class SandboxerClientMonitor {
+-public:
+- SandboxerClientMonitor(std::shared_ptr<grpc::Channel> channel, const std::string &sandboxer);
+- ~SandboxerClientMonitor() = default;
+-
+- auto Monitor(SandboxerAsyncWaitCall *call) -> bool;
+- void Start();
+- void Stop();
+-private:
+- auto IsAlive() -> bool;
+- void AddDeferredCall(SandboxerAsyncWaitCall *call);
+- void WaitForDeferredCall();
+- void InvokeDeferredCall(SandboxerAsyncWaitCall *call);
+- void DispatchDeferredCalls();
+- void AsyncCompleteRpcThread();
+- void MonitorThread();
+- void CheckCompletedFutures();
+- void DeleteRemovedCalls();
+- void ClearDeferredCalls();
+- void ClearAllCalls();
+- void Cleanup();
+-
+- std::thread m_cqThread;
+- std::thread m_deferredThread;
+- std::unique_ptr<containerd::services::sandbox::v1::Controller::StubInterface> m_stub;
+- std::shared_ptr<grpc::Channel> m_channel;
+- std::string m_sandboxer;
+- // Completion queue is thread safe, no mutex needed
+- grpc::CompletionQueue m_cq;
+- // Vector for holding all the calls for monitoring
+- std::vector<SandboxerAsyncWaitCall *> m_calls;
+- std::mutex m_callsMutex;
+- // Use to indicate whether
+- bool m_teardown;
+- // Vector for holding all the retry calls
+- std::vector<SandboxerAsyncWaitCall *> m_deferredCalls;
+- std::mutex m_deferredCallsMutex;
+- std::condition_variable m_deferredCallsCond;
+-
+- // Vector for holding all the futures in flight
+- // No need to lock, only used in m_deferredThread thread
+- std::vector<std::future<std::pair<bool, SandboxerAsyncWaitCall*>>> m_futures;
+-};
+-
+-} // namespace sandbox
+-
+-#endif // DAEMON_SANDBOX_CONTROLLER_SANDBOXER_CLIENT_GRPC_SANDBOXER_MONITOR_H
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/controller/controller_manager.cc b/src/daemon/sandbox/controller_manager.cc
+similarity index 98%
+rename from src/daemon/sandbox/controller/controller_manager.cc
+rename to src/daemon/sandbox/controller_manager.cc
+index 91c98d26..947f2d19 100644
+--- a/src/daemon/sandbox/controller/controller_manager.cc
++++ b/src/daemon/sandbox/controller_manager.cc
+@@ -57,9 +57,6 @@ bool ControllerManager::Init(Errors &error)
+
+ bool ControllerManager::Cleanup(Errors &error)
+ {
+- for (auto &it : m_controllers) {
+- it.second->Destroy();
+- }
+ return true;
+ }
+
+diff --git a/src/daemon/sandbox/controller/controller_manager.h b/src/daemon/sandbox/controller_manager.h
+similarity index 100%
+rename from src/daemon/sandbox/controller/controller_manager.h
+rename to src/daemon/sandbox/controller_manager.h
+diff --git a/src/daemon/sandbox/sandbox.cc b/src/daemon/sandbox/sandbox.cc
+index 97b77f22..3715e5e0 100644
+--- a/src/daemon/sandbox/sandbox.cc
++++ b/src/daemon/sandbox/sandbox.cc
+@@ -1098,11 +1098,6 @@ auto Sandbox::GetNetworkSettingsPath() -> std::string
+ return m_rootdir + std::string("/") + NETWORK_SETTINGS_JSON;
+ }
+
+-auto Sandbox::GetTasksJsonPath() -> std::string
+-{
+- return m_rootdir + std::string("/") + SANDBOX_TASKS_JSON;
+-}
+-
+ void Sandbox::FillSandboxMetadata(sandbox_metadata* metadata, Errors &error)
+ {
+ std::string jsonStr;
+@@ -1123,214 +1118,4 @@ void Sandbox::FillSandboxMetadata(sandbox_metadata* metadata, Errors &error)
+
+ metadata->sandbox_config_json = util_strdup_s(jsonStr.c_str());
+ }
+-
+-auto Sandbox::AddTaskById(const char *task_id, sandbox_task *task) -> bool
+-{
+-
+- std::string taskId = std::string(task_id);
+- auto iter = m_tasks.find(taskId);
+-
+- if (iter != m_tasks.end()) {
+- ERROR("Failed to add exits sandbox task %s for sandbox: %s",
+- task_id, m_id.c_str());
+- return false;
+- }
+- m_tasks[taskId] = std::make_shared<SandboxTask>(task);
+- return true;
+-}
+-
+-auto Sandbox::ReadSandboxTasksJson() -> sandbox_tasks *
+-{
+- const std::string path = GetTasksJsonPath();
+- __isula_auto_free parser_error err = nullptr;
+- sandbox_tasks *tasksArray = nullptr;
+-
+- ReadGuard<RWMutex> lock(m_tasksMutex);
+- tasksArray = sandbox_tasks_parse_file(path.c_str(), nullptr, &err);
+- if (tasksArray == nullptr) {
+- WARN("Failed to read %s tasks json: %s", path.c_str(), err);
+- }
+- return tasksArray;
+-}
+-
+-auto Sandbox::WriteSandboxTasksJson(std::string &tasks_json) -> bool
+-{
+- int nret = 0;
+- const std::string path = GetTasksJsonPath();
+-
+- WriteGuard<RWMutex> lock(m_tasksMutex);
+- nret = util_atomic_write_file(path.c_str(), tasks_json.c_str(), tasks_json.size(), CONFIG_FILE_MODE, false);
+- if (nret != 0) {
+- SYSERROR("Failed to write file %s", path.c_str());
+- }
+- return nret == 0;
+-}
+-
+-auto Sandbox::DeleteSandboxTasksJson() -> bool
+-{
+- int get_err = 0;
+- const std::string path = GetTasksJsonPath();
+-
+- WriteGuard<RWMutex> lock(m_tasksMutex);
+- if (util_fileself_exists(path.c_str()) &&
+- !util_force_remove_file(path.c_str(), &get_err)) {
+- errno = get_err;
+- SYSERROR("Failed to remove file %s", path.c_str());
+- return false;
+- }
+-
+- return true;
+-}
+-
+-void Sandbox::AddSandboxTasksByArray(sandbox_tasks *tasksArray)
+-{
+- size_t i;
+-
+- WriteGuard<RWMutex> lock(m_tasksMutex);
+- for (i = 0; i < tasksArray->tasks_len; i++) {
+- if (!AddTaskById(tasksArray->tasks[i]->task_id, tasksArray->tasks[i])) {
+- return;
+- }
+- tasksArray->tasks[i] = nullptr;
+- }
+- tasksArray->tasks_len = 0;
+-}
+-
+-void Sandbox::LoadSandboxTasks()
+-{
+- sandbox_tasks *tasksArray = nullptr;
+-
+- tasksArray = ReadSandboxTasksJson();
+- if (tasksArray == nullptr) {
+- return;
+- }
+-
+- AddSandboxTasksByArray(tasksArray);
+-
+- free_sandbox_tasks(tasksArray);
+-}
+-
+-auto Sandbox::SaveSandboxTasks() -> bool
+-{
+- std::string tasks_json;
+-
+- if (m_tasks.empty()) {
+- return DeleteSandboxTasksJson();
+- }
+-
+- tasks_json = GetAnySandboxTasks();
+- if (tasks_json.empty()) {
+- ERROR("Failed to get sandbox tasks json for sandbox: '%s'", m_id.c_str());
+- return false;
+- }
+-
+- return WriteSandboxTasksJson(tasks_json);
+-}
+-
+-auto Sandbox::AddSandboxTasks(sandbox_task *task) -> bool
+-{
+- if (task == nullptr) {
+- return true;
+- }
+- if (task->task_id == nullptr) {
+- return false;
+- }
+-
+- WriteGuard<RWMutex> lock(m_tasksMutex);
+-
+- return AddTaskById(task->task_id, task);
+-}
+-
+-auto Sandbox::GetAnySandboxTasks() -> std::string
+-{
+- __isula_auto_free parser_error err = nullptr;
+- sandbox_tasks tasksArray = { 0 };
+- size_t i = 0;
+- __isula_auto_free char *tasks_json = nullptr;
+-
+- tasksArray.tasks = (sandbox_task **)util_smart_calloc_s(sizeof(sandbox_task *), m_tasks.size());
+- if (tasksArray.tasks == nullptr) {
+- SYSERROR("Out of memory.");
+- return std::string("");
+- }
+-
+- ReadGuard<RWMutex> lock(m_tasksMutex);
+- for (auto const& [_, val] : m_tasks) {
+- /*
+- * We ignore that the processes are modified
+- * when we generate tasks json string.
+- * Because no matter whether a process is deleted or added,
+- * the Update of sandbox api will be called eventually.
+- *
+- * And we ignore that the task is freed after we do GetTask().
+- * Because the only way to free task is DeleteSandboxTasks()
+- * which needs write lock of m_tasksMutex.
+- */
+- tasksArray.tasks[i] = val->GetTask();
+- i++;
+- }
+- tasksArray.tasks_len = m_tasks.size();
+-
+- tasks_json = sandbox_tasks_generate_json(&tasksArray, nullptr, &(err));
+- if (tasks_json == nullptr || strlen(tasks_json) == 0) {
+- ERROR("Failed to get sandbox tasks json for sandbox: '%s'", m_id.c_str());
+- free(tasksArray.tasks);
+- return std::string("");
+- }
+-
+- free(tasksArray.tasks);
+- return std::string(tasks_json);
+-}
+-
+-void Sandbox::DeleteSandboxTasks(const char *containerId)
+-{
+- if (containerId == nullptr) {
+- return;
+- }
+-
+- std::string taskId = std::string(containerId);
+-
+- WriteGuard<RWMutex> lock(m_tasksMutex);
+- auto iter = m_tasks.find(taskId);
+- if (iter == m_tasks.end()) {
+- return;
+- }
+- m_tasks.erase(iter);
+-}
+-
+-auto Sandbox::AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool
+-{
+- if (containerId == nullptr || processes == nullptr) {
+- ERROR("Empty args.");
+- return false;
+- }
+-
+- std::string taskId = std::string(containerId);
+-
+- ReadGuard<RWMutex> lock(m_tasksMutex);
+- auto iter = m_tasks.find(taskId);
+- if (iter == m_tasks.end()) {
+- SYSERROR("Failed to find container %s", containerId);
+- return false;
+- }
+-
+- return iter->second->AddSandboxTasksProcess(processes);
+-}
+-
+-void Sandbox::DeleteSandboxTasksProcess(const char *containerId, const char *execId)
+-{
+- if (containerId == nullptr || execId == nullptr) {
+- return;
+- }
+-
+- std::string taskId = std::string(containerId);
+-
+- ReadGuard<RWMutex> lock(m_tasksMutex);
+- auto iter = m_tasks.find(taskId);
+- if (iter == m_tasks.end()) {
+- return;
+- }
+- iter->second->DeleteSandboxTasksProcess(execId);
+-}
+-
+ }
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/sandbox.h b/src/daemon/sandbox/sandbox.h
+index 437b6113..415406ff 100644
+--- a/src/daemon/sandbox/sandbox.h
++++ b/src/daemon/sandbox/sandbox.h
+@@ -141,13 +141,13 @@ public:
+ void Status(runtime::v1::PodSandboxStatus &status);
+
+ // for sandbox api update
+- void LoadSandboxTasks();
+- auto SaveSandboxTasks() -> bool;
+- auto AddSandboxTasks(sandbox_task *task) -> bool;
+- auto GetAnySandboxTasks() -> std::string;
+- void DeleteSandboxTasks(const char *containerId);
+- auto AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool;
+- void DeleteSandboxTasksProcess(const char *containerId, const char *execId);
++ virtual void LoadSandboxTasks() = 0;
++ virtual auto SaveSandboxTasks() -> bool = 0;
++ virtual auto AddSandboxTasks(sandbox_task *task) -> bool = 0;
++ virtual auto GetAnySandboxTasks() -> std::string = 0;
++ virtual void DeleteSandboxTasks(const char *containerId) = 0;
++ virtual auto AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool = 0;
++ virtual void DeleteSandboxTasksProcess(const char *containerId, const char *execId) = 0;
+
+ private:
+ auto SaveState(Errors &error) -> bool;
+@@ -172,7 +172,6 @@ private:
+ auto GetMetadataJsonPath() -> std::string;
+ auto GetStatePath() -> std::string;
+ auto GetNetworkSettingsPath() -> std::string;
+- auto GetTasksJsonPath() -> std::string;
+
+ void FillSandboxState(sandbox_state *state);
+ void FillSandboxMetadata(sandbox_metadata* metadata, Errors &error);
+@@ -189,12 +188,6 @@ private:
+
+ void updateSelinuxLabels(std::string &selinuxLabels);
+
+- auto AddTaskById(const char *task_id, sandbox_task *task) -> bool;
+- auto ReadSandboxTasksJson() -> sandbox_tasks *;
+- auto WriteSandboxTasksJson(std::string &tasks_json) -> bool;
+- auto DeleteSandboxTasksJson() -> bool;
+- void AddSandboxTasksByArray(sandbox_tasks *tasksArray);
+-
+ private:
+ // Since the cri module will operate concurrently on the sandbox instance,
+ // use m_mutex to ensure the correctness of the sandbox instance
+@@ -230,11 +223,6 @@ private:
+ // vsock ports
+ std::mutex m_vsockPortsMutex;
+ std::set<uint32_t> m_vsockPorts;
+-
+- // use m_tasksMutex to ensure the correctness of the tasks
+- RWMutex m_tasksMutex;
+- // for sandbox api update, containerId --> tasks
+- std::map<std::string, std::shared_ptr<SandboxTask>> m_tasks;
+ };
+
+ } // namespace sandbox
+diff --git a/src/daemon/sandbox/sandbox_manager.cc b/src/daemon/sandbox/sandbox_manager.cc
+index 4159993f..ba003d56 100644
+--- a/src/daemon/sandbox/sandbox_manager.cc
++++ b/src/daemon/sandbox/sandbox_manager.cc
+@@ -21,8 +21,13 @@
+
+ #include <isula_libutils/auto_cleanup.h>
+ #include <isula_libutils/log.h>
++#include <isula_libutils/sandbox_metadata.h>
+
+ #include "sandbox.h"
++#ifdef ENABLE_SANDBOXER
++#include "sandboxer_sandbox.h"
++#endif
++#include "shim_sandbox.h"
+ #include "isulad_config.h"
+ #include "utils_verify.h"
+ #include "utils_file.h"
+@@ -109,7 +114,15 @@ auto SandboxManager::CreateSandbox(const std::string &name, RuntimeInfo &info, s
+ return nullptr;
+ }
+
+- sandbox = std::make_shared<Sandbox>(id, m_rootdir, m_statedir, name, info, netMode, netNsPath, sandboxConfig, image);
++#ifdef ENABLE_SANDBOXER
++ if (info.sandboxer == SHIM_CONTROLLER_NAME) {
++ sandbox = std::make_shared<ShimSandbox>(id, m_rootdir, m_statedir, name, info, netMode, netNsPath, sandboxConfig, image);
++ } else {
++ sandbox = std::make_shared<SandboxerSandbox>(id, m_rootdir, m_statedir, name, info, netMode, netNsPath, sandboxConfig, image);
++ }
++#else
++ sandbox = std::make_shared<ShimSandbox>(id, m_rootdir, m_statedir, name, info, netMode, netNsPath, sandboxConfig, image);
++#endif
+ if (sandbox == nullptr) {
+ ERROR("Failed to malloc for sandbox: %s", name.c_str());
+ error.Errorf("Failed to malloc for sandbox: %s", name.c_str());
+@@ -442,6 +455,25 @@ bool SandboxManager::ListAllSandboxdir(std::vector<std::string> &allSubdir)
+ return true;
+ }
+
++#ifdef ENABLE_SANDBOXER
++static auto IsShimSandbox(const std::string &id, const std::string &rootdir) -> bool
++{
++ __isula_auto_free parser_error err = NULL;
++ const std::string path = rootdir + "/" + id + "/" + SANDBOX_METADATA_JSON;
++ sandbox_metadata *metadata = NULL;
++
++ metadata = sandbox_metadata_parse_file(path.c_str(), NULL, &err);
++ if (metadata == NULL) {
++ return false;
++ }
++
++ bool ret = (strcmp(metadata->runtime_info->sandboxer, SHIM_CONTROLLER_NAME.c_str()) == 0);
++
++ free_sandbox_metadata(metadata);
++ return ret;
++}
++#endif
++
+ auto SandboxManager::LoadSandbox(std::string &id) -> std::shared_ptr<Sandbox>
+ {
+ std::shared_ptr<Sandbox> sandbox = nullptr;
+@@ -451,7 +483,15 @@ auto SandboxManager::LoadSandbox(std::string &id) -> std::shared_ptr<Sandbox>
+ return nullptr;
+ }
+
+- sandbox = std::make_shared<Sandbox>(id, m_rootdir, m_statedir);
++#ifdef ENABLE_SANDBOXER
++ if (IsShimSandbox(id, m_rootdir)) {
++ sandbox = std::make_shared<ShimSandbox>(id, m_rootdir, m_statedir);
++ } else {
++ sandbox = std::make_shared<SandboxerSandbox>(id, m_rootdir, m_statedir);
++ }
++#else
++ sandbox = std::make_shared<ShimSandbox>(id, m_rootdir, m_statedir);
++#endif
+ if (sandbox == nullptr) {
+ ERROR("Failed to malloc for sandboxes: %s", id.c_str());
+ return nullptr;
+diff --git a/src/daemon/sandbox/sandbox_ops.cc b/src/daemon/sandbox/sandbox_ops.cc
+index 96e541a4..f50a1033 100644
+--- a/src/daemon/sandbox/sandbox_ops.cc
++++ b/src/daemon/sandbox/sandbox_ops.cc
+@@ -16,6 +16,7 @@
+
+ #include <isula_libutils/auto_cleanup.h>
+ #include <isula_libutils/log.h>
++#include <isula_libutils/sandbox_sandbox.h>
+ #include <google/protobuf/util/time_util.h>
+
+ #include "controller_manager.h"
+@@ -24,6 +25,7 @@
+ #include "namespace.h"
+ #include "utils.h"
+ #include "utils_timestamp.h"
++#include "utils_array.h"
+
+ const std::string SANDBOX_EXTENSIONS_TASKS = "extensions.tasks";
+ const std::string SANDBOX_TASKS_KEY = "tasks";
+@@ -62,42 +64,30 @@ static int generate_ctrl_rootfs(sandbox_task *task,
+ return 0;
+ }
+
+-static int do_sandbox_prepare(std::shared_ptr<sandbox::Sandbox> &sandbox, containerd::types::Sandbox &apiSandbox)
++static int do_sandbox_update(std::shared_ptr<sandbox::Sandbox> &sandbox, sandbox_sandbox *apiSandbox)
+ {
+ Errors err;
+- std::vector<std::string> fields;
+-
+- fields.push_back(SANDBOX_EXTENSIONS_TASKS);
++ size_t fields_len = 1;
++ __isula_auto_string_array_t string_array *fields = nullptr;
+
+- auto controller = sandbox::ControllerManager::GetInstance()->GetController(sandbox->GetSandboxer());
+- if (nullptr == controller) {
+- ERROR("Invalid sandboxer name: %s", sandbox->GetSandboxer().c_str());
++ fields = util_string_array_new(fields_len);
++ if (fields == nullptr) {
++ ERROR("Out of memory.");
+ return -1;
+ }
+-
+- if (!controller->Prepare(apiSandbox, fields, err)) {
+- ERROR("Failed to prepare in container controller prepare: %s", err.GetCMessage());
++ if (util_append_string_array(fields, SANDBOX_EXTENSIONS_TASKS.c_str())) {
++ ERROR("Out of memory.");
+ return -1;
+ }
+
+- return 0;
+-}
+-
+-static int do_sandbox_purge(std::shared_ptr<sandbox::Sandbox> &sandbox, containerd::types::Sandbox &apiSandbox)
+-{
+- Errors err;
+- std::vector<std::string> fields;
+-
+- fields.push_back(SANDBOX_EXTENSIONS_TASKS);
+-
+ auto controller = sandbox::ControllerManager::GetInstance()->GetController(sandbox->GetSandboxer());
+ if (nullptr == controller) {
+ ERROR("Invalid sandboxer name: %s", sandbox->GetSandboxer().c_str());
+ return -1;
+ }
+
+- if (!controller->Purge(apiSandbox, fields, err)) {
+- ERROR("Failed to purge: %s", err.GetCMessage());
++ if (!controller->Update(apiSandbox, fields, err)) {
++ ERROR("Failed to update in container controller update: %s", err.GetCMessage());
+ return -1;
+ }
+
+@@ -161,40 +151,112 @@ static std::shared_ptr<sandbox::Sandbox> get_prepare_sandbox(const container_con
+ return sandbox;
+ }
+
+-static int init_prepare_api_sandbox(std::shared_ptr<sandbox::Sandbox> sandbox, const char *containerId,
+- containerd::types::Sandbox &apiSandbox)
++static sandbox_sandbox_runtime *init_sandbox_runtime(std::shared_ptr<sandbox::Sandbox> sandbox)
++{
++ sandbox_sandbox_runtime *runtime = nullptr;
++
++ auto runtime_wrapper = makeUniquePtrCStructWrapper<sandbox_sandbox_runtime>(free_sandbox_sandbox_runtime);
++ if (runtime_wrapper == nullptr) {
++ ERROR("Out of memory");
++ return nullptr;
++ }
++ runtime = runtime_wrapper->get();
++ runtime->name = util_strdup_s(sandbox->GetRuntime().c_str());
++ // Just ignore options for now
++
++ return runtime_wrapper->move();
++}
++
++static json_map_string_string *init_sandbox_labels(std::shared_ptr<sandbox::Sandbox> sandbox)
+ {
+- google::protobuf::Map<std::string, std::string> *labels = apiSandbox.mutable_labels();
+- google::protobuf::Map<std::string, google::protobuf::Any> *extensions = apiSandbox.mutable_extensions();
+- google::protobuf::Any any;
+- auto created_at = new (std::nothrow) google::protobuf::Timestamp;
+- auto updated_at = new (std::nothrow) google::protobuf::Timestamp;
++ json_map_string_string *labels = nullptr;
++
++ auto labels_wrapper = makeUniquePtrCStructWrapper<json_map_string_string>(free_json_map_string_string);
++ if (labels_wrapper == nullptr) {
++ ERROR("Out of memory");
++ return nullptr;
++ }
++ labels = labels_wrapper->get();
++ if (append_json_map_string_string(labels, "name", sandbox->GetName().c_str()) != 0) {
++ ERROR("Out of memory");
++ return nullptr;
++ }
+
+- apiSandbox.set_sandbox_id(sandbox->GetId());
+- apiSandbox.mutable_runtime()->set_name(sandbox->GetRuntime());
+- // TODO how get options
+- // apiSandbox.mutable_runtime()->set_options(sandbox->GetRuntime());
+- // Just ignore spec
+- (*labels)[std::string("name")] = sandbox->GetName();
+-
+- *created_at = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(
+- sandbox->GetCreatedAt());
+- apiSandbox.set_allocated_created_at(created_at);
+- *updated_at = google::protobuf::util::TimeUtil::NanosecondsToTimestamp(util_get_now_time_nanos());
+- apiSandbox.set_allocated_updated_at(updated_at);
+-
+- auto any_type_url = any.mutable_type_url();
+- *any_type_url = SANDBOX_TASKS_TYPEURL;
+- auto any_value = any.mutable_value();
+- *any_value = sandbox->GetAnySandboxTasks();
+- if ((*any_value).empty()) {
++ return labels_wrapper->move();
++}
++
++static defs_map_string_object_any *init_sandbox_extensions(std::shared_ptr<sandbox::Sandbox> sandbox)
++{
++ defs_map_string_object_any *extensions = nullptr;
++ size_t len = 1;
++ std::string task_json;
++
++ auto extensions_wrapper = makeUniquePtrCStructWrapper<defs_map_string_object_any>(free_defs_map_string_object_any);
++ if (extensions_wrapper == nullptr) {
++ ERROR("Out of memory");
++ return nullptr;
++ }
++ extensions = extensions_wrapper->get();
++ extensions->keys = (char **)util_smart_calloc_s(sizeof(char *), len);
++ if (extensions->keys == nullptr) {
++ ERROR("Out of memory.");
++ return nullptr;
++ }
++ extensions->len = len;
++ extensions->values = (defs_map_string_object_any_element **)
++ util_smart_calloc_s(sizeof(defs_map_string_object_any_element *), len);
++ if (extensions->values == nullptr) {
++ ERROR("Out of memory.");
++ return nullptr;
++ }
++ extensions->values[0] = (defs_map_string_object_any_element *)
++ util_common_calloc_s(sizeof(defs_map_string_object_any_element));
++ if (extensions->values[0] == nullptr) {
++ ERROR("Out of memory.");
++ return nullptr;
++ }
++ extensions->values[0]->element = (defs_any *)util_common_calloc_s(sizeof(defs_any));
++ if (extensions->values[0]->element == nullptr) {
++ ERROR("Out of memory.");
++ return nullptr;
++ }
++
++ extensions->keys[0] = util_strdup_s(SANDBOX_TASKS_KEY.c_str());
++ task_json = sandbox->GetAnySandboxTasks();
++ if (task_json.empty()) {
+ ERROR("Failed to get any sandbox tasks");
+- return -1;
++ return nullptr;
+ }
+- DEBUG("Get any sandbox tasks %s", (*any_value).c_str());
+- (*extensions)[SANDBOX_TASKS_KEY] = any;
++ DEBUG("Get any sandbox tasks %s", task_json.c_str());
++ extensions->values[0]->element->type_url = util_strdup_s(SANDBOX_TASKS_TYPEURL.c_str());
++ extensions->values[0]->element->value = reinterpret_cast<uint8_t *>(util_strdup_s(task_json.c_str()));
++ extensions->values[0]->element->value_len = strlen(task_json.c_str());
++
++ return extensions_wrapper->move();
++}
+
+- apiSandbox.set_sandboxer(sandbox->GetSandboxer());
++static int init_api_sandbox(std::shared_ptr<sandbox::Sandbox> sandbox, sandbox_sandbox *apiSandbox)
++{
++ apiSandbox->sandbox_id = util_strdup_s(sandbox->GetId().c_str());
++ apiSandbox->runtime = init_sandbox_runtime(sandbox);
++ if (apiSandbox->runtime == nullptr) {
++ ERROR("Failed to init sandbox runtime");
++ return -1;
++ }
++ // Just ignore spec
++ apiSandbox->labels = init_sandbox_labels(sandbox);
++ if (apiSandbox->labels == nullptr) {
++ ERROR("Failed to init sandbox runtime");
++ return -1;
++ }
++ apiSandbox->created_at = sandbox->GetCreatedAt();
++ apiSandbox->updated_at = util_get_now_time_nanos();
++ apiSandbox->extensions = init_sandbox_extensions(sandbox);
++ if (apiSandbox->extensions == nullptr) {
++ ERROR("Failed to init sandbox runtime");
++ return -1;
++ }
++ apiSandbox->sandboxer = util_strdup_s(sandbox->GetSandboxer().c_str());
+
+ return 0;
+ }
+@@ -204,7 +266,7 @@ int sandbox_prepare_container(const container_config_v2_common_config *config,
+ const char * console_fifos[], bool tty)
+ {
+ sandbox_task *task = nullptr;
+- containerd::types::Sandbox apiSandbox;
++ sandbox_sandbox *apiSandbox = nullptr;
+ int ret = -1;
+
+ INFO("Prepare container for sandbox");
+@@ -220,20 +282,28 @@ int sandbox_prepare_container(const container_config_v2_common_config *config,
+ return -1;
+ }
+
+- task = (sandbox_task *)util_common_calloc_s(sizeof(sandbox_task));
+- if (task == nullptr) {
+- ERROR("Out of memory.");
++ auto apiSandbox_wrapper = makeUniquePtrCStructWrapper<sandbox_sandbox>(free_sandbox_sandbox);
++ if (apiSandbox_wrapper == nullptr) {
++ ERROR("Out of memory");
+ return -1;
+ }
++ apiSandbox = apiSandbox_wrapper->get();
++ auto task_wrapper = makeUniquePtrCStructWrapper<sandbox_task>(free_sandbox_task);
++ if (task_wrapper == nullptr) {
++ ERROR("Out of memory");
++ return -1;
++ }
++ task = task_wrapper->get();
++
+ task->task_id = util_strdup_s(config->id);
+ task->spec = clone_oci_runtime_spec(oci_spec);
+ if (task->spec == nullptr) {
+ ERROR("Out of memory.");
+- goto free_out;
++ return -1;
+ }
+ if (generate_ctrl_rootfs(task, config) != 0) {
+ ERROR("Invalid rootfs");
+- goto free_out;
++ return -1;
+ }
+ task->stdin = util_strdup_s((nullptr == console_fifos[0]) ? "" : console_fifos[0]);
+ task->stdout = util_strdup_s((nullptr == console_fifos[1]) ? "" : console_fifos[1]);
+@@ -241,15 +311,15 @@ int sandbox_prepare_container(const container_config_v2_common_config *config,
+
+ if (!sandbox->AddSandboxTasks(task)) {
+ ERROR("Failed to add sandbox %s task.", config->id);
+- goto free_out;
++ return -1;
+ }
+- task = nullptr;
+- ret = init_prepare_api_sandbox(sandbox, config->id, apiSandbox);
++ task = task_wrapper->move();
++ ret = init_api_sandbox(sandbox, apiSandbox);
+ if (ret != 0) {
+ ERROR("Failed to init %s api sandbox.", config->id);
+ goto del_out;
+ }
+- ret = do_sandbox_prepare(sandbox, apiSandbox);
++ ret = do_sandbox_update(sandbox, apiSandbox);
+
+ del_out:
+ if (ret != 0) {
+@@ -259,8 +329,7 @@ del_out:
+ ERROR("Failed to Save %s sandbox tasks.", config->id);
+ ret = -1;
+ }
+-free_out:
+- free_sandbox_task(task);
++
+ return ret;
+ }
+
+@@ -269,7 +338,7 @@ int sandbox_prepare_exec(const container_config_v2_common_config *config,
+ const char * console_fifos[], bool tty)
+ {
+ sandbox_process *process = nullptr;
+- containerd::types::Sandbox apiSandbox;
++ sandbox_sandbox *apiSandbox = nullptr;
+ int ret = -1;
+
+ INFO("Prepare exec for container in sandbox");
+@@ -285,16 +354,24 @@ int sandbox_prepare_exec(const container_config_v2_common_config *config,
+ return -1;
+ }
+
+- process = (sandbox_process *)util_common_calloc_s(sizeof(sandbox_process));
+- if (process == nullptr) {
+- ERROR("Out of memory.");
++ auto apiSandbox_wrapper = makeUniquePtrCStructWrapper<sandbox_sandbox>(free_sandbox_sandbox);
++ if (apiSandbox_wrapper == nullptr) {
++ ERROR("Out of memory");
++ return -1;
++ }
++ apiSandbox = apiSandbox_wrapper->get();
++ auto process_wrapper = makeUniquePtrCStructWrapper<sandbox_process>(free_sandbox_process);
++ if (process_wrapper == nullptr) {
++ ERROR("Out of memory");
+ return -1;
+ }
++ process = process_wrapper->get();
++
+ process->exec_id = util_strdup_s(exec_id);
+ process->spec = clone_defs_process(process_spec);
+ if (process->spec == nullptr) {
+ ERROR("Out of memory.");
+- goto free_out;
++ return -1;
+ }
+ process->stdin = util_strdup_s((nullptr == console_fifos[0]) ? "" : console_fifos[0]);
+ process->stdout = util_strdup_s((nullptr == console_fifos[1]) ? "" : console_fifos[1]);
+@@ -302,15 +379,15 @@ int sandbox_prepare_exec(const container_config_v2_common_config *config,
+
+ if (!sandbox->AddSandboxTasksProcess(config->id, process)) {
+ ERROR("Failed to add sandbox %s process.", config->id);
+- goto free_out;
++ return -1;
+ }
+- process = nullptr;
+- ret = init_prepare_api_sandbox(sandbox, config->id, apiSandbox);
++ process = process_wrapper->move();
++ ret = init_api_sandbox(sandbox, apiSandbox);
+ if (ret != 0) {
+ ERROR("Failed to init %s api sandbox.", config->id);
+ goto del_out;
+ }
+- ret = do_sandbox_prepare(sandbox, apiSandbox);
++ ret = do_sandbox_update(sandbox, apiSandbox);
+
+ del_out:
+ if (ret != 0) {
+@@ -320,14 +397,13 @@ del_out:
+ ERROR("Failed to Save %s sandbox tasks.", config->id);
+ ret = -1;
+ }
+-free_out:
+- free_sandbox_process(process);
++
+ return ret;
+ }
+
+ int sandbox_purge_container(const container_config_v2_common_config *config)
+ {
+- containerd::types::Sandbox apiSandbox;
++ sandbox_sandbox *apiSandbox = nullptr;
+
+ INFO("Purge container for sandbox");
+
+@@ -337,22 +413,29 @@ int sandbox_purge_container(const container_config_v2_common_config *config)
+ return -1;
+ }
+
++ auto apiSandbox_wrapper = makeUniquePtrCStructWrapper<sandbox_sandbox>(free_sandbox_sandbox);
++ if (apiSandbox_wrapper == nullptr) {
++ ERROR("Out of memory");
++ return -1;
++ }
++ apiSandbox = apiSandbox_wrapper->get();
++
+ sandbox->DeleteSandboxTasks(config->id);
+ if (!sandbox->SaveSandboxTasks()) {
+ ERROR("Failed to Save %s sandbox tasks.", config->id);
+ return -1;
+ }
+
+- if (init_prepare_api_sandbox(sandbox, config->id, apiSandbox) != 0) {
++ if (init_api_sandbox(sandbox, apiSandbox) != 0) {
+ ERROR("Failed to init %s api sandbox.", config->id);
+ return -1;
+ }
+- return do_sandbox_purge(sandbox, apiSandbox);
++ return do_sandbox_update(sandbox, apiSandbox);
+ }
+
+ int sandbox_purge_exec(const container_config_v2_common_config *config, const char *exec_id)
+ {
+- containerd::types::Sandbox apiSandbox;
++ sandbox_sandbox *apiSandbox = nullptr;
+
+ INFO("Purge exec for container in sandbox");
+
+@@ -362,18 +445,25 @@ int sandbox_purge_exec(const container_config_v2_common_config *config, const ch
+ return -1;
+ }
+
++ auto apiSandbox_wrapper = makeUniquePtrCStructWrapper<sandbox_sandbox>(free_sandbox_sandbox);
++ if (apiSandbox_wrapper == nullptr) {
++ ERROR("Out of memory");
++ return -1;
++ }
++ apiSandbox = apiSandbox_wrapper->get();
++
+ sandbox->DeleteSandboxTasksProcess(config->id, exec_id);
+ if (!sandbox->SaveSandboxTasks()) {
+ ERROR("Failed to Save %s sandbox tasks.", config->id);
+ return -1;
+ }
+
+- if (init_prepare_api_sandbox(sandbox, config->id, apiSandbox) != 0) {
++ if (init_api_sandbox(sandbox, apiSandbox) != 0) {
+ ERROR("Failed to init %s api sandbox.", exec_id);
+ return -1;
+ }
+
+- return do_sandbox_purge(sandbox, apiSandbox);
++ return do_sandbox_update(sandbox, apiSandbox);
+ }
+
+ int sandbox_on_sandbox_exit(const char *sandbox_id, int exit_code)
+diff --git a/src/daemon/sandbox/sandbox_task.cc b/src/daemon/sandbox/sandbox_task.cc
+index b1efc340..4533f381 100644
+--- a/src/daemon/sandbox/sandbox_task.cc
++++ b/src/daemon/sandbox/sandbox_task.cc
+@@ -91,8 +91,11 @@ void SandboxTask::DeleteSandboxTasksProcess(const char *execId)
+ return;
+ }
+ free_sandbox_process(m_task->processes[idx]);
+- (void)memcpy((void **)&m_task->processes[idx], (void **)&m_task->processes[idx + 1],
+- (m_task->processes_len - idx - 1) * sizeof(void *));
++ m_task->processes[idx] = nullptr;
++ if (idx != (int)m_task->processes_len - 1) {
++ (void)memcpy((void **)&m_task->processes[idx], (void **)&m_task->processes[idx + 1],
++ (m_task->processes_len - idx - 1) * sizeof(void *));
++ }
+ m_task->processes_len--;
+ }
+
+diff --git a/src/daemon/sandbox/sandboxer/CMakeLists.txt b/src/daemon/sandbox/sandboxer/CMakeLists.txt
+new file mode 100755
+index 00000000..2b0607e0
+--- /dev/null
++++ b/src/daemon/sandbox/sandboxer/CMakeLists.txt
+@@ -0,0 +1,15 @@
++# get current directory sources files
++aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} sandboxer_sandbox_srcs)
++
++add_subdirectory(controller)
++
++set(SANDBOXER_SANDBOX_SRCS
++ ${sandboxer_sandbox_srcs}
++ ${CONTROLLER_SANDBOXER_SRCS}
++ PARENT_SCOPE
++ )
++set(SANDBOXER_SANDBOX_INCS
++ ${CMAKE_CURRENT_SOURCE_DIR}
++ ${CONTROLLER_SANDBOXER_INCS}
++ PARENT_SCOPE
++ )
+diff --git a/src/daemon/sandbox/controller/sandboxer/CMakeLists.txt b/src/daemon/sandbox/sandboxer/controller/CMakeLists.txt
+similarity index 100%
+rename from src/daemon/sandbox/controller/sandboxer/CMakeLists.txt
+rename to src/daemon/sandbox/sandboxer/controller/CMakeLists.txt
+diff --git a/src/daemon/sandbox/sandboxer/controller/client/CMakeLists.txt b/src/daemon/sandbox/sandboxer/controller/client/CMakeLists.txt
+new file mode 100755
+index 00000000..6ecd350b
+--- /dev/null
++++ b/src/daemon/sandbox/sandboxer/controller/client/CMakeLists.txt
+@@ -0,0 +1,12 @@
++# get current directory sources files
++aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} sandbox_controller_sandboxer_client_srcs)
++
++set(CONTROLLER_SANDBOXER_CLIENT_SRCS
++ ${sandbox_controller_sandboxer_client_srcs}
++ PARENT_SCOPE
++ )
++
++set(CONTROLLER_SANDBOXER_CLIENT_INCS
++ ${CMAKE_CURRENT_SOURCE_DIR}
++ PARENT_SCOPE
++ )
+diff --git a/src/daemon/sandbox/sandboxer/controller/client/grpc_sandboxer_client.cc b/src/daemon/sandbox/sandboxer/controller/client/grpc_sandboxer_client.cc
+new file mode 100644
+index 00000000..d7ff76d7
+--- /dev/null
++++ b/src/daemon/sandbox/sandboxer/controller/client/grpc_sandboxer_client.cc
+@@ -0,0 +1,463 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2023. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: xuxuepeng
++ * Create: 2023-07-10
++ * Description: Sandboxer grpc client
++ ******************************************************************************/
++
++#include "grpc_sandboxer_client.h"
++
++#include <grpc++/grpc++.h>
++#include <iostream>
++#include <memory>
++#include <string>
++#include <random>
++
++#include <isula_libutils/log.h>
++
++#include "utils.h"
++#include "cstruct_wrapper.h"
++#include "transform.h"
++#include "sandbox_manager.h"
++
++namespace sandbox {
++
++SandboxerClient::SandboxerClient(const std::string &sandboxer, const std::string &address):
++ m_sandboxer(sandboxer), m_address(address)
++{
++ std::string unixPrefix(UNIX_SOCKET_PREFIX);
++
++ // Only support unix domain socket
++ if (m_address.compare(0, unixPrefix.length(), unixPrefix) == 0) {
++ m_address = m_address.substr(unixPrefix.length());
++ }
++ m_controller_handle = sandbox_api_build_controller(m_sandboxer.c_str(), m_address.c_str());
++ if (m_controller_handle == nullptr) {
++ ERROR("Failed to create sandboxer client, sandboxer: %s, address: %s", m_sandboxer.c_str(), m_address.c_str());
++ }
++}
++
++auto SandboxerClient::InitMountInfo(sandbox_mount &m, const ControllerMountInfo &mountInfo) -> int
++{
++ m.type = util_strdup_s(mountInfo.type.c_str());
++ m.source = util_strdup_s(mountInfo.source.c_str());
++ m.target = util_strdup_s(mountInfo.destination.c_str());
++
++ size_t mount_options_len = mountInfo.options.size();
++ int ret = 0;
++ for (size_t j = 0; j < mount_options_len; j++) {
++ ret = util_array_append(&(m.options), mountInfo.options[j].c_str());
++ if (ret != 0) {
++ ERROR("append mount options to array failed");
++ return -1;
++ }
++ m.options_len++;
++ }
++ return 0;
++}
++
++auto SandboxerClient::InitCreateRequest(sandbox_create_request &request,
++ const std::string &sandboxId,
++ const ControllerCreateParams &params) -> bool
++{
++ if (params.config == nullptr) {
++ ERROR("Sandboxer controller create request failed, config is null");
++ return false;
++ }
++ request.sandboxer = util_strdup_s(m_sandboxer.c_str());
++ request.sandbox_id = util_strdup_s(sandboxId.c_str());
++ std::string encoded;
++ if (!params.config->SerializeToString(&encoded)) {
++ ERROR("Failed to serialize config");
++ return false;
++ }
++ request.options = (defs_any *)util_common_calloc_s(sizeof(defs_any));
++ if (request.options == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ request.options->value = (uint8_t *)util_common_calloc_s(encoded.size());
++ if (request.options == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ (void)memcpy(request.options->value, encoded.c_str(), encoded.size());
++ request.options->value_len = encoded.size();
++ request.netns_path = util_strdup_s(params.netNSPath.c_str());
++ sandbox_mount **mounts = NULL;
++ size_t mounts_len = params.mounts.size();
++ if (mounts_len > 0) {
++ request.rootfs = (sandbox_mount**)util_common_calloc_s(mounts_len * sizeof(sandbox_mount *));
++ if (request.rootfs == nullptr) {
++ ERROR("Out of memory");
++ return false;
++ }
++ for (const auto &entry : params.mounts) {
++ if (entry != nullptr) {
++ sandbox_mount *m = (sandbox_mount *)util_common_calloc_s(sizeof(sandbox_mount));
++ if (m == NULL) {
++ ERROR("Out of memory");
++ return false;
++ }
++ if (InitMountInfo(*m, *entry) != 0) {
++ ERROR("Failed to init mount info");
++ free(m);
++ return false;
++ }
++ mounts[request.rootfs_len++] = m;
++ m = NULL;
++ }
++ }
++ }
++ return true;
++}
++
++auto SandboxerClient::Create(const std::string &sandboxId, const ControllerCreateParams &params, Errors &error) -> bool
++{
++ sandbox_create_request *request { nullptr };
++ sandbox_create_response *response { nullptr };
++
++ auto create_request_wrapper = makeUniquePtrCStructWrapper<sandbox_create_request>(free_sandbox_create_request);
++ if (create_request_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ request = create_request_wrapper->get();
++
++ auto create_response_wrapper = makeUniquePtrCStructWrapper<sandbox_create_response>(free_sandbox_create_response);
++ if (create_response_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ response = create_response_wrapper->get();
++
++ if (!InitCreateRequest(*request, sandboxId, params)) {
++ ERROR("Failed to init create request for sandboxer create request");
++ error.SetError("Failed to init create request for sandboxer create request");
++ return false;
++ }
++ int ret = sandbox_api_create(m_controller_handle, request, response);
++ if (ret != 0) {
++ ERROR("Failed to create sandbox");
++ error.SetError("Failed to create sandbox");
++ return false;
++ }
++
++ return true;
++}
++
++void SandboxerClient::StartResponseToSandboxInfo(sandbox_start_response &response,
++ ControllerSandboxInfo &sandboxInfo)
++{
++ sandboxInfo.id = std::string(response.sandbox_id);
++ sandboxInfo.pid = response.pid;
++ sandboxInfo.createdAt = response.created_at;
++ sandboxInfo.taskAddress = std::string(response.address);
++ sandboxInfo.version = response.version;
++ Transform::JsonMapToProtobufMapForString(response.labels, sandboxInfo.labels);
++}
++
++auto SandboxerClient::Start(const std::string &sandboxId, ControllerSandboxInfo &sandboxInfo, Errors &error) -> bool
++{
++ sandbox_start_request *request { nullptr };
++ sandbox_start_response *response { nullptr };
++
++ auto start_request_wrapper = makeUniquePtrCStructWrapper<sandbox_start_request>(free_sandbox_start_request);
++ if (start_request_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ request = start_request_wrapper->get();
++
++ auto start_response_wrapper = makeUniquePtrCStructWrapper<sandbox_start_response>(free_sandbox_start_response);
++ if (start_response_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ response = start_response_wrapper->get();
++
++ request->sandboxer = util_strdup_s(m_sandboxer.c_str());
++ request->sandbox_id = util_strdup_s(sandboxId.c_str());
++
++ int ret = sandbox_api_start(m_controller_handle, request, response);
++ if (ret != 0) {
++ ERROR("Failed to start sandbox");
++ error.SetError("Failed to start sandbox");
++ return false;
++ }
++
++ StartResponseToSandboxInfo(*response, sandboxInfo);
++
++ return true;
++}
++
++void SandboxerClient::InitUpdateRequest(sandbox_update_request &request,
++ sandbox_sandbox *apiSandbox, string_array *fields)
++{
++ request.sandbox_id = util_strdup_s(apiSandbox->sandbox_id);
++ request.sandboxer = util_strdup_s(apiSandbox->sandboxer);
++ request.sandbox = apiSandbox;
++ request.fields = fields->items;
++ request.fields_len = fields->len;
++}
++
++auto SandboxerClient::Update(sandbox_sandbox *apiSandbox, string_array *fields, Errors &error) -> bool
++{
++ sandbox_update_request *request { nullptr };
++
++ auto update_request_wrapper = makeUniquePtrCStructWrapper<sandbox_update_request>(free_sandbox_update_request);
++ if (update_request_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ request = update_request_wrapper->get();
++
++ InitUpdateRequest(*request, apiSandbox, fields);
++ int ret = sandbox_api_update(m_controller_handle, request);
++ request->sandbox = nullptr;
++ request->fields = nullptr;
++ request->fields_len = 0;
++ if (ret != 0) {
++ ERROR("Failed to update sandbox");
++ error.SetError("Failed to update sandbox");
++ return false;
++ }
++
++ return true;
++}
++
++void SandboxerClient::PlatformResponseToPlatformInfo(sandbox_platform_response &response,
++ ControllerPlatformInfo &platformInfo)
++{
++ platformInfo.os = std::string(response.os);
++ platformInfo.arch = std::string(response.architecture);
++ platformInfo.variant = std::string(response.variant);
++}
++
++auto SandboxerClient::Platform(const std::string &sandboxId, ControllerPlatformInfo &platformInfo,
++ Errors &error) -> bool
++{
++ sandbox_platform_request *request { nullptr };
++ sandbox_platform_response *response { nullptr };
++
++ auto platform_request_wrapper = makeUniquePtrCStructWrapper<sandbox_platform_request>(free_sandbox_platform_request);
++ if (platform_request_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ request = platform_request_wrapper->get();
++
++ auto platform_response_wrapper = makeUniquePtrCStructWrapper<sandbox_platform_response>(free_sandbox_platform_response);
++ if (platform_response_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ response = platform_response_wrapper->get();
++
++ request->sandboxer = util_strdup_s(m_sandboxer.c_str());
++ request->sandbox_id = util_strdup_s(sandboxId.c_str());
++ int ret = sandbox_api_platform(m_controller_handle, request, response);
++ if (ret != 0) {
++ ERROR("Failed to platform sandbox");
++ error.SetError("Failed to platform sandbox");
++ return false;
++ }
++
++ PlatformResponseToPlatformInfo(*response, platformInfo);
++
++ return true;
++}
++
++auto SandboxerClient::Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error) -> bool
++{
++ sandbox_stop_request *request { nullptr };
++
++ auto stop_request_wrapper = makeUniquePtrCStructWrapper<sandbox_stop_request>(free_sandbox_stop_request);
++ if (stop_request_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ request = stop_request_wrapper->get();
++
++ request->sandboxer = util_strdup_s(m_sandboxer.c_str());
++ request->sandbox_id = util_strdup_s(sandboxId.c_str());
++ request->timeout_secs = timeoutSecs;
++ int ret = sandbox_api_stop(m_controller_handle, request);
++ if (ret != 0) {
++ ERROR("Failed to stop sandbox");
++ error.SetError("Failed to stop sandbox");
++ return false;
++ }
++
++ return true;
++}
++
++void SandboxerClient::StatusResponseToSandboxStatus(sandbox_status_response
++ &response,
++ ControllerSandboxStatus &sandboxStatus)
++{
++ sandboxStatus.id = std::string(response.sandbox_id);
++ sandboxStatus.pid = response.pid;
++ sandboxStatus.state = std::string(response.state);
++ Transform::JsonMapToProtobufMapForString(response.info, sandboxStatus.info);
++ sandboxStatus.createdAt = response.created_at;
++ sandboxStatus.exitedAt = response.exited_at;
++ if (response.extra != nullptr && response.extra->value != nullptr) {
++ sandboxStatus.extra = std::string(response.extra->value,
++ response.extra->value + response.extra->value_len);
++ } else {
++ sandboxStatus.extra = std::string("");
++ }
++ sandboxStatus.taskAddress = std::string(response.address);
++ sandboxStatus.version = response.version;
++}
++
++auto SandboxerClient::Status(const std::string &sandboxId, bool verbose, ControllerSandboxStatus &sandboxStatus,
++ Errors &error) -> bool
++{
++ sandbox_status_request *request { nullptr };
++ sandbox_status_response *response { nullptr };
++
++ auto status_request_wrapper = makeUniquePtrCStructWrapper<sandbox_status_request>(free_sandbox_status_request);
++ if (status_request_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ request = status_request_wrapper->get();
++
++ auto status_response_wrapper = makeUniquePtrCStructWrapper<sandbox_status_response>(free_sandbox_status_response);
++ if (status_response_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ response = status_response_wrapper->get();
++
++ request->sandboxer = util_strdup_s(m_sandboxer.c_str());
++ request->sandbox_id = util_strdup_s(sandboxId.c_str());
++ request->verbose = verbose;
++ int ret = sandbox_api_status(m_controller_handle, request, response);
++ if (ret != 0) {
++ ERROR("Failed to status sandbox");
++ error.SetError("Failed to status sandbox");
++ return false;
++ }
++
++ StatusResponseToSandboxStatus(*response, sandboxStatus);
++
++ return true;
++}
++
++auto SandboxerClient::Shutdown(const std::string &sandboxId, Errors &error) -> bool
++{
++ sandbox_shutdown_request *request { nullptr };
++
++ auto shutdown_request_wrapper = makeUniquePtrCStructWrapper<sandbox_shutdown_request>(free_sandbox_shutdown_request);
++ if (shutdown_request_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ request = shutdown_request_wrapper->get();
++
++ request->sandboxer = util_strdup_s(m_sandboxer.c_str());
++ request->sandbox_id = util_strdup_s(sandboxId.c_str());
++ int ret = sandbox_api_shutdown(m_controller_handle, request);
++ if (ret != 0) {
++ ERROR("Failed to shutdown sandbox");
++ error.SetError("Failed to shutdown sandbox");
++ return false;
++ }
++
++ return true;
++}
++
++static int sandbox_api_ready(const char *sandbox_id)
++{
++ std::string sandboxId = std::string(sandbox_id);
++ auto sandbox = sandbox::SandboxManager::GetInstance()->GetSandbox(sandboxId);
++ if (nullptr == sandbox) {
++ ERROR("Sandbox not found");
++ return -1;
++ }
++
++ sandbox->OnSandboxReady();
++ return 0;
++}
++
++static int sandbox_api_pending(const char *sandbox_id)
++{
++ std::string sandboxId = std::string(sandbox_id);
++ auto sandbox = sandbox::SandboxManager::GetInstance()->GetSandbox(sandboxId);
++ if (nullptr == sandbox) {
++ ERROR("Sandbox not found");
++ return -1;
++ }
++
++ sandbox->OnSandboxPending();
++ return 0;
++}
++
++static int sandbox_api_exit(const char *sandbox_id, const sandbox_wait_response *response)
++{
++ ControllerExitInfo exitInfo;
++ std::string sandboxId = std::string(sandbox_id);
++ auto sandbox = sandbox::SandboxManager::GetInstance()->GetSandbox(sandboxId);
++ if (nullptr == sandbox) {
++ ERROR("Sandbox not found");
++ return -1;
++ }
++
++ exitInfo.exitStatus = response->exit_status;
++ exitInfo.exitedAt = response->exited_at;
++ sandbox->OnSandboxExit(exitInfo);
++ return 0;
++}
++
++auto SandboxerClient::Wait(std::shared_ptr<SandboxStatusCallback> cb, const std::string &sandboxId,
++ Errors &error) -> bool
++{
++ sandbox_wait_request *request { nullptr };
++ sandbox_api_wait_callback callback;
++
++ auto wait_request_wrapper = makeUniquePtrCStructWrapper<sandbox_wait_request>(free_sandbox_wait_request);
++ if (wait_request_wrapper == nullptr) {
++ ERROR("Out of memory");
++ error.SetError("Out of memory");
++ return false;
++ }
++ request = wait_request_wrapper->get();
++
++ request->sandboxer = util_strdup_s(m_sandboxer.c_str());
++ request->sandbox_id = util_strdup_s(sandboxId.c_str());
++ callback.ready = sandbox_api_ready;
++ callback.pending = sandbox_api_pending;
++ callback.exit = sandbox_api_exit;
++ int ret = sandbox_api_wait(m_controller_handle, request, callback);
++ if (ret != 0) {
++ ERROR("Failed to wait sandbox");
++ error.SetError("Failed to wait sandbox");
++ return false;
++ }
++
++ return true;
++}
++
++} // namespace
+diff --git a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h b/src/daemon/sandbox/sandboxer/controller/client/grpc_sandboxer_client.h
+similarity index 54%
+rename from src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h
+rename to src/daemon/sandbox/sandboxer/controller/client/grpc_sandboxer_client.h
+index eeb5d7f2..d712be04 100644
+--- a/src/daemon/sandbox/controller/sandboxer/client/grpc_sandboxer_client.h
++++ b/src/daemon/sandbox/sandboxer/controller/client/grpc_sandboxer_client.h
+@@ -20,15 +20,10 @@
+ #include <memory>
+ #include <future>
+
+-#include "sandbox/types/mount.pb.h"
+-#include "sandbox.pb.h"
+-#include "sandbox.grpc.pb.h"
+-#include "controller.h"
+-#include "grpc_async_wait_call.h"
+-#include "grpc_sandboxer_monitor.h"
++#include <isula_sandbox_api.h>
+
+-using containerd::types::Mount;
+-using google::protobuf::Timestamp;
++#include "controller.h"
++#include "utils_array.h"
+
+ namespace sandbox {
+
+@@ -38,24 +33,13 @@ public:
+
+ ~SandboxerClient() = default;
+
+- void Init(Errors &error);
+-
+- void Destroy();
+-
+ auto Create(const std::string &sandboxId, const ControllerCreateParams &params, Errors &error) -> bool;
+
+ auto Start(const std::string &sandboxId, ControllerSandboxInfo &sandboxInfo, Errors &error) -> bool;
+
+ auto Platform(const std::string &sandboxId, ControllerPlatformInfo &platformInfo, Errors &error) -> bool;
+
+- auto Prepare(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields, Errors &error) -> bool;
+-
+- auto Purge(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields, Errors &error) -> bool;
+-
+- auto UpdateResources(const std::string &sandboxId, const ControllerUpdateResourcesParams &params,
+- Errors &error) -> bool;
++ auto Update(sandbox_sandbox *apiSandbox, string_array *fields, Errors &error) -> bool;
+
+ auto Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error) -> bool;
+
+@@ -66,27 +50,23 @@ public:
+ auto Shutdown(const std::string &sandboxId, Errors &error) -> bool;
+
+ private:
+- void InitMountInfo(Mount &mount, const ControllerMountInfo &mountInfo);
+- auto InitCreateRequest(containerd::services::sandbox::v1::ControllerCreateRequest &request,
++ auto InitMountInfo(sandbox_mount &m, const ControllerMountInfo &mountInfo) -> int;
++ auto InitCreateRequest(sandbox_create_request &request,
+ const std::string &sandboxId,
+ const ControllerCreateParams &params) -> bool;
+- void StartResponseToSandboxInfo(const containerd::services::sandbox::v1::ControllerStartResponse &response,
++ void StartResponseToSandboxInfo(sandbox_start_response &response,
+ ControllerSandboxInfo &sandboxInfo);
+- void InitUpdateRequest(containerd::services::sandbox::v1::ControllerUpdateRequest &request,
+- containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields);
+- // auto InitUpdateResourcesRequest(containerd::services::sandbox::v1::UpdateResourcesRequest &request,
+- // const std::string &sandboxId,
+- // const ControllerUpdateResourcesParams &params) -> bool;
+- void PlatformResponseToPlatformInfo(const containerd::services::sandbox::v1::ControllerPlatformResponse &response,
++ void InitUpdateRequest(sandbox_update_request &request,
++ sandbox_sandbox *apiSandbox, string_array *fields);
++
++ void PlatformResponseToPlatformInfo(sandbox_platform_response &response,
+ ControllerPlatformInfo &platformInfo);
+- void StatusResponseToSandboxStatus(const containerd::services::sandbox::v1::ControllerStatusResponse &response,
++ void StatusResponseToSandboxStatus(sandbox_status_response &response,
+ ControllerSandboxStatus &sandboxStatus);
+ protected:
+ std::string m_sandboxer;
+ std::string m_address;
+- std::shared_ptr<grpc::Channel> m_channel;
+- std::unique_ptr<containerd::services::sandbox::v1::Controller::StubInterface> m_stub;
+- std::unique_ptr<SandboxerClientMonitor> m_monitor;
++ ControllerHandle_t m_controller_handle;
+ };
+
+ } // namespace
+diff --git a/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.cc b/src/daemon/sandbox/sandboxer/controller/sandboxer_controller.cc
+similarity index 78%
+rename from src/daemon/sandbox/controller/sandboxer/sandboxer_controller.cc
+rename to src/daemon/sandbox/sandboxer/controller/sandboxer_controller.cc
+index 70cab015..bbe52c85 100644
+--- a/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.cc
++++ b/src/daemon/sandbox/sandboxer/controller/sandboxer_controller.cc
+@@ -27,15 +27,9 @@ SandboxerController::~SandboxerController() {}
+
+ bool SandboxerController::Init(Errors &error)
+ {
+- m_client->Init(error);
+ return true;
+ }
+
+-void SandboxerController::Destroy()
+-{
+- m_client->Destroy();
+-}
+-
+ bool SandboxerController::Create(const std::string &sandboxId,
+ const ControllerCreateParams &params,
+ Errors &error)
+@@ -61,25 +55,10 @@ std::unique_ptr<ControllerPlatformInfo> SandboxerController::Platform(const std:
+ return platformInfo;
+ }
+
+-bool SandboxerController::Prepare(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields,
+- Errors &error)
+-{
+- return m_client->Prepare(apiSandbox, fields, error);
+-}
+-
+-bool SandboxerController::Purge(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields,
+- Errors &error)
+-{
+- return m_client->Purge(apiSandbox, fields, error);
+-}
+-
+-bool SandboxerController::UpdateResources(const std::string &sandboxId,
+- const ControllerUpdateResourcesParams &params,
+- Errors &error)
++bool SandboxerController::Update(sandbox_sandbox *apiSandbox,
++ string_array *fields, Errors &error)
+ {
+- return m_client->UpdateResources(sandboxId, params, error);
++ return m_client->Update(apiSandbox, fields, error);
+ }
+
+ bool SandboxerController::Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error)
+diff --git a/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.h b/src/daemon/sandbox/sandboxer/controller/sandboxer_controller.h
+similarity index 82%
+rename from src/daemon/sandbox/controller/sandboxer/sandboxer_controller.h
+rename to src/daemon/sandbox/sandboxer/controller/sandboxer_controller.h
+index 8cb7fe7c..13ab86ab 100644
+--- a/src/daemon/sandbox/controller/sandboxer/sandboxer_controller.h
++++ b/src/daemon/sandbox/sandboxer/controller/sandboxer_controller.h
+@@ -31,19 +31,12 @@ public:
+ SandboxerController(const std::string &sandboxer, const std::string &address);
+ virtual ~SandboxerController();
+ bool Init(Errors &error) override;
+- void Destroy() override;
+ bool Create(const std::string &sandboxId,
+ const ControllerCreateParams &params,
+ Errors &error) override;
+ std::unique_ptr<ControllerSandboxInfo> Start(const std::string &sandboxId, Errors &error) override;
+ std::unique_ptr<ControllerPlatformInfo> Platform(const std::string &sandboxId, Errors &error) override;
+- bool Prepare(containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields,
+- Errors &error) override;
+- bool Purge(containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields,
+- Errors &error) override;
+- bool UpdateResources(const std::string &sandboxId,
+- const ControllerUpdateResourcesParams &params,
+- Errors &error) override;
++ bool Update(sandbox_sandbox *apiSandbox, string_array *fields, Errors &error) override;
+ bool Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error) override;
+ bool Wait(std::shared_ptr<SandboxStatusCallback> cb, const std::string &sandboxId, Errors &error) override;
+ std::unique_ptr<ControllerSandboxStatus> Status(const std::string &sandboxId, bool verbose, Errors &error) override;
+diff --git a/src/daemon/sandbox/sandboxer/sandboxer_sandbox.cc b/src/daemon/sandbox/sandboxer/sandboxer_sandbox.cc
+new file mode 100644
+index 00000000..726b7b3a
+--- /dev/null
++++ b/src/daemon/sandbox/sandboxer/sandboxer_sandbox.cc
+@@ -0,0 +1,254 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: liuxu
++ * Create: 2024-11-20
++ * Description: provide sandboxer sandbox class definition
++ *********************************************************************************/
++#include "sandboxer_sandbox.h"
++
++#include <sys/stat.h>
++#include <unistd.h>
++#include <string>
++#include <mutex>
++#include <memory>
++#include <sys/mount.h>
++
++#include <isula_libutils/log.h>
++#include <isula_libutils/auto_cleanup.h>
++
++#include "utils_file.h"
++#include "utils.h"
++#include "cxxutils.h"
++
++namespace sandbox {
++
++SandboxerSandbox::SandboxerSandbox(const std::string id, const std::string &rootdir, const std::string &statedir, const std::string name,
++ const RuntimeInfo info, std::string netMode, std::string netNsPath, const runtime::v1::PodSandboxConfig sandboxConfig,
++ const std::string image):Sandbox(id, rootdir, statedir, name, info, netMode,
++ netNsPath, sandboxConfig, image)
++{
++}
++
++auto SandboxerSandbox::GetTasksJsonPath() -> std::string
++{
++ return GetStateDir() + std::string("/") + SANDBOX_TASKS_JSON;
++}
++
++auto SandboxerSandbox::AddTaskById(const char *task_id, sandbox_task *task) -> bool
++{
++
++ std::string taskId = std::string(task_id);
++ auto iter = m_tasks.find(taskId);
++
++ if (iter != m_tasks.end()) {
++ ERROR("Failed to add existing sandbox task %s for sandbox: %s",
++ task_id, GetId().c_str());
++ return false;
++ }
++ m_tasks[taskId] = std::make_shared<SandboxTask>(task);
++ return true;
++}
++
++auto SandboxerSandbox::ReadSandboxTasksJson() -> sandbox_tasks *
++{
++ const std::string path = GetTasksJsonPath();
++ __isula_auto_free parser_error err = nullptr;
++ sandbox_tasks *tasksArray = nullptr;
++
++ ReadGuard<RWMutex> lock(m_tasksMutex);
++ tasksArray = sandbox_tasks_parse_file(path.c_str(), nullptr, &err);
++ if (tasksArray == nullptr) {
++ WARN("Failed to read %s tasks json: %s", path.c_str(), err);
++ }
++ return tasksArray;
++}
++
++auto SandboxerSandbox::WriteSandboxTasksJson(std::string &tasks_json) -> bool
++{
++ int nret = 0;
++ const std::string path = GetTasksJsonPath();
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++ nret = util_atomic_write_file(path.c_str(), tasks_json.c_str(), tasks_json.size(), CONFIG_FILE_MODE, false);
++ if (nret != 0) {
++ SYSERROR("Failed to write file %s", path.c_str());
++ }
++ return nret == 0;
++}
++
++auto SandboxerSandbox::DeleteSandboxTasksJson() -> bool
++{
++ int get_err = 0;
++ const std::string path = GetTasksJsonPath();
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++ if (util_fileself_exists(path.c_str()) &&
++ !util_force_remove_file(path.c_str(), &get_err)) {
++ errno = get_err;
++ SYSERROR("Failed to remove file %s", path.c_str());
++ return false;
++ }
++
++ return true;
++}
++
++void SandboxerSandbox::AddSandboxTasksByArray(sandbox_tasks *tasksArray)
++{
++ size_t i;
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++ for (i = 0; i < tasksArray->tasks_len; i++) {
++ if (!AddTaskById(tasksArray->tasks[i]->task_id, tasksArray->tasks[i])) {
++ return;
++ }
++ tasksArray->tasks[i] = nullptr;
++ }
++ tasksArray->tasks_len = 0;
++}
++
++void SandboxerSandbox::LoadSandboxTasks()
++{
++ sandbox_tasks *tasksArray = nullptr;
++
++ tasksArray = ReadSandboxTasksJson();
++ if (tasksArray == nullptr) {
++ return;
++ }
++
++ AddSandboxTasksByArray(tasksArray);
++
++ free_sandbox_tasks(tasksArray);
++}
++
++auto SandboxerSandbox::SaveSandboxTasks() -> bool
++{
++ std::string tasks_json;
++
++ if (m_tasks.empty()) {
++ return DeleteSandboxTasksJson();
++ }
++
++ tasks_json = GetAnySandboxTasks();
++ if (tasks_json.empty()) {
++ ERROR("Failed to get sandbox tasks json for sandbox: '%s'", GetId().c_str());
++ return false;
++ }
++
++ return WriteSandboxTasksJson(tasks_json);
++}
++
++auto SandboxerSandbox::AddSandboxTasks(sandbox_task *task) -> bool
++{
++ if (task == nullptr) {
++ return true;
++ }
++ if (task->task_id == nullptr) {
++ return false;
++ }
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++
++ return AddTaskById(task->task_id, task);
++}
++
++auto SandboxerSandbox::GetAnySandboxTasks() -> std::string
++{
++ __isula_auto_free parser_error err = nullptr;
++ sandbox_tasks tasksArray = { 0 };
++ size_t i = 0;
++ __isula_auto_free char *tasks_json = nullptr;
++
++ tasksArray.tasks = (sandbox_task **)util_smart_calloc_s(sizeof(sandbox_task *), m_tasks.size());
++ if (tasksArray.tasks == nullptr) {
++ SYSERROR("Out of memory.");
++ return std::string("");
++ }
++
++ ReadGuard<RWMutex> lock(m_tasksMutex);
++ for (auto const& [_, val] : m_tasks) {
++ /*
++ * We ignore that the processes are modified
++ * when we generate tasks json string.
++ * Because no matter whether a process is deleted or added,
++ * the Update of sandbox api will be called eventually.
++ *
++ * And we ignore that the task is freed after we do GetTask().
++ * Because the only way to free task is DeleteSandboxTasks()
++ * which needs write lock of m_tasksMutex.
++ */
++ tasksArray.tasks[i] = val->GetTask();
++ i++;
++ }
++ tasksArray.tasks_len = m_tasks.size();
++
++ tasks_json = sandbox_tasks_generate_json(&tasksArray, nullptr, &(err));
++ if (tasks_json == nullptr || strlen(tasks_json) == 0) {
++ ERROR("Failed to get sandbox tasks json for sandbox: '%s'", GetId().c_str());
++ free(tasksArray.tasks);
++ return std::string("");
++ }
++
++ free(tasksArray.tasks);
++ return std::string(tasks_json);
++}
++
++void SandboxerSandbox::DeleteSandboxTasks(const char *containerId)
++{
++ if (containerId == nullptr) {
++ return;
++ }
++
++ std::string taskId = std::string(containerId);
++
++ WriteGuard<RWMutex> lock(m_tasksMutex);
++ auto iter = m_tasks.find(taskId);
++ if (iter == m_tasks.end()) {
++ return;
++ }
++ m_tasks.erase(iter);
++}
++
++auto SandboxerSandbox::AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool
++{
++ if (containerId == nullptr || processes == nullptr) {
++ ERROR("Empty args.");
++ return false;
++ }
++
++ std::string taskId = std::string(containerId);
++
++ ReadGuard<RWMutex> lock(m_tasksMutex);
++ auto iter = m_tasks.find(taskId);
++ if (iter == m_tasks.end()) {
++ SYSERROR("Failed to find container %s", containerId);
++ return false;
++ }
++
++ return iter->second->AddSandboxTasksProcess(processes);
++}
++
++void SandboxerSandbox::DeleteSandboxTasksProcess(const char *containerId, const char *execId)
++{
++ if (containerId == nullptr || execId == nullptr) {
++ return;
++ }
++
++ std::string taskId = std::string(containerId);
++
++ ReadGuard<RWMutex> lock(m_tasksMutex);
++ auto iter = m_tasks.find(taskId);
++ if (iter == m_tasks.end()) {
++ return;
++ }
++ iter->second->DeleteSandboxTasksProcess(execId);
++}
++
++}
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/sandboxer/sandboxer_sandbox.h b/src/daemon/sandbox/sandboxer/sandboxer_sandbox.h
+new file mode 100644
+index 00000000..552eb328
+--- /dev/null
++++ b/src/daemon/sandbox/sandboxer/sandboxer_sandbox.h
+@@ -0,0 +1,63 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: liuxu
++ * Create: 2024-11-20
++ * Description: provide sandboxer sandbox class definition
++ *********************************************************************************/
++
++#ifndef DAEMON_SANDBOX_SANDBOXER_SANDBOX_H
++#define DAEMON_SANDBOX_SANDBOXER_SANDBOX_H
++
++#include <string>
++#include <mutex>
++#include <google/protobuf/map.h>
++
++#include "read_write_lock.h"
++#include "sandbox_task.h"
++#include "sandbox.h"
++
++namespace sandbox {
++
++class SandboxerSandbox : public Sandbox {
++public:
++ SandboxerSandbox(const std::string id, const std::string &rootdir, const std::string &statedir, const std::string name = "",
++ const RuntimeInfo info = {"", "", ""}, std::string netMode = DEFAULT_NETMODE, std::string netNsPath = "",
++ const runtime::v1::PodSandboxConfig sandboxConfig = runtime::v1::PodSandboxConfig::default_instance(),
++ const std::string image = "");
++ virtual ~SandboxerSandbox() = default;
++
++ // for sandbox api update
++ auto GetTasksJsonPath() -> std::string;
++ void LoadSandboxTasks() override;
++ auto SaveSandboxTasks() -> bool override;
++ auto AddSandboxTasks(sandbox_task *task) -> bool override;
++ auto GetAnySandboxTasks() -> std::string override;
++ void DeleteSandboxTasks(const char *containerId) override;
++ auto AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool override;
++ void DeleteSandboxTasksProcess(const char *containerId, const char *execId) override;
++
++private:
++ auto AddTaskById(const char *task_id, sandbox_task *task) -> bool;
++ auto ReadSandboxTasksJson() -> sandbox_tasks *;
++ auto WriteSandboxTasksJson(std::string &tasks_json) -> bool;
++ auto DeleteSandboxTasksJson() -> bool;
++ void AddSandboxTasksByArray(sandbox_tasks *tasksArray);
++
++private:
++ // use m_tasksMutex to ensure the correctness of the tasks
++ RWMutex m_tasksMutex;
++ // for sandbox api update, containerId --> tasks
++ std::map<std::string, std::shared_ptr<SandboxTask>> m_tasks;
++};
++
++} // namespace sandbox
++
++#endif // DAEMON_SANDBOX_SANDBOXER_SANDBOX_H
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/shim/CMakeLists.txt b/src/daemon/sandbox/shim/CMakeLists.txt
+new file mode 100755
+index 00000000..66fff738
+--- /dev/null
++++ b/src/daemon/sandbox/shim/CMakeLists.txt
+@@ -0,0 +1,15 @@
++# get current directory sources files
++aux_source_directory(${CMAKE_CURRENT_SOURCE_DIR} shim_sandbox_srcs)
++
++add_subdirectory(controller)
++
++set(SHIM_SANDBOX_SRCS
++ ${shim_sandbox_srcs}
++ ${CONTROLLER_SHIM_SRCS}
++ PARENT_SCOPE
++ )
++set(SHIM_SANDBOX_INCS
++ ${CMAKE_CURRENT_SOURCE_DIR}
++ ${CONTROLLER_SHIM_INCS}
++ PARENT_SCOPE
++ )
+diff --git a/src/daemon/sandbox/controller/shim/CMakeLists.txt b/src/daemon/sandbox/shim/controller/CMakeLists.txt
+similarity index 100%
+rename from src/daemon/sandbox/controller/shim/CMakeLists.txt
+rename to src/daemon/sandbox/shim/controller/CMakeLists.txt
+diff --git a/src/daemon/sandbox/controller/shim/shim_controller.cc b/src/daemon/sandbox/shim/controller/shim_controller.cc
+similarity index 97%
+rename from src/daemon/sandbox/controller/shim/shim_controller.cc
+rename to src/daemon/sandbox/shim/controller/shim_controller.cc
+index 14c99168..7e4338f6 100644
+--- a/src/daemon/sandbox/controller/shim/shim_controller.cc
++++ b/src/daemon/sandbox/shim/controller/shim_controller.cc
+@@ -45,8 +45,6 @@ bool ShimController::Init(Errors &error)
+ return true;
+ }
+
+-void ShimController::Destroy() {}
+-
+ void ShimController::ApplySandboxLinuxOptions(const runtime::v1::LinuxPodSandboxConfig &lc, host_config *hc,
+ container_config *custom_config, Errors &error)
+ {
+@@ -340,21 +338,8 @@ std::unique_ptr<ControllerPlatformInfo> ShimController::Platform(const std::stri
+ return nullptr;
+ }
+
+-bool ShimController::Prepare(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields, Errors &error)
+-{
+- return true;
+-}
+-
+-bool ShimController::Purge(containerd::types::Sandbox &apiSandbox,
+- std::vector<std::string> &fields, Errors &error)
+-{
+- return true;
+-}
+-
+-bool ShimController::UpdateResources(const std::string &sandboxId,
+- const ControllerUpdateResourcesParams &params,
+- Errors &error)
++bool ShimController::Update(sandbox_sandbox *apiSandbox,
++ string_array *fields, Errors &error)
+ {
+ return true;
+ }
+diff --git a/src/daemon/sandbox/controller/shim/shim_controller.h b/src/daemon/sandbox/shim/controller/shim_controller.h
+similarity index 89%
+rename from src/daemon/sandbox/controller/shim/shim_controller.h
+rename to src/daemon/sandbox/shim/controller/shim_controller.h
+index 1985ddc0..fc86be98 100644
+--- a/src/daemon/sandbox/controller/shim/shim_controller.h
++++ b/src/daemon/sandbox/shim/controller/shim_controller.h
+@@ -32,26 +32,18 @@
+
+ namespace sandbox {
+
+-const std::string SHIM_CONTROLLER_NAME = "shim";
+-
+ class ShimController : public Controller {
+ public:
+ ShimController(const std::string &sandboxer);
+ virtual ~ShimController();
+ bool Init(Errors &error) override;
+- void Destroy() override;
+ bool Create(const std::string &sandboxId,
+ const ControllerCreateParams &params,
+ Errors &error) override;
+ std::unique_ptr<ControllerSandboxInfo> Start(const std::string &sandboxId, Errors &error) override;
+ std::unique_ptr<ControllerPlatformInfo> Platform(const std::string &sandboxId, Errors &error) override;
+- bool Prepare(containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields,
+- Errors &error) override;
+- bool Purge(containerd::types::Sandbox &apiSandbox, std::vector<std::string> &fields,
+- Errors &error) override;
+- bool UpdateResources(const std::string &sandboxId,
+- const ControllerUpdateResourcesParams &params,
+- Errors &error) override;
++ bool Update(sandbox_sandbox *apiSandbox,
++ string_array *fields, Errors &error) override;
+ bool Stop(const std::string &sandboxId, uint32_t timeoutSecs, Errors &error) override;
+ bool Wait(std::shared_ptr<SandboxStatusCallback> cb, const std::string &sandboxId, Errors &error) override;
+ std::unique_ptr<ControllerSandboxStatus> Status(const std::string &sandboxId, bool verbose, Errors &error) override;
+diff --git a/src/daemon/sandbox/shim/shim_sandbox.cc b/src/daemon/sandbox/shim/shim_sandbox.cc
+new file mode 100644
+index 00000000..2efb8d7c
+--- /dev/null
++++ b/src/daemon/sandbox/shim/shim_sandbox.cc
+@@ -0,0 +1,65 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: liuxu
++ * Create: 2024-11-20
++ * Description: provide sandboxer sandbox class definition
++ *********************************************************************************/
++#include "shim_sandbox.h"
++
++#include <unistd.h>
++#include <string>
++
++#include <isula_libutils/log.h>
++#include <isula_libutils/auto_cleanup.h>
++
++
++namespace sandbox {
++
++ShimSandbox::ShimSandbox(const std::string id, const std::string &rootdir, const std::string &statedir, const std::string name,
++ const RuntimeInfo info, std::string netMode, std::string netNsPath, const runtime::v1::PodSandboxConfig sandboxConfig,
++ const std::string image):Sandbox(id, rootdir, statedir, name, info, netMode,
++ netNsPath, sandboxConfig, image)
++{
++}
++
++void ShimSandbox::LoadSandboxTasks()
++{
++}
++
++auto ShimSandbox::SaveSandboxTasks() -> bool
++{
++ return true;
++}
++
++auto ShimSandbox::AddSandboxTasks(sandbox_task *task) -> bool
++{
++ return true;
++}
++
++auto ShimSandbox::GetAnySandboxTasks() -> std::string
++{
++ return std::string("Nothing for shim.");
++}
++
++void ShimSandbox::DeleteSandboxTasks(const char *containerId)
++{
++}
++
++auto ShimSandbox::AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool
++{
++ return true;
++}
++
++void ShimSandbox::DeleteSandboxTasksProcess(const char *containerId, const char *execId)
++{
++}
++
++}
+\ No newline at end of file
+diff --git a/src/daemon/sandbox/shim/shim_sandbox.h b/src/daemon/sandbox/shim/shim_sandbox.h
+new file mode 100644
+index 00000000..82da0573
+--- /dev/null
++++ b/src/daemon/sandbox/shim/shim_sandbox.h
+@@ -0,0 +1,49 @@
++/******************************************************************************
++ * Copyright (c) Huawei Technologies Co., Ltd. 2024. All rights reserved.
++ * iSulad licensed under the Mulan PSL v2.
++ * You can use this software according to the terms and conditions of the Mulan PSL v2.
++ * You may obtain a copy of Mulan PSL v2 at:
++ * http://license.coscl.org.cn/MulanPSL2
++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR
++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR
++ * PURPOSE.
++ * See the Mulan PSL v2 for more details.
++ * Author: liuxu
++ * Create: 2024-11-20
++ * Description: provide shim sandbox class definition
++ *********************************************************************************/
++
++#ifndef DAEMON_SANDBOX_SHIM_SANDBOX_H
++#define DAEMON_SANDBOX_SHIM_SANDBOX_H
++
++#include <string>
++#include <mutex>
++#include <google/protobuf/map.h>
++
++#include "read_write_lock.h"
++#include "sandbox_task.h"
++#include "sandbox.h"
++
++namespace sandbox {
++
++class ShimSandbox : public Sandbox {
++public:
++ ShimSandbox(const std::string id, const std::string &rootdir, const std::string &statedir, const std::string name = "",
++ const RuntimeInfo info = {"", "", ""}, std::string netMode = DEFAULT_NETMODE, std::string netNsPath = "",
++ const runtime::v1::PodSandboxConfig sandboxConfig = runtime::v1::PodSandboxConfig::default_instance(),
++ const std::string image = "");
++ virtual ~ShimSandbox() = default;
++
++ // for sandbox api update
++ void LoadSandboxTasks() override;
++ auto SaveSandboxTasks() -> bool override;
++ auto AddSandboxTasks(sandbox_task *task) -> bool override;
++ auto GetAnySandboxTasks() -> std::string override;
++ void DeleteSandboxTasks(const char *containerId) override;
++ auto AddSandboxTasksProcess(const char *containerId, sandbox_process *processes) -> bool override;
++ void DeleteSandboxTasksProcess(const char *containerId, const char *execId) override;
++};
++
++} // namespace sandbox
++
++#endif // DAEMON_SANDBOX_SHIM_SANDBOX_H
+\ No newline at end of file
+--
+2.34.1
+