blob: f889e2485397327a0cb6373a7b35501e3256f3fc [file] [log] [blame]
/*
* Copyright (C) 2021 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License") * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.app.appops.cts
import android.app.AppOpsManager
import android.app.AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE
import android.app.AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE
import android.app.AppOpsManager.HistoricalOps
import android.app.AppOpsManager.HISTORY_FLAG_AGGREGATE
import android.app.AppOpsManager.HISTORY_FLAG_DISCRETE
import android.app.AppOpsManager.HISTORY_FLAGS_ALL
import android.app.AppOpsManager.KEY_FG_SERVICE_STATE_SETTLE_TIME
import android.app.AppOpsManager.KEY_TOP_STATE_SETTLE_TIME
import android.app.AppOpsManager.KEY_BG_STATE_SETTLE_TIME
import android.app.AppOpsManager.MODE_ALLOWED
import android.app.AppOpsManager.MODE_IGNORED
import android.app.AppOpsManager.OPSTR_CAMERA
import android.app.AppOpsManager.OPSTR_FINE_LOCATION
import android.app.AppOpsManager.OP_FLAGS_ALL
import android.app.AppOpsManager.OP_FLAG_SELF
import android.app.AppOpsManager.OP_FLAG_TRUSTED_PROXIED
import android.app.AppOpsManager.UID_STATE_CACHED
import android.app.AppOpsManager.UID_STATE_PERSISTENT
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.IBinder
import android.platform.test.annotations.AppModeFull
import android.provider.DeviceConfig
import android.provider.DeviceConfig.NAMESPACE_PRIVACY
import android.provider.Settings
import androidx.test.platform.app.InstrumentationRegistry
import androidx.test.uiautomator.UiDevice
import com.android.compatibility.common.util.SystemUtil
import com.google.common.truth.Truth.assertThat
import org.junit.After
import org.junit.Assert
import org.junit.Before
import org.junit.Test
import java.util.concurrent.CompletableFuture
import java.util.concurrent.locks.ReentrantLock
import java.util.concurrent.TimeUnit
import java.util.function.Consumer
private const val PACKAGE_NAME = "android.app.appops.cts.appfordiscretetest"
private const val TIMEOUT_MILLIS = 45000L
private const val DEFAULT_TIME_QUANT_MILLIS = 60000L
private const val SHORT_TIME_QUANT_MILLIS = 2000L
private const val CALLBACK_PROPAGATION_DELAY = 5000L
private const val SAFETY_MARGIN_MILLIS = 5000L
private const val TEN_MINUTES_MILLIS = 600000L
private const val ONE_MINUTE_MILLIS = 60000L
private const val TAG1 = "tag1"
private const val TAG2 = "tag2"
private const val PROPERTY_CUTOFF = "discrete_history_cutoff_millis"
private const val PROPERTY_QUANTIZATION = "discrete_history_quantization_millis"
private const val PROPERTY_FLAGS = "discrete_history_op_flags"
private const val PROPERTY_OPS_LIST = "discrete_history_ops_cslist"
private const val INTERVAL_COMPRESSION_MULTIPLIER = 10
private const val SNAPSHOT_INTERVAL_MILLIS = 1000L
@AppModeFull(reason = "This test connects to other test app")
class DiscreteAppopsTest {
private var previousAppOpsConstants: String? = null
private val instrumentation get() = InstrumentationRegistry.getInstrumentation()
private val context get() = instrumentation.context
private val uid = context.packageManager.getPackageUid(PACKAGE_NAME, 0)
private val uiAutomation get() = instrumentation.uiAutomation
private lateinit var foregroundControlService: IAppOpsForegroundControlService
private lateinit var serviceConnection: ServiceConnection
private var wasPermissionsHubEnabled = false
private var previousDiscreteHistoryCutoffMillis: String? = null
private var previousDiscreteHistoryQuantizationMillis: String? = null
private var previousDiscreteHistoryOpFlags: String? = null
private var previousDiscreteHistoryOpsCslist: String? = null
private lateinit var appOpsManager: AppOpsManager
private val uiDevice = UiDevice.getInstance(instrumentation)
private val testPkgAppOpMode: Int
get() {
return SystemUtil.callWithShellPermissionIdentity {
appOpsManager.noteOp(OPSTR_FINE_LOCATION, uid, PACKAGE_NAME, null, null)
}
}
@Before
fun setUpTest() {
appOpsManager = context.getSystemService(AppOpsManager::class.java)!!
runWithShellPermissionIdentity {
previousDiscreteHistoryCutoffMillis = DeviceConfig.getString(
NAMESPACE_PRIVACY, PROPERTY_CUTOFF, null)
previousDiscreteHistoryQuantizationMillis = DeviceConfig.getString(
NAMESPACE_PRIVACY, PROPERTY_QUANTIZATION, null)
previousDiscreteHistoryOpFlags = DeviceConfig.getString(
NAMESPACE_PRIVACY, PROPERTY_FLAGS, null)
previousDiscreteHistoryOpsCslist = DeviceConfig.getString(
NAMESPACE_PRIVACY, PROPERTY_OPS_LIST, null)
wasPermissionsHubEnabled = DeviceConfig.getBoolean(NAMESPACE_PRIVACY,
PROPERTY_PERMISSIONS_HUB_ENABLED, false)
DeviceConfig.setProperty(NAMESPACE_PRIVACY,
PROPERTY_PERMISSIONS_HUB_ENABLED, true.toString(), false)
appOpsManager.clearHistory()
appOpsManager.resetHistoryParameters()
previousAppOpsConstants = Settings.Global.getString(context.contentResolver,
Settings.Global.APP_OPS_CONSTANTS)
// Speed up app-ops service proc state transitions
Settings.Global.putString(context.contentResolver, Settings.Global.APP_OPS_CONSTANTS,
"$KEY_TOP_STATE_SETTLE_TIME=300,$KEY_FG_SERVICE_STATE_SETTLE_TIME=100," +
"$KEY_BG_STATE_SETTLE_TIME=10")
}
enableDiscreteRegistryDebugMode()
val serviceIntent = Intent().setComponent(ComponentName(PACKAGE_NAME,
"$PACKAGE_NAME.AppOpsForegroundControlService"))
val newService = CompletableFuture<IAppOpsForegroundControlService>()
serviceConnection = object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
newService.complete(IAppOpsForegroundControlService.Stub.asInterface(service))
}
override fun onServiceDisconnected(name: ComponentName?) {
Assert.fail("foreground control service disconnected")
}
}
context.bindService(serviceIntent, serviceConnection,
Context.BIND_AUTO_CREATE or Context.BIND_NOT_FOREGROUND)
foregroundControlService = newService.get(TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
}
@Before
fun wakeScreenUp() {
uiDevice.wakeUp()
uiDevice.executeShellCommand("wm dismiss-keyguard")
uiDevice.executeShellCommand("input keyevent KEYCODE_HOME")
}
@After
fun tearDownTest() {
runWithShellPermissionIdentity {
appOpsManager.clearHistory()
appOpsManager.resetHistoryParameters()
DeviceConfig.setProperty(NAMESPACE_PRIVACY, PROPERTY_PERMISSIONS_HUB_ENABLED,
wasPermissionsHubEnabled.toString(), false)
}
foregroundControlService.cleanup()
context.unbindService(serviceConnection)
runWithShellPermissionIdentity {
Settings.Global.putString(context.contentResolver, Settings.Global.APP_OPS_CONSTANTS,
previousAppOpsConstants)
}
uiDevice.executeShellCommand("device_config put " + NAMESPACE_PRIVACY + " " +
PROPERTY_CUTOFF + " " + previousDiscreteHistoryCutoffMillis)
uiDevice.executeShellCommand("device_config put " + NAMESPACE_PRIVACY + " " +
PROPERTY_QUANTIZATION + " " + previousDiscreteHistoryQuantizationMillis)
uiDevice.executeShellCommand("device_config put " + NAMESPACE_PRIVACY + " " +
PROPERTY_FLAGS + " " + previousDiscreteHistoryOpFlags)
uiDevice.executeShellCommand("device_config put " + NAMESPACE_PRIVACY + " " +
PROPERTY_OPS_LIST + " " + previousDiscreteHistoryOpsCslist)
}
@Test
fun testRecordAndCheckAppOp() {
waitUntilSafelyInTimeQuant(DEFAULT_TIME_QUANT_MILLIS, SAFETY_MARGIN_MILLIS)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
val timeStamp = System.currentTimeMillis() /
DEFAULT_TIME_QUANT_MILLIS * DEFAULT_TIME_QUANT_MILLIS
Thread.sleep(250)
// Get all ops for the package
var allOps = getHistoricalOps(HISTORY_FLAGS_ALL)
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
// Get only discrete accesses
allOps = getHistoricalOps(HISTORY_FLAG_DISCRETE)
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
// Get only aggregate accesses
allOps = getHistoricalOps(HISTORY_FLAG_AGGREGATE)
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(0)
}
@Test
fun testNotedTwiceRecordedOnce() {
waitUntilSafelyInTimeQuant(DEFAULT_TIME_QUANT_MILLIS, SAFETY_MARGIN_MILLIS)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
val timeStamp = System.currentTimeMillis() /
DEFAULT_TIME_QUANT_MILLIS * DEFAULT_TIME_QUANT_MILLIS
var allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
}
@Test
fun testAdjustedQuantization() {
setQuantization(SHORT_TIME_QUANT_MILLIS)
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
val timeStamp = System.currentTimeMillis() /
SHORT_TIME_QUANT_MILLIS * SHORT_TIME_QUANT_MILLIS
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
Thread.sleep(100)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
Thread.sleep(100)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
var allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(2)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
discrete = op.getDiscreteAccessAt(1)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL))
.isEqualTo(timeStamp + SHORT_TIME_QUANT_MILLIS)
}
@Test
fun testTimeTravel() {
waitUntilSafelyInTimeQuant(DEFAULT_TIME_QUANT_MILLIS, SAFETY_MARGIN_MILLIS)
val timeStamp = System.currentTimeMillis() /
DEFAULT_TIME_QUANT_MILLIS * DEFAULT_TIME_QUANT_MILLIS
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
var allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
runWithShellPermissionIdentity {
appOpsManager.offsetHistory(DEFAULT_TIME_QUANT_MILLIS)
}
allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL))
.isEqualTo(timeStamp - DEFAULT_TIME_QUANT_MILLIS)
}
@Test
fun testHistoryTimeParameter() {
waitUntilSafelyInTimeQuant(DEFAULT_TIME_QUANT_MILLIS, SAFETY_MARGIN_MILLIS)
var timeStamp = System.currentTimeMillis() /
DEFAULT_TIME_QUANT_MILLIS * DEFAULT_TIME_QUANT_MILLIS - TEN_MINUTES_MILLIS
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
runWithShellPermissionIdentity {
appOpsManager.offsetHistory(TEN_MINUTES_MILLIS)
}
var allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL))
.isEqualTo(timeStamp)
allOps = getHistoricalOps(HISTORY_FLAGS_ALL, null, OP_FLAGS_ALL,
System.currentTimeMillis() - ONE_MINUTE_MILLIS, Long.MAX_VALUE)
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(0)
}
@Test
fun testDeduplicationUidState() {
makeTop() // pre-warm application uid state change to make it faster during test run
makeBackground()
setQuantization(SHORT_TIME_QUANT_MILLIS)
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
val timestamp = System.currentTimeMillis() /
SHORT_TIME_QUANT_MILLIS * SHORT_TIME_QUANT_MILLIS
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
makeTop()
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
makeBackground()
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
var allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
var op = packageOps.getOp(OPSTR_CAMERA)
assertThat(op).isNotNull()
assertThat(op.discreteAccessCount).isEqualTo(2)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
discrete = op.getDiscreteAccessAt(1)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL))
.isEqualTo(timestamp + SHORT_TIME_QUANT_MILLIS)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
}
@Test
fun testDeduplicationAttributions() {
setQuantization(SHORT_TIME_QUANT_MILLIS)
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
val timestamp = System.currentTimeMillis() /
SHORT_TIME_QUANT_MILLIS * SHORT_TIME_QUANT_MILLIS
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG1)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG2)
Thread.sleep(SHORT_TIME_QUANT_MILLIS)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG1)
var allOps = getHistoricalOps(HISTORY_FLAG_DISCRETE)
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(2)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
discrete = op.getDiscreteAccessAt(1)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL))
.isEqualTo(timestamp + SHORT_TIME_QUANT_MILLIS)
assertThat(packageOps.attributedOpsCount).isEqualTo(2)
var attribution = packageOps.getAttributedOps(TAG1)
assertThat(attribution).isNotNull()
assertThat(attribution!!.opCount).isEqualTo(1)
op = attribution.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(2)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
discrete = op.getDiscreteAccessAt(1)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL))
.isEqualTo(timestamp + SHORT_TIME_QUANT_MILLIS)
attribution = packageOps.getAttributedOps(TAG2)
assertThat(attribution).isNotNull()
assertThat(attribution!!.opCount).isEqualTo(1)
op = attribution.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
}
@Test
fun testCutoffTime() {
runWithShellPermissionIdentity {
DeviceConfig.setProperty(NAMESPACE_PRIVACY, PROPERTY_CUTOFF, 120000L.toString(), false)
}
// Pause to give the AppOpsService (DiscreteRegistry) time to pick up the new value.
Thread.sleep(1000)
waitUntilSafelyInTimeQuant(DEFAULT_TIME_QUANT_MILLIS, SAFETY_MARGIN_MILLIS)
val timeStamp = System.currentTimeMillis() /
DEFAULT_TIME_QUANT_MILLIS * DEFAULT_TIME_QUANT_MILLIS
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME)
var allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
runWithShellPermissionIdentity {
appOpsManager.offsetHistory(180000)
}
allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(0)
}
@Test
fun testMixedDeduplication() {
setQuantization(SHORT_TIME_QUANT_MILLIS)
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
makeTop() // pre-warm application uid state change to make it faster during test run
makeBackground()
val timestamp = System.currentTimeMillis() /
SHORT_TIME_QUANT_MILLIS * SHORT_TIME_QUANT_MILLIS
val timestamp2 = timestamp + SHORT_TIME_QUANT_MILLIS
val timestamp3 = timestamp2 + SHORT_TIME_QUANT_MILLIS
val timestamp4 = timestamp3 + SHORT_TIME_QUANT_MILLIS
// first quant - foreground access in tag1, background in tag2
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG2)
makeTop()
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG1)
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
// second quant - background access in tag1, foreground in tag2
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG2, null)
makeBackground()
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG1, null)
makeTop()
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
// third quant - single foreground access in tag1, nothing in tag2
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG1, null)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG1, null)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG1, null)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG1, null)
makeBackground()
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
// fourth quant - single background access in tag2, nothing in tag1
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG2, null)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, TAG2, null)
var allOps = getHistoricalOps(HISTORY_FLAG_DISCRETE)
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
var op = packageOps.getOp(OPSTR_CAMERA)
assertThat(op).isNotNull()
assertThat(op.discreteAccessCount).isEqualTo(4)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
discrete = op.getDiscreteAccessAt(1)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp2)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp2)
discrete = op.getDiscreteAccessAt(2)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp3)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
discrete = op.getDiscreteAccessAt(3)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp4)
var attribution = packageOps.getAttributedOps(TAG1)
assertThat(attribution).isNotNull()
assertThat(attribution!!.opCount).isEqualTo(1)
op = attribution.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(3)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
discrete = op.getDiscreteAccessAt(1)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp2)
discrete = op.getDiscreteAccessAt(2)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp3)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
attribution = packageOps.getAttributedOps(TAG2)
assertThat(attribution).isNotNull()
assertThat(attribution!!.opCount).isEqualTo(1)
op = attribution.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(3)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
discrete = op.getDiscreteAccessAt(1)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp2)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
discrete = op.getDiscreteAccessAt(2)
assertThat(discrete.getLastAccessForegroundTime(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessBackgroundTime(OP_FLAGS_ALL)).isEqualTo(timestamp4)
// Test the same result using alternative accessors.
var accesses = op.getBackgroundDiscreteAccesses(OP_FLAGS_ALL)
assertThat(accesses.size).isEqualTo(2)
assertThat(accesses[0].getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
assertThat(accesses[1].getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp4)
accesses = op.getForegroundDiscreteAccesses(OP_FLAGS_ALL)
assertThat(accesses.size).isEqualTo(1)
assertThat(accesses[0].getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp2)
accesses = op.getDiscreteAccesses(UID_STATE_PERSISTENT, UID_STATE_CACHED, OP_FLAGS_ALL)
assertThat(accesses.size).isEqualTo(3)
assertThat(accesses[0].getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
assertThat(accesses[1].getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp2)
assertThat(accesses[2].getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp4)
}
@Test
fun testOperationWithDuration() {
setQuantization(SHORT_TIME_QUANT_MILLIS)
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
val timestamp = System.currentTimeMillis() /
SHORT_TIME_QUANT_MILLIS * SHORT_TIME_QUANT_MILLIS
runWithShellPermissionIdentity {
appOpsManager.startOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
}
// First test that unfinished op was added without duration
var allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
Thread.sleep(SHORT_TIME_QUANT_MILLIS)
runWithShellPermissionIdentity {
appOpsManager.finishOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null)
}
allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(2 * SHORT_TIME_QUANT_MILLIS)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
}
@Test
fun testOperationWithDurationForcedSavedDuringTransaction() {
setQuantization(SHORT_TIME_QUANT_MILLIS)
waitUntilNextQuantStarts(SHORT_TIME_QUANT_MILLIS)
val timestamp = System.currentTimeMillis() /
SHORT_TIME_QUANT_MILLIS * SHORT_TIME_QUANT_MILLIS
runWithShellPermissionIdentity {
appOpsManager.startOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
}
// Force persistence
runWithShellPermissionIdentity {
appOpsManager.offsetHistory(0)
}
// First test that unfinished op was added without duration
var allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
Thread.sleep(SHORT_TIME_QUANT_MILLIS)
runWithShellPermissionIdentity {
appOpsManager.finishOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null)
}
allOps = getHistoricalOps()
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(2 * SHORT_TIME_QUANT_MILLIS)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timestamp)
}
@Test
fun testOpFlagsAndDeduplication() {
waitUntilSafelyInTimeQuant(DEFAULT_TIME_QUANT_MILLIS, SAFETY_MARGIN_MILLIS)
runWithShellPermissionIdentity {
appOpsManager.noteProxyOp(OPSTR_CAMERA, PACKAGE_NAME, uid, null, null)
appOpsManager.noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
}
val timeStamp = System.currentTimeMillis() /
DEFAULT_TIME_QUANT_MILLIS * DEFAULT_TIME_QUANT_MILLIS
Thread.sleep(500)
var allOps = getHistoricalOps(HISTORY_FLAG_DISCRETE)
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
assertThat(discrete.getLastAccessTime(OP_FLAG_TRUSTED_PROXIED)).isEqualTo(timeStamp)
assertThat(discrete.getLastAccessTime(OP_FLAG_SELF)).isEqualTo(timeStamp)
allOps = getHistoricalOps(HISTORY_FLAG_DISCRETE, null, OP_FLAG_TRUSTED_PROXIED)
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
assertThat(discrete.getLastAccessTime(OP_FLAG_TRUSTED_PROXIED)).isEqualTo(timeStamp)
assertThat(discrete.getLastAccessTime(OP_FLAG_SELF)).isEqualTo(-1)
// test alternative accessor
var accesses = op.getDiscreteAccesses(UID_STATE_CACHED, UID_STATE_PERSISTENT, OP_FLAG_SELF)
assertThat(accesses.size).isEqualTo(0)
accesses = op.getDiscreteAccesses(
UID_STATE_PERSISTENT, UID_STATE_CACHED, OP_FLAG_TRUSTED_PROXIED)
assertThat(accesses.size).isEqualTo(1)
}
@Test
fun testOpFlagsParameter() {
// Collect only OP_FLAG_TRUSTED_PROXIED (8)
runWithShellPermissionIdentity {
DeviceConfig.setProperty(NAMESPACE_PRIVACY, PROPERTY_FLAGS, 8.toString(), false)
}
var allOps: HistoricalOps? = null
for (i in 1..3) {
waitUntilSafelyInTimeQuant(DEFAULT_TIME_QUANT_MILLIS, SAFETY_MARGIN_MILLIS)
runWithShellPermissionIdentity {
appOpsManager.noteProxyOp(OPSTR_CAMERA, PACKAGE_NAME, uid, null, null)
appOpsManager.noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
}
allOps = getHistoricalOps(HISTORY_FLAG_DISCRETE)
if (allOps!!.getUidOpsAt(0).getPackageOpsAt(0).getOpAt(0).getDiscreteAccessAt(0)
.getLastAccessTime(OP_FLAG_SELF) == -1L) {
break
}
runWithShellPermissionIdentity {
appOpsManager.clearHistory()
}
// maybe device_config callback didn't propagate yet, give it some more time
Thread.sleep(CALLBACK_PROPAGATION_DELAY)
}
val timeStamp = System.currentTimeMillis() /
DEFAULT_TIME_QUANT_MILLIS * DEFAULT_TIME_QUANT_MILLIS
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_CAMERA)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
assertThat(discrete.getLastAccessTime(OP_FLAG_TRUSTED_PROXIED)).isEqualTo(timeStamp)
assertThat(discrete.getLastAccessTime(OP_FLAG_SELF)).isEqualTo(-1)
}
@Test
fun testOpsListParameter() {
// collect only OP_FINE_LOCATION = 1
makeTop()
runWithShellPermissionIdentity {
DeviceConfig.setProperty(NAMESPACE_PRIVACY, PROPERTY_OPS_LIST, "1", false)
}
var allOps: HistoricalOps? = null
for (i in 1..3) {
waitUntilSafelyInTimeQuant(DEFAULT_TIME_QUANT_MILLIS, SAFETY_MARGIN_MILLIS)
noteOp(OPSTR_FINE_LOCATION, uid, PACKAGE_NAME, null, null)
noteOp(OPSTR_CAMERA, uid, PACKAGE_NAME, null, null)
allOps = getHistoricalOps(HISTORY_FLAG_DISCRETE)
if (allOps!!.getUidOpsAt(0).getPackageOpsAt(0).opCount == 1) break
runWithShellPermissionIdentity {
appOpsManager.clearHistory()
}
// maybe device_config callback didn't propagate yet, give it some more time
Thread.sleep(CALLBACK_PROPAGATION_DELAY)
}
val timeStamp = System.currentTimeMillis() /
DEFAULT_TIME_QUANT_MILLIS * DEFAULT_TIME_QUANT_MILLIS
assertThat(allOps).isNotNull()
assertThat(allOps!!.uidCount).isEqualTo(1)
var uidOps = allOps.getUidOpsAt(0)
assertThat(uidOps).isNotNull()
assertThat(uidOps.uid).isEqualTo(uid)
assertThat(uidOps.packageCount).isEqualTo(1)
var packageOps = uidOps.getPackageOpsAt(0)
assertThat(packageOps).isNotNull()
assertThat(packageOps.packageName).isEqualTo(PACKAGE_NAME)
assertThat(packageOps.opCount).isEqualTo(1)
var op = packageOps.getOpAt(0)
assertThat(op).isNotNull()
assertThat(op.opName).isEqualTo(OPSTR_FINE_LOCATION)
assertThat(op.discreteAccessCount).isEqualTo(1)
var discrete = op.getDiscreteAccessAt(0)
assertThat(discrete.getLastDuration(OP_FLAGS_ALL)).isEqualTo(-1)
assertThat(discrete.getLastAccessTime(OP_FLAGS_ALL)).isEqualTo(timeStamp)
}
/** Provides guarantee that there is at least requiredSafetyMarginMillis milliseconds until next
* time quant starts.
*/
private fun waitUntilSafelyInTimeQuant(
quantSizeMillis: Long,
requiredSafetyMarginMillis: Long
) {
while (System.currentTimeMillis() / quantSizeMillis * quantSizeMillis
!= (System.currentTimeMillis() + requiredSafetyMarginMillis) /
quantSizeMillis * quantSizeMillis) {
Thread.sleep(1)
}
}
private fun waitUntilNextQuantStarts(quantSizeMillis: Long) {
val currentTimeQuant = System.currentTimeMillis() / quantSizeMillis * quantSizeMillis
while (System.currentTimeMillis() / quantSizeMillis * quantSizeMillis
== currentTimeQuant) {
Thread.sleep(1)
}
}
private fun enableDiscreteRegistryDebugMode() {
runWithShellPermissionIdentity {
appOpsManager.setHistoryParameters(HISTORICAL_MODE_ENABLED_PASSIVE,
SNAPSHOT_INTERVAL_MILLIS, INTERVAL_COMPRESSION_MULTIPLIER)
appOpsManager.setHistoryParameters(HISTORICAL_MODE_ENABLED_ACTIVE,
SNAPSHOT_INTERVAL_MILLIS, INTERVAL_COMPRESSION_MULTIPLIER)
}
}
private fun setQuantization(timeQuantMillis: Long) {
runWithShellPermissionIdentity {
DeviceConfig.setProperty(NAMESPACE_PRIVACY, PROPERTY_QUANTIZATION,
timeQuantMillis.toString(), false)
}
}
private fun noteOp(
op: String,
uid: Int,
packageName: String,
tag: String? = null,
message: String? = null
) {
runWithShellPermissionIdentity {
appOpsManager.noteOp(op, uid, packageName, tag, message)
}
}
private fun getHistoricalOps(
historyFlags: Int = HISTORY_FLAGS_ALL,
opNames: List<String>? = null,
flags: Int = OP_FLAGS_ALL,
beginTimeMillis: Long = 0,
endTimeMillis: Long = Long.MAX_VALUE
): HistoricalOps? {
uiAutomation.adoptShellPermissionIdentity()
val array = arrayOfNulls<HistoricalOps>(1)
val lock = ReentrantLock()
val condition = lock.newCondition()
try {
lock.lock()
val request = AppOpsManager.HistoricalOpsRequest.Builder(
beginTimeMillis, endTimeMillis)
.setUid(uid)
.setPackageName(PACKAGE_NAME)
.setOpNames(opNames?.toList())
.setHistoryFlags(historyFlags)
.setFlags(flags)
.build()
appOpsManager.getHistoricalOps(request, context.mainExecutor, Consumer { ops ->
array[0] = ops
try {
lock.lock()
condition.signalAll()
} finally {
lock.unlock()
}
})
condition.await(5, TimeUnit.SECONDS)
return array[0]
} finally {
lock.unlock()
uiAutomation.dropShellPermissionIdentity()
}
}
private fun makeTop() {
while (true) {
context.startActivity(Intent().setComponent(
ComponentName(PACKAGE_NAME,
"$PACKAGE_NAME.AppOpsForegroundControlActivity"))
.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK))
if (testPkgAppOpMode == MODE_ALLOWED) {
break
}
Thread.sleep(100)
}
}
private fun makeBackground() {
while (true) {
foregroundControlService.finishActivity()
foregroundControlService.stopForegroundService()
foregroundControlService.stopLocationForegroundService()
if (testPkgAppOpMode == MODE_IGNORED) {
break
}
Thread.sleep(100)
}
}
}