تم تصميم ميزة "التخصيص على الجهاز فقط" لحماية معلومات المستخدمين النهائيين من التطبيقات. تستخدم التطبيقات واجهة برمجة التطبيقات ODP لتخصيص منتجاتها وخدماتها للمستخدمين النهائيين، ولكن لن يتمكّنوا من الاطّلاع على عمليات التخصيص الدقيقة التي تم إجراؤها للمستخدم (ما لم تكن هناك تفاعلات مباشرة خارج واجهة برمجة التطبيقات ODP بين التطبيق والمستخدم النهائي). بالنسبة إلى التطبيقات التي تتضمّن نماذج تعلُّم آلي أو تحليلات إحصائية، يوفّر "إطار عمل الخصوصية الفاضلة" مجموعة من الخدمات والخوارزميات لضمان إخفاء هوية المستخدمين بشكل صحيح باستخدام آليات الخصوصية الفاضلة المناسبة. لمزيد من التفاصيل، يُرجى الاطّلاع على الشرح المفصّل عن التخصيص على الجهاز.
تُشغِّل ميزة "الوصول إلى البيانات على الجهاز فقط" رمز المطوّر في IsolatedProcess
لا يمكنه الوصول مباشرةً إلى الشبكة أو الأقراص المحلية أو الخدمات الأخرى التي تعمل على الجهاز، ولكن يمكنه الوصول إلى مصادر البيانات الثابتة التالية على الجهاز:
RemoteData
- بيانات مفاتيح القيمة غير القابلة للتغيير التي تم تنزيلها من الخلفيات البعيدة التي يديرها المطوّرون، إن أمكن.-
LocalData
: بيانات متغيرة من النوع "مفتاح/قيمة" يحفظها المطوّر محليًا، إن أمكن. UserData
- بيانات المستخدم المقدَّمة من المنصة
تتوفّر النتائج التالية:
- النتائج الثابتة: يمكن استخدام هذه النتائج في عمليات المعالجة المحلية المستقبلية، أو لإنشاء نتائج معروضة، أو تسهيل تدريب النماذج من خلال "التعلم الموحّد"، أو تسهيل التحليل الإحصائي على جميع الأجهزة من خلال "الإحصاءات الموحّدة".
- الإخراج المعروض:
- يمكن للمطوّرين عرض محتوى HTML يعرضه ODP في
WebView
داخلSurfaceView
. ولن يظهر المحتوى المعروض هناك للتطبيق الذي بدأ عملية الربط. - يمكن للمطوّرين تضمين عناوين URL للأحداث المقدَّمة من ODP في إخراج HTML لبدء تسجيل تفاعلات المستخدمين مع HTML المعروض ومعالجتها. يعترض ODP الطلبات الموجَّهة إلى عناوين URL هذه ويُشغّل الرمز لإنشاء البيانات التي يتم كتابتها في جدول
EVENTS
.
- يمكن للمطوّرين عرض محتوى HTML يعرضه ODP في
يمكن للتطبيقات العميلة وحِزم تطوير البرامج (SDK) استدعاء ODP لعرض محتوى HTML في SurfaceView
باستخدام واجهات برمجة التطبيقات ODP. لا يظهر المحتوى المعروض في SurfaceView
للتطبيق المُرسِل. يمكن أن يكون تطبيق العميل أو حزمة تطوير البرامج (SDK) كيانًا مختلفًا عن الكيان الذي يتم تطويره باستخدام ODP.
تدير خدمة ODP تطبيق العميل الذي يريد استدعاء ODP لعرض محتوى مخصّص ضمن واجهة المستخدم. ويتم تنزيل المحتوى من نقاط النهاية التي يقدّمها المطوّر، كما يتمّ استدعاء منطق لمعالجة البيانات التي تم تنزيلها بعد ذلك. وتتوسّط هذه الخدمة أيضًا في جميع المراسلات بين IsolatedProcess
والخدمات والتطبيقات الأخرى.
تستخدم تطبيقات العميل طرقًا في فئة OnDevicePersonalizationManager
للتفاعل مع رمز المطوّر الذي يتم تشغيله في IsolatedProcess
. تُوسّع التعليمات البرمجية للمطوّر التي تعمل في IsolatedProcess
فئة IsolatedService
وتنفّذ واجهة IsolatedWorker
. يجب أن ينشئ IsolatedService
مثيلًا من IsolatedWorker
لكل طلب.
يوضّح الرسم البياني التالي العلاقة بين الطريقتَين في OnDevicePersonalizationManager
وIsolatedWorker
.
OnDevicePersonalizationManager
وIsolatedWorker
يطلب تطبيق العميل ODP باستخدام طريقة execute
مع IsolatedService
مُسمّى. تعيد خدمة ODP توجيه الطلب إلى طريقة onExecute
في IsolatedWorker
. يعرض IsolatedWorker
السجلّات التي يجب الاحتفاظ بها والمحتوى الذي يجب عرضه. تُسجِّل خدمة ODP الإخراج الدائم في جدول REQUESTS
أو EVENTS
، وتُرجع مرجعًا غير شفاف إلى الإخراج المعروض لتطبيق العميل. ويمكن لتطبيق العميل استخدام هذا المرجع غير الشفاف في طلب requestSurfacePackage
مستقبلي لعرض أيّ من محتوى العرض ضمن واجهة المستخدم.
الإخراج الثابت
تُحفظ خدمة ODP لسجلّ في جدول REQUESTS
بعد تنفيذ المطوّر لـ onExecute
. يحتوي كل سجلّ في جدول REQUESTS
على بعض البيانات الشائعة لكل طلب تنشئها خدمة ODP، وقائمة بقيم Rows
التي تم عرضها. يحتوي كل Row
على قائمة بأزواج (key, value)
. كل قيمة هي عددية أو سلسلة أو ملف نصي. يمكن الإبلاغ عن القيم الرقمية بعد التجميع، ويمكن الإبلاغ عن بيانات السلسلة أو البيانات غير القابلة للتغيير بعد تطبيق "الخصوصية التفاضلية" المحلية أو المركزية. يمكن للمطوّرين أيضًا كتابة أحداث تفاعل المستخدِم اللاحقة في جدول EVENTS
، ويرتبط كلّ سجلّ في جدول EVENTS
بصف في جدول REQUESTS
. تسجِّل خدمة ODP بشكلٍ شفاف طابعًا زمنيًا واسم حزمة التطبيق المُرسِل وحزمة APK لمطوّر ODP مع كل سجلّ.
قبل البدء
قبل بدء التطوير باستخدام ODP، عليك إعداد بيان الحزمة وتفعيل وضع المطوّر.
إعدادات بيان الحزمة
لاستخدام ODP، يجب استيفاء المتطلبات التالية:
- علامة
<property>
فيAndroidManifest.xml
تشير إلى مورد XML في الحزمة يحتوي على معلومات إعدادات ODP - علامة
<service>
فيAndroidManifest.xml
لتحديد الفئة التي تمتد إلىIsolatedService
، كما هو موضّح في المثال التالي يجب ضبط السمتَينexported
وisolatedProcess
في الخدمة ضمن علامة<service>
علىtrue
. - علامة
<service>
في مورد XML المحدّد في الخطوة 1 والتي تحدّد فئة الخدمة من الخطوة 2 يجب أن تتضمّن علامة<service>
أيضًا إعدادات إضافية خاصة بـ ODP داخل العلامة نفسها، كما هو موضّح في المثال الثاني.
AndroidManifest.xml
<!-- Contents of AndroidManifest.xml -->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.odpsample" >
<application android:label="OdpSample">
<!-- XML resource that contains other ODP settings. -->
<property android:name="android.ondevicepersonalization.ON_DEVICE_PERSONALIZATION_CONFIG"
android:resource="@xml/OdpSettings"></property>
<!-- The service that ODP binds to. -->
<service android:name="com.example.odpsample.SampleService"
android:exported="true" android:isolatedProcess="true" />
</application>
</manifest>
ملف البيان الخاص بتنسيق ODP في ملف XML
يجب أن يُعلن ملف موارد XML المحدّد في علامة <property>
أيضًا عن فئة الخدمة في علامة <service>
، وأن يحدّد نقطة نهاية عنوان URL التي ستنزِّل منها خدمة ODP المحتوى لتعبئة جدول RemoteData
، كما هو موضّح في المثال التالي. إذا كنت تستخدم ميزات الحوسبة الموحّدة، عليك أيضًا تحديد نقطة نهاية عنوان URL لخادم الحوسبة الموحّدة التي سيتصل بها برنامج "عميل الحوسبة الموحّدة".
<!-- Contents of res/xml/OdpSettings.xml -->
<on-device-personalization>
<!-- Name of the service subclass -->
<service name="com.example.odpsample.SampleService">
<!-- If this tag is present, ODP will periodically poll this URL and
download content to populate REMOTE_DATA. Developers that do not need to
download content from their servers can skip this tag. -->
<download-settings url="https://example.com/get" />
<!-- If you want to use federated compute feature to train a model, you
need to specify this tag. -->
<federated-compute-settings url="https://fcpserver.example.com/" />
</service>
</on-device-personalization>
تفعيل "وضع المطوّر"
فعِّل وضع المطوّر باتّباع التعليمات الواردة في قسم تفعيل خيارات المطوّرين ضمن مستندات Android Studio.
إعدادات التبديل والإبلاغ
يحتوي ODP على مجموعة من المفاتيح والعلامات التي تُستخدَم للتحكّم في وظائف معيّنة:
- _global_killswitch: مفتاح التبديل العام لجميع ميزات ODP، يتم ضبطه على false لاستخدام ODP
- _federated_compute_kill_switch: _التبديل الذي يتحكّم في جميع وظائف التدريب (التعلم الموحّد) في ODP، ويتم ضبطه على false لاستخدام التدريب
- _caller_app_allowlist: للتحكّم في المستخدمين المسموح لهم بالاتصال بـ ODP، يمكن إضافة التطبيقات (اسم الحزمة، الشهادة [اختيارية]) هنا أو ضبطها على * للسماح للجميع
- _isolated_service_allowlist: تتحكّم في الخدمات التي يمكن تشغيلها في عملية "الخدمة المعزولة".
يمكنك تنفيذ الأوامر التالية لضبط جميع مفاتيح التبديل والعلامات لاستخدام ODP بدون قيود:
# Set flags and killswitches
adb shell device_config set_sync_disabled_for_tests persistent
adb shell device_config put on_device_personalization global_kill_switch false
adb shell device_config put on_device_personalization federated_compute_kill_switch false
adb shell device_config put on_device_personalization caller_app_allow_list \"*\"
adb shell device_config put on_device_personalization isolated_service_allow_list \"*\"
واجهات برمجة التطبيقات على الجهاز
اطّلِع على المستندات المرجعية لواجهة برمجة التطبيقات Android المتعلّقة بتنسيق ODP.
التفاعلات مع IsolatedService
فئة IsolatedService
هي فئة أساسية مجردة يجب أن ينشئها جميع المطوّرين الذين يريدون تطوير التطبيقات باستخدام ODP، ويجب أن يُعلنوا في بيان الحزمة أنّها تعمل في عملية معزولة. تبدأ خدمة ODP هذه الخدمة في عملية معزولة وتقدّم طلبات إليها. يتلقّى IsolatedService
طلبات من خدمة ODP وينشئ IsolatedWorker
لمعالجة الطلب.
على المطوّرين تنفيذ الطرق من واجهة IsolatedWorker
لمعالجة طلبات تطبيقات العميل وإكمال عمليات التنزيل والأحداث التي تسبّب فيها تنسيق HTML المعروض. تتضمّن جميع هذه الطرق عمليات تنفيذ تلقائية لا تؤدي إلى أي إجراء، ما يتيح للمطوّرين تخطّي تنفيذ الطرق التي لا تهمّهم.
توفّر فئة OnDevicePersonalizationManager
واجهة برمجة تطبيقات للتطبيقات وحِزم SDK للتفاعل مع IsolatedService
من تنفيذ المطوّر ويتم تشغيله في عملية معزولة. في ما يلي بعض حالات الاستخدام المقصودة:
إنشاء محتوى HTML لعرضه في SurfaceView
لإنشاء محتوى لعرضه، يمكن للتطبيق المُرسِل استخدام عنصر SurfacePackageToken
الذي تم إرجاعه في طلب requestSurfacePackage
لاحق لطلب عرض النتيجة في SurfaceView
باستخدام OnDevicePersonalizationManager#execute
.
عند اكتمال العملية بنجاح، يتم استدعاء المستلِم باستخدام SurfacePackage
لعرض يعرضه محرّك بحث ODP. يجب أن تُدرِج تطبيقات العميل SurfacePackage
في SurfaceView
ضمن التسلسل الهرمي لعرضها.
عندما يُجري تطبيق طلبًا إلى requestSurfacePackage
باستخدام SurfacePackageToken
تم إرجاعه من طلب OnDevicePersonalizationManager#execute
سابق، يُجري تطبيق ODP طلبًا إلى IsolatedWorker#onRender
لجلب مقتطف HTML الذي سيتم عرضه داخل إطار محدود. لا يمكن للمطوّر الوصول إلى LocalData
أو UserData
خلال هذه المرحلة. ويمنع ذلك المطوّر من تضمين UserData
يُحتمل أن يكون حسّاسًا ضمن عناوين URL لطلب جلب مواد العرض في ملف HTML الذي تم إنشاؤه. يمكن للمطوّرين استخدام IsolatedService#getEventUrlProvider
لإنشاء عناوين URL للتتبّع لتضمينها في رمز HTML الذي تم إنشاؤه. عند عرض صفحات HTML، ستعترض خدمة ODP الطلبات الموجَّهة إلى عناوين URL هذه وستتصل بخدمة IsolatedWorker#onEvent
. يمكن استدعاء getRemoteData()
عند تنفيذ onRender()
.
تتبُّع الأحداث ضمن محتوى HTML
توفّر فئة EventUrlProvider
واجهات برمجة تطبيقات لإنشاء عناوين URL لتتبُّع الأحداث التي يمكن للمطوّرين تضمينها في إخراج HTML. عند عرض صفحات HTML، سيستدعي ODP IsolatedWorker#onEvent
مع الحمولة من عنوان URL للحدث.
تعترض خدمة ODP طلبات عناوين URL للأحداث التي أنشأتها ODP ضمن رمز HTML المعروض، وتستدعي IsolatedWorker#onEvent
وتسجّل EventLogRecord
المعروض في جدول EVENTS
.
كتابة نتائج دائمة
باستخدام OnDevicePersonalizationManager#execute
، تتوفّر للخدمة خيارات لكتابة البيانات في مساحة تخزين دائمة (جداول REQUESTS
وEVENTS
). في ما يلي الإدخالات التي يمكن كتابتها في هذه الجداول:
RequestLogRecord
ليتمّت إضافتها إلى جدولREQUESTS
- قائمة بعناصر
EventLogRecord
المطلوب إضافتها إلى جدولEVENTS
، وكلّ منها يحتوي على مؤشر إلىRequestLogRecord
سبق أن تمّ كتابته
يمكن أن تستخدم تقنية "التعلّم الموحّد" النتائج الثابتة في مساحة التخزين على الجهاز لتدريب النماذج.
إدارة مهام التدريب على الجهاز
تستدعي خدمة ODP IsolatedWorker#onTrainingExample
عند بدء مهمة تدريب الحوسبة الموحّدة وتريد الحصول على أمثلة تدريبية يوفّرها المطوّرون الذين يتّبعون ODP. يمكنك استدعاء getRemoteData()
وgetLocalData()
وgetUserData()
وgetLogReader()
عند تنفيذ onTrainingExample()
.
لجدولة مهام الحوسبة الموحّدة أو إلغائها، يمكنك استخدام فئة FederatedComputeScheduler
التي توفّر واجهات برمجة تطبيقات لجميع IsolatedService
ODP. يمكن تحديد كل وظيفة حساب موحّد باستخدام اسم قاعدة البيانات.
قبل جدولة مهمة جديدة للحوسبة الموحّدة:
- من المفترض أن تكون قد تمّت إنشاء مهمة باسم هذه المجموعة على خادم الحوسبة الموحّد عن بُعد.
- يجب أن تكون نقطة نهاية عنوان URL لخادم الحوسبة الموحّد قد تم تحديدها مسبقًا في إعدادات بيان الحزمة باستخدام العلامة
federated-compute-settings
.
التفاعلات مع الإخراج الدائم
يوضّح القسم التالي كيفية التفاعل مع الإخراج الدائم في ODP.
قراءة الجداول المحلية
توفّر فئة LogReader
واجهات برمجة تطبيقات لقراءة جدولَي REQUESTS
وEVENTS
. تحتوي هذه الجداول على بيانات كتبها IsolatedService
أثناء مكالمات onExecute()
أو onEvent()
. يمكن استخدام البيانات الواردة في هذه الجداول لتدريب النماذج التي تسهّل ميزة "التعلّم التعاوني" أو التحليل الإحصائي على جميع الأجهزة الذي تسهّله ميزة "إحصاءات Google".
التفاعلات مع المحتوى الذي تم تنزيله
يوضّح القسم التالي كيفية التفاعل مع المحتوى الذي تم تنزيله في ODP.
تنزيل المحتوى من الخوادم
تعمل خدمة ODP على تنزيل المحتوى بشكل دوري من عنوان URL المحدَّد في بيان حِزمة IsolatedService
، وتستدعي onDownloadCompleted
بعد انتهاء عملية التنزيل. الملف الذي يتم تنزيله هو ملف JSON يحتوي على أزواج مفاتيح وقيم.
يمكن للمطوّرين الذين يستخدمون ODP اختيار المجموعة الفرعية من المحتوى الذي تم تنزيله والتي يجب إضافتها إلى جدول RemoteData
والمجموعة التي يجب حذفها. لا يمكن للمطوّرين تعديل المحتوى الذي تم تنزيله، ما يضمن عدم احتواء جدول RemoteData
على أي بيانات مستخدمين. بالإضافة إلى ذلك، يمكن للمطوّرين تعبئة جدول LocalData
بالطريقة التي يختارونها، على سبيل المثال، يمكنهم تخزين بعض النتائج المحسوبة مسبقًا في ذاكرة التخزين المؤقت.
تنسيق طلب التنزيل
يُجري "الدليل الوصفي للتطبيقات" استطلاعات دورية لنقطة نهاية عنوان URL المحدّدة في بيان حِزمة المطوّر لجلب المحتوى لملء جدول RemoteData
.
من المتوقّع أن تعرض نقطة النهاية استجابة JSON كما هو موضّح لاحقًا. يجب أن يحتوي ردّ JSON على syncToken
يحدِّد إصدار البيانات التي يتم إرسالها، بالإضافة إلى قائمة بأزواج المفتاح والقيمة المطلوب تعبئتها. يجب أن تكون قيمة syncToken
طابعًا زمنيًا بالثواني، ويتم ضبطها على حدود ساعة بالتوقيت العالمي المتفق عليه. كجزء من طلب التنزيل، يوفّر ODP syncToken
للتنزيل المكتمل سابقًا والبلد الذي يقع فيه الجهاز كمَعلمتَي syncToken وcountry في عنوان URL للتنزيل. يمكن للخادم استخدام syncToken
السابق لتنفيذ عمليات التنزيل المتزايدة.
تنسيق الملف الذي يتم تنزيله
الملف الذي يتم تنزيله هو ملف JSON بالتنسيق التالي. من المتوقّع أن يحتوي ملف JSON على رمز مميّز للتزامن لتحديد إصدار البيانات التي يتم تنزيلها. يجب أن يكون syncToken طابعًا زمنيًا بالتوقيت العالمي المتفق عليه تم ضبطه على حدود ساعة، ويجب أن يكون أكبر من syncToken للتنزيل السابق. إذا لم يستوفِ syncToken كلا الشرطَين، يتم تجاهل المحتوى الذي تم تنزيله بدون معالجته.
حقل المحتوى هو قائمة بمجموعات (المفتاح، البيانات، الترميز). من المفترض أن تكون key
سلسلة UTF-8. حقل encoding
هو مَعلمة اختيارية تحدّد كيفية ترميز حقل data
، ويمكن ضبطه على "utf8" أو "base64"، ويُفترض أن يكون "utf8" تلقائيًا. يتم تحويل الحقل key
إلى عنصر String
ويتم تحويل الحقل data
إلى صفيف بايت قبل استدعاء onDownloadCompleted().
.
{
// syncToken must be a UTC timestamp clamped to an hour boundary, and must be
// greater than the syncToken of the previously completed download.
"syncToken": <timeStampInSecRoundedToUtcHour>,
"contents": [
// List of { key, data } pairs.
{ "key": "key1",
"data": "data1"
},
{ "key": "key2",
"data": "data2",
"encoding": "base64"
},
// ...
]
}
واجهات برمجة التطبيقات من جهة الخادم
يصف هذا القسم كيفية التفاعل مع واجهات برمجة تطبيقات خادم الحوسبة الموحّد.
واجهات برمجة تطبيقات Federated Compute Server
لجدولة وظيفة حساب موحّد على جانب العميل، تحتاج إلى مهمة تحمل اسم قاعدة بيانات تم إنشاؤها على خادم الحساب الموحّد عن بُعد. في هذا القسم، نتناول كيفية إنشاء مهمة كهذه على خادم الحوسبة الموحّد.
عند إنشاء مهمة جديدة لأداة "إنشاء المهام"، على مطوّري التطبيقات التي تستخدم تنسيق ODP تقديم مجموعتَين من الملفات:
- نموذج tff.learning.models.FunctionalModel محفوظ من خلال طلب بيانات واجهة برمجة التطبيقات tff.learning.models.save_functional_model يمكنك العثور على نموذج واحد في مستودع GitHub.
- ملف fcp_server_config.json الذي يتضمّن السياسات وإعداد التعلّم الموحّد وإعداد الخصوصية التفاضلية في ما يلي مثال على ملف fcp_server_config.json:
{
# Task execution mode.
mode: TRAINING_AND_EVAL
# Identifies the set of client devices that participate.
population_name: "mnist_cnn_task"
policies {
# Policy for sampling on-device examples. It is checked every
# time a device is attempting to start a new training.
min_separation_policy {
# The minimum separation required between two successful
# consective task executions. If a client successfully contributes
# to a task at index `x`, the earliest they can contribute again
# is at index `(x + minimum_separation)`. This is required by
# DP.
minimum_separation: 1
}
data_availability_policy {
# The minimum number of examples on a device to be considered
# eligible for training.
min_example_count: 1
}
# Policy for releasing training results to developers adopting ODP.
model_release_policy {
# The maximum number of training rounds.
num_max_training_rounds: 512
}
}
# Federated learning setups. They are applied inside Task Builder.
federated_learning {
# Use federated averaging to build federated learning process.
# Options you can choose:
# * FED_AVG: Federated Averaging algorithm
# (https://arxiv.org/abs/2003.00295)
# * FED_SGD: Federated SGD algorithm
# (https://arxiv.org/abs/1602.05629)
type: FED_AVG
learning_process {
# Optimizer used at client side training. Options you can choose:
# * ADAM
# * SGD
client_optimizer: SGD
# Learning rate used at client side training.
client_learning_rate: 0.02
# Optimizer used at server side training. Options you can choose:
# * ADAM
# * SGD
server_optimizer: SGD
# Learning rate used at server side training.
server_learning_rate: 1.0
runtime_config {
# Number of participating devices for each round of training.
report_goal: 2
}
metrics {
name: "sparse_categorical_accuracy"
}
}
evaluation {
# A checkpoint selector controls how checkpoints are chosen for
# evaluation. One evaluation task typically runs per training
# task, and on each round of execution, the eval task
# randomly picks one checkpoint from the past 24 hours that has
# been selected for evaluation by these rules.
# Every_k_round and every_k_hour are definitions of quantization
# buckets which each checkpoint is placed in for selection.
checkpoint_selector: "every_1_round"
# The percentage of a populate that should delicate to this
# evaluation task.
evaluation_traffic: 0.2
# Number of participating devices for each round of evaluation.
report_goal: 2
}
}
# Differential Privacy setups. They are enforced inside the Task
# Builder.
differential_privacy {
# * fixed_gaussian: DP-SGD with fixed clipping norm described in
# "Learning Differentially Private Recurrent
# Language Models"
# (https://arxiv.org/abs/1710.06963).
type: FIXED_GAUSSIAN
# The value of the clipping norm.
clip_norm: 0.1
# Noise multiplier for the Gaussian noise.
noise_multiplier: 0.1
}
}
يمكنك العثور على مزيد من العيّنات في مستودع GitHub.
بعد إعداد هذين المدخلَين، استخدِم "أداة إنشاء المهام" لإنشاء عناصر وإنشاء مهام جديدة. تتوفّر تعليمات أكثر تفصيلاً في مستودع GitHub.