ডেটা অ্যাক্সেস অডিট করুন

ডেটা অ্যাক্সেস অডিটিং করে, আপনার অ্যাপ এবং এর ডিপেন্ডেন্সি কীভাবে ব্যবহারকারীদের ব্যক্তিগত ডেটা অ্যাক্সেস করে সেই সম্পর্কে আপনি ইনসাইট পেতে পারেন। Android 11 (API লেভেল 30) এবং তার পরবর্তী যেকোনও ভার্সনে রান করা ডিভাইসে উপলভ্য এই প্রসেস, আপনাকে সম্ভাব্য অপ্রত্যাশিত ডেটা অ্যাক্সেস আরও ভালোভাবে শনাক্ত করতে দেয়। আপনার অ্যাপ AppOpsManager.OnOpNotedCallback-এর একটি ইনস্ট্যান্স রেজিস্টার করতে পারে, যা নিম্নলিখিত ইভেন্টগুলির মধ্যে কোনও একটি ঘটলে প্রতিবার অ্যাকশন নিতে পারে:

  • আপনার অ্যাপের কোড ব্যক্তিগত ডেটা অ্যাক্সেস করে। আপনার অ্যাপের কোন লজিক্যাল অংশ ইভেন্টটি চালু করেছে তা নির্ধারণ করতে আপনাকে সাহায্য করার জন্য, আপনি অ্যাট্রিবিউশন ট্যাগ দ্বারা ডেটা অ্যাক্সেস অডিট করতে পারেন।
  • নির্ভরশীল লাইব্রেরি বা SDK-তে থাকা কোড ব্যক্তিগত ডেটা অ্যাক্সেস করে।

যে থ্রেডে ডেটার অনুরোধ করা হয় সেখানে ডেটা অ্যাক্সেস অডিটিং চালু করা হয়। এর অর্থ হল, আপনার অ্যাপে কোনও থার্ড-পার্টি SDK বা লাইব্রেরি যদি ব্যক্তিগত ডেটা অ্যাক্সেস করে এমন কোনও API কল করে, তাহলে ডেটা অ্যাক্সেস অডিটিং আপনার 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)
}

জাভা

@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() কল করা হয় যদি আপনার অ্যাপের API কলের সময় ডেটা অ্যাক্সেস না হয়। সবচেয়ে সাধারণ উদাহরণ হল যখন আপনার অ্যাপ কোনও লিসেনার রেজিস্টার করে এবং লিসেনারের কলব্যাক চালু করার সময় প্রতিবার ডেটা অ্যাক্সেস করা হয়।

    onAsyncNoted()-এ পাস করা AsyncNotedOp আর্গুমেন্টে getMessage() নামের একটি মেথড কল আছে। এই পদ্ধতি ডেটা অ্যাক্সেস সম্পর্কে আরও তথ্য প্রদান করে। লোকেশন কলব্যাকের ক্ষেত্রে, মেসেজে লিসনারের system-identity-hash থাকে।

  • onSelfNoted() খুব বিরল ক্ষেত্রে কল করা হয় যখন কোনও অ্যাপ নিজের UID noteOp()-এ পাস করে।

অ্যাট্রিবিউশন ট্যাগ অনুযায়ী ডেটা অ্যাক্সেস অডিট করা

আপনার অ্যাপের একাধিক প্রাথমিক ব্যবহারের কেস থাকতে পারে, যেমন ব্যবহারকারীদের ফটো তুলতে এবং এই ফটোগুলি তাদের পরিচিতিদের সাথে শেয়ার করতে দেওয়া। আপনি যদি একটি মাল্টি-পারপাস অ্যাপ ডেভেলপ করেন, তাহলে আপনি অ্যাপের প্রতিটি অংশে একটি অ্যাট্রিবিউশন ট্যাগ প্রয়োগ করতে পারেন যখন আপনি এর ডেটা অ্যাক্সেস অডিট করেন। attributionTag কনটেক্সট onNoted()-এ কল করার জন্য পাস করা অবজেক্টে ফেরত পাঠানো হয়। এটি আপনাকে আরও সহজে আপনার কোডের লজিক্যাল অংশে ডেটা অ্যাক্সেস ট্রেস করতে সাহায্য করে।

আপনার অ্যাপে অ্যাট্রিবিউশন ট্যাগ নির্ধারণ করতে, নিম্নলিখিত বিভাগে উল্লেখ করা ধাপগুলি সম্পূর্ণ করুন।

ম্যানিফেস্টে অ্যাট্রিবিউশন ট্যাগ ঘোষণা করুন

আপনার অ্যাপ Android 12 (API লেভেল 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.
    }
}

জাভা

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)
    }
}

জাভা

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