Netzwerke und Telefonie

Mit den Funktionen in diesem Leitfaden werden Netzwerk- und Telefonieverwaltungsfunktionen beschrieben, die Sie in Ihrer DPC-App (Device Policy Controller) implementieren können. Dieses Dokument enthält Codebeispiele. Sie können auch die App Test DPC als Quellcode für Android-Unternehmensfunktionen verwenden.

Eine DPC-App kann auf privaten Geräten im Profilinhabermodus oder auf vollständig verwalteten Geräten im Geräteinhabermodus ausgeführt werden. In der folgenden Tabelle sehen Sie, welche Features verfügbar sind, wenn der DPC im Profilinhabermodus oder Geräteinhabermodus ausgeführt wird:

Funktion Profilinhaber Geräteinhaber
Profilübergreifend auf Arbeitskontakte zugreifen
Sichere Netzwerkverbindung für geschäftlichen Traffic sicherstellen
Eine einzelne WLAN-ID für Regionen einrichten
Separate Telefon für das Arbeitsprofil angeben

Profilübergreifend auf Arbeitskontakte zugreifen

EMMs können dem privaten Profil eines Nutzers den Zugriff auf seine geschäftlichen Kontakte ermöglichen, sodass die privaten und beruflichen Kontakte eines Nutzers über die lokale Suche und die Remoteverzeichnis-Suche zugänglich sind. Auf privaten Geräten kann ein einzelner Dialer im privaten Profil sowohl private als auch geschäftliche Anrufe tätigen und empfangen. Darüber hinaus sind Arbeitskontakte gut in die System-UI integriert. Wenn das Arbeitsprofil verschlüsselt ist, sind seine Daten für das private Profil nicht verfügbar.

In die System-UI eingebunden

Auf der System-UI werden eingehende geschäftliche Anrufe durch ein Aktentaschensymbol angezeigt. Das callLog zeigt auch das Symbol zum Kennzeichnen eingehender und ausgehender geschäftlicher Anrufe an. Die Apps „Persönliche Telefon“- und „Kontakt“-App können die Anrufer-ID eines geschäftlichen Kontakts über eine Remote-Verzeichnissuche anzeigen lassen. Der Kontakt muss also nicht bereits auf dem lokalen Gerät synchronisiert sein. Die Messaging-App kann eine lokale Anrufer-ID und eine Suche durchführen.

Das Android Compatibility Definition Document (CDD) enthält Anforderungen für geschäftliche Kontakte, die in der Standard-Telefon-App angezeigt werden sollen, sowie Anforderungen, dass Kontakte und Messaging-Apps gekennzeichnet sein müssen, um darauf hinzuweisen, dass sie aus dem Arbeitsprofil stammen.

Geschäftliche Kontakte sind zugänglich und suchbar

Der Nutzer kann über sein privates Profil, das auf dem Suchbildschirm der Telefon-App angezeigt wird, auf geschäftliche Kontakte zugreifen und diese anrufen. Der Nutzer kann mithilfe der automatischen Vervollständigung nach geschäftlichen Kontakten suchen, die lokal mit dem Gerät synchronisiert und über eine Remoteverzeichnis-Suche aufgelistet werden.

Berufliche Kontakte im primären Profil verwalten

Der DPC steuert die Berechtigung zum Durchsuchen geschäftlicher Kontakte. Der DPC wird im Profilinhabermodus ausgeführt und verwaltet die Sichtbarkeit der geschäftlichen Kontakte im privaten Profil. Weitere Informationen finden Sie unter Device Policy Controller erstellen.

Die Suche nach geschäftlichen Kontakten über das private Profil ist standardmäßig aktiviert.

Sichere Netzwerkverbindung für geschäftlichen Traffic sicherstellen

Wenn ein Geräterichtlinien-Controller entweder im Modus „Geräteeigentümer“ oder im Profilinhabermodus ausgeführt wird, kann er über eine durchgehend aktive VPN-Verbindung (Virtual Private Network) erzwingen, dass Anwendungen Traffic über eine angegebene VPN-App weiterleiten, die nicht umgangen werden kann. Mithilfe einer durchgehend aktiven VPN-Verbindung kann der DPC sicherstellen, dass der Netzwerkverkehr von einem Arbeitsprofil oder einem verwalteten Gerät ohne Eingriff des Nutzers einen VPN-Dienst durchläuft. Dadurch wird eine sichere Netzwerkverbindung für kontinuierlichen Traffic innerhalb eines Arbeitsprofils erstellt.

Über durchgehend aktive VPN-Verbindungen

Als Teil des System-Frameworks wird das VPN-Routing automatisch verwaltet, damit der Nutzer den VPN-Dienst nicht umgehen kann. Wenn der VPN-Dienst im Sperrmodus getrennt ist, kann kein Datenverkehr in das offene Internet gelangen. Für Anwendungen, die VpnService implementieren, bietet ein durchgehend aktives VPN ein Framework zum Verwalten einer sicheren VPN-Verbindung über einen vertrauenswürdigen Server und zur Aufrechterhaltung dieser Verbindung. Der VPN-Dienst startet die Verbindung über App-Updates automatisch neu, unabhängig davon, ob sie über WLAN oder Mobilfunk erfolgt. Und falls das Gerät neu gestartet wird, startet das Framework die VPN-Verbindung neu.

Die Verbindung zum VPN-Dienst ist für den Nutzer transparent. Bei einem unternehmenseigenen Gerät muss der Nutzer keinen Einwilligungsdialog für ein VPN im Always-on-Modus bestätigen. Über die VPN-Netzwerkeinstellungen des Nutzers kann manuell eine durchgehend aktive Verbindung aktiviert werden.

Wenn DISALLOW_CONFIG_VPN den Wert true hat, kann der Nutzer das VPN nicht konfigurieren. Aktivieren Sie DISALLOW_DEBUGGING_FEATURES, um zu verhindern, dass Nutzer das durchgehend aktive VPN mit dem Befehl „adb debug“ überschreiben. Wenn Sie verhindern möchten, dass ein Nutzer das VPN deinstalliert, rufen Sie DevicePolicyManager.setUninstallBlocked auf.

VPN-Dienst einrichten

Die Organisation, die Ihre Unternehmenslösung für Android verwendet, richtet das VPN ein.

  1. Installieren Sie eine VPN-App, die VpnService implementiert. Sie können nach aktiven VPN-Diensten suchen, indem Sie einen Intent-Filter verwenden, der der Aktion VpnService.SERVICE_INTERFACE entspricht.
  2. Deklarieren Sie im Manifest der App eine VpnService, die durch die Berechtigung BIND_VPN_SERVICE geschützt ist.
  3. Konfigurieren Sie VpnService so, dass es vom System gestartet wird. Vermeiden Sie es, die VPN-App so einzustellen, dass sie auf einen Systemstart wartet und ihren eigenen Lebenszyklus steuert.
  4. Legen Sie die verwalteten Konfigurationen für die VPN-Anwendung fest (siehe Beispiel unten).

Durchgehend aktive VPN-Verbindung aktivieren

Der DPC kann durch Aufrufen von DevicePolicyManager.setAlwaysOnVpnPackage() über eine bestimmte Anwendung eine durchgehend aktive VPN-Verbindung konfigurieren.

Diese Verbindung wird automatisch gewährt und bleibt nach einem Neustart bestehen. Wenn lockdownEnabled auf „false“ gesetzt ist, ist der Netzwerkverkehr möglicherweise ab dem Zeitpunkt des Neustarts des Smartphones und der Verbindung des VPN nicht sicher. Dies ist nützlich, wenn Sie die Netzwerkverbindung nicht beenden möchten, wenn das VPN ausfällt oder das VPN nicht erforderlich ist.

Durchgehend aktive VPN-Verbindung prüfen

Der DPC kann den Namen des Pakets lesen, das eine durchgehend aktive VPN-Verbindung für den aktuellen Nutzer mit DevicePolicyManager.getAlwaysOnVpnPackage(). verwaltet

Wenn kein solches Paket vorhanden ist oder das VPN in den Systemeinstellungen erstellt wurde, wird null zurückgegeben.

Beispiel

In der TestDPC-App verwendet AlwaysOnVpnFragment.java diese APIs, um die Einstellung für eine durchgehend aktive VPN-Verbindung zu aktivieren.

Im folgenden Beispiel:

  • Die verwalteten Konfigurationen des VPN-Dienstes werden vom DevicePolicyManager mithilfe der Methode setApplicationRestrictions() festgelegt.
  • Verwaltete Konfigurationen verwenden beliebige Schlüssel/Wert-Paare, die in dieser Beispielanwendung an anderer Stelle verwendet werden, um die Netzwerkeinstellungen des VPN zu konfigurieren (siehe Verwaltete Konfigurationen prüfen).
  • In diesem Beispiel wird das Installationsprogramm für das Android-Paket einer Sperrliste hinzugefügt, damit Systempakete über das VPN nicht aktualisiert werden. Der gesamte Netzwerkverkehr des Nutzers innerhalb des Arbeitsprofils oder des Geräts wird über diese VPN-App geleitet, mit Ausnahme des Paketinstallationsprogramms. Für seine Updates wird das offene Internet verwendet.
  • DevicePolicyManager aktiviert dann die durchgehend aktive VPN-Verbindung für das VPN-Paket mithilfe von setAlwaysOnVpnPackage() und aktiviert den Sperrmodus.

Kotlin

// Set VPN's managed configurations
val config = Bundle().apply {
  putString(Extras.VpnApp.ADDRESS, "192.0.2.0")
  putString(Extras.VpnApp.IDENTITY, "vpn.account1")
  putString(Extras.VpnApp.CERTIFICATE, "keystore://auth_certificate")
  putStringArray(Extras.VpnApp.DENYLIST,
        arrayOf("com.android.packageinstaller"))
}

val dpm = getSystemService(Context.DEVICE_POLICY_SERVICE) as DevicePolicyManager

val admin = myDeviceAdminReceiver.getComponentName(this)

// Name of package to update managed configurations
val vpnPackageName = "com.example.vpnservice"

// Associate managed configurations with DeviceAdminReceiver
dpm.setApplicationRestrictions(admin, vpnPackageName, config)

// Enable always-on VPN connection through VPN package
try {
  val lockdownEnabled = true
  dpm.setAlwaysOnVpnPackage(admin, vpnPackageName, lockdownEnabled)
} catch (ex: Exception) {
  throw PolicyException()
}

Java

// Set VPN's managed configurations
final Bundle config = new Bundle();
config.putString(Extras.VpnApp.ADDRESS, "192.0.2.0");
config.putString(Extras.VpnApp.IDENTITY, "vpn.account1");
config.putString(Extras.VpnApp.CERTIFICATE, "keystore://auth_certificate");
config.putStringArray(Extras.VpnApp.DENYLIST,
                      new String[]{"com.android.packageinstaller"});

DevicePolicyManager dpm = (DevicePolicyManager) getSystemService(Context.DEVICE_POLICY_SERVICE);

ComponentName admin = myDeviceAdminReceiver.getComponentName(this);

// Name of package to update managed configurations
final String vpnPackageName = "com.example.vpnservice";

// Associate managed configurations with DeviceAdminReceiver
dpm.setApplicationRestrictions(admin, vpnPackageName, config);

// Enable always-on VPN connection through VPN package
try {
  boolean lockdownEnabled = true;
  dpm.setAlwaysOnVpnPackage(admin, vpnPackageName, lockdownEnabled));
} catch (Exception ex) {
  throw new PolicyException(...);
}

Eine einzige WLAN-ID für mehrere Regionen einrichten

Wenn ein Device Policy Controller (DPC) entweder im Modus „Geräteeigentümer“ oder im Profilinhabermodus ausgeführt wird, kann er einer einzelnen WLAN-Konfiguration mehrere CA-Zertifikate (Certificate Authority, CA) zuordnen. Mit dieser Konfiguration kann ein Gerät eine Verbindung zu Wireless-Zugangspunkten herstellen, die denselben Netzwerknamen oder Service Set Identifier (SSID) haben, aber mit unterschiedlichen CA-Zertifikaten konfiguriert sind. Dies ist nützlich, wenn sich die drahtlosen Netzwerke Ihrer Organisation in mehreren geografischen Regionen befinden und für jede Region eine andere Zertifizierungsstelle erforderlich ist. Für rechtsgültige Signaturen kann beispielsweise eine lokale Behörde erforderlich sein, die eine regionale Zertifizierungsstelle benötigt.

Hinweis:setCaCertificate wird seit API 18 (Jelly Bean) von Android unterstützt. IT-Administratoren müssen ihre Netzwerke jedoch für jede Zertifizierungsstelle separat bereitstellen, damit Geräte unabhängig von ihrer Region an jedem Zugangspunkt eine nahtlose Authentifizierung haben.

CA-Zertifikate angeben, um den Server zu identifizieren

Wenn Sie eine Liste von X.509-Zertifikaten angeben möchten, die den Server mit derselben SSID identifizieren, schließen Sie alle relevanten Zertifizierungsstellen mit WifiEnterpriseConfig.setCaCertificates() in die WLAN-Konfiguration ein.

Ein Serverzertifikat ist gültig, wenn seine Zertifizierungsstelle mit einem der angegebenen Zertifikate übereinstimmt. Standardnamen werden den Zertifikaten automatisch zugewiesen und innerhalb der Konfiguration verwendet. WifiManager installiert das Zertifikat und speichert die Konfiguration automatisch, wenn das Netzwerk aktiviert wird. Beim Löschen der Konfiguration wird das Zertifikat entfernt.

Wenn Sie alle CA-Zertifikate abrufen möchten, die mit der WLAN-Konfiguration verknüpft sind, verwenden Sie WifiEnterpriseConfig.getCaCertificates(), um eine Liste von X509Certificate-Objekten zurückzugeben.

Drahtloskonfiguration mit mehreren CA-Zertifikaten hinzufügen

  1. Überprüfen Sie die Identität des Servers:
    1. Laden Sie die X.509-CA-Zertifikate.
    2. Laden Sie den privaten Schlüssel und das Zertifikat des Clients. Ein Beispiel für das Lesen einer Zertifikatsdatei finden Sie unter Sicherheit mit HTTPS und SSL.
  2. Erstellen Sie eine neue WifiConfiguration und legen Sie die SSID und die Schlüsselverwaltung fest.
  3. Richten Sie die WifiEnterpriseConfig-Instanz auf diesem WifiConfiguration ein.
    1. Ermitteln Sie den Server mit einer Liste von X509Certificate-Objekten mithilfe von setCaCertificates().
    2. Legen Sie die Clientanmeldedaten, die Identität und das Passwort fest.
    3. Legen Sie das erweiterbare Authentifizierungsprotokoll (EAP) und die Methode der Phase 2 beim Herstellen der Verbindung fest.
  4. Fügen Sie das Netzwerk mit der WifiManager hinzu.
  5. Aktivieren Sie das Netzwerk. WifiManager speichert die Konfiguration automatisch während der Einrichtung.

In diesem Beispiel werden die Schritte zusammengefasst:

Kotlin

// Verify the server's identity
val caCert0 = getCaCert("cert0.crt")
val caCert1 = getCaCert("cert1.crt")
val clientKey = getClientKey()
val clientCert = getClientCert()

// Create Wi-Fi configuration
val wifiConfig = WifiConfiguration().apply {
  SSID = "mynetwork"
  allowedKeyManagement.set(KeyMgmt.WPA_EAP)
  allowedKeyManagement.set(KeyMgmt.IEEE8021X)

  // Set up Wi-Fi enterprise configuration
  enterpriseConfig.setCaCertificates(arrayOf<X509Certificate>(caCert0, caCert1))
  enterpriseConfig.setClientKeyEntry(clientKey, clientCert)
  enterpriseConfig.setIdentity("myusername")
  enterpriseConfig.setEapMethod(Eap.TLS)
  enterpriseConfig.setPhase2Method(Phase2.NONE)
}


// Add network
val wifiManager = getSystemService(Context.WIFI_SERVICE) as WifiManager
val netId = wifiManager.addNetwork(wifiConfig)

// Enable network
if (netId < 0) {
  // Error creating new network
} else {
  wifiManager.enableNetwork(netId, true)
}

Java

// Verify the server's identity
X509Certificate caCert0 = getCaCert("cert0.crt");
X509Certificate caCert1 = getCaCert("cert1.crt");
PrivateKey clientKey = getClientKey();
X509Certificate clientCert = getClientCert();

// Create Wi-Fi configuration
WifiConfiguration wifiConfig = new WifiConfiguration();
wifiConfig.SSID = "mynetwork";
wifiConfig.allowedKeyManagement.set(KeyMgmt.WPA_EAP);
wifiConfig.allowedKeyManagement.set(KeyMgmt.IEEE8021X);

// Set up Wi-Fi enterprise configuration
wifiConfig.enterpriseConfig.setCaCertificates(new X509Certificate[] {caCert0, caCert1});
wifiConfig.enterpriseConfig.setClientKeyEntry(clientKey, clientCert);
wifiConfig.enterpriseConfig.setIdentity("myusername");
wifiConfig.enterpriseConfig.setEapMethod(Eap.TLS);
wifiConfig.enterpriseConfig.setPhase2Method(Phase2.NONE);

// Add network
WifiManager wifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);
int netId = wifiManager.addNetwork(wifiConfig);

// Enable network
if (netId < 0) {
  // Error creating new network
} else {
  wifiManager.enableNetwork(netId, true);
}

Separate Telefon App für das Arbeitsprofil angeben

Sie können eine separate Telefon-App für die Verwendung in einem Arbeitsprofil auf die Zulassungsliste setzen. Das kann das Telefon selbst oder eine VoIP-App (Voice over IP) sein, in der die ConnectionService API für das aufrufende Back-End implementiert ist. Dies bietet die gleiche integrierte System-UI-Anruffunktionen für VoIP-Anwendungen im Arbeitsprofil, wodurch der Arbeits-Dialer effektiv zu einer Kernfunktion wird. Eingehende Anrufe an die geschäftlichen Anrufkonten werden von eingehenden Anrufen an die privaten Anrufkonten unterschieden.

Der Nutzer kann über ein Telefonkonto über die Zulassungsliste für Arbeitsprofile Anrufe starten und annehmen. Alle Anrufe über diese Telefon App oder eingehende Anrufe über das geschäftliche Telefonkonto werden beim Anbieter CallLog des Arbeitsprofils aufgezeichnet. Die Telefon App führt eine reine geschäftliche Anrufliste, die ausschließlich auf geschäftliche Kontakte zugreifen kann. Eingehende Anrufe mit Netzwerkwechsel werden vom Haupt-Telefon bearbeitet und in einer persönlichen Anrufliste gespeichert. Wenn ein Arbeitsprofil gelöscht wird, werden auch die damit verknüpften Anruflisten und alle Arbeitsprofildaten gelöscht.

Drittanbieter-Apps müssen ConnectionService implementieren

VoIP-Apps von Drittanbietern, die Anrufe tätigen müssen und bei denen diese Anrufe in die integrierte Telefon-App integriert sind, können die ConnectionService API implementieren. Dies ist für jeden VoIP-Dienst erforderlich, der für geschäftliche Anrufe verwendet wird. Bei diesen Apps werden Anrufe wie herkömmliche Mobilfunkanrufe behandelt. Sie werden beispielsweise in der integrierten Telefonfunktion des Systems und in der Anrufliste angezeigt. Wenn die App, die ConnectionService implementiert, im Arbeitsprofil installiert ist, ist sie nur über eine Telefon App zugänglich, die ebenfalls in diesem Arbeitsprofil installiert ist.

Sobald der Entwickler ConnectionService implementiert hat, sollte er es der Manifestdatei der App hinzufügen und ein PhoneAccount mit der TelecomManager registrieren. Ein Telefonkonto stellt eine separate Methode zum Tätigen oder Empfangen von Anrufen dar. Für jede ConnectionService können mehrere PhoneAccounts vorhanden sein. Nach der Registrierung des Telefonkontos kann der Nutzer es über die Telefoneinstellungen aktivieren.

Integration der System-UI und Benachrichtigungen

Die System-UI bietet Nutzern eine konsistente und integrierte Anruffunktion für Drittanbieter-Apps, die die ConnectionService API als Back-End für Anrufe verwenden. Wenn Sie die App in einem Arbeitsprofil verwenden, wird bei eingehenden Anrufen und in der Statusleiste ein Aktentaschensymbol angezeigt. Eine Anwendung, die ConnectionService implementiert, die im Arbeitsprofil installiert ist, kann den System-Dialer verwenden oder einen separaten Work-Dialer erstellen. Dabei kann es sich um eine einzelne App oder unterschiedliche Apps handeln.

Die Telefonanwendung prüft anhand des Flags android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL, ob ein geschäftlicher Anruf getätigt oder empfangen wird. Wenn es sich um einen geschäftlichen Anruf handelt, zeigt das Telefon dies dem Nutzer durch Hinzufügen eines Arbeitskennzeichens (Aktentaschensymbol) an:

Kotlin

// Call placed through a work phone account. getCurrentCall() is defined by the
// dialer.
val call = getCurrentCall()
if (call.hasProperty(android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL)) {
  // Set briefcase icon
}

Java

// Call placed through a work phone account. getCurrentCall() is defined by the
// dialer.
Call call = getCurrentCall();
if (call.hasProperty(android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL)) {
  // Set briefcase icon
}