Giới thiệu
Như đã giải thích trên trang Tổng quan, HostCode thực hiện các lệnh gọi RPC đến Thư viện hộp cát. Việc tạo hộp cát dẫn đến sự phân tách bộ nhớ giữa các quy trình, do đó, Mã máy chủ không thể truy cập trực tiếp vào bộ nhớ trong Thư viện hộp cát.
Để đảm bảo rằng Mã máy chủ có thể truy cập vào các biến và khối bộ nhớ trong một quy trình từ xa, đồng thời để đơn giản hoá việc triển khai mã logic chính, SAPI cung cấp một bộ lớp C++ toàn diện. Tuy nhiên, trong nhiều trường hợp, bạn cũng có thể sử dụng các loại C gốc.
Bạn cần các loại đặc biệt (Loại SAPI) khi truyền con trỏ đến các loại đơn giản và khối bộ nhớ (cấu trúc, mảng).
Ví dụ: khi gọi một hàm lấy con trỏ, con trỏ phải được chuyển đổi thành một con trỏ tương ứng trong bộ nhớ của Thư viện hộp cát.
Đoạn mã dưới đây minh hoạ tình huống này. Thay vì một mảng gồm 3 số nguyên, một đối tượng ::sapi::v::Array<int>
sẽ được tạo, sau đó có thể được truyền trong lệnh gọi API của Thư viện có môi trường hộp cát:
int arr[3] = {1, 2, 3};
sapi::v::Array<int> sarr(arr, ABSL_ARRAYSIZE(arr));
Để biết thông tin tổng quan toàn diện về tất cả các loại SAPI có sẵn, hãy xem các tệp tiêu đề var_*.h
trong mã nguồn dự án SAPI. Các tệp tiêu đề này cung cấp các lớp và mẫu đại diện cho nhiều loại dữ liệu, ví dụ:
::sapi::v::UChar
biểu thị các ký tự chưa ký nổi tiếng::sapi::v::Array<int>
biểu thị một mảng số nguyên
Các loại SAPI
Phần này giới thiệu 3 Loại SAPI thường thấy trong Mã máy chủ.
Con trỏ SAPI
Nếu một hàm cần được đưa vào hộp cát yêu cầu truyền một con trỏ, thì con trỏ này phải được lấy từ một trong các phương thức PtrXXX()
bên dưới. Các phương thức này được triển khai bằng các lớp biến SAPI.
Các loại con trỏ | |
---|---|
::PtrNone() |
Không đồng bộ hoá bộ nhớ cơ bản giữa quy trình Mã máy chủ và quy trình Thư viện hộp cát khi được truyền đến một hàm API trong hộp cát. |
::PtrBefore() |
Đồng bộ hoá bộ nhớ của đối tượng mà nó trỏ đến trước khi lệnh gọi hàm API được cách ly diễn ra. Điều này có nghĩa là bộ nhớ cục bộ của biến được trỏ đến sẽ được chuyển sang quy trình Thư viện hộp cát trước khi lệnh gọi được bắt đầu. |
::PtrAfter() |
Đồng bộ hoá bộ nhớ của đối tượng mà nó trỏ đến sau khi lệnh gọi hàm API trong hộp cát diễn ra. Điều này có nghĩa là bộ nhớ từ xa của biến được trỏ sẽ được chuyển vào bộ nhớ của quy trình Mã máy chủ sau khi lệnh gọi hoàn tất. |
::PtrBoth() |
Kết hợp chức năng của ::PtrBefore() và ::PtrAfter() . |
Bạn có thể xem tài liệu về con trỏ SAPI tại đây.
Cấu trúc SAPI
Mẫu ::sapi::v::Struct
được ghi lại trong var_struct.h. Mẫu này cung cấp một hàm khởi tạo có thể dùng để bao bọc các cấu trúc hiện có. SAPI Struct cung cấp tất cả các phương thức được nêu trong Con trỏ SAPI để lấy một đối tượng ::sapi::v::Ptr
có thể dùng cho các lệnh gọi đến thư viện trong hộp cát.
Đoạn mã dưới đây cho thấy một cấu trúc đang được khởi tạo rồi được truyền đến một lệnh gọi hàm được cách ly trong ví dụ zlib:
sapi::v::Struct<sapi::zlib::z_stream> strm;
…
if (ret = api.deflateInit_(strm.PtrBoth(), Z_DEFAULT_COMPRESSION,
version.PtrBefore(), sizeof(sapi::zlib::z_stream));
…
Nếu cấu trúc hiện có của bạn chứa con trỏ, thì những con trỏ đó sẽ trỏ đến các địa chỉ trong Sandboxee. Do đó, bạn sẽ phải chuyển dữ liệu Sandboxee trước khi Mã máy chủ có thể truy cập vào dữ liệu đó.
Mảng SAPI
Mẫu ::sapi::v::Array
được ghi lại trong var_array.h. Mẫu này cung cấp 2 hàm khởi tạo, một hàm có thể dùng để bao bọc các mảng phần tử hiện có và một hàm khác để tạo mảng một cách linh động.
Đoạn mã này (lấy từ ví dụ về tổng) cho thấy cách sử dụng hàm khởi tạo bao bọc xung quanh một mảng không thuộc sở hữu của đối tượng này:
int arr[10];
sapi::v::Array<int> iarr(arr, ABSL_ARRAYSIZE(arr));
Đoạn mã này cho thấy ví dụ về hàm khởi tạo dùng để tạo một mảng một cách linh động:
sapi::v::Array<uint8_t> buffer(PNG_IMAGE_SIZE(*image.mutable_data()));
Mảng SAPI cung cấp tất cả các phương thức được nêu trong Con trỏ SAPI để lấy một đối tượng ::sapi::v::Ptr
có thể dùng cho các lệnh gọi đến thư viện trong hộp cát.