คุณจะได้รับข้อมูลเชิงลึกเกี่ยวกับวิธีที่แอปและทรัพยากร Dependency เข้าถึงข้อมูลส่วนตัว
จากผู้ใช้ได้โดยการตรวจสอบการเข้าถึงข้อมูล กระบวนการนี้พร้อมให้บริการใน
อุปกรณ์ที่ใช้ Android 11 (API ระดับ 30) ขึ้นไป ซึ่งช่วยให้คุณระบุ
การเข้าถึงข้อมูลที่อาจไม่คาดคิดได้ดียิ่งขึ้น แอปของคุณสามารถลงทะเบียนอินสแตนซ์ของ AppOpsManager.OnOpNotedCallback
ซึ่งสามารถดำเนินการ
ได้ทุกครั้งที่เกิดเหตุการณ์ต่อไปนี้
- โค้ดของแอปเข้าถึงข้อมูลส่วนตัว หากต้องการช่วยคุณระบุส่วนตรรกะของแอปที่เรียกใช้เหตุการณ์ คุณสามารถตรวจสอบการเข้าถึงข้อมูลตามแท็กการระบุแหล่งที่มา
- โค้ดในไลบรารีหรือ SDK ที่ขึ้นต่อกันเข้าถึงข้อมูลส่วนตัว
การตรวจสอบการเข้าถึงข้อมูลจะเรียกใช้ในเธรดที่มีการขอข้อมูล ซึ่งหมายความว่าหาก SDK หรือไลบรารีของบุคคลที่สามในแอปของคุณเรียก API
ที่เข้าถึงข้อมูลส่วนตัว การตรวจสอบการเข้าถึงข้อมูลจะช่วยให้คุณ
OnOpNotedCallback
ตรวจสอบข้อมูลเกี่ยวกับการเรียกได้ โดยปกติแล้ว ออบเจ็กต์การเรียกกลับนี้
จะบอกได้ว่าการเรียกมาจากแอปหรือ SDK โดย
ดูสถานะปัจจุบันของแอป เช่น Stack Trace ของเธรดปัจจุบัน
บันทึกการเข้าถึงข้อมูล
หากต้องการทำการตรวจสอบการเข้าถึงข้อมูลโดยใช้อินสแตนซ์ของ
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()
จะเรียกใช้หากการเข้าถึงข้อมูลไม่เกิดขึ้นระหว่างการเรียก API ของแอป ตัวอย่างที่พบบ่อยที่สุดคือเมื่อแอปของคุณลงทะเบียน Listener และการเข้าถึงข้อมูลจะเกิดขึ้นทุกครั้งที่มีการเรียกใช้การเรียกกลับของ Listenerอาร์กิวเมนต์
AsyncNotedOp
ที่ส่งไปยังonAsyncNoted()
มีเมธอดชื่อgetMessage()
วิธีนี้จะให้ข้อมูลเพิ่มเติมเกี่ยวกับการเข้าถึงข้อมูล ในกรณีของ Location Callback ข้อความจะมี แฮชของตัวตนของระบบของผู้ฟังonSelfNoted()
จะเรียกใช้ในกรณีที่เกิดขึ้นได้ยากมากเมื่อแอปส่ง UID ของตัวเองไปยังnoteOp()
ตรวจสอบการเข้าถึงข้อมูลตามแท็กแอตทริบิวต์
แอปของคุณอาจมีกรณีการใช้งานหลักหลายอย่าง เช่น การอนุญาตให้ผู้ใช้ถ่ายรูปภาพและแชร์รูปภาพเหล่านี้กับรายชื่อติดต่อ หากพัฒนาแอปแบบ
อเนกประสงค์ คุณสามารถใช้แท็กการระบุแหล่งที่มากับแต่ละส่วนของแอป
เมื่อตรวจสอบการเข้าถึงข้อมูล ระบบจะส่งคืนบริบท attributionTag
ในออบเจ็กต์ที่ส่งไปยังการเรียกใช้ onNoted()
ซึ่งจะช่วยให้คุณติดตามการเข้าถึงข้อมูลกลับไปยังส่วนตรรกะของโค้ดได้ง่ายขึ้น
หากต้องการกําหนดแท็กการระบุแหล่งที่มาในแอป ให้ทําตามขั้นตอนในส่วนต่อไปนี้
ประกาศแท็กการระบุแหล่งที่มาในไฟล์ Manifest
หากแอปกำหนดเป้าหมายเป็น Android 12 (API ระดับ 31) ขึ้นไป คุณต้องประกาศ
แท็กการระบุแหล่งที่มาในไฟล์ Manifest ของแอปโดยใช้รูปแบบที่แสดงใน
ข้อมูลโค้ดต่อไปนี้ หากคุณพยายามใช้แท็กการระบุแหล่งที่มาที่ไม่ได้ประกาศในไฟล์ Manifest ของแอป ระบบจะสร้างแท็ก 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); } }