ممیزی دسترسی به داده‌ها

با انجام ممیزی داده‌های دسترسی می‌توانید اطلاعات آماری درباره نحوه دسترسی برنامه‌تان و وابستگی‌های آن به داده‌های خصوصی کاربران به‌دست آورید. این فرایند که در دستگاه‌های دارای Android 11 (سطح API‏ ۳۰) و بالاتر دردسترس است، به شما امکان می‌دهد دسترسی به داده‌های بالقوه غیرمنتظره را بهتر شناسایی کنید. برنامه شما می‌تواند نمونه‌ای از AppOpsManager.OnOpNotedCallback را ثبت کند که می‌تواند هر بار که یکی از رویدادهای زیر رخ می‌دهد، کنش‌هایی را انجام دهد:

  • کد برنامه‌تان به داده‌های خصوصی دسترسی دارد. برای کمک به شما در تعیین اینکه کدام بخش منطقی برنامه‌تان رویداد را فراخوانی کرده است، می‌توانید دسترسی به داده‌ها را براساس برچسب ارجاع حسابرسی کنید.
  • کد موجود در کتابخانه وابسته یا کیت توسعه نرم‌افزار به داده‌های خصوصی دسترسی دارد.

ممیزی دسترسی به داده‌ها در رشته‌ای که درخواست داده در آن انجام می‌شود فراخوانی می‌شود. این یعنی اگر کیت توسعه نرم‌افزار یا کتابخانه شخص ثالثی در برنامه‌تان میانای برنامه‌سازی کاربردی‌ای را فراخوانی کند که به داده‌های خصوصی دسترسی دارد، ممیزی دسترسی به داده‌ها به OnOpNotedCallback شما امکان می‌دهد اطلاعات مربوط به فراخوانی را بررسی کنید. معمولاً این شیء فراخوانی برگشتی می‌تواند با بررسی وضعیت فعلی برنامه، مثلاً ردیابی پشته رشته فعلی، تشخیص دهد که فراخوانی از برنامه شما بوده است یا کیت توسعه نرم‌افزار.

ثبت دسترسی به داده‌ها

برای انجام ممیزی دسترسی به داده‌ها بااستفاده از نمونه‌ای از AppOpsManager.OnOpNotedCallback، منطق فراخوانی را در مؤلفه‌ای که قصد دارید دسترسی به داده‌ها را ممیزی کنید پیاده‌سازی کنید، مثلاً در روش onCreate() فعالیت یا روش onCreate() برنامه.

تکه‌کد زیر یک AppOpsManager.OnOpNotedCallback را برای حسابرسی دسترسی به داده‌ها در یک فعالیت واحد تعریف می‌کند:

کاتلین

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() را فراخوانی کنید و برچسب ارجاعی را که می‌خواهید با بخشی از برنامه‌تان مرتبط شود ارسال کنید.

تکه‌کد زیر نشان می‌دهد که چگونه می‌توان برچسب ارجاعی برای بخش هم‌رسانی مکان عکس در برنامه ایجاد کرد:

کاتلین

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 را به‌روز کنید تا گزارش‌های برنامه‌تان شامل نام برچسب‌های ارجاعی باشد که تعریف کرده‌اید.

تکه‌کد زیر منطق به‌روزشده‌ای را نشان می‌دهد که برچسب‌های ارجاع را ثبت می‌کند:

کاتلین

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.setOnOpNotedCallback(getMainExecutor(), appOpsCallback);
    }
}