Możesz uzyskać informacje o tym, jak Twoja aplikacja i jej zależności uzyskują dostęp do prywatnych danych użytkowników, wykonując audyt dostępu do danych. Ten proces, dostępny od
urządzeń z Androidem 11 (poziom interfejsu API 30) lub nowszym,
identyfikować potencjalnie nieoczekiwany dostęp do danych. Aplikacja może zarejestrować instancję AppOpsManager.OnOpNotedCallback
, która może wykonywać działania za każdym razem, gdy wystąpi jedno z tych zdarzeń:
- Kod Twojej aplikacji uzyskuje dostęp do danych prywatnych. Aby dowiedzieć się, która część logiczna aplikacji wywołała zdarzenie, możesz przeprowadzić audyt dostępu do danych za pomocą tagu atrybucji.
- Kod w bibliotece zależnej lub pakiecie SDK uzyskuje dostęp do danych prywatnych.
Sprawdzanie dostępu do danych jest wywoływane w wątku, w którym odbywa się proces żądania danych. Oznacza to, że jeśli zewnętrzny pakiet SDK lub biblioteka w Twojej aplikacji wywoła interfejs API,
który ma dostęp do prywatnych danych, kontrola dostępu do danych pozwala
OnOpNotedCallback
sprawdza informacje o połączeniu. Zwykle
może określić, czy wywołanie pochodzi z aplikacji, czy z pakietu SDK,
na bieżący stan aplikacji, na przykład zrzut stosu bieżącego wątku.
Dostęp do logu danych
Aby przeprowadzić kontrolę dostępu do danych przy użyciu instancji
AppOpsManager.OnOpNotedCallback
, zaimplementuj w komponencie logikę wywołania zwrotnego
w której chcesz kontrolować dostęp do danych, na przykład w ramach działania
onCreate()
.
lub argumentu aplikacji
onCreate()
.
Ten fragment kodu definiuje funkcję AppOpsManager.OnOpNotedCallback
do sprawdzania dostępu do danych w ramach pojedynczej aktywności:
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); } }
Metody onAsyncNoted()
i onSelfNoted()
są wywoływane w określonych
w sytuacjach:
onAsyncNoted()
zostaje wywołana, jeśli dostęp do danych nie jest uzyskiwany podczas wywołania interfejsu API aplikacji. Najczęstszym przykładem jest to, że aplikacja rejestruje detektor, dostęp do danych ma miejsce za każdym razem, gdy wywoływane jest wywołanie zwrotne detektora.Argument
AsyncNotedOp
przekazany do funkcjionAsyncNoted()
zawiera metodę o nazwiegetMessage()
. Ta metoda zapewnia więcej informacji o dostępie do danych. W przypadku wywołań zwrotnych lokalizacji wiadomość zawiera hasz tożsamości systemowej odbiorcy.onSelfNoted()
jest wywoływany w bardzo rzadkich przypadkach, gdy aplikacja przekazuje swój własny identyfikator UID do funkcjinoteOp()
.
Sprawdzanie dostępu do danych według tagu atrybucji
Aplikacja może mieć kilka podstawowych zastosowań, np. umożliwiać użytkownikom robienie zdjęć i udostępnianie ich kontaktom. Jeśli opracowujesz aplikację wielofunkcyjną, możesz zastosować tag atrybucji do każdej jej części podczas sprawdzania dostępu do danych. Zwracany jest kontekst attributionTag
.
w obiektach przekazywanych do wywołań funkcji onNoted()
.
Dzięki temu łatwiej będzie Ci śledzić dostęp do danych w logicznych częściach kodu.
Aby zdefiniować tagi atrybucji w aplikacji, wykonaj czynności opisane w tych sekcjach.
Deklarowanie tagów atrybucji w pliku manifestu
Jeśli Twoja aplikacja jest przeznaczona na Androida 12 (poziom interfejsu API 31) lub nowszego, musisz zadeklarować tagi atrybucji w pliku manifestu aplikacji, używając formatu pokazanego w tym fragmencie kodu. Jeśli spróbujesz użyć tagu atrybucji, którego nie zadeklarujesz w pliku manifestu aplikacji, system utworzy dla Ciebie tag null
i zapisze wiadomość w 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>
Tworzenie tagów atrybucji
W onCreate()
metodzie działania, w której uzyskujesz dostęp do danych, np. w działaniu, w którym żądasz lokalizacji lub uzyskujesz dostęp do listy kontaktów użytkownika, wywołaj metodęcreateAttributionContext()
, podając tag atrybucji, który chcesz powiązać z częścią aplikacji.
Ten fragment kodu pokazuje, jak utworzyć tag atrybucji na potrzeby strony w której w aplikacji można udostępniać lokalizację zdjęć:
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. } } }
Dołączanie tagów atrybucji w dziennikach dostępu
Zaktualizuj wywołanie zwrotne AppOpsManager.OnOpNotedCallback
, aby uwzględnić logi aplikacji
zawierać nazwy zdefiniowanych przez Ciebie tagów atrybucji.
Ten fragment kodu zawiera zaktualizowaną logikę rejestrującą tagi atrybucji:
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); } }