يمكنك الحصول على إحصاءات حول كيفية وصول تطبيقك وتبعياته إلى البيانات الخاصة
للمستخدمين من خلال إجراء تدقيق الوصول إلى البيانات. تتيح لك هذه العملية، المتوفّرة على الأجهزة التي تعمل بالإصدار 11 (المستوى 30 من واجهة برمجة التطبيقات) والإصدارات الأحدث من نظام Android، تحديد حالات الوصول غير المتوقّع إلى البيانات بشكل أفضل. يمكن لتطبيقك تسجيل مثيل من AppOpsManager.OnOpNotedCallback
، والذي يمكنه تنفيذ إجراءات في كل مرة يحدث فيها أحد الأحداث التالية:
- يصل رمز تطبيقك إلى بيانات خاصة. لمساعدتك في تحديد الجزء المنطقي من تطبيقك الذي استدعى الحدث، يمكنك تدقيق الوصول إلى البيانات حسب علامة تحديد المصدر.
- يصل الرمز البرمجي في مكتبة أو حزمة تطوير برامج (SDK) تابعة إلى البيانات الخاصة.
يتم استدعاء التدقيق في الوصول إلى البيانات في سلسلة التعليمات البرمجية التي يتم فيها تنفيذ طلب البيانات. وهذا يعني أنّه إذا كانت حزمة تطوير برامج (SDK) أو مكتبة تابعة لجهة خارجية في تطبيقك تستدعي واجهة برمجة تطبيقات يمكنها الوصول إلى البيانات الخاصة، ستتيح لك ميزة "تدقيق الوصول إلى البيانات" OnOpNotedCallback
فحص المعلومات المتعلقة بهذا الاستدعاء. في العادة، يمكن لكائن معاودة الاتصال هذا تحديد ما إذا كانت المكالمة واردة من تطبيقك أو حزمة SDK من خلال الاطّلاع على حالة التطبيق الحالية، مثل تتبُّع تسلسل استدعاء الدوال البرمجية الحالي.
تسجيل الوصول إلى البيانات
لتنفيذ تدقيق الوصول إلى البيانات باستخدام مثيل من AppOpsManager.OnOpNotedCallback
، عليك تنفيذ منطق معاودة الاتصال في المكوّن الذي تريد تدقيق الوصول إلى البيانات فيه، مثل داخل طريقة onCreate()
الخاصة بنشاط أو طريقة onCreate()
الخاصة بتطبيق.
يحدّد مقتطف الرمز التالي AppOpsManager.OnOpNotedCallback
لتدقيق الوصول إلى البيانات ضمن نشاط واحد:
Kotlin
override fun onCreate(savedInstanceState: Bundle?) { val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() { private fun logPrivateDataAccess(opCode: String, trace: String) { Log.i(MY_APP_TAG, "Private data accessed. " + "Operation: $opCode\nStack Trace:\n$trace") } override fun onNoted(syncNotedAppOp: SyncNotedAppOp) { logPrivateDataAccess( syncNotedAppOp.op, Throwable().stackTrace.toString()) } override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) { logPrivateDataAccess( syncNotedAppOp.op, Throwable().stackTrace.toString()) } override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) { logPrivateDataAccess(asyncNotedAppOp.op, asyncNotedAppOp.message) } } val appOpsManager = getSystemService(AppOpsManager::class.java) as AppOpsManager appOpsManager.setOnOpNotedCallback(mainExecutor, appOpsCallback) }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { AppOpsManager.OnOpNotedCallback appOpsCallback = new AppOpsManager.OnOpNotedCallback() { private void logPrivateDataAccess(String opCode, String trace) { Log.i(MY_APP_TAG, "Private data accessed. " + "Operation: $opCode\nStack Trace:\n$trace"); } @Override public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.getOp(), Arrays.toString(new Throwable().getStackTrace())); } @Override public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.getOp(), Arrays.toString(new Throwable().getStackTrace())); } @Override public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) { logPrivateDataAccess(asyncNotedAppOp.getOp(), asyncNotedAppOp.getMessage()); } }; AppOpsManager appOpsManager = getSystemService(AppOpsManager.class); if (appOpsManager != null) { appOpsManager.setOnOpNotedCallback(getMainExecutor(), appOpsCallback); } }
يتم استدعاء الطريقتَين onAsyncNoted()
وonSelfNoted()
في حالات معيّنة:
يتم استدعاء
onAsyncNoted()
إذا لم يتم الوصول إلى البيانات أثناء طلب واجهة برمجة التطبيقات في تطبيقك. وأكثر الأمثلة شيوعًا هو عندما يسجّل تطبيقك أداة معالجة ويحدث الوصول إلى البيانات في كل مرة يتم فيها استدعاء أداة المعالجة.تحتوي الوسيطة
AsyncNotedOp
التي يتم تمريرها إلىonAsyncNoted()
على طريقة تُسمىgetMessage()
. توفّر هذه الطريقة المزيد من المعلومات حول الوصول إلى البيانات. في حالة عمليات معاودة الاتصال المتعلقة بالموقع الجغرافي، تحتوي الرسالة على قيمة التجزئة الخاصة بمعرّف النظام للمستمع.يتم استدعاء
onSelfNoted()
في حالات نادرة جدًا عندما يمرّر تطبيق معرّف UID الخاص به إلىnoteOp()
.
تدقيق الوصول إلى البيانات حسب علامة تحديد المصدر
قد يتضمّن تطبيقك عدة حالات استخدام أساسية، مثل السماح للمستخدمين بالتقاط الصور ومشاركتها مع جهات الاتصال. إذا كنت تطوّر تطبيقًا متعدد الأغراض، يمكنك تطبيق علامة تحديد المصدر على كل جزء من تطبيقك عند تدقيق إذن الوصول إلى البيانات. يتم عرض سياق attributionTag
مرة أخرى
في العناصر التي تم تمريرها إلى طلبات onNoted()
.
يساعدك ذلك في تتبُّع الوصول إلى البيانات بسهولة أكبر وصولاً إلى الأجزاء المنطقية من الرمز البرمجي.
لتحديد علامات تحديد المصدر في تطبيقك، أكمِل الخطوات الواردة في الأقسام التالية.
تحديد علامات تحديد المصدر في ملف البيان
إذا كان تطبيقك يستهدف الإصدار 12 من نظام التشغيل Android (المستوى 31 من واجهة برمجة التطبيقات) أو الإصدارات الأحدث، عليك تقديم بيان بعلامات تحديد المصدر في ملف البيان الخاص بتطبيقك باستخدام التنسيق الموضّح في مقتطف الرمز التالي. إذا حاولت استخدام علامة تحديد المصدر لم يتم تعريفها في ملف البيان الخاص بتطبيقك، سينشئ النظام علامة null
لك ويسجّل رسالة في Logcat.
<manifest ...> <!-- The value of "android:tag" must be a literal string, and the value of "android:label" must be a resource. The value of "android:label" is user-readable. --> <attribution android:tag="sharePhotos" android:label="@string/share_photos_attribution_label" /> ... </manifest>
إنشاء علامات تحديد المصدر
في طريقة
onCreate()
النشاط الذي يمكنك من خلاله الوصول إلى البيانات، مثل النشاط الذي
تطلب فيه الموقع الجغرافي أو تصل إلى قائمة جهات اتصال المستخدم، استخدِم
createAttributionContext()
،
مع إدخال علامة تحديد المصدر التي تريد ربطها بجزء من
تطبيقك.
يوضّح مقتطف الرمز التالي كيفية إنشاء علامة تحديد مصدر البيانات لجزء من تطبيق يتيح مشاركة الموقع الجغرافي للصور:
Kotlin
class SharePhotoLocationActivity : AppCompatActivity() { lateinit var attributionContext: Context override fun onCreate(savedInstanceState: Bundle?) { attributionContext = createAttributionContext("sharePhotos") } fun getLocation() { val locationManager = attributionContext.getSystemService( LocationManager::class.java) as LocationManager // Use "locationManager" to access device location information. } }
Java
public class SharePhotoLocationActivity extends AppCompatActivity { private Context attributionContext; @Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { attributionContext = createAttributionContext("sharePhotos"); } public void getLocation() { LocationManager locationManager = attributionContext.getSystemService(LocationManager.class); if (locationManager != null) { // Use "locationManager" to access device location information. } } }
تضمين علامات تحديد المصدر في سجلّات الوصول
عدِّل AppOpsManager.OnOpNotedCallback
دالة الرجوع حتى تتضمّن سجلّات تطبيقك أسماء علامات تحديد المصدر التي حدّدتها.
يعرض مقتطف الرمز التالي منطقًا معدَّلاً يسجّل علامات تحديد المصدر:
Kotlin
val appOpsCallback = object : AppOpsManager.OnOpNotedCallback() { private fun logPrivateDataAccess( opCode: String, attributionTag: String, trace: String) { Log.i(MY_APP_TAG, "Private data accessed. " + "Operation: $opCode\n " + "Attribution Tag:$attributionTag\nStack Trace:\n$trace") } override fun onNoted(syncNotedAppOp: SyncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.op, syncNotedAppOp.attributionTag, Throwable().stackTrace.toString()) } override fun onSelfNoted(syncNotedAppOp: SyncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.op, syncNotedAppOp.attributionTag, Throwable().stackTrace.toString()) } override fun onAsyncNoted(asyncNotedAppOp: AsyncNotedAppOp) { logPrivateDataAccess(asyncNotedAppOp.op, asyncNotedAppOp.attributionTag, asyncNotedAppOp.message) } }
Java
@Override public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) { AppOpsManager.OnOpNotedCallback appOpsCallback = new AppOpsManager.OnOpNotedCallback() { private void logPrivateDataAccess(String opCode, String attributionTag, String trace) { Log.i("MY_APP_TAG", "Private data accessed. " + "Operation: $opCode\n " + "Attribution Tag:$attributionTag\nStack Trace:\n$trace"); } @Override public void onNoted(@NonNull SyncNotedAppOp syncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.getOp(), syncNotedAppOp.getAttributionTag(), Arrays.toString(new Throwable().getStackTrace())); } @Override public void onSelfNoted(@NonNull SyncNotedAppOp syncNotedAppOp) { logPrivateDataAccess(syncNotedAppOp.getOp(), syncNotedAppOp.getAttributionTag(), Arrays.toString(new Throwable().getStackTrace())); } @Override public void onAsyncNoted(@NonNull AsyncNotedAppOp asyncNotedAppOp) { logPrivateDataAccess(asyncNotedAppOp.getOp(), asyncNotedAppOp.getAttributionTag(), asyncNotedAppOp.getMessage()); } }; AppOpsManager appOpsManager = getSystemService(AppOpsManager.class); if (appOpsManager != null) { appOpsManager.setNotedAppOpsCollector(appOpsCollector); } }