คุณจะได้รับข้อมูลเชิงลึกเกี่ยวกับวิธีที่แอปและทรัพยากร Dependencies เข้าถึงข้อมูลส่วนตัวจากผู้ใช้โดยทำการตรวจสอบการเข้าถึงข้อมูล กระบวนการนี้พร้อมใช้งานในอุปกรณ์ที่ใช้ Android 11 (API ระดับ 30) ขึ้นไป ซึ่งจะช่วยให้คุณระบุการเข้าถึงข้อมูลที่ไม่คาดคิดได้ดีขึ้น แอปสามารถลงทะเบียนอินสแตนซ์ของ AppOpsManager.OnOpNotedCallback
ซึ่งจะดําเนินการทุกครั้งที่มีเหตุการณ์อย่างใดอย่างหนึ่งต่อไปนี้เกิดขึ้น
- โค้ดของแอปเข้าถึงข้อมูลส่วนตัว คุณสามารถตรวจสอบการเข้าถึงข้อมูลตามแท็กการระบุแหล่งที่มาเพื่อช่วยระบุส่วนตรรกะของแอปที่เรียกเหตุการณ์
- โค้ดในไลบรารีหรือ SDK ที่ใช้ร่วมกันเข้าถึงข้อมูลส่วนตัว
ระบบจะเรียกใช้การตรวจสอบการเข้าถึงข้อมูลในเธรดที่มีการส่งคำขอข้อมูล ซึ่งหมายความว่าหาก SDK หรือไลบรารีของบุคคลที่สามในแอปเรียก API ที่เข้าถึงข้อมูลส่วนตัว การตรวจสอบการเข้าถึงข้อมูลจะช่วยให้ OnOpNotedCallback
ตรวจสอบข้อมูลเกี่ยวกับการเรียกนั้นได้ โดยปกติแล้ว ออบเจ็กต์ Callback นี้จะบอกได้ว่าการเรียกมาจากแอปของคุณหรือ 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) }
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()
วิธีนี้จะให้ข้อมูลเพิ่มเติมเกี่ยวกับการเข้าถึงข้อมูล ในกรณีของคอลแบ็กตำแหน่ง ข้อความจะมีแฮชข้อมูลประจำตัวของระบบของผู้ฟัง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); } }