Merge "Add carrier privilege utils to CarrierConfigRule" into main
diff --git a/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt b/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
index ae0de79..c9d2527 100644
--- a/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
+++ b/staticlibs/testutils/devicetests/com/android/testutils/CarrierConfigRule.kt
@@ -18,20 +18,28 @@
import android.Manifest.permission.MODIFY_PHONE_STATE
import android.Manifest.permission.READ_PHONE_STATE
+import android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.content.IntentFilter
+import android.content.pm.PackageManager
import android.os.ConditionVariable
+import android.os.ParcelFileDescriptor
import android.os.PersistableBundle
+import android.os.Process
import android.telephony.CarrierConfigManager
import android.telephony.CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED
+import android.telephony.SubscriptionManager
import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.CarrierPrivilegesCallback
import android.util.Log
import androidx.test.platform.app.InstrumentationRegistry
-import com.android.modules.utils.build.SdkLevel.isAtLeastU
+import com.android.modules.utils.build.SdkLevel
import com.android.testutils.runAsShell
import com.android.testutils.tryTest
+import java.security.MessageDigest
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
import org.junit.rules.TestRule
@@ -46,12 +54,20 @@
* configuration automatically on teardown.
*/
class CarrierConfigRule : TestRule {
+ private val HEX_CHARS: CharArray = charArrayOf(
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+ )
+
private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
+ private val uiAutomation by lazy { InstrumentationRegistry.getInstrumentation().uiAutomation }
private val ccm by lazy { context.getSystemService(CarrierConfigManager::class.java) }
// Map of (subId) -> (original values of overridden settings)
private val originalConfigs = mutableMapOf<Int, PersistableBundle>()
+ // Map of (subId) -> (original values of carrier service package)
+ private val originalCarrierServicePackages = mutableMapOf<Int, String?>()
+
override fun apply(base: Statement, description: Description): Statement {
return CarrierConfigStatement(base, description)
}
@@ -118,6 +134,177 @@
}
}
+ private fun runShellCommand(cmd: String) {
+ val fd: ParcelFileDescriptor = uiAutomation.executeShellCommand(cmd)
+ fd.close() // Don't care about the output.
+ }
+
+ /**
+ * Converts a byte array into a String of hexadecimal characters.
+ *
+ * @param bytes an array of bytes
+ * @return hex string representation of bytes array
+ */
+ private fun bytesToHexString(bytes: ByteArray?): String? {
+ if (bytes == null) return null
+
+ val ret = StringBuilder(2 * bytes.size)
+
+ for (i in bytes.indices) {
+ var b: Int
+ b = 0x0f and (bytes[i].toInt() shr 4)
+ ret.append(HEX_CHARS[b])
+ b = 0x0f and bytes[i].toInt()
+ ret.append(HEX_CHARS[b])
+ }
+
+ return ret.toString()
+ }
+
+ private fun setHoldCarrierPrivilege(hold: Boolean, subId: Int) {
+ if (!SdkLevel.isAtLeastT()) {
+ throw UnsupportedOperationException(
+ "Acquiring carrier privilege requires at least T SDK"
+ )
+ }
+
+ fun getCertHash(): String {
+ val pkgInfo = context.packageManager.getPackageInfo(
+ context.opPackageName,
+ PackageManager.GET_SIGNATURES
+ )
+ val digest = MessageDigest.getInstance("SHA-256")
+ val certHash = digest.digest(pkgInfo.signatures!![0]!!.toByteArray())
+ return bytesToHexString(certHash)!!
+ }
+
+ val tm = context.getSystemService(TelephonyManager::class.java)!!
+
+ val cv = ConditionVariable()
+ val cpb = PrivilegeWaiterCallback(cv)
+ // The lambda below is capturing |cpb|, whose type inherits from a class that appeared in
+ // T. This means the lambda will compile as a private method of this class taking a
+ // PrivilegeWaiterCallback argument. As JUnit uses reflection to enumerate all methods
+ // including private methods, this would fail with a link error when running on S-.
+ // To solve this, make the lambda serializable, which causes the compiler to emit a
+ // synthetic class instead of a synthetic method.
+ tryTest @JvmSerializableLambda {
+ val slotIndex = SubscriptionManager.getSlotIndex(subId)!!
+ runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
+ tm.registerCarrierPrivilegesCallback(slotIndex, { it.run() }, cpb)
+ }
+ // Wait for the callback to be registered
+ assertTrue(cv.block(CARRIER_CONFIG_CHANGE_TIMEOUT_MS),
+ "Can't register CarrierPrivilegesCallback")
+ if (cpb.hasPrivilege == hold) {
+ if (hold) {
+ Log.w(TAG, "Package ${context.opPackageName} already is privileged")
+ } else {
+ Log.w(TAG, "Package ${context.opPackageName} already isn't privileged")
+ }
+ return@tryTest
+ }
+ if (hold) {
+ addConfigOverrides(subId, PersistableBundle().also {
+ it.putStringArray(CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY,
+ arrayOf(getCertHash()))
+ })
+ } else {
+ cleanUpNow()
+ }
+ } cleanup @JvmSerializableLambda {
+ runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
+ tm.unregisterCarrierPrivilegesCallback(cpb)
+ }
+ }
+ }
+
+ /**
+ * Acquires carrier privilege on the given subscription ID.
+ */
+ fun acquireCarrierPrivilege(subId: Int) = setHoldCarrierPrivilege(true, subId)
+
+ /**
+ * Drops carrier privilege from the given subscription ID.
+ */
+ fun dropCarrierPrivilege(subId: Int) = setHoldCarrierPrivilege(false, subId)
+
+ /**
+ * Sets the carrier service package override for the given subscription ID. A null argument will
+ * clear any previously-set override.
+ */
+ fun setCarrierServicePackageOverride(subId: Int, pkg: String?) {
+ if (!SdkLevel.isAtLeastU()) {
+ throw UnsupportedOperationException(
+ "Setting carrier service package override requires at least U SDK"
+ )
+ }
+
+ val tm = context.getSystemService(TelephonyManager::class.java)!!
+
+ val cv = ConditionVariable()
+ val cpb = CarrierServiceChangedWaiterCallback(cv)
+ // The lambda below is capturing |cpb|, whose type inherits from a class that appeared in
+ // T. This means the lambda will compile as a private method of this class taking a
+ // PrivilegeWaiterCallback argument. As JUnit uses reflection to enumerate all methods
+ // including private methods, this would fail with a link error when running on S-.
+ // To solve this, make the lambda serializable, which causes the compiler to emit a
+ // synthetic class instead of a synthetic method.
+ tryTest @JvmSerializableLambda {
+ val slotIndex = SubscriptionManager.getSlotIndex(subId)!!
+ runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
+ tm.registerCarrierPrivilegesCallback(slotIndex, { it.run() }, cpb)
+ }
+ // Wait for the callback to be registered
+ assertTrue(cv.block(CARRIER_CONFIG_CHANGE_TIMEOUT_MS),
+ "Can't register CarrierPrivilegesCallback")
+ if (cpb.pkgName == pkg) {
+ Log.w(TAG, "Carrier service package was already $pkg")
+ return@tryTest
+ }
+ if (!originalCarrierServicePackages.contains(subId)) {
+ originalCarrierServicePackages.put(subId, cpb.pkgName)
+ }
+ cv.close()
+ runAsShell(MODIFY_PHONE_STATE) {
+ if (null == pkg) {
+ // There is a bug in clear-carrier-service-package-override where not adding
+ // the -s argument will use the wrong slot index : b/299604822
+ runShellCommand("cmd phone clear-carrier-service-package-override" +
+ " -s $subId")
+ } else {
+ runShellCommand("cmd phone set-carrier-service-package-override $pkg" +
+ " -s $subId")
+ }
+ }
+ assertTrue(cv.block(CARRIER_CONFIG_CHANGE_TIMEOUT_MS),
+ "Can't modify carrier service package")
+ } cleanup @JvmSerializableLambda {
+ runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
+ tm.unregisterCarrierPrivilegesCallback(cpb)
+ }
+ }
+ }
+
+ private class PrivilegeWaiterCallback(private val cv: ConditionVariable) :
+ CarrierPrivilegesCallback {
+ var hasPrivilege = false
+ override fun onCarrierPrivilegesChanged(p: MutableSet<String>, uids: MutableSet<Int>) {
+ hasPrivilege = uids.contains(Process.myUid())
+ cv.open()
+ }
+ }
+
+ private class CarrierServiceChangedWaiterCallback(private val cv: ConditionVariable) :
+ CarrierPrivilegesCallback {
+ var pkgName: String? = null
+ override fun onCarrierPrivilegesChanged(p: MutableSet<String>, u: MutableSet<Int>) {}
+ override fun onCarrierServiceChanged(pkgName: String?, uid: Int) {
+ this.pkgName = pkgName
+ cv.open()
+ }
+ }
+
/**
* Cleanup overrides that were added by the test case.
*
@@ -138,6 +325,10 @@
}
originalConfigs.clear()
}
+ originalCarrierServicePackages.forEach { (subId, pkg) ->
+ setCarrierServicePackageOverride(subId, pkg)
+ }
+ originalCarrierServicePackages.clear()
}
}
@@ -145,7 +336,7 @@
subId: Int,
keys: Set<String>
): PersistableBundle {
- return if (isAtLeastU()) {
+ return if (SdkLevel.isAtLeastU()) {
// This method is U+
getConfigForSubId(subId, *keys.toTypedArray())
} else {
diff --git a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
index 5e035a2..6dc23ff 100644
--- a/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
+++ b/tests/cts/net/src/android/net/cts/NetworkAgentTest.kt
@@ -15,7 +15,6 @@
*/
package android.net.cts
-import android.Manifest.permission.MODIFY_PHONE_STATE
import android.Manifest.permission.NETWORK_SETTINGS
import android.Manifest.permission.READ_PRIVILEGED_PHONE_STATE
import android.app.Instrumentation
@@ -80,12 +79,10 @@
import android.net.cts.NetworkAgentTest.TestableQosCallback.CallbackEntry.OnQosSessionLost
import android.net.wifi.WifiInfo
import android.os.Build
-import android.os.ConditionVariable
import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.os.Message
-import android.os.PersistableBundle
import android.os.Process
import android.os.SystemClock
import android.platform.test.annotations.AppModeFull
@@ -94,19 +91,15 @@
import android.system.OsConstants.IPPROTO_TCP
import android.system.OsConstants.IPPROTO_UDP
import android.system.OsConstants.SOCK_DGRAM
-import android.telephony.CarrierConfigManager
import android.telephony.SubscriptionManager
import android.telephony.TelephonyManager
-import android.telephony.TelephonyManager.CarrierPrivilegesCallback
import android.telephony.data.EpsBearerQosSessionAttributes
import android.util.ArraySet
import android.util.DebugUtils.valueToString
-import android.util.Log
import androidx.test.InstrumentationRegistry
import com.android.compatibility.common.util.SystemUtil.runShellCommand
import com.android.compatibility.common.util.SystemUtil.runWithShellPermissionIdentity
import com.android.compatibility.common.util.ThrowingSupplier
-import com.android.compatibility.common.util.UiccUtil
import com.android.modules.utils.build.SdkLevel
import com.android.net.module.util.ArrayTrackRecord
import com.android.net.module.util.NetworkStackConstants.ETHER_MTU
@@ -151,7 +144,6 @@
import java.net.InetSocketAddress
import java.net.Socket
import java.nio.ByteBuffer
-import java.security.MessageDigest
import java.time.Duration
import java.util.Arrays
import java.util.Random
@@ -708,102 +700,6 @@
doTestAllowedUids(transports, uid, expectUidsPresent, specifier, transportInfo)
}
- private fun setHoldCarrierPrivilege(hold: Boolean, subId: Int) {
- fun getCertHash(): String {
- val pkgInfo = realContext.packageManager.getPackageInfo(
- realContext.opPackageName,
- PackageManager.GET_SIGNATURES
- )
- val digest = MessageDigest.getInstance("SHA-256")
- val certHash = digest.digest(pkgInfo.signatures!![0]!!.toByteArray())
- return UiccUtil.bytesToHexString(certHash)!!
- }
-
- val tm = realContext.getSystemService(TelephonyManager::class.java)!!
-
- val cv = ConditionVariable()
- val cpb = PrivilegeWaiterCallback(cv)
- // The lambda below is capturing |cpb|, whose type inherits from a class that appeared in
- // T. This means the lambda will compile as a private method of this class taking a
- // PrivilegeWaiterCallback argument. As JUnit uses reflection to enumerate all methods
- // including private methods, this would fail with a link error when running on S-.
- // To solve this, make the lambda serializable, which causes the compiler to emit a
- // synthetic class instead of a synthetic method.
- tryTest @JvmSerializableLambda {
- val slotIndex = SubscriptionManager.getSlotIndex(subId)!!
- runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
- tm.registerCarrierPrivilegesCallback(slotIndex, { it.run() }, cpb)
- }
- // Wait for the callback to be registered
- assertTrue(cv.block(DEFAULT_TIMEOUT_MS), "Can't register CarrierPrivilegesCallback")
- if (cpb.hasPrivilege == hold) {
- if (hold) {
- Log.w(TAG, "Package ${realContext.opPackageName} already is privileged")
- } else {
- Log.w(TAG, "Package ${realContext.opPackageName} already isn't privileged")
- }
- return@tryTest
- }
- if (hold) {
- carrierConfigRule.addConfigOverrides(subId, PersistableBundle().also {
- it.putStringArray(CarrierConfigManager.KEY_CARRIER_CERTIFICATE_STRING_ARRAY,
- arrayOf(getCertHash()))
- })
- } else {
- carrierConfigRule.cleanUpNow()
- }
- } cleanup @JvmSerializableLambda {
- runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
- tm.unregisterCarrierPrivilegesCallback(cpb)
- }
- }
- }
-
- private fun acquireCarrierPrivilege(subId: Int) = setHoldCarrierPrivilege(true, subId)
- private fun dropCarrierPrivilege(subId: Int) = setHoldCarrierPrivilege(false, subId)
-
- private fun setCarrierServicePackageOverride(subId: Int, pkg: String?) {
- val tm = realContext.getSystemService(TelephonyManager::class.java)!!
-
- val cv = ConditionVariable()
- val cpb = CarrierServiceChangedWaiterCallback(cv)
- // The lambda below is capturing |cpb|, whose type inherits from a class that appeared in
- // T. This means the lambda will compile as a private method of this class taking a
- // PrivilegeWaiterCallback argument. As JUnit uses reflection to enumerate all methods
- // including private methods, this would fail with a link error when running on S-.
- // To solve this, make the lambda serializable, which causes the compiler to emit a
- // synthetic class instead of a synthetic method.
- tryTest @JvmSerializableLambda {
- val slotIndex = SubscriptionManager.getSlotIndex(subId)!!
- runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
- tm.registerCarrierPrivilegesCallback(slotIndex, { it.run() }, cpb)
- }
- // Wait for the callback to be registered
- assertTrue(cv.block(DEFAULT_TIMEOUT_MS), "Can't register CarrierPrivilegesCallback")
- if (cpb.pkgName == pkg) {
- Log.w(TAG, "Carrier service package was already $pkg")
- return@tryTest
- }
- cv.close()
- runAsShell(MODIFY_PHONE_STATE) {
- if (null == pkg) {
- // There is a bug is clear-carrier-service-package-override where not adding
- // the -s argument will use the wrong slot index : b/299604822
- runShellCommand("cmd phone clear-carrier-service-package-override" +
- " -s $subId")
- } else {
- // -s could set the subId, but this test works with the default subId.
- runShellCommand("cmd phone set-carrier-service-package-override $pkg")
- }
- }
- assertTrue(cv.block(DEFAULT_TIMEOUT_MS), "Can't modify carrier service package")
- } cleanup @JvmSerializableLambda {
- runAsShell(READ_PRIVILEGED_PHONE_STATE) @JvmSerializableLambda {
- tm.unregisterCarrierPrivilegesCallback(cpb)
- }
- }
- }
-
private fun String.execute() = runShellCommand(this).trim()
@Test
@@ -856,8 +752,8 @@
if (!SdkLevel.isAtLeastU()) return@tryTest
// Acquiring carrier privilege is necessary to override the carrier service package.
val defaultSlotIndex = SubscriptionManager.getSlotIndex(defaultSubId)
- acquireCarrierPrivilege(defaultSubId)
- setCarrierServicePackageOverride(defaultSubId, servicePackage)
+ carrierConfigRule.acquireCarrierPrivilege(defaultSubId)
+ carrierConfigRule.setCarrierServicePackageOverride(defaultSubId, servicePackage)
val actualServicePackage: String? = runAsShell(READ_PRIVILEGED_PHONE_STATE) {
tm.getCarrierServicePackageNameForLogicalSlot(defaultSlotIndex)
}
@@ -896,10 +792,6 @@
expectUidsPresent = false)
doTestAllowedUidsWithSubId(defaultSubId, intArrayOf(TRANSPORT_CELLULAR, TRANSPORT_WIFI),
uid, expectUidsPresent = false)
- } cleanupStep {
- if (SdkLevel.isAtLeastU()) setCarrierServicePackageOverride(defaultSubId, null)
- } cleanup {
- if (SdkLevel.isAtLeastU()) dropCarrierPrivilege(defaultSubId)
}
}
@@ -2001,25 +1893,3 @@
doTestNativeNetworkCreation(expectCreatedImmediately = true, intArrayOf(TRANSPORT_VPN))
}
}
-
-// Subclasses of CarrierPrivilegesCallback can't be inline, or they'll be compiled as
-// inner classes of the test class and will fail resolution on R as the test harness
-// uses reflection to list all methods and classes
-class PrivilegeWaiterCallback(private val cv: ConditionVariable) :
- CarrierPrivilegesCallback {
- var hasPrivilege = false
- override fun onCarrierPrivilegesChanged(p: MutableSet<String>, uids: MutableSet<Int>) {
- hasPrivilege = uids.contains(Process.myUid())
- cv.open()
- }
-}
-
-class CarrierServiceChangedWaiterCallback(private val cv: ConditionVariable) :
- CarrierPrivilegesCallback {
- var pkgName: String? = null
- override fun onCarrierPrivilegesChanged(p: MutableSet<String>, u: MutableSet<Int>) {}
- override fun onCarrierServiceChanged(pkgName: String?, uid: Int) {
- this.pkgName = pkgName
- cv.open()
- }
-}