Anda dapat memeroleh analisis tentang cara aplikasi dan dependensinya mengakses data pribadi dari pengguna dengan melakukan audit akses data. Proses ini, yang tersedia pada perangkat yang menjalankan Android 11 (API level 30) dan yang lebih tinggi, membantu Anda mengidentifikasi akses data berpotensi tidak terduga dengan lebih baik. Aplikasi Anda dapat mendaftarkan instance AppOpsManager.OnOpNotedCallback
, yang dapat menjalankan tindakan setiap kali salah satu peristiwa berikut terjadi:
- Kode aplikasi Anda akan mengakses data pribadi. Untuk membantu Anda menentukan bagian logis aplikasi yang memanggil peristiwa, Anda dapat mengaudit akses data dengan tag atribusi.
- Kode di SDK atau library dependen akan mengakses data pribadi.
Audit akses data dipanggil pada thread tempat permintaan data dilakukan. Ini berarti, jika SDK atau library pihak ketiga di aplikasi Anda memanggil API yang mengakses data pribadi, audit akses data akan memungkinkan OnOpNotedCallback
Anda memeriksa informasi tentang panggilan tersebut. Biasanya, objek callback ini dapat memberi tahu apakah panggilan berasal dari aplikasi Anda atau SDK dengan melihat status aplikasi saat ini, seperti pelacakan tumpukan thread saat ini.
Mencatat log akses data
Untuk menjalankan audit akses data menggunakan instance AppOpsManager.OnOpNotedCallback
, implementasikan logika callback di komponen tempat Anda ingin mengaudit akses data, seperti dalam metode onCreate()
aktivitas.
Cuplikan kode berikut akan menentukan AppOpsManager.OnOpNotedCallback
untuk mengaudit akses data dalam aktivitas tunggal:
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); } }
Metode onAsyncNoted()
dan onSelfNoted()
akan dipanggil dalam situasi tertentu:
onAsyncNoted()
akan dipanggil jika akses data tidak terjadi selama panggilan API aplikasi Anda. Contoh yang paling umum adalah saat aplikasi Anda mendaftarkan pemroses dan akses data terjadi setiap kali callback pemroses dipanggil.Argumen
AsyncNotedOp
yang diteruskan keonAsyncNoted()
berisi metode yang disebutgetMessage()
. Metode ini akan memberikan informasi selengkapnya tentang akses data. Pesan dengan callback lokasi akan berisi hash identitas sistem pemroses.onSelfNoted()
akan sangat jarang dipanggil ketika aplikasi meneruskan UID-nya sendiri kenoteOp()
.
Mengaudit akses data dengan tag atribusi
Aplikasi Anda mungkin memiliki beberapa kasus penggunaan utama, seperti mengizinkan pengguna mengambil foto dan membagikan foto tersebut kepada kontak mereka. Jika Anda mengembangkan aplikasi multitujuan semacam itu, Anda dapat menerapkan tag atribusi ke setiap bagian aplikasi saat mengaudit akses datanya. Konteks attributionTag
dikembalikan ke objek yang diteruskan ke panggilan untuk onNoted()
.
Hal ini akan mempermudah Anda melacak akses data kembali ke bagian logis kode Anda.
Untuk menetapkan tag atribusi dalam aplikasi Anda, selesaikan langkah-langkah di bagian berikut ini.
Membuat tag atribusi
Dalam metode onCreate()
dari aktivitas tempat Anda mengakses data, seperti aktivitas tempat Anda meminta lokasi atau mengakses daftar kontak pengguna, panggil createAttributionContext()
, yang meneruskan tag atribusi yang ingin Anda kaitkan dengan bagian dari aplikasi.
Cuplikan kode berikut akan menunjukkan cara membuat tag atribusi untuk bagian "berbagi lokasi foto" pada aplikasi:
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. } } }
Menyertakan tag atribusi di log akses
Perbarui callback AppOpsManager.OnOpNotedCallback
agar log aplikasi menyertakan nama tag atribusi yang telah Anda tetapkan.
Cuplikan kode berikut menunjukkan logika terbaru yang membuat log tag atribusi:
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); } }