Kontrolowanie dostępu do danych

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ń:

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:

KotlinJava
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 funkcji onAsyncNoted() zawiera metodę o nazwie getMessage(). 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 funkcji noteOp().

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

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ęć:

KotlinJava
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:

KotlinJava
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);
    }
}