Controlla l'accesso ai dati

Puoi ottenere insight su come la tua app e le sue dipendenze accedono ai dati privati dagli utenti eseguendo un controllo dell'accesso ai dati. Questa procedura, disponibile su con Android 11 (livello API 30) e versioni successive, ti consente di identificare un accesso ai dati potenzialmente imprevisto. La tua app può registrare un'istanza di AppOpsManager.OnOpNotedCallback, che possono eseguire azioni ogni volta che si verifica uno dei seguenti eventi:

Il controllo dell'accesso ai dati viene richiamato nel thread in cui viene richiesta la richiesta di dati posto. Ciò significa che se un SDK o una libreria di terze parti nella tua app chiama un'API che accede a dati privati, il controllo dell'accesso ai dati consente a OnOpNotedCallback di esaminare le informazioni sulla chiamata. Di solito, questo può capire se la chiamata proviene dalla tua app o dall'SDK e controllare lo stato attuale dell'app, ad esempio l'analisi dello stack del thread attuale.

Accesso ai dati nei log

Per eseguire il controllo dell'accesso ai dati utilizzando un'istanza di AppOpsManager.OnOpNotedCallback, implementa la logica di callback nel componente dove intendi controllare l'accesso ai dati, ad esempio all'interno del metodo onCreate() di un'attività o del metodo onCreate() di un'applicazione.

Il seguente snippet di codice definisce un AppOpsManager.OnOpNotedCallback per per controllare l'accesso ai dati nell'ambito di una singola attività:

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

I metodi onAsyncNoted() e onSelfNoted() vengono chiamati in modo specifico situazioni seguenti:

  • onAsyncNoted() viene chiamato se l'accesso ai dati non avviene durante la chiamata all'API della tua app. L'esempio più comune è quando l'app registra un listener e l'accesso ai dati viene eseguito ogni volta che viene richiamato il callback del listener.

    L'argomento AsyncNotedOp passato in onAsyncNoted() contiene un denominato getMessage(). Questo metodo fornisce maggiori informazioni sull'accesso ai dati. Nel caso dei callback della posizione, il messaggio contiene l'hash dell'identità di sistema del listener.

  • onSelfNoted() viene chiamato nei rari casi in cui un'app trasmette il proprio UID in noteOp().

Controllare l'accesso ai dati per tag di attribuzione

La tua app potrebbe avere diversi casi d'uso principali, ad esempio consentire agli utenti di acquisire foto e condividile con i loro contatti. Se sviluppi un app multiuso, puoi applicare un tag di attribuzione a ogni parte dell'app durante la verifica dell'accesso ai dati. Viene restituito il contesto attributionTag negli oggetti passati alle chiamate a onNoted(). Ciò consente di risalire più facilmente all'accesso ai dati alle parti logiche del tuo le API nel tuo codice.

Per definire i tag di attribuzione nella tua app, completa i passaggi descritti nelle seguenti sezioni.

Dichiara i tag di attribuzione nel file manifest

Se la tua app ha come target Android 12 (livello API 31) o versioni successive, devi dichiarare dei tag di attribuzione nel file manifest dell'app, utilizzando il formato mostrato nei successivo snippet di codice. Se provi a utilizzare un tag di attribuzione che non dichiari nel file manifest della tua app, il sistema crea un tag null per te e registra un messaggio 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>

Creare tag di attribuzione

Nella onCreate() Il metodo dell'attività a cui accedi ai dati, come l'attività in cui accedi richiedere la posizione o accedere all'elenco di contatti dell'utente, chiamare createAttributionContext(), trasferire il tag di attribuzione che desideri associare a una parte dei tuoi dell'app.

Il seguente snippet di codice mostra come creare un tag di attribuzione per la funzionalità di condivisione di foto e posizione di un'app:

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

Includi i tag di attribuzione nei log di accesso

Aggiorna il callback AppOpsManager.OnOpNotedCallback in modo che i log dell'app includi i nomi dei tag di attribuzione che hai definito.

Il seguente snippet di codice mostra la logica aggiornata che registra i tag di attribuzione:

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