Сети и телефонная связь

В этом руководстве описаны функции управления сетями и телефонией, которые можно реализовать в приложении контроллера правил для устройств (DPC). Документ содержит образцы кода. В качестве источника образцов кода для корпоративных функций Android также можно использовать приложение Test DPC.

Приложение DPC может работать в режиме владельца профиля на личных устройствах или в режиме владельца устройства на полностью управляемых устройствах. В таблице ниже указано, какие функции доступны, когда контроллер политики устройств работает в режиме владельца профиля или владельца устройства.

Функция Владелец профиля Владелец устройства
Доступ к рабочим контактам из разных профилей ✓
Как обеспечить безопасность сетевого подключения для рабочего трафика ✓ ✓
Настройте единый идентификатор беспроводной сети для всех регионов ✓ ✓
Как указать отдельное приложение для звонков в рабочем профиле ✓

Доступ к рабочим контактам из разных профилей

EMM-решения могут разрешать доступ к рабочим контактам из личного профиля пользователя, чтобы он мог находить личные и рабочие контакты с помощью локального поиска и удаленного поиска в каталоге. На личных устройствах одна программа набора номера в личном профиле может совершать и принимать как личные, так и рабочие звонки. Кроме того, рабочие контакты хорошо интегрированы в интерфейс системы. Если рабочий профиль зашифрован, его данные недоступны для личного профиля.

Интеграция с системным интерфейсом

Входящие рабочие вызовы обозначаются значком портфеля. В callLog также показывается значок, обозначающий входящие и исходящие рабочие вызовы. Приложения для звонков и контактов в личном профиле могут показывать информацию о звонящем из рабочего профиля, используя удаленный поиск по каталогу. Для этого не требуется синхронизировать контакт с локальным устройством. Мессенджер может выполнять локальный поиск и определять номера.

В документе с описанием совместимости Android (CDD) указаны требования к показу рабочих контактов в номеронабирателе по умолчанию, а также требования к пометке контактов и мессенджеров, чтобы было понятно, что они относятся к рабочему профилю.

Рабочие контакты доступны и их можно найти

Пользователь может просматривать рабочие контакты и звонить им из личного профиля. Они отображаются на экране поиска приложения для звонков. Пользователь может искать рабочие контакты, синхронизированные с устройством, с помощью автозаполнения, а также просматривать их в удаленном каталоге.

Управление рабочими контактами в основном профиле

Разрешение на поиск рабочих контактов контролируется контроллером политики устройств. В режиме владельца профиля контроллер политики управляет видимостью рабочих контактов в личном профиле. Подробнее о том, как создать контроллер правил для устройств…

Поиск рабочих контактов в личном профиле включен по умолчанию.

Обеспечьте безопасное сетевое подключение для рабочего трафика

Контроллер политик устройств, работающий в режиме владельца устройства или профиля, может использовать постоянное подключение к виртуальной частной сети (VPN), чтобы принудительно направлять трафик приложений через указанное VPN-приложение, которое нельзя обойти. Используя постоянное VPN-подключение, контроллер политики устройств может обеспечить передачу сетевого трафика из рабочего профиля или управляемого устройства через VPN-сервис без вмешательства пользователя. Таким образом повышается уровень безопасности сетевого подключения для трафика в рабочем профиле.

О постоянных VPN-подключениях

Маршрутизация VPN управляется автоматически, поэтому пользователь не может обойти VPN-сервис. Если VPN-сервис отключится в режиме блокировки, трафик не попадет в открытый интернет. Для приложений, в которых реализован класс VpnService, постоянная VPN предоставляет фреймворк, позволяющий управлять защищенным VPN-подключением через доверенный сервер и поддерживать его. VPN-сервис автоматически перезапускает подключение при обновлении приложения, независимо от того, используется ли Wi-Fi или мобильная сеть. Если устройство перезагружается, фреймворк перезапускает VPN-подключение.

Подключение к VPN-сервису происходит незаметно для пользователя. Если устройство принадлежит компании, пользователю не нужно подтверждать согласие на использование VPN в режиме постоянного подключения. Настройки VPN-сети пользователя позволяют вручную включить постоянное подключение.

Если для правила DISALLOW_CONFIG_VPN задано значение true, пользователь не сможет настраивать VPN. Включите правило DISALLOW_DEBUGGING_FEATURES, чтобы запретить пользователям отключать постоянную сеть VPN с помощью команды отладки adb. Чтобы запретить пользователю удалять VPN, вызовите DevicePolicyManager.setUninstallBlocked.

Как настроить VPN-сервис

Организация, которая использует ваше корпоративное решение для Android, настраивает VPN.

  1. Установите VPN-приложение, в котором реализован класс VpnService. Чтобы найти активные VPN-сервисы, используйте фильтр интентов, соответствующий действию VpnService.SERVICE_INTERFACE.
  2. Объявите VpnService в манифесте приложения, защищенном разрешением BIND_VPN_SERVICE.
  3. Настройте VpnService так, чтобы он запускался системой. Не настраивайте приложение VPN так, чтобы оно запускалось при загрузке системы и управляло своим жизненным циклом.
  4. Задайте управляемые конфигурации для VPN-приложения (см. пример ниже).

Как включить постоянное VPN-подключение

Контроллер политики устройств может настроить постоянное VPN-подключение через определенное приложение, вызвав метод DevicePolicyManager.setAlwaysOnVpnPackage().

Это подключение предоставляется автоматически и сохраняется после перезагрузки. Если для параметра lockdownEnabled задано значение False, сетевой трафик может быть незащищенным в период между перезагрузкой телефона и VPN-подключением. Это полезно, если вы не хотите, чтобы сетевое подключение прерывалось при сбое VPN, или если VPN не является обязательным.

Как проверить постоянное VPN-подключение

Контроллер политики устройств может считывать название пакета, управляющего постоянным VPN-подключением для текущего пользователя, с помощью метода DevicePolicyManager.getAlwaysOnVpnPackage()..

Если такого пакета нет или VPN-подключение было создано в системном приложении "Настройки", возвращается значение null.

Пример

В приложении TestDPC AlwaysOnVpnFragment.java использует эти API, чтобы включить параметр для постоянного VPN-подключения.

Рассмотрим пример:

  • Управляемые конфигурации VPN-сервиса задаются DevicePolicyManager с помощью метода setApplicationRestrictions().
  • В управляемых конфигурациях используются произвольные пары "ключ-значение". В нашем примере приложения они применяются для настройки параметров сети VPN (см. раздел Проверка управляемых конфигураций).
  • В примере ниже установщик пакетов Android добавляется в черный список, чтобы он не обновлял системные пакеты через VPN. Весь сетевой трафик пользователя в рабочем профиле или на устройстве проходит через это VPN-приложение, за исключением установщика пакетов, обновления которого используют открытый интернет.
  • Затем DevicePolicyManager включает постоянное VPN-подключение для пакета VPN с помощью setAlwaysOnVpnPackage() и активирует режим блокировки.

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

Как настроить один идентификатор беспроводной сети для нескольких регионов

Контроллер политик устройств (DPC), работающий в режиме владельца устройства или профиля, может связать несколько сертификатов центра сертификации (ЦС) с одной конфигурацией беспроводной сети. При такой конфигурации устройство может подключаться к беспроводным точкам доступа, которые имеют одинаковое название сети или идентификатор беспроводной сети (SSID), но настроены с разными сертификатами ЦС. Это удобно, если беспроводные сети вашей организации расположены в нескольких географических регионах и для каждого региона требуется отдельный центр сертификации. Например, для юридических подписей может потребоваться местный орган власти, которому нужен региональный ЦС.

Примечание. Android поддерживает setCaCertificate с API 18 (Jelly Bean), но системные администраторы должны настраивать сети отдельно для каждого ЦС, чтобы обеспечить бесперебойную аутентификацию устройств в каждой точке доступа независимо от региона.

Укажите сертификаты ЦС для идентификации сервера

Чтобы указать список сертификатов X.509, которые идентифицируют сервер, использующий тот же SSID, включите все нужные ЦС в конфигурацию беспроводной сети с помощью WifiEnterpriseConfig.setCaCertificates().

Сертификат сервера считается действительным, если его ЦС совпадает с одним из указанных сертификатов. Сертификатам автоматически присваиваются названия по умолчанию, которые используются в конфигурации. WifiManager устанавливает сертификат и автоматически сохраняет конфигурацию, когда сеть включена, и удаляет сертификат, когда конфигурация удалена.

Чтобы получить все сертификаты ЦС, связанные с конфигурацией беспроводной сети, используйте WifiEnterpriseConfig.getCaCertificates(). Будет возвращен список объектов X509Certificate.

Как добавить конфигурацию беспроводной сети с несколькими сертификатами ЦС

  1. Проверьте идентификационные данные сервера:
    1. Загрузите сертификаты ЦС X.509.
    2. Загрузите закрытый ключ и сертификат клиента. Пример того, как прочитать файл сертификата, можно найти в статье Security with HTTPS and SSL (Обеспечение безопасности с помощью HTTPS и SSL).
  2. Создайте новую сеть WifiConfiguration, укажите ее SSID и настройте управление ключами.
  3. Настройте экземпляр WifiEnterpriseConfig на этом устройстве (WifiConfiguration).
    1. Укажите сервер со списком объектов X509Certificate, используя setCaCertificates().
    2. Укажите учетные данные клиента, идентификатор и пароль.
    3. При установке подключения задайте расширяемый протокол аутентификации (EAP) и метод второго этапа.
  4. Добавьте сеть с помощью WifiManager.
  5. Включите сеть. WifiManager автоматически сохраняет конфигурацию во время настройки.

В этом примере показано, как связать шаги:

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

Как указать отдельное приложение для звонков в рабочем профиле

Вы можете добавить в белый список отдельное приложение для звонков, которое будет использоваться в рабочем профиле. Это может быть как само приложение для набора номера, так и приложение для IP-телефонии, в котором реализован API ConnectionService для серверной части. Это позволяет использовать системный интерфейс для звонков в приложениях VoIP в рабочем профиле, фактически делая рабочий номеронабиратель основной функцией. Входящие вызовы на рабочие аккаунты для звонков отличаются от входящих вызовов на личные аккаунты для звонков.

Пользователь может совершать и принимать звонки с помощью одобренного рабочего приложения для звонков в аккаунте телефона. Все вызовы, сделанные с помощью этого приложения или поступившие на рабочий номер, записываются в CallLog рабочего профиля. В рабочем профиле ведется отдельный список вызовов, и у него есть доступ только к рабочим контактам. Входящие звонки с коммутацией каналов обрабатываются основным приложением для звонков и сохраняются в личном списке вызовов. Если рабочий профиль удален, список вызовов, связанный с ним, также удаляется вместе со всеми данными рабочего профиля.

Сторонние приложения должны использовать ConnectionService

Сторонние приложения для VoIP-телефонии, которым нужно совершать звонки и интегрировать их со встроенным приложением "Телефон", могут использовать API ConnectionService. Это необходимо для любого сервиса VoIP, используемого для рабочих звонков. Звонки в таких приложениях обрабатываются так же, как и обычные вызовы по сотовой связи. Например, они отображаются во встроенном системном номеронабирателе и списке вызовов. Если приложение, реализующее ConnectionService, установлено в рабочем профиле, оно доступно только для номеронабирателя, также установленного в этом рабочем профиле.

После реализации ConnectionService разработчик должен добавить его в файл манифеста приложения и зарегистрировать PhoneAccount с помощью TelecomManager. Аккаунт для звонков – это отдельный способ совершать и принимать вызовы. Для каждого ConnectionService может быть несколько PhoneAccounts. После регистрации аккаунта пользователь может включить его в настройках приложения для звонков.

Интеграция с системным интерфейсом и уведомлениями

Системный интерфейс обеспечивает пользователям единообразный и интегрированный опыт набора номера для сторонних приложений, которые используют API ConnectionService в качестве серверной части для совершения звонков. Если вы используете приложение в рабочем профиле, при входящих вызовах и в строке состояния будет показываться значок портфеля. Приложение, которое реализует ConnectionService и установлено в рабочем профиле, может использовать системный номеронабиратель или создать отдельный рабочий номеронабиратель. Это может быть одно приложение или несколько.

Приложение для набора номера определяет, является ли звонок рабочим, по флагу android.telecom.Call.Details.PROPERTY_ENTERPRISE_CALL. Если звонок рабочий, на панели набора номера показывается значок портфеля.

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
}