1 /* 2 * Copyright (C) 2022 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package android.nearby.integration.untrusted 18 19 import android.content.Context 20 import android.nearby.BroadcastCallback 21 import android.nearby.BroadcastRequest 22 import android.nearby.NearbyDevice 23 import android.nearby.NearbyManager 24 import android.nearby.PresenceBroadcastRequest 25 import android.nearby.PresenceCredential 26 import android.nearby.PrivateCredential 27 import android.nearby.ScanCallback 28 import android.nearby.ScanRequest 29 import androidx.test.core.app.ApplicationProvider 30 import androidx.test.ext.junit.runners.AndroidJUnit4 31 import androidx.test.uiautomator.LogcatWaitMixin 32 import com.google.common.truth.Truth.assertThat 33 import java.time.Duration 34 import java.util.Calendar 35 import org.junit.Assert.assertThrows 36 import org.junit.Before 37 import org.junit.Test 38 import org.junit.runner.RunWith 39 40 @RunWith(AndroidJUnit4::class) 41 class NearbyManagerTest { 42 private lateinit var appContext: Context 43 44 @Before setUpnull45 fun setUp() { 46 appContext = ApplicationProvider.getApplicationContext<Context>() 47 } 48 49 /** Verify untrusted app can get Nearby service. */ 50 @Test testContextGetNearbyService_fromUnTrustedApp_returnsNotNullnull51 fun testContextGetNearbyService_fromUnTrustedApp_returnsNotNull() { 52 assertThat(appContext.getSystemService(Context.NEARBY_SERVICE)).isNotNull() 53 } 54 55 /** 56 * Verify untrusted app can't start scan because it needs BLUETOOTH_PRIVILEGED 57 * permission which is not for use by third-party applications. 58 */ 59 @Test testNearbyManagerStartScan_fromUnTrustedApp_throwsExceptionnull60 fun testNearbyManagerStartScan_fromUnTrustedApp_throwsException() { 61 val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager 62 val scanRequest = ScanRequest.Builder() 63 .setScanMode(ScanRequest.SCAN_MODE_LOW_LATENCY) 64 .setScanType(ScanRequest.SCAN_TYPE_FAST_PAIR) 65 .setBleEnabled(true) 66 .build() 67 val scanCallback = object : ScanCallback { 68 override fun onDiscovered(device: NearbyDevice) {} 69 70 override fun onUpdated(device: NearbyDevice) {} 71 72 override fun onLost(device: NearbyDevice) {} 73 } 74 75 assertThrows(SecurityException::class.java) { 76 nearbyManager.startScan(scanRequest, /* executor */ { it.run() }, scanCallback) 77 } 78 } 79 80 /** Verify untrusted app can't stop scan because it never successfully registers a callback. */ 81 @Test testNearbyManagerStopScan_fromUnTrustedApp_logsErrornull82 fun testNearbyManagerStopScan_fromUnTrustedApp_logsError() { 83 val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager 84 val scanCallback = object : ScanCallback { 85 override fun onDiscovered(device: NearbyDevice) {} 86 87 override fun onUpdated(device: NearbyDevice) {} 88 89 override fun onLost(device: NearbyDevice) {} 90 } 91 val startTime = Calendar.getInstance().time 92 93 nearbyManager.stopScan(scanCallback) 94 95 assertThat( 96 LogcatWaitMixin().waitForSpecificLog( 97 "Cannot stop scan with this callback because it is never registered.", 98 startTime, 99 WAIT_INVALID_OPERATIONS_LOGS_TIMEOUT 100 ) 101 ).isTrue() 102 } 103 104 /** 105 * Verify untrusted app can't start broadcast because it needs BLUETOOTH_PRIVILEGED 106 * permission which is not for use by third-party applications. 107 */ 108 @Test testNearbyManagerStartBroadcast_fromUnTrustedApp_throwsExceptionnull109 fun testNearbyManagerStartBroadcast_fromUnTrustedApp_throwsException() { 110 val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager 111 val salt = byteArrayOf(1, 2) 112 val secreteId = byteArrayOf(1, 2, 3, 4) 113 val metadataEncryptionKey = ByteArray(14) 114 val authenticityKey = byteArrayOf(0, 1, 1, 1) 115 val deviceName = "test_device" 116 val mediums = listOf(BroadcastRequest.MEDIUM_BLE) 117 val credential = 118 PrivateCredential.Builder(secreteId, authenticityKey, metadataEncryptionKey, deviceName) 119 .setIdentityType(PresenceCredential.IDENTITY_TYPE_PRIVATE) 120 .build() 121 val broadcastRequest: BroadcastRequest = 122 PresenceBroadcastRequest.Builder(mediums, salt, credential) 123 .addAction(123) 124 .build() 125 val broadcastCallback = BroadcastCallback { } 126 127 assertThrows(SecurityException::class.java) { 128 nearbyManager.startBroadcast( 129 broadcastRequest, /* executor */ { it.run() }, broadcastCallback 130 ) 131 } 132 } 133 134 /** 135 * Verify untrusted app can't stop broadcast because it never successfully registers a callback. 136 */ 137 @Test testNearbyManagerStopBroadcast_fromUnTrustedApp_logsErrornull138 fun testNearbyManagerStopBroadcast_fromUnTrustedApp_logsError() { 139 val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager 140 val broadcastCallback = BroadcastCallback { } 141 val startTime = Calendar.getInstance().time 142 143 nearbyManager.stopBroadcast(broadcastCallback) 144 145 assertThat( 146 LogcatWaitMixin().waitForSpecificLog( 147 "Cannot stop broadcast with this callback because it is never registered.", 148 startTime, 149 WAIT_INVALID_OPERATIONS_LOGS_TIMEOUT 150 ) 151 ).isTrue() 152 } 153 154 /** 155 * Verify untrusted app can't set powered off finding ephemeral IDs because it needs 156 * BLUETOOTH_PRIVILEGED permission which is not for use by third-party applications. 157 */ 158 @Test testNearbyManagerSetPoweredOffFindingEphemeralIds_fromUnTrustedApp_throwsExceptionnull159 fun testNearbyManagerSetPoweredOffFindingEphemeralIds_fromUnTrustedApp_throwsException() { 160 val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager 161 val eid = ByteArray(20) 162 163 assertThrows(SecurityException::class.java) { 164 nearbyManager.setPoweredOffFindingEphemeralIds(listOf(eid)) 165 } 166 } 167 168 /** 169 * Verify untrusted app can't set powered off finding mode because it needs BLUETOOTH_PRIVILEGED 170 * permission which is not for use by third-party applications. 171 */ 172 @Test testNearbyManagerSetPoweredOffFindingMode_fromUnTrustedApp_throwsExceptionnull173 fun testNearbyManagerSetPoweredOffFindingMode_fromUnTrustedApp_throwsException() { 174 val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager 175 176 assertThrows(SecurityException::class.java) { 177 nearbyManager.setPoweredOffFindingMode(NearbyManager.POWERED_OFF_FINDING_MODE_ENABLED) 178 } 179 } 180 181 /** 182 * Verify untrusted app can't get powered off finding mode because it needs BLUETOOTH_PRIVILEGED 183 * permission which is not for use by third-party applications. 184 */ 185 @Test testNearbyManagerGetPoweredOffFindingMode_fromUnTrustedApp_throwsExceptionnull186 fun testNearbyManagerGetPoweredOffFindingMode_fromUnTrustedApp_throwsException() { 187 val nearbyManager = appContext.getSystemService(Context.NEARBY_SERVICE) as NearbyManager 188 189 assertThrows(SecurityException::class.java) { 190 nearbyManager.getPoweredOffFindingMode() 191 } 192 } 193 194 companion object { 195 private val WAIT_INVALID_OPERATIONS_LOGS_TIMEOUT = Duration.ofSeconds(5) 196 } 197 } 198