بدءًا من Android 10، توفّر واجهة برمجة التطبيقات Neural Networks API (NNAPI)
وظائف تتيح
تخزين نتائج الترجمة مؤقتًا، ما يقلّل من الوقت المستغرَق في الترجمة
عند بدء تشغيل أحد التطبيقات. باستخدام وظيفة التخزين المؤقت هذه، لن يحتاج برنامج التشغيل إلى إدارة الملفات المخزّنة مؤقتًا أو تنظيفها. هذه ميزة اختيارية يمكن تنفيذها باستخدام NN HAL 1.2. لمزيد من المعلومات حول هذه الدالة، يُرجى الاطّلاع على ANeuralNetworksCompilation_setCaching
.
يمكن للسائق أيضًا تنفيذ التخزين المؤقت للتجميع بشكل مستقل عن NNAPI. ويمكن تنفيذ ذلك سواء تم استخدام ميزتَي التخزين المؤقت في NNAPI NDK وHAL أم لا. يوفر مشروع AOSP مكتبة أدوات مساعدة منخفضة المستوى (محرك تخزين مؤقت). لمزيد من المعلومات، يُرجى الاطّلاع على تنفيذ محرك تخزين مؤقت.
نظرة عامة على سير العمل
يوضّح هذا القسم سير العمل العام مع تفعيل ميزة التخزين المؤقت للتجميع.
تم تقديم معلومات ذاكرة التخزين المؤقت وتم العثور على تطابق في ذاكرة التخزين المؤقت
- يمرِّر التطبيق دليل تخزين مؤقت ومجموعًا اختباريًا فريدًا للطراز.
- يبحث وقت تشغيل NNAPI عن ملفات ذاكرة التخزين المؤقت استنادًا إلى المجموع الاختباري، وإعدادات التنفيذ المفضّلة، ونتيجة التقسيم، ثم يعثر على الملفات.
- تفتح واجهة برمجة التطبيقات NNAPI ملفات ذاكرة التخزين المؤقت وتمرّر المقابض إلى برنامج التشغيل باستخدام
prepareModelFromCache
. - يُعدّ برنامج التشغيل النموذج مباشرةً من ملفات ذاكرة التخزين المؤقت ويعرض النموذج المُعدّ.
تم تقديم معلومات ذاكرة التخزين المؤقت ولم يتم العثور على البيانات المطلوبة
- أن يجتاز التطبيق عملية التحقّق من المجموع الاختباري الفريد الخاص بالطراز ودليل التخزين المؤقت.
- يبحث وقت تشغيل NNAPI عن ملفات التخزين المؤقت استنادًا إلى المجموع الاختباري والإعداد المفضّل للتنفيذ ونتيجة التقسيم، ولا يعثر على ملفات التخزين المؤقت.
- تنشئ واجهة برمجة التطبيقات NNAPI ملفات ذاكرة تخزين مؤقت فارغة استنادًا إلى المجموع الاختباري، وإعدادات التنفيذ المفضّلة، والتقسيم، وتفتح ملفات ذاكرة التخزين المؤقت، وتمرِّر المقابض والنموذج إلى برنامج التشغيل باستخدام
prepareModel_1_2
. - يجمع برنامج التشغيل النموذج ويكتب معلومات التخزين المؤقت في ملفات التخزين المؤقت، ثم يعرض النموذج المُعدّ.
لم يتم تقديم معلومات عن ذاكرة التخزين المؤقت
- يطلب التطبيق إجراء عملية تجميع بدون تقديم أي معلومات تخزين مؤقت.
- لا يمرّر التطبيق أي بيانات ذات صلة بالتخزين المؤقت.
- يمرّر وقت تشغيل NNAPI النموذج إلى برنامج التشغيل باستخدام
prepareModel_1_2
. - يجمع برنامج التشغيل النموذج ويعرض النموذج المُعدّ.
معلومات ذاكرة التخزين المؤقت
تتألف معلومات التخزين المؤقت المقدَّمة إلى برنامج التشغيل من رمز مميز ومقابض ملفات التخزين المؤقت.
الرمز المميز
الرمز المميز هو رمز مميز للتخزين المؤقت يبلغ طوله 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، يكون برنامج التشغيل مسؤولاً عن تحرير العناصر المخزَّنة مؤقتًا عندما لا تكون هناك حاجة إليها.