التخزين المؤقت للتجميع

من نظام التشغيل Android 10، أصبحت واجهة برمجة تطبيقات الشبكات العصبونية (NNAPI) توفر دوال لدعم التخزين المؤقت لعناصر التجميع، ما يقلّل من الوقت المُستغرَق في التجميع عند تشغيل التطبيق. وباستخدام وظيفة التخزين المؤقت هذه، لا إدارة أو مسح الملفات المخزنة مؤقتًا. هذه ميزة اختيارية يمكن تنفيذها باستخدام NN HAL 1.2. لمزيد من المعلومات عن هذه الدالة، يُرجى قراءة مقالة ANeuralNetworksCompilation_setCaching.

يمكن لبرنامج التشغيل أيضًا تنفيذ التخزين المؤقت للتجميع البرمجي بشكل مستقل عن NNAPI. يمكن تنفيذ ذلك سواءً تم استخدام ميزتَي التخزين المؤقت في NNAPI NDK وHAL أم لا. يوفّر إطار عمل AOSP مكتبة أدوات من المستوى الأدنى (محرك تخزين مؤقت). لمزيد من المعلومات، يُرجى الاطّلاع على تنفيذ محرك تخزين مؤقت.

نظرة عامة على سير العمل

يصف هذا القسم سير العمل العام مع ميزة ذاكرة التخزين المؤقت للترجمة.

تم تقديم معلومات ذاكرة التخزين المؤقت ونتيجة ذاكرة التخزين المؤقت

  1. يجتاز التطبيق دليل تخزين مؤقت ومجموع اختباري فريد للنموذج.
  2. يبحث وقت تشغيل NNAPI عن ملفات التخزين المؤقت استنادًا إلى الملخّص ومقدّمة التنفيذ ونتيجة التقسيم، ويجد الملفات.
  3. يفتح NNAPI ملفات ذاكرة التخزين المؤقت ويُرسِل المعرّفات إلى برنامج التشغيل باستخدام prepareModelFromCache.
  4. يُعدّ السائق النموذج مباشرةً من ملفات التخزين المؤقت ويعرض النموذج المعدّ.

معلومات ذاكرة التخزين المؤقت المقدَّمة وعدم توفّر ذاكرة التخزين المؤقت

  1. يُرسل التطبيق قيمة تحقّق فريدة للنموذج ودليل تخزين مؤقت.
  2. يبحث وقت تشغيل NNAPI عن ملفات التخزين المؤقت استنادًا إلى المجموع الاختباري وملف ملف التشغيل المفضّل ونتيجة التقسيم، ولا يعثر على ملفات التخزين المؤقت.
  3. تنشئ NNAPI ملفات ذاكرة تخزين مؤقت فارغة بناءً على المجموع الاختباري وعملية التنفيذ والتقسيم، وفتح ملفات ذاكرة التخزين المؤقت، وتمرير المقابض والنموذج إلى السائق مع prepareModel_1_2
  4. يُجمِّع برنامج التشغيل النموذج ويكتب معلومات التخزين المؤقت في ملفات التخزين المؤقت ويُعيد النموذج المُعدّ.

لم يتم توفير معلومات ذاكرة التخزين المؤقت

  1. يستدعي التطبيق التجميع بدون توفير أي معلومات عن التخزين المؤقت.
  2. لا يُرسِل التطبيق أي بيانات متعلّقة بتخزين البيانات المؤقت.
  3. ويمرر وقت تشغيل NNAPI النموذج إلى برنامج التشغيل باستخدام prepareModel_1_2
  4. يقوم برنامج التشغيل بتجميع النموذج وعرض النموذج المعد.

معلومات ذاكرة التخزين المؤقت

تتكون معلومات التخزين المؤقت التي يتم تقديمها إلى السائق من رمز مؤشرات ملفات ذاكرة التخزين المؤقت.

الرمز المميز

تشير رسالة الأشكال البيانية الرمز المميّز هو رمز التخزين المؤقت للطول Constant::BYTE_SIZE_OF_CACHE_TOKEN تحدد النموذج المعدّ. يتم تقديم الرمز المميّز نفسه عند حفظملف التمهيد باستخدام prepareModel_1_2 واسترداد النموذج المُعدّ باستخدام prepareModelFromCache. يجب على عميل السائق اختيار رمز مميز يحمل بمعدل منخفض من التصادم. لا يمكن للسائق اكتشاف تضارب الرمز المميز. يؤدي التصادم إلى تعذُّر التنفيذ أو إلى تنفيذ ناجح ينتج عنه قيم ناتجة غير صحيحة.

عناصر تحكّم ملفات التخزين المؤقت (نوعان من ملفات التخزين المؤقت)

نوعا ملفات ذاكرة التخزين المؤقت هما ذاكرة التخزين المؤقت للبيانات وذاكرة التخزين المؤقت للنماذج.

  • ذاكرة التخزين المؤقت للبيانات: تُستخدَم لتخزين البيانات الثابتة، بما في ذلك ذاكرات التخزين المؤقت للمتسلسلات العقدية التي تمت معالجتها مسبقًا وتحويلها. يجب ألا يؤدي تعديل ذاكرة التخزين المؤقت للبيانات إلى أي تأثير أسوأ من إنشاء قيم ناتجة غير صالحة في وقت التنفيذ .
  • ذاكرة التخزين المؤقت للنموذج: تُستخدَم لتخزين البيانات الحسّاسة للأمان، مثل الترميز المُجمَّع القابل للتنفيذ على الآلة بتنسيق الجهاز الثنائي الأصلي. حاسمة قد يؤثر تعديل ذاكرة التخزين المؤقت للنموذج على تنفيذ برنامج التشغيل ويمكن أن يستفيد عميل ضار من هذه الطريقة لتنفيذ ما بعد الإذن الممنوح. وبالتالي، على برنامج التشغيل التحقّق مما إذا كانت ذاكرة التخزين المؤقت للنموذج تضمّن بيانات فاسدة قبل تجهيز النموذج من ذاكرة التخزين المؤقت. لمزيد من المعلومات راجِع الأمان.

على برنامج تشغيل الجهاز تحديد كيفية توزيع معلومات ذاكرة التخزين المؤقت بين نوعَي ملفّات ذاكرة التخزين المؤقت، والإبلاغ عن عدد ملفات ذاكرة التخزين المؤقت التي يحتاجها لكل نوع باستخدام getNumberOfCacheFilesNeeded.

يفتح بيئة تشغيل NNAPI دائمًا مؤشرات ملفات ذاكرة التخزين المؤقت التي تتضمّن كلاً من القراءة والكتابة إذن.

الأمان

في ميزة التخزين المؤقت للترجمة، قد تحتوي ذاكرة التخزين المؤقت للنموذج على بيانات حسّاسة للأمان، مثل الرمز البرمجي القابل للتنفيذ والمُجمَّع بتنسيق ثنائي أصلي للجهاز. إذا لم يكن كذلك محمي بشكل صحيح، فإن تعديل ذاكرة التخزين المؤقت للطراز قد يؤثر على تخزين والتنفيذ. لأنّه يتم تخزين محتوى ذاكرة التخزين المؤقت في التطبيق الدليل، تكون ملفات ذاكرة التخزين المؤقت قابلة للتعديل بواسطة العميل. قد يؤدي عيوب العميل إلى تلف ذاكرة التخزين المؤقت عن طريق الخطأ، ويمكن للعميل الضار استخدام هذا عن قصد لتنفيذ رمز غير تم التحقّق منه على الجهاز. استنادًا إلى من خصائص الجهاز، فربما تكون هناك مشكلة أمنية. وبالتالي، يجب أن يكون السائق قادرًا على اكتشاف احتمال تلف في ذاكرة التخزين المؤقت للنموذج قبل إعداد النموذج من ذاكرة التخزين المؤقت.

تتمثل إحدى طرق إجراء ذلك في أن يحتفظ برنامج التشغيل بخريطة من الرمز المميّز إلى هِش التشفير لمخزّن النموذج المؤقت. يمكن لبرنامج التشغيل تخزين الرمز المميّز والرمز المميّز لملف التخزين المؤقت للنموذج عند حفظ عملية التجميع في ذاكرة التخزين المؤقت. عمليات فحص السائق التجزئة الجديدة لذاكرة التخزين المؤقت للنموذج مع الرمز المميز المسجل وزوج التجزئة عند استرداد التحويل البرمجي من ذاكرة التخزين المؤقت. يجب أن يظلّ هذا الربط ثابتًا عند إعادة تشغيل النظام. يمكن لبرنامج التشغيل استخدام خدمة "متجر مفاتيح Android" أو مكتبة الأداة في framework/ml/nn/driver/cache، أو أي آلية أخرى مناسبة لتنفيذ مدير الربط. عند السائق يجب إعادة إعداد مدير التعيين هذا لمنع إعداد ذاكرة التخزين المؤقت من إصدار سابق.

لمنع وقت التحقّق من وقت الاستخدام (TOCTOU)، يجب على برنامج التشغيل حساب التجزئة المسجلة قبل الحفظ في وتحسب التجزئة الجديدة بعد نسخ محتوى الملف إلى قسم المورد الاحتياطي.

يوضح نموذج التعليمات البرمجية هذا كيفية تنفيذ هذا المنطق.

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;
    }
}

حالات الاستخدام المتقدّمة

في بعض حالات الاستخدام المتقدمة، يحتاج السائق إلى الوصول إلى محتوى ذاكرة التخزين المؤقت (قراءة أو كتابة) بعد مكالمة التجميع. تشمل أمثلة حالات الاستخدام ما يلي:

  • تجميع المحتوى في الوقت المناسب: يتأخّر الفيديو التجميعي حتى والتنفيذ الأول.
  • التجميع على مراحل متعددة: يتم إجراء عملية تجميع سريعة في البداية ويتم إجراء عملية تجميع محسّنة اختيارية في وقت لاحق استنادًا إلى معدّل الاستخدام.

للوصول إلى محتوى ذاكرة التخزين المؤقت (القراءة أو الكتابة) بعد طلب الترجمة، تأكَّد مما يلي:

  • تكرار عناصر تحكّم الملفات أثناء استدعاء prepareModel_1_2 أو prepareModelFromCache وقراءة/تعديل محتوى ملف التخزين المؤقت في وقت لاحق
  • تنفيذ منطق قفل الملف خارج استدعاء التجميع العادي لمنع حدوث الكتابة بالتزامن مع قراءة أو كتابة أخرى.

استخدام محرّك تخزين مؤقت

بالإضافة إلى واجهة التخزين المؤقت للتجميعات NN HAL 1.2، يمكنك أيضًا العثور على للتخزين المؤقت في مكتبة frameworks/ml/nn/driver/cache الدليل. يحتوي الدليل الفرعي nnCache على رمز تخزين دائم يتيح لبرنامج التشغيل تنفيذ تخزين الترجمة بدون استخدام ميزات تخزين مؤقت في NNAPI. يُعد هذا الشكل من يمكن تنفيذ التخزين المؤقت للتجميع مع أي إصدار من NN HAL. إذا اختار العميل تنفيذ ميزة التخزين المؤقت غير المتصلة بواجهة HAL، يتحمّل العميل مسؤولية تحرير العناصر المخزّنة مؤقتًا عندما لا تكون مطلوبة.