Datenzugriff prüfen

Sie können Audit-Logs zum Datenzugriff verwenden, um herauszufinden, wie Ihre App und ihre Abhängigkeiten auf private Nutzerdaten zugreifen. Mit diesem Prozess, der auf Geräten mit Android 11 (API‑Level 30) und höher verfügbar ist, können Sie potenziell unerwartete Datenzugriffe besser erkennen. Ihre App kann eine Instanz von AppOpsManager.OnOpNotedCallback registrieren, die jedes Mal Aktionen ausführen kann, wenn eines der folgenden Ereignisse eintritt:

  • Der Code Ihrer App greift auf private Daten zu. Um herauszufinden, welcher logische Teil Ihrer App das Ereignis ausgelöst hat, können Sie den Datenzugriff nach Attributions-Tag prüfen.
  • Code in einer abhängigen Bibliothek oder einem abhängigen SDK greift auf private Daten zu.

Die Prüfung des Datenzugriffs wird in dem Thread aufgerufen, in dem die Datenanfrage erfolgt. Wenn in Ihrer App ein Drittanbieter-SDK oder eine Drittanbieterbibliothek eine API aufruft, über die auf private Daten zugegriffen wird, können Sie mit der Datenzugriffsprüfung Informationen zum Aufruf untersuchen.OnOpNotedCallback Normalerweise kann dieses Callback-Objekt anhand des aktuellen Status der App, z. B. des Stack-Trace des aktuellen Threads, erkennen, ob der Aufruf von Ihrer App oder vom SDK stammt.

Zugriff auf Daten protokollieren

Wenn Sie die Prüfung des Datenzugriffs mit einer Instanz von AppOpsManager.OnOpNotedCallback durchführen möchten, implementieren Sie die Callback-Logik in der Komponente, in der Sie den Datenzugriff prüfen möchten, z. B. in der Methode onCreate() einer Aktivität oder in der Methode onCreate() einer Anwendung.

Das folgende Code-Snippet definiert eine AppOpsManager.OnOpNotedCallback für die Überwachung des Datenzugriffs innerhalb einer einzelnen Aktivität:

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

Die Methoden onAsyncNoted() und onSelfNoted() werden in bestimmten Situationen aufgerufen:

  • onAsyncNoted() wird aufgerufen, wenn der Datenzugriff nicht während des API-Aufrufs Ihrer App erfolgt. Das häufigste Beispiel ist, wenn Ihre App einen Listener registriert und der Datenzugriff jedes Mal erfolgt, wenn der Callback des Listeners aufgerufen wird.

    Das AsyncNotedOp-Argument, das an onAsyncNoted() übergeben wird, enthält eine Methode namens getMessage(). Diese Methode bietet mehr Informationen zum Datenzugriff. Bei den Standort-Callbacks enthält die Nachricht den System-Identitätshash des Zuhörers.

  • onSelfNoted() wird in dem sehr seltenen Fall aufgerufen, wenn eine App ihre eigene UID an noteOp() übergibt.

Datenzugriff nach Attributions-Tag prüfen

Ihre App kann mehrere primäre Anwendungsfälle haben, z. B. dass Nutzer Fotos aufnehmen und diese mit ihren Kontakten teilen können. Wenn Sie eine Mehrzweck-App entwickeln, können Sie beim Überprüfen des Datenzugriffs ein Attributions-Tag auf jeden Teil Ihrer App anwenden. Der attributionTag-Kontext wird in den Objekten zurückgegeben, die an die Aufrufe von onNoted() übergeben werden. So können Sie den Datenzugriff leichter auf logische Teile Ihres Codes zurückführen.

Führen Sie die Schritte in den folgenden Abschnitten aus, um Attributions-Tags in Ihrer App zu definieren.

Attributions-Tags im Manifest deklarieren

Wenn Ihre App auf Android 12 (API-Level 31) oder höher ausgerichtet ist, müssen Sie Attributions-Tags in der Manifestdatei Ihrer App deklarieren. Verwenden Sie dazu das Format im folgenden Code-Snippet. Wenn Sie versuchen, ein Attributions-Tag zu verwenden, das Sie nicht in der Manifestdatei Ihrer App deklarieren, erstellt das System ein null-Tag für Sie und protokolliert eine Meldung in 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>

Attributions-Tags erstellen

Rufen Sie in der Methode onCreate() der Aktivität, in der Sie auf Daten zugreifen, z. B. in der Aktivität, in der Sie den Standort anfordern oder auf die Kontaktliste des Nutzers zugreifen, createAttributionContext() auf und übergeben Sie das Attributions-Tag, das Sie einem Teil Ihrer App zuordnen möchten.

Das folgende Code-Snippet zeigt, wie Sie ein Attribut-Tag für einen Teil einer App erstellen, in dem der Standort von Fotos geteilt wird:

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.
        }
    }
}

Attributions-Tags in Zugriffslogs einfügen

Aktualisieren Sie den AppOpsManager.OnOpNotedCallback-Callback, damit die Protokolle Ihrer App die Namen der von Ihnen definierten Attributions-Tags enthalten.

Das folgende Code-Snippet zeigt die aktualisierte Logik zum Protokollieren von Attribut-Tags:

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