Questa guida spiega come utilizzare l'SDK dell'API Android Management (AMAPI) in un controller dei criteri dei dispositivi (DPC) personalizzato per configurare i controlli degli aggiornamenti unificati (UUC) sui dispositivi di proprietà dell'azienda.
Utilizzando l'SDK AMAPI, il tuo DPC personalizzato invia una policy UUC direttamente all'app Android Device Policy (ADP) sul dispositivo. ADP valuta le regole della policy in base allo stato attuale del dispositivo e indica a Google Play e al client OTA dell'OEM come gestire gli aggiornamenti in attesa.
Prima di iniziare, leggi Unified Update Controls per scoprire come funzionano regole, target, predicati e risultati e quali limitazioni si applicano a tutte le integrazioni UUC.
Prerequisiti
Prima di integrare UUC nel tuo DPC personalizzato, verifica i seguenti requisiti:
- Il dispositivo è di proprietà dell'azienda, configurato come dispositivo completamente gestito o con un profilo di lavoro su un dispositivo di proprietà dell'azienda.
- La tua DPC personalizzata è integrata con l'SDK AMAPI.
- Il dispositivo viene registrato utilizzando l'API Google Play EMM.
- Il dispositivo soddisfa i requisiti minimi di versione per la modalità di gestione e per ogni target di aggiornamento che vuoi controllare:
- Dispositivi completamente gestiti (proprietario del dispositivo): Android 13 (livello API 33) o versioni successive.
- Dispositivi di proprietà aziendale con un profilo di lavoro (COPE): Android 15 (livello API 35) o versioni successive.
- Sui dispositivi di proprietà dell'azienda con un profilo di lavoro (COPE):
- La DPC personalizzata deve chiamare
EnvironmentClientePolicyClientdal profilo di lavoro (dove la DPC personalizzata è il proprietario del profilo). - Nel profilo di lavoro deve essere presente un account Google Play gestito (fornito tramite l'API Google Play EMM) affinché UUC possa applicare le policy sugli aggiornamenti di Google Play (
GOOGLE_SYSTEM_SERVICES,SINGLE_APPeGOOGLE_PLAY_SYSTEM_UPDATE).
- La DPC personalizzata deve chiamare
Esegui l'integrazione con l'SDK AMAPI nel tuo DPC personalizzato
Per configurare una policy UUC su un dispositivo, il DPC personalizzato deve essere integrato con l'SDK AMAPI. Per istruzioni su come aggiungere la libreria e configurare il manifest dell'app, consulta la guida all'integrazione dell'SDK AMAPI.
Passaggi per configurare i controlli degli aggiornamenti unificati
Per configurare le policy UUC dal tuo DPC personalizzato, assicurati che l'ambiente client sul dispositivo sia pronto e aggiornato prima di inviare richieste di policy ad ADP:
- Verifica l'ambiente client
- Prepara l'ambiente client
- Imposta, recupera e cancella la policy di aggiornamento
Verifica l'ambiente client
L'esempio seguente mostra come chiamare getEnvironment (in Kotlin) o getEnvironmentAsync (in Java) con Role.RoleType.DEVICE_POLICY_CONTROLLER per ispezionare lo stato dell'app ADP. Se l'ambiente è READY e UP_TO_DATE, la DPC personalizzata può procedere alla configurazione delle policy UUC utilizzando PolicyClient. In caso contrario, chiama prepareEnvironment per installare o aggiornare l'app ADP (consulta Prepara l'ambiente client).
Kotlin
import android.content.Context import android.util.Log import com.google.android.managementapi.common.model.Role import com.google.android.managementapi.environment.EnvironmentClientFactory import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE import com.google.android.managementapi.environment.model.GetEnvironmentRequest private suspend fun checkEnvironmentForUuc(context: Context): Boolean { try { val roles = listOf( Role.builder() .setRoleType(Role.RoleType.DEVICE_POLICY_CONTROLLER) .build() ) val request = GetEnvironmentRequest.builder().setRoles(roles).build() val environmentClient = EnvironmentClientFactory.create(context) val environmentResponse = environmentClient.getEnvironment(request) if (environmentResponse.hasAndroidDevicePolicyEnvironment()) { val adpEnvironment = environmentResponse.androidDevicePolicyEnvironment when (adpEnvironment.state) { READY -> { return if (adpEnvironment.version == UP_TO_DATE) { // AMAPI environment state and version are ready. true } else { prepareEnvironment(context, environmentClient) } } INSTALLED -> { // Call prepareEnvironment to silently update ADP. return prepareEnvironment(context, environmentClient) } NOT_INSTALLED -> { // Call prepareEnvironment to install ADP. return prepareEnvironment(context, environmentClient) } else -> {} } } } catch (e: Exception) { Log.e(TAG, "Exception checking environment", e) } return false }
Java
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.INSTALLED; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.NOT_INSTALLED; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE; import android.content.Context; import android.util.Log; import com.google.android.managementapi.common.model.Role; import com.google.android.managementapi.environment.EnvironmentClient; import com.google.android.managementapi.environment.EnvironmentClientFactory; import com.google.android.managementapi.environment.model.Environment; import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment; import com.google.android.managementapi.environment.model.GetEnvironmentRequest; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; private void checkEnvironmentForUuc(Context context) { try { ImmutableListroles = new ImmutableList.Builder () .add(Role.builder() .setRoleType(Role.RoleType.DEVICE_POLICY_CONTROLLER) .build()) .build(); EnvironmentClient environmentClient = EnvironmentClientFactory.create(context); GetEnvironmentRequest getRequest = GetEnvironmentRequest.builder() .setRoles(roles) .build(); ListenableFuture getEnvironmentFuture = environmentClient.getEnvironmentAsync(getRequest); Futures.addCallback(getEnvironmentFuture, new FutureCallback () { @Override public void onSuccess(Environment environment) { if (!environment.hasAndroidDevicePolicyEnvironment()) { return; } AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment(); AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState(); AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion(); if (state == READY && version == UP_TO_DATE) { // AMAPI environment state and version are ready. return; } else if (state == INSTALLED || state == NOT_INSTALLED) { // Call prepareEnvironment to silently install or update ADP. prepareEnvironment(context, environmentClient); } } @Override public void onFailure(Throwable t) { Log.e(TAG, "Failed to verify environment", t); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Exception verifying environment", e); } }
Prepara l'ambiente client
Se l'ambiente sul dispositivo non è pronto o aggiornato, chiama
prepareEnvironment prima di utilizzare PolicyClient.
Se viene chiamato da un DPC personalizzato con Role.RoleType.DEVICE_POLICY_CONTROLLER e
il nome del componente DeviceAdminReceiver del tuo DPC viene passato a setAdmin(),
prepareEnvironment installa l'app ADP in modo invisibile (se non è già installata)
e aggiorna l'app ADP e il Google Play Store senza l'interazione dell'utente. Per saperne di più sulla preparazione dell'ambiente nei flussi DPC personalizzati, consulta Preparazione dell'ambiente e registrazione degli utenti.
Kotlin
import android.content.ComponentName import android.content.Context import android.util.Log import com.google.android.managementapi.common.model.Role import com.google.android.managementapi.environment.EnvironmentClient import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest private suspend fun prepareEnvironment( context: Context, environmentClient: EnvironmentClient ): Boolean { try { val roles = listOf( Role.builder() .setRoleType(Role.RoleType.DEVICE_POLICY_CONTROLLER) .build() ) val request = PrepareEnvironmentRequest.builder() .setRoles(roles) .setAdmin( ComponentName( context, DeviceAdminReceiver::class.java ) ) .build() val response = environmentClient.prepareEnvironment(request, null) val environment = response.environment val adpEnvironment = environment.androidDevicePolicyEnvironment val state = adpEnvironment.state val version = adpEnvironment.version return (state == READY && version == UP_TO_DATE) } catch (e: Exception) { Log.e(TAG, "Failed to prepare environment", e) } return false }
Java
import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.State.READY; import static com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment.Version.UP_TO_DATE; import android.content.ComponentName; import android.content.Context; import android.util.Log; import androidx.annotation.NonNull; import com.google.android.managementapi.common.model.Role; import com.google.android.managementapi.environment.EnvironmentClient; import com.google.android.managementapi.environment.model.Environment; import com.google.android.managementapi.environment.model.Environment.AndroidDevicePolicyEnvironment; import com.google.android.managementapi.environment.model.PrepareEnvironmentRequest; import com.google.android.managementapi.environment.model.PrepareEnvironmentResponse; import com.google.common.collect.ImmutableList; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; private void prepareEnvironment(Context context, EnvironmentClient environmentClient) { try { ImmutableListroles = new ImmutableList.Builder () .add(Role.builder() .setRoleType(Role.RoleType.DEVICE_POLICY_CONTROLLER) .build()) .build(); ComponentName adminComponent = new ComponentName( context, DeviceAdminReceiver.class ); PrepareEnvironmentRequest request = PrepareEnvironmentRequest.builder() .setRoles(roles) .setAdmin(adminComponent) .build(); ListenableFuture environmentFuture = environmentClient.prepareEnvironmentAsync(request, null); Futures.addCallback(environmentFuture, new FutureCallback () { @Override public void onSuccess(PrepareEnvironmentResponse response) { Environment environment = response.getEnvironment(); AndroidDevicePolicyEnvironment adpEnvironment = environment.getAndroidDevicePolicyEnvironment(); AndroidDevicePolicyEnvironment.State state = adpEnvironment.getState(); AndroidDevicePolicyEnvironment.Version version = adpEnvironment.getVersion(); if (state == READY && version == UP_TO_DATE) { // Environment is prepared; configure UUC policy using PolicyClient. } else { Log.w( TAG, "AMAPI environment was not ready: " + state + " - " + version ); } } @Override public void onFailure(@NonNull Throwable t) { Log.e(TAG, "Failed to prepare environment", t); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Exception preparing environment", e); } }
Imposta, recupera e cancella la policy di aggiornamento
Una volta pronto l'ambiente, utilizza PolicyClient (creato con
PolicyClientFactory.create(context)) per applicare un Policy contenente le tue
regole UnifiedUpdatePolicy, ispezionare la policy attiva o cancellare la policy UUC
dal dispositivo.
Suggerimento per l'utilizzo di PolicyClient
La creazione di un'istanza PolicyClient stabilisce un canale di comunicazione con l'app ADP. Per ottimizzare le prestazioni, ti consigliamo di creare una singola istanza di PolicyClient utilizzando PolicyClientFactory.create() e di memorizzarla nella cache per riutilizzarla nell'applicazione. Evita di creare una nuova istanza PolicyClient mentre un'altra è attiva, perché ciò può forzare la chiusura del canale di comunicazione esistente, il che comporta un overhead e può portare a perdite di risorse.
Imposta la policy di aggiornamento
Per applicare le regole UUC, crea un Policy.UnifiedUpdatePolicy contenente l'elenco di oggetti Rule, collegalo a un Policy all'interno di un UpdatePolicyRequest e chiama updatePolicy (in Kotlin) o updatePolicyFuture (in Java):
Kotlin
import android.util.Log import com.google.android.managementapi.policy.PolicyClient import com.google.android.managementapi.policy.model.Policy import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.UpdatePolicyRequest suspend fun setUucPolicy( policyClient: PolicyClient, rules: Iterable): Boolean { // Build the UnifiedUpdatePolicy and attach it to the overall Policy. val unifiedUpdatePolicy = Policy.UnifiedUpdatePolicy.builder() .setRules(rules) .build() val policy = Policy.builder() .setUnifiedUpdatePolicy(unifiedUpdatePolicy) .build() // Create the UpdatePolicyRequest. val updateRequest = UpdatePolicyRequest.builder() .setPolicy(policy) .build() // Apply the policy using PolicyClient within a CoroutineScope. return try { val updatedPolicy = policyClient.updatePolicy(updateRequest) Log.d(TAG, "Policy updated successfully: $updatedPolicy") true } catch (e: Exception) { Log.e(TAG, "Error updating policy: ${e.message}", e) false } }
Java
import android.util.Log; import com.google.android.managementapi.policy.PolicyClient; import com.google.android.managementapi.policy.model.Policy; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.UpdatePolicyRequest; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.stream.Collectors; import java.util.stream.StreamSupport; ListenableFuturesetUucPolicy( PolicyClient policyClient, Iterable rules ) { // Build the UnifiedUpdatePolicy and attach it to the overall Policy. UnifiedUpdatePolicy unifiedUpdatePolicy = UnifiedUpdatePolicy.builder() .setRules( StreamSupport.stream(rules.spliterator(), false) .collect(Collectors.toList()) ) .build(); Policy policy = Policy.builder() .setUnifiedUpdatePolicy(unifiedUpdatePolicy) .build(); // Create the UpdatePolicyRequest. UpdatePolicyRequest updateRequest = UpdatePolicyRequest.builder() .setPolicy(policy) .build(); // Apply the policy using PolicyClient. try { ListenableFuture updateFuture = policyClient.updatePolicyFuture(updateRequest); return Futures.transform(updateFuture, updatedPolicy -> { Log.d(TAG, "Policy updated successfully: " + updatedPolicy); return true; }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Error updating policy: " + e.getMessage(), e); return Futures.immediateFuture(false); } }
Recupera la policy di aggiornamento attiva
Per ispezionare la policy UUC attiva sul dispositivo, crea un GetPolicyRequest e chiama getPolicy (in Kotlin) o getPolicyFuture (in Java). Utilizza hasUnifiedUpdatePolicy() sull'oggetto Policy restituito per verificare se è configurata una policy UUC:
Kotlin
import android.util.Log import com.google.android.managementapi.policy.PolicyClient import com.google.android.managementapi.policy.model.GetPolicyRequest import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule suspend fun getActiveUucPolicy(policyClient: PolicyClient) { try { val getPolicyRequest = GetPolicyRequest.builder().build() val activePolicy = policyClient.getPolicy(getPolicyRequest) Log.i(TAG, "Policy version: ${activePolicy.version}") if (!activePolicy.hasUnifiedUpdatePolicy()) { Log.i(TAG, "No Unified Update Policy set.") return } val activeUucPolicy = activePolicy.unifiedUpdatePolicy val rules: List= activeUucPolicy.rules.toList() rules.forEachIndexed { index, rule -> val outcome = if (rule.hasOutcome()) rule.outcome.toString() else "[no outcome]" val predicate = if (rule.hasPredicate()) rule.predicate.toString() else "[no predicate]" Log.i(TAG, "Rule [$index] targets: ${rule.targets}") Log.i(TAG, "Rule [$index] outcome: $outcome") Log.i(TAG, "Rule [$index] predicate: $predicate") } } catch (e: Exception) { Log.e(TAG, "Error retrieving policy: ${e.message}", e) } }
Java
import android.util.Log; import com.google.android.managementapi.policy.PolicyClient; import com.google.android.managementapi.policy.model.GetPolicyRequest; import com.google.android.managementapi.policy.model.Policy; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.common.util.concurrent.FutureCallback; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; import java.util.List; import java.util.stream.Collectors; import java.util.stream.StreamSupport; void getActiveUucPolicy(PolicyClient policyClient) { try { GetPolicyRequest getPolicyRequest = GetPolicyRequest.builder().build(); ListenableFuturegetActivePolicy = policyClient.getPolicyFuture(getPolicyRequest); Futures.addCallback(getActivePolicy, new FutureCallback () { @Override public void onSuccess(Policy result) { if (!result.hasUnifiedUpdatePolicy()) { Log.i(TAG, "No Unified Update Policy set."); return; } UnifiedUpdatePolicy activeUucPolicy = result.getUnifiedUpdatePolicy(); List uucRules = StreamSupport.stream( activeUucPolicy.getRules().spliterator(), false) .collect(Collectors.toList()); for (int i = 0; i < uucRules.size(); i++) { Rule rule = uucRules.get(i); String outcome = rule.hasOutcome() ? rule.getOutcome().toString() : "[no outcome]"; String predicate = rule.hasPredicate() ? rule.getPredicate().toString() : "[no predicate]"; Log.i(TAG, "Rule [" + i + "] targets: " + rule.getTargets()); Log.i(TAG, "Rule [" + i + "] outcome: " + outcome); Log.i(TAG, "Rule [" + i + "] predicate: " + predicate); } } @Override public void onFailure(Throwable t) { Log.e(TAG, "Error retrieving policy", t); } }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Exception retrieving policy", e); } }
Cancella la policy di aggiornamento
Per rimuovere UnifiedUpdatePolicy dal dispositivo senza cancellare altri campi su Policy, recupera l'attuale Policy utilizzando getPolicy, chiama currentPolicy.toBuilder().clearUnifiedUpdatePolicy().build() e applica l'aggiornamento Policy:
Kotlin
import android.util.Log import com.google.android.managementapi.policy.PolicyClient import com.google.android.managementapi.policy.model.GetPolicyRequest import com.google.android.managementapi.policy.model.UpdatePolicyRequest suspend fun clearUucPolicy(policyClient: PolicyClient): Boolean { try { // 1. Retrieve the current policy. val currentPolicy = policyClient.getPolicy( GetPolicyRequest.builder().build() ) if (!currentPolicy.hasUnifiedUpdatePolicy()) { Log.i(TAG, "Policy does not have a UnifiedUpdatePolicy to clear.") return true } // 2. Convert to a builder and clear the UnifiedUpdatePolicy field. val policyWithUucCleared = currentPolicy.toBuilder() .clearUnifiedUpdatePolicy() .build() // 3. Apply the modified Policy object. val updateRequest = UpdatePolicyRequest.builder() .setPolicy(policyWithUucCleared) .build() val updatedPolicy = policyClient.updatePolicy(updateRequest) return !updatedPolicy.hasUnifiedUpdatePolicy() } catch (e: Exception) { Log.e(TAG, "Error clearing policy: ${e.message}", e) return false } }
Java
import android.util.Log; import com.google.android.managementapi.policy.PolicyClient; import com.google.android.managementapi.policy.model.GetPolicyRequest; import com.google.android.managementapi.policy.model.Policy; import com.google.android.managementapi.policy.model.UpdatePolicyRequest; import com.google.common.util.concurrent.Futures; import com.google.common.util.concurrent.ListenableFuture; import com.google.common.util.concurrent.MoreExecutors; ListenableFutureclearUucPolicy(PolicyClient policyClient) { try { ListenableFuture currentPolicyFuture = policyClient.getPolicyFuture(GetPolicyRequest.builder().build()); return Futures.transformAsync(currentPolicyFuture, currentPolicy -> { if (!currentPolicy.hasUnifiedUpdatePolicy()) { Log.i(TAG, "Policy does not have a UnifiedUpdatePolicy to clear."); return Futures.immediateFuture(true); } Policy policyWithUucCleared = currentPolicy.toBuilder() .clearUnifiedUpdatePolicy() .build(); UpdatePolicyRequest updateRequest = UpdatePolicyRequest.builder() .setPolicy(policyWithUucCleared) .build(); ListenableFuture updateFuture = policyClient.updatePolicyFuture(updateRequest); return Futures.transform( updateFuture, updatedPolicy -> !updatedPolicy.hasUnifiedUpdatePolicy(), MoreExecutors.directExecutor() ); }, MoreExecutors.directExecutor()); } catch (Exception e) { Log.e(TAG, "Error clearing policy: " + e.getMessage(), e); return Futures.immediateFuture(false); } }
Precedenza di SystemUpdatePolicy di AOSP
In un DPC personalizzato, il Compatibility Definition Document (CDD) di Android richiede che i dispositivi rispettino l'AOSP SystemUpdatePolicy impostato tramite DevicePolicyManager.setSystemUpdatePolicy.
Di conseguenza, il comportamento degli aggiornamenti OTA dell'OEM dipende dal fatto che sul dispositivo sia attiva o meno una SystemUpdatePolicy
AOSP:
- Sono impostate sia la policy UUC sia la policy AOSP
SystemUpdatePolicy: la policy AOSPSystemUpdatePolicyha la precedenza per gli aggiornamenti OTA OEM e i target UUCOS_UPDATE_WITH_API_LEVEL_CHANGEeOS_UPDATE_WITHOUT_API_LEVEL_CHANGEvengono ignorati. Cancella l'AOSPSystemUpdatePolicynel tuo DPC personalizzato se vuoi che UUC gestisca gli aggiornamenti OTA OEM. - È impostata solo la policy UUC (AOSP
SystemUpdatePolicyè deselezionata): l'agente OTA OEM applica la policy UUC per gli aggiornamenti OTA OEM sui dispositivi supportati, a meno che non sia attivo un servizio di gestione degli aggiornamenti specifico dell'OEM (ad esempio una soluzione FOTA aziendale) che ha la precedenza sul dispositivo. - Dispositivi che non supportano ancora UUC per gli aggiornamenti OTA OEM: sui dispositivi in cui il supporto OTA OEM richiede Android 17 (livello API 37), puoi utilizzare UUC per controllare gli aggiornamenti di sistema Google Play (
GOOGLE_PLAY_SYSTEM_UPDATE) e i servizi di sistema di Google (GOOGLE_SYSTEM_SERVICESeSINGLE_APP) continuando a utilizzare AOSPSystemUpdatePolicyper gli aggiornamenti OTA OEM.
Puoi verificare se un SystemUpdatePolicy AOSP è attivo sul dispositivo utilizzando
DevicePolicyManager:
Kotlin
import android.app.admin.DevicePolicyManager import android.content.Context fun Context.isSystemUpdatePolicyActive(): Boolean { val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as? DevicePolicyManager return dpm?.systemUpdatePolicy != null }
Java
import android.app.admin.DevicePolicyManager; import android.content.Context; boolean isSystemUpdatePolicyActive(Context context) { DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); return dpm != null && dpm.getSystemUpdatePolicy() != null; }
Esempi di configurazione delle policy
Gli esempi seguenti mostrano come creare regole UUC in Kotlin e Java e applicarle utilizzando l'helper setUucPolicy definito in Imposta, recupera e cancella la policy di aggiornamento. Per il significato di ogni campo, consulta Informazioni sulle policy UUC. Gli stessi scenari sono disponibili in formato JSON in Unified Update Controls.
Blocca gli aggiornamenti principali del sistema operativo durante l'orario di apertura
La seguente regola blocca gli aggiornamenti principali del sistema operativo (OS_UPDATE_WITH_API_LEVEL_CHANGE)
dalle 09:00 alle 17:00, dal lunedì al venerdì:
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE import java.time.DayOfWeek import java.time.LocalTime // 1. Define the target (OS update with API level change). val target = Target.builder() .setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE) .build() // 2. Define the predicate (Monday through Friday, 09:00 to 17:00). val predicate = Predicate.builder() .setDaysOfWeek( listOf( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build() // 3. Define the outcome (BLOCK). val outcome = Outcome.builder() .setOutcomeType(BLOCK) .build() // 4. Assemble and apply the rule. val rule = Rule.builder() .setTargets(listOf(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Block Policy") .build() setUucPolicy(policyClient, listOf(rule))
Java
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target; import java.time.DayOfWeek; import java.time.LocalTime; import java.util.List; // 1. Define the target (OS update with API level change). Target target = Target.builder() .setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE) .build(); // 2. Define the predicate (Monday through Friday, 09:00 to 17:00). Predicate predicate = Predicate.builder() .setDaysOfWeek( List.of( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build(); // 3. Define the outcome (BLOCK). Outcome outcome = Outcome.builder() .setOutcomeType(BLOCK) .build(); // 4. Assemble and apply the rule. Rule rule = Rule.builder() .setTargets(List.of(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Block Policy") .build(); setUucPolicy(policyClient, List.of(rule));
Forza gli aggiornamenti del sistema operativo in base alla data dell'aggiornamento
La seguente regola forza gli aggiornamenti principali del sistema operativo (OS_UPDATE_WITH_API_LEVEL_CHANGE)
con un limite massimo di età dell'aggiornamento di 7 giorni:
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.FORCE import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE import java.time.Duration val target = Target.builder() .setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE) .build() val predicate = Predicate.builder() .setUpdateAgeUpperBound(Duration.ofDays(7)) .build() val outcome = Outcome.builder() .setOutcomeType(FORCE) .build() val rule = Rule.builder() .setTargets(listOf(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Force Policy") .build() setUucPolicy(policyClient, listOf(rule))
Java
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.FORCE; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target; import java.time.Duration; import java.util.List; Target target = Target.builder() .setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE) .build(); Predicate predicate = Predicate.builder() .setUpdateAgeUpperBound(Duration.ofDays(7)) .build(); Outcome outcome = Outcome.builder() .setOutcomeType(FORCE) .build(); Rule rule = Rule.builder() .setTargets(List.of(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Force Policy") .build(); setUucPolicy(policyClient, List.of(rule));
Blocca gli aggiornamenti per una singola app di servizi di sistema Google
Per controllare un pacchetto specifico che fa parte dei servizi di sistema di Google, ad esempio Android System WebView (com.google.android.webview), imposta il tipo di target su SINGLE_APP e fornisci un oggetto SingleApp con il nome del pacchetto:
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.SingleApp import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.SINGLE_APP import java.time.DayOfWeek import java.time.LocalTime val target = Target.builder() .setTargetType(SINGLE_APP) .setSingleApp( SingleApp.builder() .setPackageName("com.google.android.webview") .build() ) .build() val predicate = Predicate.builder() .setDaysOfWeek( listOf( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build() val outcome = Outcome.builder() .setOutcomeType(BLOCK) .build() val rule = Rule.builder() .setTargets(listOf(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Block Webview Policy") .build() setUucPolicy(policyClient, listOf(rule))
Java
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.SINGLE_APP; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.SingleApp; import java.time.DayOfWeek; import java.time.LocalTime; import java.util.List; Target target = Target.builder() .setTargetType(SINGLE_APP) .setSingleApp( SingleApp.builder() .setPackageName("com.google.android.webview") .build() ) .build(); Predicate predicate = Predicate.builder() .setDaysOfWeek( List.of( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build(); Outcome outcome = Outcome.builder() .setOutcomeType(BLOCK) .build(); Rule rule = Rule.builder() .setTargets(List.of(target)) .setPredicate(predicate) .setOutcome(outcome) .setId("Block Webview Policy") .build(); setUucPolicy(policyClient, List.of(rule));
Combina più regole in tutti i target di aggiornamento
Poiché le regole vengono valutate in ordine, puoi combinare più regole per bloccare gli aggiornamenti durante periodi specifici (ad esempio l'orario di apertura o prima di una data di calendario target) e forzare gli aggiornamenti al di fuori di questi periodi.
L'esempio seguente applica due regole sequenziali a tutti e quattro i target di categoria (OS_UPDATE_WITH_API_LEVEL_CHANGE, OS_UPDATE_WITHOUT_API_LEVEL_CHANGE, GOOGLE_SYSTEM_SERVICES e GOOGLE_PLAY_SYSTEM_UPDATE):
- Blocca tutti gli aggiornamenti durante l'orario di apertura (dal lunedì al venerdì, dalle 09:00 alle 17:00).
- Al di fuori dell'orario di apertura, forza gli aggiornamenti disponibili da un massimo di 7 giorni.
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.FORCE import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.GOOGLE_PLAY_SYSTEM_UPDATE import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.GOOGLE_SYSTEM_SERVICES import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITHOUT_API_LEVEL_CHANGE import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE import java.time.DayOfWeek import java.time.Duration import java.time.LocalTime // 1. Define the targets to reuse across both rules. val allTargets = listOf( Target.builder().setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE).build(), Target.builder().setTargetType(OS_UPDATE_WITHOUT_API_LEVEL_CHANGE).build(), Target.builder().setTargetType(GOOGLE_SYSTEM_SERVICES).build(), Target.builder().setTargetType(GOOGLE_PLAY_SYSTEM_UPDATE).build() ) // 2. Rule 1: Block updates during business hours. val blockPredicate = Predicate.builder() .setDaysOfWeek( listOf( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build() val blockOutcome = Outcome.builder() .setOutcomeType(BLOCK) .build() val rule1 = Rule.builder() .setTargets(allTargets) .setPredicate(blockPredicate) .setOutcome(blockOutcome) .setId("Block Policy - rule1") .build() // 3. Rule 2: Force updates within 7 days of availability. val forcePredicate = Predicate.builder() .setUpdateAgeUpperBound(Duration.ofDays(7)) .build() val forceOutcome = Outcome.builder() .setOutcomeType(FORCE) .build() val rule2 = Rule.builder() .setTargets(allTargets) .setPredicate(forcePredicate) .setOutcome(forceOutcome) .setId("Force Policy - rule2") .build() setUucPolicy(policyClient, listOf(rule1, rule2))
Java
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.FORCE; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.GOOGLE_PLAY_SYSTEM_UPDATE; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.GOOGLE_SYSTEM_SERVICES; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITHOUT_API_LEVEL_CHANGE; import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target.TargetType.OS_UPDATE_WITH_API_LEVEL_CHANGE; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Target; import java.time.DayOfWeek; import java.time.Duration; import java.time.LocalTime; import java.util.List; // 1. Define the targets to reuse across both rules. ListallTargets = List.of( Target.builder().setTargetType(OS_UPDATE_WITH_API_LEVEL_CHANGE).build(), Target.builder().setTargetType(OS_UPDATE_WITHOUT_API_LEVEL_CHANGE).build(), Target.builder().setTargetType(GOOGLE_SYSTEM_SERVICES).build(), Target.builder().setTargetType(GOOGLE_PLAY_SYSTEM_UPDATE).build() ); // 2. Rule 1: Block updates during business hours. Predicate blockPredicate = Predicate.builder() .setDaysOfWeek( List.of( DayOfWeek.MONDAY, DayOfWeek.TUESDAY, DayOfWeek.WEDNESDAY, DayOfWeek.THURSDAY, DayOfWeek.FRIDAY ) ) .setTimeOfDayLowerBound(LocalTime.of(9, 0)) .setTimeOfDayUpperBound(LocalTime.of(17, 0)) .build(); Outcome blockOutcome = Outcome.builder() .setOutcomeType(BLOCK) .build(); Rule rule1 = Rule.builder() .setTargets(allTargets) .setPredicate(blockPredicate) .setOutcome(blockOutcome) .setId("Block Policy - rule1") .build(); // 3. Rule 2: Force updates within 7 days of availability. Predicate forcePredicate = Predicate.builder() .setUpdateAgeUpperBound(Duration.ofDays(7)) .build(); Outcome forceOutcome = Outcome.builder() .setOutcomeType(FORCE) .build(); Rule rule2 = Rule.builder() .setTargets(allTargets) .setPredicate(forcePredicate) .setOutcome(forceOutcome) .setId("Force Policy - rule2") .build(); setUucPolicy(policyClient, List.of(rule1, rule2));
Limita gli aggiornamenti fino a una data del calendario
Puoi utilizzare setDateLowerBound e setDateUpperBound su Predicate.Builder
per limitare o consentire gli aggiornamenti entro un intervallo di date di calendario specifico nel
fuso orario locale del dispositivo:
Kotlin
import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate import java.time.LocalDate val blockUntilDateRule = Rule.builder() .setId("block_until_date") .setTargets(allTargets) .setPredicate( Predicate.builder() .setDateUpperBound(LocalDate.of(2026, 3, 14)) .build() ) .setOutcome(Outcome.builder().setOutcomeType(BLOCK).build()) .build() setUucPolicy(policyClient, listOf(blockUntilDateRule))
Java
import static com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome.OutcomeType.BLOCK; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Outcome; import com.google.android.managementapi.policy.model.Policy.UnifiedUpdatePolicy.Rule.Predicate; import java.time.LocalDate; import java.util.List; Rule blockUntilDateRule = Rule.builder() .setId("block_until_date") .setTargets(allTargets) .setPredicate( Predicate.builder() .setDateUpperBound(LocalDate.of(2026, 3, 14)) .build() ) .setOutcome(Outcome.builder().setOutcomeType(BLOCK).build()) .build(); setUucPolicy(policyClient, List.of(blockUntilDateRule));
Gestisci gli errori
Se una chiamata PolicyClient non va a buon fine, la tua DPC personalizzata riceve un'eccezione (generata direttamente dai metodi Kotlin suspend getPolicy e updatePolicy o aggregata come causa di ExecutionException in getPolicyFuture e updatePolicyFuture). Le eccezioni comuni includono:
ApiLevelException: il dispositivo esegue una versione di Android precedente ad Android 13 (livello API 33).DeviceNotManagedException: il dispositivo non è gestito come dispositivo completamente gestito (proprietario del dispositivo) o come dispositivo di proprietà aziendale con un profilo di lavoro (COPE).AndroidDevicePolicyAppNotInstalledException,AndroidDevicePolicyAppDisabledExceptionoAndroidDevicePolicyAppNotUpdatedException: l'app ADP non è installata, è disattivata o esegue una versione precedente che non supportaPolicyClient. ChiamaprepareEnvironmentper installare o aggiornare l'app ADP.InvalidArgumentException: la richiesta non è corretta o contiene regole della policy non valide (ad esempio, l'omissione di una regolaido l'utilizzo di unidduplicato, l'impostazione di minuti o secondi su un limite di ora, la specifica di una durata dell'età di aggiornamento che non è un multiplo di 24 ore, l'inclusione di target duplicati o l'impostazione esplicita diOutcomeType.DEFAULTin una regola).SecurityException: l'app di chiamate non è autorizzata a gestire la policy per i dispositivi.TimeoutException(java.util.concurrent.TimeoutException),InternalExceptiono un'altra sottoclasse diAmapiSdkException: si è verificato un errore IPC o interno temporaneo durante la comunicazione con l'app ADP. Riprova la chiamata utilizzando una strategia di backoff esponenziale.
Strategie di ripetizione dei tentativi
Per le eccezioni causate da una condizione temporanea (ad esempio TimeoutException o
InternalException), implementa una strategia di ripetizione dei tentativi con backoff esponenziale:
- Dopo il primo errore, attendi un ritardo iniziale di 5 secondi prima di riprovare.
- Aumenta il ritardo in modo esponenziale a ogni tentativo successivo (10 secondi, 20 secondi e così via) fino a un numero massimo di tentativi.