네트워크 및 통신

이 가이드의 기능은 기기 정책 컨트롤러 (DPC) 앱에서 구현할 수 있는 네트워킹 및 전화 통신 관리 기능을 설명합니다. 이 문서에는 코드 샘플이 포함되어 있으며 Test DPC 앱을 Android 엔터프라이즈 기능의 샘플 코드 소스로 사용할 수도 있습니다.

DPC 앱은 개인 기기의 프로필 소유자 모드 또는 완전 관리형 기기의 기기 소유자 모드에서 실행할 수 있습니다. 다음 표는 DPC가 프로필 소유자 모드 또는 기기 소유자 모드에서 실행될 때 사용할 수 있는 기능을 나타냅니다.

기능 프로필 소유자 기기 소유자
여러 프로필에서 직장 연락처에 액세스
업무용 트래픽에 안전한 네트워크 연결 보장
리전 간에 단일 무선 네트워크 ID 설정
직장 프로필에 별도의 다이얼러 지정

여러 프로필에서 직장 연락처에 액세스

EMM을 사용하면 사용자의 개인 프로필에서 직장 연락처에 액세스하도록 허용하여 사용자의 개인 연락처와 직장 연락처에 로컬 검색 및 원격 디렉터리 조회를 통해 액세스할 수 있습니다. 개인 기기에서는 개인 프로필의 단일 다이얼러로 직장 통화뿐만 아니라 개인 전화를 걸고 받을 수 있습니다. 또한 직장 연락처가 시스템 UI에 잘 통합됩니다. 직장 프로필이 암호화되면 개인 프로필에서 데이터를 사용할 수 없습니다.

시스템 UI와 통합

시스템 UI는 서류 가방 아이콘을 사용하여 수신 업무 전화를 표시합니다. callLog에는 수신 및 발신 작업 전화를 지정하는 아이콘도 표시됩니다. 개인 다이얼러 및 연락처 앱은 원격 디렉터리 조회를 사용하여 직장 연락처의 발신번호 표시 정보를 표시할 수 있으므로 연락처가 이미 로컬 기기에 동기화되어 있지 않아도 됩니다. 메시지 앱에서 지역 발신번호 표시 및 검색 기능을 사용할 수 있습니다.

Android 호환성 정의 문서 (CDD)에는 직장 연락처가 기본 다이얼러에 표시되어야 하는 요구사항과 연락처 및 메시지 앱에서 직장 프로필임을 나타내기 위해 배지를 지정하는 요구사항이 포함됩니다.

직장 연락처에 액세스하고 검색할 수 있습니다.

사용자는 다이얼러 앱의 검색 화면에 표시되는 개인 프로필에서 직장 연락처에 액세스하여 전화를 걸 수 있습니다. 사용자는 자동 완성을 사용하여 기기에 로컬로 동기화되고 원격 디렉터리 조회를 통해 나열되는 직장 연락처를 검색할 수 있습니다.

기본 프로필에서 직장 연락처 관리하기

DPC는 직장 연락처를 검색할 권한을 제어합니다. 프로필 소유자 모드에서 실행되는 DPC는 개인 프로필에서 직장 연락처의 공개 상태를 관리합니다. 자세한 내용은 기기 정책 컨트롤러 빌드를 참고하세요.

개인 프로필로 직장 연락처 검색은 기본적으로 사용 설정되어 있습니다.

직장 트래픽을 위한 안전한 네트워크 연결 보장

기기 소유자 모드 또는 프로필 소유자 모드에서 실행되는 기기 정책 컨트롤러는 상시 사용 설정 가상 사설망 (VPN) 연결을 사용하여 애플리케이션이 우회할 수 없는 지정된 VPN 앱을 통해 트래픽을 전달하도록 할 수 있습니다. 상시 사용 설정 VPN 연결을 사용하여 DPC는 직장 프로필 또는 관리 기기의 네트워크 트래픽이 사용자의 개입 없이 VPN 서비스를 통과하도록 할 수 있습니다. 이 프로세스는 직장 프로필 내에서 지속적인 트래픽을 위해 보안 네트워크 연결을 만듭니다.

연결 유지 VPN 연결 정보

시스템 프레임워크의 일부로 VPN 라우팅은 자동으로 관리되므로 사용자가 VPN 서비스를 우회할 수 없습니다. 잠금 모드에서 VPN 서비스 연결이 해제되면 트래픽이 개방형 인터넷에 유출될 수 없습니다. VpnService를 구현하는 애플리케이션의 경우 상시 사용 VPN은 신뢰할 수 있는 서버를 통해 보안 VPN 연결을 관리하고 유지하기 위한 프레임워크를 제공합니다. VPN 서비스는 연결이 Wi-Fi를 통해서든 모바일 데이터를 통해서든 관계없이 앱 업데이트 시 연결을 자동으로 다시 시작합니다. 그리고 기기가 재부팅되면 프레임워크는 VPN 연결을 다시 시작합니다.

VPN 서비스에 대한 연결은 사용자에게 투명하게 공개됩니다. 회사 소유 기기의 경우 사용자가 상시 사용 설정 모드의 VPN에 대한 동의 대화상자를 확인할 필요가 없습니다. 사용자의 VPN 네트워크 설정을 통해 상시 사용 설정 연결을 수동으로 사용 설정할 수 있습니다.

DISALLOW_CONFIG_VPNtrue이면 사용자가 VPN을 구성할 수 없습니다. 사용자가 adb 디버그 명령어를 사용하여 상시 사용 설정 VPN을 재정의하지 못하도록 제한하려면 DISALLOW_DEBUGGING_FEATURES를 사용 설정합니다. 사용자가 VPN을 제거하지 못하게 하려면 DevicePolicyManager.setUninstallBlocked를 호출합니다.

VPN 서비스 설정

Android용 엔터프라이즈 솔루션을 사용하는 조직에서 VPN을 설정합니다.

  1. VpnService를 구현하는 VPN 앱을 설치합니다. VpnService.SERVICE_INTERFACE 작업과 일치하는 인텐트 필터를 사용하여 활성 VPN 서비스를 찾을 수 있습니다.
  2. BIND_VPN_SERVICE 권한으로 보호되는 앱의 매니페스트에서 VpnService를 선언합니다.
  3. 시스템에서 시작되도록 VpnService를 구성합니다. 시스템 부팅을 수신 대기하고 자체 수명 주기를 제어하여 VPN 앱이 자체적으로 시작되도록 설정하지 마세요.
  4. VPN 앱의 관리 구성을 설정합니다 (아래 예시 참고).

연결 유지 VPN 연결 사용 설정

DPC는 DevicePolicyManager.setAlwaysOnVpnPackage()를 호출하여 특정 앱을 통한 상시 사용 설정 VPN 연결을 구성할 수 있습니다.

이 연결은 자동으로 부여되고 재부팅 후에도 지속됩니다. lockdownEnabled가 false인 경우 휴대전화가 재부팅되고 VPN이 연결될 때부터 네트워크 트래픽이 보호되지 않을 수 있습니다. 이 기능은 VPN이 실패할 때마다 네트워크 연결을 중지하지 않거나 VPN이 필수적이지 않은 경우에 유용합니다.

상시 사용 설정 VPN 연결 확인하기

DPC는 DevicePolicyManager.getAlwaysOnVpnPackage().를 사용하여 현재 사용자를 위한 상시 사용 설정 VPN 연결을 관리하는 패키지의 이름을 읽을 수 있습니다.

이러한 패키지가 없거나 VPN이 시스템 설정 앱 내에서 생성된 경우 null가 반환됩니다.

TestDPC 앱에서 AlwaysOnVpnFragment.java는 이러한 API를 사용하여 연결 유지 VPN 연결을 설정합니다.

아래 예의 경우:

  • VPN 서비스의 관리 구성setApplicationRestrictions() 메서드를 사용하여 DevicePolicyManager에 의해 설정됩니다.
  • 관리 구성은 임의의 키-값 쌍을 사용하며 이 예시 앱은 이를 다른 곳에서 사용하여 VPN의 네트워크 설정을 구성합니다 (관리 구성 확인 참조).
  • 이 예에서는 VPN을 통해 시스템 패키지를 업데이트하지 않도록 Android 패키지 설치 프로그램을 차단 목록에 추가합니다. 직장 프로필 또는 기기 내 사용자의 모든 네트워크 트래픽은 패키지 설치 프로그램을 제외하고 이 VPN 앱을 통과합니다. 업데이트는 개방형 인터넷을 사용합니다.
  • 그러면 DevicePolicyManagersetAlwaysOnVpnPackage()를 사용하여 VPN 패키지에 상시 사용 설정 VPN 연결을 사용 설정하고 잠금 모드를 사용 설정합니다.

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

여러 리전에 단일 무선 네트워크 ID 설정

기기 소유자 모드 또는 프로필 소유자 모드에서 실행되는 기기 정책 컨트롤러 (DPC)는 여러 인증 기관 (CA) 인증서를 단일 무선 네트워크 구성과 연결할 수 있습니다. 이 구성을 사용하면 네트워크 이름 또는 서비스 세트 식별자 (SSID)는 동일하지만 다른 CA 인증서로 구성된 무선 액세스 포인트에 기기를 연결할 수 있습니다. 이는 조직의 무선 네트워크가 여러 지리적 리전에 있고 각 리전에 다른 인증 기관이 필요한 경우 유용합니다. 예를 들어 법적 서명에는 지역 CA가 필요한 현지 기관이 필요할 수 있습니다.

참고: Android는 API 18 (Jelly Bean)부터 setCaCertificate를 지원했지만, IT 관리자는 기기가 리전에 관계없이 각 액세스 포인트에서 원활한 인증을 유지하려면 각 CA에 네트워크를 별도로 프로비저닝해야 합니다.

서버를 식별하기 위한 CA 인증서 지정

동일한 SSID를 사용하여 서버를 식별하는 X.509 인증서 목록을 지정하려면 WifiEnterpriseConfig.setCaCertificates()를 사용하여 무선 구성에 모든 관련 CA를 포함합니다.

서버의 CA가 지정된 인증서 중 하나와 일치하는 경우 서버 인증서가 유효합니다. 기본 이름은 자동으로 인증서에 할당되고 구성 내에서 사용됩니다. WifiManager는 인증서를 설치하고 네트워크가 사용 설정되면 구성을 자동으로 저장하며 구성이 삭제되면 인증서를 삭제합니다.

무선 구성과 연결된 모든 CA 인증서를 가져오려면 WifiEnterpriseConfig.getCaCertificates()를 사용하여 X509Certificate 객체 목록을 반환합니다.

여러 CA 인증서를 사용하여 무선 구성 추가

  1. 서버의 ID를 확인합니다.
    1. X.509 CA 인증서를 로드합니다.
    2. 클라이언트의 비공개 키 및 인증서를 로드합니다. 인증서 파일을 읽는 방법의 예는 HTTPS 및 SSL을 사용한 보안을 참조하세요.
  2. WifiConfiguration를 만들고 SSID 및 키 관리를 설정합니다.
  3. WifiConfiguration에서 WifiEnterpriseConfig 인스턴스를 설정합니다.
    1. setCaCertificates()를 사용하여 X509Certificate 객체 목록으로 서버를 식별합니다.
    2. 클라이언트 사용자 인증 정보, ID, 비밀번호를 설정합니다.
    3. 연결 설정 과정에서 확장 가능 인증 프로토콜 (EAP) 및 2단계 방법을 설정합니다.
  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);
}

직장 프로필에 별도의 다이얼러 지정

직장 프로필에서 별도의 다이얼러 애플리케이션을 사용하도록 허용할 수 있습니다. 다이얼러 자체 또는 호출 백엔드의 ConnectionService API를 구현하는 VoIP (Voice over IP) 앱일 수 있습니다. 이렇게 하면 직장 프로필의 VoIP 애플리케이션에 동일한 통합 시스템 UI 다이얼링 환경이 제공되므로 업무 다이얼러가 핵심 기능이 됩니다. 업무 통화 계정으로 수신되는 전화는 개인 통화 계정으로 수신되는 수신 통화와 구분됩니다.

사용자는 전화 계정의 허용 목록에 있는 직장 다이얼러에서 전화를 걸고 받도록 선택할 수 있습니다. 다이얼러에서 건 전화 또는 직장 전화 계정으로 수신되는 모든 통화는 직장 프로필의 CallLog 제공자에 기록됩니다. 업무용 다이얼러는 직장 연락처에만 액세스할 수 있는 업무 전용 통화 기록을 유지합니다. 수신 회로 스위치 통화는 기본 다이얼러에서 처리되며 개인 통화 기록에 저장됩니다. 직장 프로필이 삭제되면 해당 직장 프로필과 연결된 통화 기록과 모든 직장 프로필 데이터도 삭제됩니다.

서드 파티 앱은 ConnectionService를 구현해야 합니다.

전화를 걸고 통화를 내장된 전화 앱에 통합해야 하는 서드 파티 VoIP 앱은 ConnectionService API를 구현할 수 있습니다. 업무 통화에 사용되는 모든 VoIP 서비스에 필요합니다. 이러한 앱은 통화를 기존의 모바일 데이터 통화처럼 취급하여 이점을 활용합니다. 예를 들어 내장 시스템 다이얼러 및 통화 기록에 표시됩니다. ConnectionService를 구현하는 앱이 직장 프로필에 설치되어 있으면 이 직장 프로필에도 설치된 다이얼러만 액세스할 수 있습니다.

개발자는 ConnectionService를 구현한 후 앱의 매니페스트 파일에 이를 추가하고 TelecomManager와 함께 PhoneAccount를 등록해야 합니다. 전화 계정은 전화를 걸거나 받는 고유한 메서드를 나타내며 각 ConnectionService에 여러 PhoneAccounts가 있을 수 있습니다. 전화 계정이 등록되면 사용자는 다이얼러 설정을 통해 이를 사용 설정할 수 있습니다.

시스템 UI 통합 및 알림

시스템 UI는 ConnectionService API를 백엔드로 사용하여 전화를 거는 서드 파티 앱을 위한 일관된 통합 통화 환경을 사용자에게 제공합니다. 직장 프로필에서 앱을 사용하는 경우 수신 전화와 상태 표시줄에 서류 가방 아이콘이 표시됩니다. 직장 프로필에 설치된 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
}