الوصول إلى البيانات للتدقيق

يمكنك الحصول على إحصاءات حول كيفية وصول تطبيقك وتبعياته إلى البيانات الخاصة. من المستخدمين عن طريق إجراء تدقيق الوصول إلى البيانات. تتوفّر هذه العملية على الأجهزة التي تعمل بالإصدار 11 (المستوى 30 لواجهة برمجة التطبيقات) من نظام Android والإصدارات الأحدث، وتتيح لك معرفة بشكل أفضل حالات الوصول إلى البيانات غير المتوقّعة. يمكن لتطبيقك تسجيل مثيل من AppOpsManager.OnOpNotedCallback، والذي يمكنه تنفيذ إجراءات في كل مرة يحدث فيها أحد الأحداث التالية:

يتم استدعاء تدقيق الوصول إلى البيانات في سلسلة المحادثات التي يحصل عليها طلب البيانات الْمَكَانْ. وهذا يعني أنّه إذا كانت حزمة SDK أو مكتبة تابعة لجهة خارجية في تطبيقك تستدعي واجهة برمجة تطبيقات تتمكّن من الوصول إلى البيانات الخاصة، تسمح لك ميزة "تدقيق الوصول إلى البيانات" في OnOpNotedCallback بفحص معلومات عن الطلب. عادة، هذا يمكن لعنصر رد الاتصال معرفة ما إذا كانت المكالمة واردة من تطبيقك أم من حزمة تطوير البرامج (SDK) من خلال الاطّلاع على الحالة الحالية للتطبيق، مثل تتبُّع تسلسل استدعاء الدوال البرمجية لسلسلة المحادثات الحالية.

تسجيل الوصول إلى البيانات

لإجراء تدقيق في الوصول إلى البيانات باستخدام مثيل AppOpsManager.OnOpNotedCallback، نفِّذ منطق الاستدعاء في المكوّن الذي تريد تدقيق الوصول إلى البيانات فيه، مثل ضمن onCreate() طريقة النشاط أو onCreate()طريقة التطبيق.

يحدِّد المقتطف التالي من الرمز البرمجي AppOpsManager.OnOpNotedCallback لتسجيل عمليات الوصول إلى البيانات في نشاط واحد:

KotlinJava
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)
}
@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() في حالات نادرة جدًا عندما يمرر أحد التطبيقات المعرّف الفريد الخاص به إلى noteOp()

تدقيق الوصول إلى البيانات حسب علامة تحديد المصدر

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

لتحديد علامات الإسناد في تطبيقك، أكمِل الخطوات الواردة في القسمين التاليين:

إدراج علامات تحديد المصدر في البيان

إذا كان تطبيقك يستهدف نظام التشغيل Android 12 (المستوى 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()، مع إدخال علامة الإحالة التي تريد ربطها بجزء من تطبيقك.

يوضح مقتطف الرمز التالي كيفية إنشاء علامة إحالة جزء من مشاركة موقع الصورة في التطبيق:

KotlinJava
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.
    }
}
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" لكي يتم حفظ سجلات تطبيقك. أن تتضمّن أسماء علامات تحديد المصدر التي حدّدتها

يعرض مقتطف الرمز التالي المنطق المعدَّل الذي يسجّل علامات الإسناد:

KotlinJava
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)
    }
}
@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);
    }
}