Lưu nội dung tổng hợp vào bộ nhớ đệm

Trên Android 10, Neural Networks API (NNAPI) cung cấp các hàm hỗ trợ lưu các cấu phần phần mềm biên dịch vào bộ nhớ đệm, giúp giảm thời gian biên dịch khi một ứng dụng khởi động. Khi sử dụng chức năng lưu vào bộ nhớ đệm này, trình điều khiển sẽ không cần quản lý hoặc xoá các tệp được lưu vào bộ nhớ đệm. Đây là tính năng tuỳ chọn có thể được thực hiện với NN HAL 1.2. Để biết thêm thông tin về chức năng này, xem ANeuralNetworksCompilation_setCaching.

Trình điều khiển cũng có thể triển khai việc lưu hoạt động biên dịch vào bộ nhớ đệm mà không phụ thuộc vào NNAPI. Chiến dịch này có thể triển khai được bất kể có sử dụng các tính năng lưu vào bộ nhớ đệm của NNAPI NDK và HAL hay không thì không. AOSP cung cấp một thư viện tiện ích cấp thấp (công cụ lưu vào bộ nhớ đệm). Để biết thêm Vui lòng xem phần Triển khai công cụ lưu vào bộ nhớ đệm.

Tổng quan về quy trình công việc

Phần này mô tả quy trình công việc chung với tính năng lưu biên dịch vào bộ nhớ đệm triển khai.

Đã cung cấp thông tin bộ nhớ đệm và kết quả tìm kiếm trong bộ nhớ đệm

  1. Ứng dụng truyền một thư mục lưu vào bộ nhớ đệm và một giá trị tổng kiểm duy nhất cho mô hình.
  2. Môi trường thời gian chạy NNAPI tìm các tệp bộ nhớ đệm dựa trên giá trị tổng kiểm, lựa chọn ưu tiên thực thi và kết quả phân vùng cũng như tìm các tệp.
  3. NNAPI mở các tệp bộ nhớ đệm và truyền các tên người dùng đến trình điều khiển thông qua tính năng prepareModelFromCache.
  4. Trình điều khiển chuẩn bị mô hình ngay từ các tệp bộ nhớ đệm rồi trả về mô hình chuẩn bị.

Đã cung cấp thông tin bộ nhớ đệm và thiếu bộ nhớ đệm

  1. Ứng dụng truyền một giá trị tổng kiểm duy nhất cho mô hình và một bộ nhớ đệm thư mục.
  2. Môi trường thời gian chạy NNAPI tìm các tệp lưu vào bộ nhớ đệm dựa trên giá trị tổng kiểm, tùy chọn thực thi và kết quả phân vùng cũng như không tìm thấy các tệp bộ nhớ đệm.
  3. NNAPI tạo các tệp bộ nhớ đệm trống dựa trên giá trị tổng kiểm, quá trình thực thi tuỳ chọn và phân vùng, mở các tệp bộ nhớ đệm và chuyển và mô hình cho người lái xe bằng prepareModel_1_2.
  4. Trình điều khiển biên dịch mô hình, ghi thông tin lưu vào bộ nhớ đệm vào bộ nhớ đệm tệp và trả về mô hình đã chuẩn bị.

Chưa cung cấp thông tin bộ nhớ đệm

  1. Ứng dụng gọi quá trình biên dịch mà không cung cấp bất kỳ thông tin nào về việc lưu vào bộ nhớ đệm.
  2. Ứng dụng không truyền dữ liệu nào liên quan đến việc lưu vào bộ nhớ đệm.
  3. Môi trường thời gian chạy NNAPI truyền mô hình cho trình điều khiển bằng prepareModel_1_2.
  4. Trình điều khiển biên dịch mô hình và trả về mô hình đã chuẩn bị.

Thông tin bộ nhớ đệm

Thông tin lưu vào bộ nhớ đệm được cung cấp cho người điều khiển bao gồm một mã thông báo và xử lý tệp bộ nhớ đệm.

Mã thông báo

Chiến lược phát hành đĩa đơn mã thông báo là một mã thông báo có độ dài được lưu vào bộ nhớ đệm Constant::BYTE_SIZE_OF_CACHE_TOKEN để xác định mô hình đã chuẩn bị. Mã thông báo tương tự được cung cấp khi lưu lưu các tệp vào bộ nhớ đệm bằng prepareModel_1_2 và truy xuất mô hình đã chuẩn bị bằng prepareModelFromCache. Ứng dụng của người lái xe nên chọn một mã thông báo có tốc độ va chạm thấp. Người lái xe không thể phát hiện xung đột mã thông báo. Một vụ va chạm dẫn đến việc thực thi không thành công hoặc quá trình thực thi thành công tạo ra giá trị đầu ra không chính xác.

Xử lý tệp bộ nhớ đệm (hai loại tệp bộ nhớ đệm)

Hai loại tệp bộ nhớ đệm là bộ nhớ đệm dữ liệubộ nhớ đệm mô hình.

  • Bộ nhớ đệm dữ liệu: Dùng để lưu dữ liệu hằng số vào bộ nhớ đệm, bao gồm cả dữ liệu đã xử lý trước và biến đổi bộ đệm tensor. Sửa đổi bộ nhớ đệm dữ liệu không được dẫn đến bất kỳ ảnh hưởng nào tệ hơn việc tạo ra các giá trị đầu ra không hợp lệ khi thực thi bất cứ lúc nào.
  • Bộ nhớ đệm mô hình: Dùng để lưu dữ liệu nhạy cảm về tính bảo mật vào bộ nhớ đệm, chẳng hạn như dữ liệu đã biên dịch mã máy có thể thực thi ở định dạng nhị phân gốc của thiết bị. Đáp việc sửa đổi bộ nhớ đệm của mô hình có thể ảnh hưởng đến quá trình thực thi của trình điều khiển máy khách độc hại có thể tận dụng điều này để thực thi quyền đã cấp. Do đó, trình điều khiển phải kiểm tra xem bộ nhớ đệm của mô hình bị lỗi trước khi chuẩn bị mô hình từ bộ nhớ đệm. Để biết thêm thông tin, hãy xem phần Bảo mật.

Trình điều khiển phải quyết định cách phân phối thông tin bộ nhớ đệm giữa các loại tệp bộ nhớ đệm và báo cáo số lượng tệp bộ nhớ đệm cần thiết cho mỗi loại thông qua tính năng getNumberOfCacheFilesNeeded.

Môi trường thời gian chạy NNAPI luôn mở các xử lý bộ nhớ đệm ở cả quyền đọc và ghi quyền.

Bảo mật

Khi lưu kết quả biên dịch vào bộ nhớ đệm, bộ nhớ đệm của mô hình có thể chứa dữ liệu nhạy cảm về bảo mật như dưới dạng mã máy thực thi được biên dịch ở định dạng nhị phân gốc của thiết bị. Nếu không được bảo vệ đúng cách, việc sửa đổi bộ nhớ đệm của mô hình có thể ảnh hưởng đến hành vi thực thi. Vì nội dung trong bộ nhớ đệm được lưu trữ trong ứng dụng thư mục, các tệp bộ nhớ đệm có thể sửa đổi được bởi ứng dụng. Một máy khách bị lỗi có thể vô tình làm hỏng bộ nhớ đệm và một ứng dụng khách độc hại có thể cố tình sử dụng mã này để thực thi mã chưa được xác minh trên thiết bị. Tuỳ thuộc vào của thiết bị, đây có thể là vấn đề bảo mật. Do đó, người lái xe phải có thể phát hiện có thể xảy ra trong bộ nhớ đệm của mô hình trước khi chuẩn bị mô hình từ bộ nhớ đệm.

Một cách để thực hiện việc này là để người lái xe duy trì bản đồ từ mã thông báo đến hàm băm mật mã của bộ nhớ đệm của mô hình. Người lái xe có thể lưu trữ mã thông báo và hàm băm của bộ nhớ đệm mô hình khi lưu quá trình biên dịch vào bộ nhớ đệm. Tài xế kiểm tra hàm băm mới của bộ nhớ đệm mô hình với mã thông báo và cặp hàm băm được ghi lại khi truy xuất kết quả biên dịch từ bộ nhớ đệm. Việc liên kết này phải liên tục trên hệ thống khởi động lại. Người lái xe có thể sử dụng Dịch vụ kho khoá Android, thư viện tiện ích trong framework/ml/nn/driver/cache! hoặc bất kỳ cơ chế phù hợp nào khác để triển khai trình quản lý bản đồ. Khi lái xe trình quản lý ánh xạ này phải được khởi chạy lại để ngăn việc chuẩn bị bộ nhớ đệm từ phiên bản cũ hơn.

Để ngăn chặn thời gian kiểm tra so với thời gian sử dụng (TOSTOU), thì người lái xe phải tính toán hàm băm đã ghi trước khi lưu vào và tính toán hàm băm mới sau khi sao chép nội dung tệp vào một vùng đệm.

Mã mẫu này minh hoạ cách triển khai logic này.

bool saveToCache(const sp<V1_2::IPreparedModel> preparedModel,
                 const hidl_vec<hidl_handle>& modelFds, const hidl_vec<hidl_handle>& dataFds,
                 const HidlToken& token) {
    // Serialize the prepared model to internal buffers.
    auto buffers = serialize(preparedModel);

    // This implementation detail is important: the cache hash must be computed from internal
    // buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
    auto hash = computeHash(buffers);

    // Store the {token, hash} pair to a mapping manager that is persistent across reboots.
    CacheManager::get()->store(token, hash);

    // Write the cache contents from internal buffers to cache files.
    return writeToFds(buffers, modelFds, dataFds);
}

sp<V1_2::IPreparedModel> prepareFromCache(const hidl_vec<hidl_handle>& modelFds,
                                          const hidl_vec<hidl_handle>& dataFds,
                                          const HidlToken& token) {
    // Copy the cache contents from cache files to internal buffers.
    auto buffers = readFromFds(modelFds, dataFds);

    // This implementation detail is important: the cache hash must be computed from internal
    // buffers instead of cache files to prevent time-of-check to time-of-use (TOCTOU) attacks.
    auto hash = computeHash(buffers);

    // Validate the {token, hash} pair by a mapping manager that is persistent across reboots.
    if (CacheManager::get()->validate(token, hash)) {
        // Retrieve the prepared model from internal buffers.
        return deserialize<V1_2::IPreparedModel>(buffers);
    } else {
        return nullptr;
    }
}

Các trường hợp sử dụng nâng cao

Trong một số trường hợp sử dụng nâng cao, trình điều khiển yêu cầu quyền truy cập vào nội dung bộ nhớ đệm (đọc hoặc ghi) sau lệnh gọi biên dịch. Sau đây là một số ví dụ về trường hợp sử dụng:

  • Biên dịch đúng thời điểm: Quá trình biên dịch bị trì hoãn cho đến khi lần thực thi đầu tiên.
  • Biên dịch nhiều giai đoạn: Ban đầu, quá trình biên dịch nhanh được thực hiện và quá trình biên dịch tối ưu hoá (không bắt buộc) sẽ được thực hiện sau này tuỳ thuộc vào tần suất sử dụng.

Để truy cập vào nội dung bộ nhớ đệm (đọc hoặc ghi) sau lệnh gọi biên dịch, hãy đảm bảo rằng người lái xe:

  • Sao chép tệp xử lý trong quá trình gọi prepareModel_1_2 hoặc prepareModelFromCache và đọc/cập nhật bộ nhớ đệm nội dung sau này.
  • Triển khai logic khoá tệp bên ngoài lệnh gọi biên dịch thông thường để ngăn việc ghi xảy ra đồng thời với quá trình đọc hoặc ghi khác.

Triển khai công cụ lưu vào bộ nhớ đệm

Ngoài giao diện bộ nhớ đệm biên dịch NN HAL 1.2, bạn cũng có thể tìm thấy lưu thư viện tiện ích vào bộ nhớ đệm trong frameworks/ml/nn/driver/cache thư mục. Chiến lược phát hành đĩa đơn nnCache thư mục con chứa mã lưu trữ cố định để trình điều khiển triển khai lưu kết quả biên dịch vào bộ nhớ đệm mà không cần sử dụng các tính năng lưu vào bộ nhớ đệm của NNAPI. Biểu mẫu này của có thể triển khai lưu biên dịch vào bộ nhớ đệm với bất kỳ phiên bản NN HAL nào. Nếu trình điều khiển chọn triển khai chức năng lưu vào bộ nhớ đệm được ngắt kết nối khỏi giao diện HAL, người lái xe là chịu trách nhiệm giải phóng các cấu phần phần mềm được lưu vào bộ nhớ đệm khi chúng không còn cần thiết nữa.