Home | History | Annotate | Download | only in cts
      1 /*
      2  * Copyright (C) 2018 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.app.appops.cts
     18 
     19 import android.app.AppOpsManager
     20 import android.app.AppOpsManager.HistoricalOp
     21 import android.app.AppOpsManager.HistoricalOps
     22 import android.app.Instrumentation
     23 import android.content.Context
     24 import android.os.Process
     25 import android.os.SystemClock
     26 import androidx.test.InstrumentationRegistry
     27 import androidx.test.rule.ActivityTestRule
     28 import androidx.test.uiautomator.UiDevice
     29 import androidx.test.runner.AndroidJUnit4
     30 import com.google.common.truth.Truth.assertThat
     31 import org.junit.After
     32 import org.junit.Before
     33 import org.junit.Ignore
     34 import org.junit.Rule
     35 import org.junit.Test
     36 import org.junit.runner.RunWith
     37 import java.util.ArrayList
     38 import java.util.concurrent.TimeUnit
     39 import java.util.concurrent.locks.ReentrantLock
     40 import java.util.function.Consumer
     41 
     42 @RunWith(AndroidJUnit4::class)
     43 class HistoricalAppopsTest {
     44     private val uid = Process.myUid()
     45     private var appOpsManager: AppOpsManager? = null
     46     private var packageName: String? = null
     47 
     48     // Start an activity to make sure this app counts as being in the foreground
     49     @Rule @JvmField
     50     var activityRule = ActivityTestRule(UidStateForceActivity::class.java)
     51 
     52     @Before
     53     fun wakeScreenUp() {
     54         val device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation())
     55         device.wakeUp()
     56         device.executeShellCommand("wm dismiss-keyguard")
     57     }
     58 
     59     @Before
     60     fun setUpTest() {
     61         appOpsManager = getContext().getSystemService(AppOpsManager::class.java)
     62         packageName = getContext().packageName
     63         val uiAutomation = getInstrumentation().getUiAutomation()
     64         uiAutomation.adoptShellPermissionIdentity()
     65         appOpsManager!!.clearHistory()
     66         appOpsManager!!.resetHistoryParameters()
     67     }
     68 
     69     @After
     70     fun tearDownTest() {
     71         appOpsManager!!.clearHistory()
     72         appOpsManager!!.resetHistoryParameters()
     73         val uiAutomation = getInstrumentation().getUiAutomation()
     74         uiAutomation.dropShellPermissionIdentity()
     75     }
     76 
     77     @Ignore("Feature is disabled in Android Q")
     78     @Test
     79     fun testGetHistoricalPackageOpsForegroundAccessInMemoryBucket() {
     80         testGetHistoricalPackageOpsForegroundAtDepth(0)
     81     }
     82 
     83     @Ignore("Feature is disabled in Android Q")
     84     @Test
     85     fun testGetHistoricalPackageOpsForegroundAccessFirstOnDiskBucket() {
     86         testGetHistoricalPackageOpsForegroundAtDepth(1)
     87     }
     88 
     89     @Ignore("Feature is disabled in Android Q")
     90     @Test
     91     fun testHistoricalAggregationOneLevelsDeep() {
     92         testHistoricalAggregationSomeLevelsDeep(0)
     93     }
     94 
     95     @Ignore("Feature is disabled in Android Q")
     96     @Test
     97     fun testHistoricalAggregationTwoLevelsDeep() {
     98         testHistoricalAggregationSomeLevelsDeep(1)
     99     }
    100 
    101     @Ignore("Feature is disabled in Android Q")
    102     @Test
    103     fun testHistoricalAggregationOverflow() {
    104         // Configure historical registry behavior.
    105         appOpsManager!!.setHistoryParameters(
    106                 AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE,
    107                 SNAPSHOT_INTERVAL_MILLIS,
    108                 INTERVAL_COMPRESSION_MULTIPLIER)
    109 
    110         // Add the data to the history
    111         val chunk = createDataChunk()
    112         val chunkCount = (INTERVAL_COMPRESSION_MULTIPLIER * 2) + 3
    113         for (i in 0 until chunkCount) {
    114             appOpsManager!!.addHistoricalOps(chunk)
    115         }
    116 
    117         // Validate the data for the first interval
    118         val firstIntervalBeginMillis = computeIntervalBeginRawMillis(0)
    119         val firstIntervalEndMillis = computeIntervalBeginRawMillis(1)
    120         val firstOps = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    121                 null /*opNames*/, firstIntervalBeginMillis, firstIntervalEndMillis)
    122         assertHasCounts(firstOps!!, 197)
    123 
    124         // Validate the data for the second interval
    125         val secondIntervalBeginMillis = computeIntervalBeginRawMillis(1)
    126         val secondIntervalEndMillis = computeIntervalBeginRawMillis(2)
    127         val secondOps = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    128                 null /*opNames*/, secondIntervalBeginMillis, secondIntervalEndMillis)
    129         assertHasCounts(secondOps!!, 33)
    130 
    131         // Validate the data for both intervals
    132         val thirdIntervalBeginMillis = firstIntervalEndMillis - SNAPSHOT_INTERVAL_MILLIS
    133         val thirdIntervalEndMillis = secondIntervalBeginMillis + SNAPSHOT_INTERVAL_MILLIS
    134         val thirdOps = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    135                 null /*opNames*/, thirdIntervalBeginMillis, thirdIntervalEndMillis)
    136         assertHasCounts(thirdOps!!, 33)
    137     }
    138 
    139     @Ignore("Feature is disabled in Android Q")
    140     @Test
    141     fun testHistoryTimeTravel() {
    142         // Configure historical registry behavior.
    143         appOpsManager!!.setHistoryParameters(
    144                 AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE,
    145                 SNAPSHOT_INTERVAL_MILLIS,
    146                 INTERVAL_COMPRESSION_MULTIPLIER)
    147 
    148         // Fill the first two intervals with data
    149         val chunk = createDataChunk()
    150         val chunkCount = computeSlotCount(2) * SNAPSHOT_INTERVAL_MILLIS / chunk.endTimeMillis
    151         for (i in 0 until chunkCount) {
    152             appOpsManager!!.addHistoricalOps(chunk)
    153         }
    154 
    155         // Move history in past with the first interval duration
    156         val firstIntervalDurationMillis = computeIntervalDurationMillis(0)
    157         appOpsManager!!.offsetHistory(firstIntervalDurationMillis)
    158 
    159         // Validate the data for the first interval
    160         val firstIntervalBeginMillis = computeIntervalBeginRawMillis(0)
    161         val firstIntervalEndMillis = firstIntervalBeginMillis + firstIntervalDurationMillis
    162         val firstOps = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    163                 null /*opNames*/, firstIntervalBeginMillis, firstIntervalEndMillis)
    164         assertThat(firstOps).isNotNull()
    165         assertThat(firstOps!!.uidCount).isEqualTo(0)
    166 
    167         // Validate the data for the second interval
    168         val secondIntervalBeginMillis = computeIntervalBeginRawMillis(1)
    169         val secondIntervalDurationMillis = computeIntervalDurationMillis(1)
    170         val secondIntervalEndMillis = secondIntervalBeginMillis + secondIntervalDurationMillis
    171         val secondOps = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    172                 null /*opNames*/, secondIntervalBeginMillis, secondIntervalEndMillis)
    173         val secondChunkCount = ((computeSlotCount(2) - computeSlotCount(1))
    174             .times(SNAPSHOT_INTERVAL_MILLIS) / chunk.endTimeMillis)
    175         assertHasCounts(secondOps!!, 10 * secondChunkCount)
    176 
    177         // Validate the data for the third interval
    178         val thirdIntervalBeginMillis = computeIntervalBeginRawMillis(2)
    179         val thirdIntervalDurationMillis = computeIntervalDurationMillis(2)
    180         val thirdIntervalEndMillis = thirdIntervalBeginMillis + thirdIntervalDurationMillis
    181         val thirdOps = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    182                 null /*opNames*/, thirdIntervalBeginMillis, thirdIntervalEndMillis)
    183         val thirdChunkCount = secondChunkCount / INTERVAL_COMPRESSION_MULTIPLIER
    184         assertHasCounts(thirdOps!!, 10 * thirdChunkCount)
    185 
    186         // Move history in future with the first interval duration
    187         appOpsManager!!.offsetHistory(- (2.5f * firstIntervalDurationMillis).toLong())
    188 
    189         // Validate the data for the first interval
    190         val fourthOps = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    191                 null /*opNames*/, firstIntervalBeginMillis, firstIntervalEndMillis)
    192         assertHasCounts(fourthOps!!, 194)
    193 
    194         // Validate the data for the second interval
    195         val fifthOps = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    196                 null /*opNames*/, secondIntervalBeginMillis, secondIntervalEndMillis)
    197 
    198         assertThat(fifthOps).isNotNull()
    199         assertHasCounts(fifthOps!!, 1703)
    200     }
    201 
    202     private fun testHistoricalAggregationSomeLevelsDeep(depth: Int) {
    203         // Configure historical registry behavior.
    204         appOpsManager!!.setHistoryParameters(
    205                 AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE,
    206                 SNAPSHOT_INTERVAL_MILLIS,
    207                 INTERVAL_COMPRESSION_MULTIPLIER)
    208 
    209         // Add the data to the history
    210         val chunk = createDataChunk()
    211         val chunkCount = (computeSlotCount(depth + 1)
    212             .times(SNAPSHOT_INTERVAL_MILLIS) / chunk.endTimeMillis)
    213         for (i in 0 until chunkCount) {
    214             appOpsManager!!.addHistoricalOps(chunk)
    215         }
    216 
    217         // Validate the data for the full interval
    218         val intervalBeginMillis = computeIntervalBeginRawMillis(depth)
    219         val intervalEndMillis = computeIntervalBeginRawMillis(depth + 1)
    220         val ops = getHistoricalOpsFromDiskRaw(appOpsManager!!, uid, packageName!!,
    221                 null /*opNames*/, intervalBeginMillis, intervalEndMillis)
    222         val expectedOpCount = ((computeSlotCount(depth + 1) - computeSlotCount(depth))
    223             .times(SNAPSHOT_INTERVAL_MILLIS) / chunk.endTimeMillis) * 10
    224         assertHasCounts(ops!!, expectedOpCount)
    225     }
    226 
    227     private fun testGetHistoricalPackageOpsForegroundAtDepth(depth: Int) {
    228         // Configure historical registry behavior.
    229         appOpsManager!!.setHistoryParameters(
    230                 AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE,
    231                 SNAPSHOT_INTERVAL_MILLIS,
    232                 INTERVAL_COMPRESSION_MULTIPLIER)
    233 
    234         appOpsManager!!.setUidMode(AppOpsManager.OPSTR_START_FOREGROUND, uid,
    235                 AppOpsManager.MODE_ALLOWED)
    236         appOpsManager!!.setUidMode(AppOpsManager.OPSTR_START_FOREGROUND, 2000,
    237                 AppOpsManager.MODE_ALLOWED)
    238 
    239         activityRule.activity.waitForResumed()
    240 
    241         try {
    242             val noteCount = 5
    243 
    244             var beginTimeMillis = 0L
    245             var endTimeMillis = 0L
    246 
    247             // Note ops such that we have data at all levels
    248             for (d in depth downTo 0) {
    249                 for (i in 0 until noteCount) {
    250                     appOpsManager!!.noteOp(AppOpsManager.OPSTR_START_FOREGROUND, uid, packageName)
    251                 }
    252 
    253                 if (d > 0) {
    254                     val previousIntervalDuration = computeIntervalDurationMillis(d - 2)
    255                     val currentIntervalDuration = computeIntervalDurationMillis(d - 1)
    256 
    257                     endTimeMillis -= previousIntervalDuration
    258                     beginTimeMillis -= currentIntervalDuration
    259 
    260                     val sleepDurationMillis = currentIntervalDuration / 2
    261                     SystemClock.sleep(sleepDurationMillis)
    262                 }
    263             }
    264 
    265             val nowMillis = System.currentTimeMillis()
    266             if (depth > 0) {
    267                 beginTimeMillis += nowMillis
    268                 endTimeMillis += nowMillis
    269             } else {
    270                 beginTimeMillis = nowMillis - SNAPSHOT_INTERVAL_MILLIS
    271                 endTimeMillis = Long.MAX_VALUE
    272             }
    273 
    274             // Get all ops for the package
    275             val allOps = getHistoricalOps(appOpsManager!!, uid, packageName!!,
    276                     null, beginTimeMillis, endTimeMillis)
    277 
    278             assertThat(allOps).isNotNull()
    279             assertThat(allOps!!.uidCount).isEqualTo(1)
    280             assertThat(allOps.beginTimeMillis).isEqualTo(beginTimeMillis)
    281             assertThat(allOps.endTimeMillis).isGreaterThan(beginTimeMillis)
    282 
    283             val uidOps = allOps.getUidOpsAt(0)
    284             assertThat(uidOps).isNotNull()
    285             assertThat(uidOps.uid).isEqualTo(Process.myUid())
    286             assertThat(uidOps.packageCount).isEqualTo(1)
    287 
    288             val packageOps = uidOps.getPackageOpsAt(0)
    289             assertThat(packageOps).isNotNull()
    290             assertThat(packageOps.packageName).isEqualTo(getContext().packageName)
    291             assertThat(packageOps.opCount).isEqualTo(1)
    292 
    293             val op = packageOps.getOpAt(0)
    294             assertThat(op).isNotNull()
    295             assertThat(op.opName).isEqualTo(AppOpsManager.OPSTR_START_FOREGROUND)
    296 
    297             assertThat(op.getForegroundAccessCount(AppOpsManager.OP_FLAGS_ALL))
    298                     .isEqualTo(noteCount)
    299             assertThat(op.getBackgroundAccessCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0)
    300             assertThat(getAccessCount(op, AppOpsManager.UID_STATE_PERSISTENT)).isEqualTo(0)
    301             assertThat(getAccessCount(op, AppOpsManager.UID_STATE_TOP)).isEqualTo(noteCount)
    302             assertThat(getAccessCount(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION))
    303                     .isEqualTo(0)
    304             assertThat(getAccessCount(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE))
    305                     .isEqualTo(0)
    306             assertThat(getAccessCount(op, AppOpsManager.UID_STATE_FOREGROUND)).isEqualTo(0)
    307             assertThat(getAccessCount(op, AppOpsManager.UID_STATE_BACKGROUND)).isEqualTo(0)
    308             assertThat(getAccessCount(op, AppOpsManager.UID_STATE_CACHED)).isEqualTo(0)
    309 
    310             assertThat(op.getForegroundAccessDuration(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0)
    311             assertThat(op.getBackgroundAccessDuration(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0)
    312             assertThat(op.getAccessDuration(AppOpsManager.UID_STATE_TOP,
    313                     AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAGS_ALL))
    314                     .isEqualTo(0)
    315             assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_PERSISTENT)).isEqualTo(0)
    316             assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_TOP)).isEqualTo(0)
    317             assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION))
    318                     .isEqualTo(0)
    319             assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE))
    320                     .isEqualTo(0)
    321             assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_FOREGROUND)).isEqualTo(0)
    322             assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_BACKGROUND)).isEqualTo(0)
    323             assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_CACHED)).isEqualTo(0)
    324 
    325             assertThat(op.getForegroundRejectCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0)
    326             assertThat(op.getBackgroundRejectCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0)
    327             assertThat(op.getRejectCount(AppOpsManager.UID_STATE_TOP,
    328                     AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAGS_ALL))
    329                     .isEqualTo(0)
    330             assertThat(getRejectCount(op, AppOpsManager.UID_STATE_PERSISTENT)).isEqualTo(0)
    331             assertThat(getRejectCount(op, AppOpsManager.UID_STATE_TOP)).isEqualTo(0)
    332             assertThat(getRejectCount(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION))
    333                     .isEqualTo(0)
    334             assertThat(getRejectCount(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE))
    335                     .isEqualTo(0)
    336             assertThat(getRejectCount(op, AppOpsManager.UID_STATE_FOREGROUND)).isEqualTo(0)
    337             assertThat(getRejectCount(op, AppOpsManager.UID_STATE_BACKGROUND)).isEqualTo(0)
    338             assertThat(getRejectCount(op, AppOpsManager.UID_STATE_CACHED)).isEqualTo(0)
    339         } finally {
    340             appOpsManager!!.setUidMode(AppOpsManager.OPSTR_START_FOREGROUND, uid,
    341                     AppOpsManager.MODE_FOREGROUND)
    342             appOpsManager!!.setUidMode(AppOpsManager.OPSTR_START_FOREGROUND, 2000,
    343                     AppOpsManager.MODE_FOREGROUND)
    344         }
    345     }
    346 
    347     private fun createDataChunk(): HistoricalOps {
    348         val chunk = HistoricalOps(SNAPSHOT_INTERVAL_MILLIS / 4,
    349                 SNAPSHOT_INTERVAL_MILLIS / 2)
    350         chunk.increaseAccessCount(AppOpsManager.OP_START_FOREGROUND, uid,
    351                 packageName, AppOpsManager.UID_STATE_TOP, AppOpsManager.OP_FLAG_SELF, 10)
    352         chunk.increaseAccessCount(AppOpsManager.OP_START_FOREGROUND, uid,
    353                 packageName, AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAG_SELF, 10)
    354         chunk.increaseRejectCount(AppOpsManager.OP_START_FOREGROUND, uid,
    355                 packageName, AppOpsManager.UID_STATE_TOP, AppOpsManager.OP_FLAG_SELF, 10)
    356         chunk.increaseRejectCount(AppOpsManager.OP_START_FOREGROUND, uid,
    357                 packageName, AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAG_SELF, 10)
    358         chunk.increaseAccessDuration(AppOpsManager.OP_START_FOREGROUND, uid,
    359                 packageName, AppOpsManager.UID_STATE_TOP, AppOpsManager.OP_FLAG_SELF, 10)
    360         chunk.increaseAccessDuration(AppOpsManager.OP_START_FOREGROUND, uid,
    361                 packageName, AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAG_SELF, 10)
    362         return chunk
    363     }
    364 
    365     private fun getHistoricalOps(appOpsManager: AppOpsManager, uid: Int,
    366             packageName: String, opNames: List<String>?, beginTimeMillis: Long,
    367             endTimeMillis: Long): HistoricalOps? {
    368         val array = arrayOfNulls<HistoricalOps>(1)
    369         val lock = ReentrantLock()
    370         val condition = lock.newCondition()
    371         try {
    372             lock.lock()
    373             val request = AppOpsManager.HistoricalOpsRequest.Builder(
    374                     beginTimeMillis, endTimeMillis)
    375                     .setUid(uid)
    376                     .setPackageName(packageName)
    377                     .setOpNames(if (opNames != null) ArrayList(opNames) else null)
    378                     .build()
    379             appOpsManager.getHistoricalOps(request, getContext().getMainExecutor(),
    380                     Consumer { ops ->
    381                 array[0] = ops
    382                 try {
    383                     lock.lock()
    384                     condition.signalAll()
    385                 } finally {
    386                     lock.unlock()
    387                 }
    388             })
    389             condition.await(5, TimeUnit.SECONDS)
    390             return array[0]
    391         } finally {
    392             lock.unlock()
    393         }
    394     }
    395 
    396     private fun assertHasCounts(ops: HistoricalOps, count: Long) {
    397         assertThat(ops).isNotNull()
    398         assertThat(ops.uidCount).isEqualTo(1)
    399 
    400         val uidOps = ops.getUidOpsAt(0)
    401         assertThat(uidOps).isNotNull()
    402 
    403         val packageOps = uidOps.getPackageOpsAt(0)
    404         assertThat(packageOps).isNotNull()
    405 
    406         val op = packageOps.getOpAt(0)
    407         assertThat(op).isNotNull()
    408 
    409         assertThat(op.getForegroundAccessCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count)
    410         assertThat(op.getBackgroundAccessCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count)
    411         assertThat(op.getForegroundRejectCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count)
    412         assertThat(op.getBackgroundRejectCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count)
    413         assertThat(op.getForegroundAccessDuration(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count)
    414         assertThat(op.getBackgroundAccessDuration(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count)
    415     }
    416 
    417     private fun getAccessCount(op: HistoricalOp, uidState: Int): Long {
    418         return op.getAccessCount(uidState, uidState, AppOpsManager.OP_FLAGS_ALL)
    419     }
    420 
    421     private fun getRejectCount(op: HistoricalOp, uidState: Int): Long {
    422         return op.getRejectCount(uidState, uidState, AppOpsManager.OP_FLAGS_ALL)
    423     }
    424 
    425     private fun getAccessDuration(op: HistoricalOp, uidState: Int): Long {
    426         return op.getAccessDuration(uidState, uidState, AppOpsManager.OP_FLAGS_ALL)
    427     }
    428 
    429     private fun getHistoricalOpsFromDiskRaw(appOpsManager: AppOpsManager, uid: Int,
    430             packageName: String, opNames: List<String>?, beginTimeMillis: Long,
    431             endTimeMillis: Long): HistoricalOps? {
    432         val array = arrayOfNulls<HistoricalOps>(1)
    433         val lock = ReentrantLock()
    434         val condition = lock.newCondition()
    435         try {
    436             lock.lock()
    437             val request = AppOpsManager.HistoricalOpsRequest.Builder(
    438                     beginTimeMillis, endTimeMillis)
    439                     .setUid(uid)
    440                     .setPackageName(packageName)
    441                     .setOpNames(if (opNames != null) ArrayList(opNames) else null)
    442                     .build()
    443             appOpsManager.getHistoricalOpsFromDiskRaw(request, getContext().getMainExecutor(),
    444                 Consumer { ops ->
    445                   array[0] = ops
    446                   try {
    447                       lock.lock()
    448                       condition.signalAll()
    449                   } finally {
    450                       lock.unlock()
    451                   }
    452               })
    453             condition.await(5, TimeUnit.SECONDS)
    454             return array[0]
    455         } finally {
    456             lock.unlock()
    457         }
    458     }
    459 
    460     companion object {
    461         const val INTERVAL_COMPRESSION_MULTIPLIER = 10
    462         const val SNAPSHOT_INTERVAL_MILLIS = 1000L
    463 
    464         private fun computeIntervalDurationMillis(depth: Int): Long {
    465             return Math.pow(INTERVAL_COMPRESSION_MULTIPLIER.toDouble(),
    466                     (depth + 1).toDouble()).toLong() * SNAPSHOT_INTERVAL_MILLIS
    467         }
    468 
    469         private fun computeSlotCount(depth: Int): Int {
    470             var count = 0
    471             for (i in 1..depth) {
    472                 count += Math.pow(INTERVAL_COMPRESSION_MULTIPLIER.toDouble(), i.toDouble()).toInt()
    473             }
    474             return count
    475         }
    476 
    477         private fun computeIntervalBeginRawMillis(depth: Int): Long {
    478             var beginTimeMillis: Long = 0
    479             for (i in 0 until depth + 1) {
    480                 beginTimeMillis += Math.pow(INTERVAL_COMPRESSION_MULTIPLIER.toDouble(),
    481                         i.toDouble()).toLong()
    482             }
    483             return beginTimeMillis * SNAPSHOT_INTERVAL_MILLIS
    484         }
    485 
    486         private fun getInstrumentation(): Instrumentation {
    487             return InstrumentationRegistry.getInstrumentation()
    488         }
    489 
    490         private fun getContext(): Context {
    491             return getInstrumentation().context
    492         }
    493     }
    494 }
    495