ডেটা অ্যাক্সেস অডিটিং করার মাধ্যমে আপনি জানতে পারবেন আপনার অ্যাপ এবং এর ডিপেন্ডেন্সিগুলো কীভাবে ব্যবহারকারীদের ব্যক্তিগত ডেটা অ্যাক্সেস করে। অ্যান্ড্রয়েড ১১ (এপিআই লেভেল ৩০) এবং তার উপরের সংস্করণে চালিত ডিভাইসগুলোতে উপলব্ধ এই প্রক্রিয়াটি আপনাকে সম্ভাব্য অপ্রত্যাশিত ডেটা অ্যাক্সেস আরও ভালোভাবে শনাক্ত করতে সাহায্য করে। আপনার অ্যাপ AppOpsManager.OnOpNotedCallback এর একটি ইনস্ট্যান্স রেজিস্টার করতে পারে, যা নিম্নলিখিত ইভেন্টগুলোর যেকোনো একটি ঘটলে কিছু অ্যাকশন সম্পাদন করতে পারে:
- আপনার অ্যাপের কোড ব্যক্তিগত ডেটা অ্যাক্সেস করে। আপনার অ্যাপের কোন যৌক্তিক অংশ ইভেন্টটি চালু করেছে তা নির্ধারণ করতে, আপনি অ্যাট্রিবিউশন ট্যাগ ব্যবহার করে ডেটা অ্যাক্সেস নিরীক্ষা করতে পারেন।
- নির্ভরশীল লাইব্রেরি বা এসডিকে-র কোড ব্যক্তিগত ডেটা অ্যাক্সেস করে।
যে থ্রেডে ডেটার জন্য অনুরোধ করা হয়, সেখানেই ডেটা অ্যাক্সেস অডিটিং চালু করা হয়। এর মানে হলো, যদি আপনার অ্যাপের কোনো থার্ড-পার্টি SDK বা লাইব্রেরি এমন কোনো API কল করে যা ব্যক্তিগত ডেটা অ্যাক্সেস করে, তাহলে ডেটা অ্যাক্সেস অডিটিং আপনার OnOpNotedCallback সেই কল সম্পর্কিত তথ্য পরীক্ষা করার সুযোগ দেয়। সাধারণত, এই কলব্যাক অবজেক্টটি অ্যাপের বর্তমান স্ট্যাটাস, যেমন বর্তমান থ্রেডের স্ট্যাক ট্রেস দেখে, কলটি আপনার অ্যাপ থেকে এসেছে নাকি SDK থেকে এসেছে তা বলে দিতে পারে।
ডেটার লগ অ্যাক্সেস
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()কল করা হয়। এর সবচেয়ে সাধারণ উদাহরণ হলো, যখন আপনার অ্যাপ একটি লিসেনার রেজিস্টার করে এবং প্রতিবার লিসেনারের কলব্যাক কল করার সময় ডেটা অ্যাক্সেস ঘটে।onAsyncNoted()ফাংশনে পাস করাAsyncNotedOpআর্গুমেন্টটিতেgetMessage()নামে একটি মেথড থাকে। এই মেথডটি ডেটা অ্যাক্সেস সম্পর্কে আরও তথ্য প্রদান করে। লোকেশন কলব্যাকের ক্ষেত্রে, মেসেজটিতে লিসেনারের সিস্টেম-আইডেন্টিটি-হ্যাশ থাকে।খুবই বিরল ক্ষেত্রে যখন কোনো অ্যাপ
noteOp()ফাংশনে তার নিজের UID পাস করে, তখনonSelfNoted()কল করা হয়।
অ্যাট্রিবিউশন ট্যাগ দ্বারা অডিট ডেটা অ্যাক্সেস
আপনার অ্যাপের কয়েকটি প্রধান ব্যবহার থাকতে পারে, যেমন ব্যবহারকারীদের ছবি তুলতে দেওয়া এবং সেই ছবিগুলো তাদের পরিচিতদের সাথে শেয়ার করা। আপনি যদি একটি বহুমুখী অ্যাপ তৈরি করেন, তবে এর ডেটা অ্যাক্সেস নিরীক্ষা করার সময় আপনার অ্যাপের প্রতিটি অংশে একটি অ্যাট্রিবিউশন ট্যাগ প্রয়োগ করতে পারেন। onNoted() কলে পাঠানো অবজেক্টগুলোর মধ্যে attributionTag কনটেক্সটটি ফেরত আসে। এটি আপনাকে আপনার কোডের যৌক্তিক অংশ পর্যন্ত ডেটা অ্যাক্সেস আরও সহজে খুঁজে বের করতে সাহায্য করে।
আপনার অ্যাপে অ্যাট্রিবিউশন ট্যাগ নির্ধারণ করতে, নিম্নলিখিত বিভাগগুলিতে দেওয়া ধাপগুলি সম্পূর্ণ করুন।
ম্যানিফেস্টে অ্যাট্রিবিউশন ট্যাগ ঘোষণা করুন
আপনার অ্যাপটি যদি অ্যান্ড্রয়েড ১২ (এপিআই লেভেল ৩১) বা তার উচ্চতর সংস্করণকে টার্গেট করে, তাহলে আপনাকে অবশ্যই আপনার অ্যাপের ম্যানিফেস্ট ফাইলে অ্যাট্রিবিউশন ট্যাগ ঘোষণা করতে হবে, যা নিম্নলিখিত কোড স্নিপেটে দেখানো ফরম্যাট অনুযায়ী করতে হবে। আপনি যদি এমন কোনো অ্যাট্রিবিউশন ট্যাগ ব্যবহার করার চেষ্টা করেন যা আপনার অ্যাপের ম্যানিফেস্ট ফাইলে ঘোষণা করা হয়নি, তাহলে সিস্টেম আপনার জন্য একটি null ট্যাগ তৈরি করবে এবং লগক্যাটে একটি বার্তা লগ করবে।
<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.setNotedAppOpsCollector(appOpsCollector); } }