Anda dapat memperoleh analisis tentang cara aplikasi dan dependensinya mengakses data
pribadi dari pengguna dengan melakukan audit akses data. Proses ini, yang tersedia di
perangkat yang menjalankan Android 11 (level API 30) dan yang lebih tinggi, membantu Anda
mengidentifikasi potensi akses data yang tidak diinginkan dengan lebih baik. Aplikasi Anda dapat mendaftarkan instance AppOpsManager.OnOpNotedCallback
yang dapat menjalankan
tindakan setiap kali salah satu peristiwa berikut terjadi:
- Kode aplikasi Anda 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 stack trace thread saat ini.
Membuat log akses data
Untuk menjalankan audit akses data menggunakan instance
AppOpsManager.OnOpNotedCallback
, terapkan logika callback di komponen
tempat Anda ingin mengaudit akses data, seperti dalam
metode onCreate()
aktivitas atau metode
onCreate()
aplikasi.
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 memungkinkan pengguna mengambil
foto dan membagikan foto tersebut kepada kontak mereka. Jika Anda mengembangkan
aplikasi multi-tujuan, 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.
Mendeklarasikan tag atribusi dalam manifes
Jika aplikasi menargetkan Android 12 (level API 31) atau yang lebih baru, Anda harus mendeklarasikan
tag atribusi dalam file manifes aplikasi, menggunakan format yang ditampilkan dalam
cuplikan kode berikut. Jika Anda mencoba menggunakan tag atribusi yang tidak
dideklarasikan dalam file manifes aplikasi, sistem akan membuat tag null
untuk Anda dan
mencatat pesan dalam 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>
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 menunjukkan cara membuat tag atribusi untuk bagian "berbagi lokasi foto" dari suatu 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
Update 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); } }