1 /* <lambda>null2 * 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.AppOpsManager.OPSTR_REQUEST_DELETE_PACKAGES 23 import android.app.AppOpsManager.OP_FLAGS_ALL 24 import android.os.Process 25 import android.os.SystemClock 26 import android.provider.DeviceConfig 27 import androidx.test.InstrumentationRegistry 28 import androidx.test.rule.ActivityTestRule 29 import androidx.test.runner.AndroidJUnit4 30 import androidx.test.uiautomator.UiDevice 31 import com.google.common.truth.Truth.assertThat 32 import org.junit.After 33 import org.junit.Before 34 import org.junit.Rule 35 import org.junit.Test 36 import org.junit.runner.RunWith 37 import java.time.Instant 38 import java.util.concurrent.TimeUnit 39 import java.util.concurrent.locks.ReentrantLock 40 import java.util.function.Consumer 41 42 const val PROPERTY_PERMISSIONS_HUB_ENABLED = "permissions_hub_enabled" 43 44 @RunWith(AndroidJUnit4::class) 45 class HistoricalAppopsTest { 46 private val uid = Process.myUid() 47 private lateinit var appOpsManager: AppOpsManager 48 private lateinit var packageName: String 49 50 private var wasPermissionsHubEnabled = false 51 52 // Start an activity to make sure this app counts as being in the foreground 53 @Rule @JvmField 54 var activityRule = ActivityTestRule(UidStateForceActivity::class.java) 55 56 @Before 57 fun wakeScreenUp() { 58 val uiDevice = UiDevice.getInstance(instrumentation) 59 uiDevice.wakeUp() 60 uiDevice.executeShellCommand("wm dismiss-keyguard") 61 } 62 63 @Before 64 fun setUpTest() { 65 appOpsManager = context.getSystemService(AppOpsManager::class.java)!! 66 packageName = context.packageName!! 67 runWithShellPermissionIdentity { 68 wasPermissionsHubEnabled = DeviceConfig.getBoolean(DeviceConfig.NAMESPACE_PRIVACY, 69 PROPERTY_PERMISSIONS_HUB_ENABLED, false) 70 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, 71 PROPERTY_PERMISSIONS_HUB_ENABLED, true.toString(), false) 72 appOpsManager.clearHistory() 73 appOpsManager.resetHistoryParameters() 74 } 75 } 76 77 @After 78 fun tearDownTest() { 79 runWithShellPermissionIdentity { 80 appOpsManager.clearHistory() 81 appOpsManager.resetHistoryParameters() 82 DeviceConfig.setProperty(DeviceConfig.NAMESPACE_PRIVACY, 83 PROPERTY_PERMISSIONS_HUB_ENABLED, wasPermissionsHubEnabled.toString(), false) 84 } 85 } 86 87 @Test 88 fun testGetHistoricalPackageOpsForegroundAccessInMemoryBucket() { 89 testGetHistoricalPackageOpsForegroundAtDepth(0) 90 } 91 92 @Test 93 fun testGetHistoricalPackageOpsForegroundAccessFirstOnDiskBucket() { 94 testGetHistoricalPackageOpsForegroundAtDepth(1) 95 } 96 97 @Test 98 fun testHistoricalAggregationOneLevelsDeep() { 99 testHistoricalAggregationSomeLevelsDeep(0) 100 } 101 102 @Test 103 fun testHistoricalAggregationTwoLevelsDeep() { 104 testHistoricalAggregationSomeLevelsDeep(1) 105 } 106 107 @Test 108 fun testRebootHistory() { 109 // Configure historical registry behavior. 110 setHistoryParameters( 111 AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE, 112 SNAPSHOT_INTERVAL_MILLIS, 113 INTERVAL_COMPRESSION_MULTIPLIER) 114 115 // Add the data to the history 116 val chunk = createDataChunk() 117 val chunkCount = (INTERVAL_COMPRESSION_MULTIPLIER * 2) + 3 118 for (i in 0 until chunkCount) { 119 addHistoricalOps(chunk) 120 } 121 122 // Validate the data for the first interval 123 val firstIntervalBeginMillis = computeIntervalBeginRawMillis(0) 124 val firstIntervalEndMillis = computeIntervalBeginRawMillis(1) 125 var firstOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 126 firstIntervalBeginMillis, firstIntervalEndMillis) 127 assertHasCounts(firstOps!!, 197) 128 129 // Validate the data for the second interval 130 val secondIntervalBeginMillis = computeIntervalBeginRawMillis(1) 131 val secondIntervalEndMillis = computeIntervalBeginRawMillis(2) 132 var secondOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 133 secondIntervalBeginMillis, secondIntervalEndMillis) 134 assertHasCounts(secondOps!!, 33) 135 136 // Validate the data for all intervals 137 val everythingIntervalBeginMillis = Instant.EPOCH.toEpochMilli() 138 val everythingIntervalEndMillis = Long.MAX_VALUE 139 var allOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 140 everythingIntervalBeginMillis, everythingIntervalEndMillis) 141 assertHasCounts(allOps!!, 230) 142 143 // Now reboot the history 144 runWithShellPermissionIdentity { 145 appOpsManager.rebootHistory(firstIntervalEndMillis) 146 } 147 148 // Validate the data for the first interval 149 firstOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 150 firstIntervalBeginMillis, firstIntervalEndMillis) 151 assertHasCounts(firstOps!!, 0) 152 153 // Validate the data for the second interval 154 secondOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 155 secondIntervalBeginMillis, secondIntervalEndMillis) 156 assertHasCounts(secondOps!!, 230) 157 158 // Validate the data for all intervals 159 allOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 160 everythingIntervalBeginMillis, everythingIntervalEndMillis) 161 assertHasCounts(allOps!!, 230) 162 163 // Write some more ops to the first interval 164 for (i in 0 until chunkCount) { 165 addHistoricalOps(chunk) 166 } 167 168 // Validate the data for the first interval 169 firstOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 170 firstIntervalBeginMillis, firstIntervalEndMillis) 171 assertHasCounts(firstOps!!, 197) 172 173 // Validate the data for the second interval 174 secondOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 175 secondIntervalBeginMillis, secondIntervalEndMillis) 176 assertHasCounts(secondOps!!, 263) 177 178 // Validate the data for all intervals 179 allOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 180 everythingIntervalBeginMillis, everythingIntervalEndMillis) 181 assertHasCounts(allOps!!, 460) 182 } 183 184 @Test 185 fun testHistoricalAggregationOverflow() { 186 // Configure historical registry behavior. 187 setHistoryParameters( 188 AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE, 189 SNAPSHOT_INTERVAL_MILLIS, 190 INTERVAL_COMPRESSION_MULTIPLIER) 191 192 // Add the data to the history 193 val chunk = createDataChunk() 194 val chunkCount = (INTERVAL_COMPRESSION_MULTIPLIER * 2) + 3 195 for (i in 0 until chunkCount) { 196 addHistoricalOps(chunk) 197 } 198 199 // Validate the data for the first interval 200 val firstIntervalBeginMillis = computeIntervalBeginRawMillis(0) 201 val firstIntervalEndMillis = computeIntervalBeginRawMillis(1) 202 val firstOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 203 firstIntervalBeginMillis, firstIntervalEndMillis) 204 assertHasCounts(firstOps!!, 197) 205 206 // Validate the data for the second interval 207 val secondIntervalBeginMillis = computeIntervalBeginRawMillis(1) 208 val secondIntervalEndMillis = computeIntervalBeginRawMillis(2) 209 val secondOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 210 secondIntervalBeginMillis, secondIntervalEndMillis) 211 assertHasCounts(secondOps!!, 33) 212 213 // Validate the data for both intervals 214 val thirdIntervalBeginMillis = firstIntervalEndMillis - SNAPSHOT_INTERVAL_MILLIS 215 val thirdIntervalEndMillis = secondIntervalBeginMillis + SNAPSHOT_INTERVAL_MILLIS 216 val thirdOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 217 thirdIntervalBeginMillis, thirdIntervalEndMillis) 218 assertHasCounts(thirdOps!!, 33) 219 } 220 221 @Test 222 fun testHistoryTimeTravel() { 223 // Configure historical registry behavior. 224 setHistoryParameters( 225 AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE, 226 SNAPSHOT_INTERVAL_MILLIS, 227 INTERVAL_COMPRESSION_MULTIPLIER) 228 229 // Fill the first two intervals with data 230 val chunk = createDataChunk() 231 val chunkCount = computeSlotCount(2) * SNAPSHOT_INTERVAL_MILLIS / chunk.endTimeMillis 232 for (i in 0 until chunkCount) { 233 addHistoricalOps(chunk) 234 } 235 236 // Move history in past with the first interval duration 237 val firstIntervalDurationMillis = computeIntervalDurationMillis(0) 238 runWithShellPermissionIdentity { 239 appOpsManager.offsetHistory(firstIntervalDurationMillis) 240 } 241 242 // Validate the data for the first interval 243 val firstIntervalBeginMillis = computeIntervalBeginRawMillis(0) 244 val firstIntervalEndMillis = firstIntervalBeginMillis + firstIntervalDurationMillis 245 val firstOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 246 firstIntervalBeginMillis, firstIntervalEndMillis) 247 assertThat(firstOps).isNotNull() 248 assertThat(firstOps!!.uidCount).isEqualTo(0) 249 250 // Validate the data for the second interval 251 val secondIntervalBeginMillis = computeIntervalBeginRawMillis(1) 252 val secondIntervalDurationMillis = computeIntervalDurationMillis(1) 253 val secondIntervalEndMillis = secondIntervalBeginMillis + secondIntervalDurationMillis 254 val secondOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 255 secondIntervalBeginMillis, secondIntervalEndMillis) 256 val secondChunkCount = ((computeSlotCount(2) - computeSlotCount(1)) 257 .times(SNAPSHOT_INTERVAL_MILLIS) / chunk.endTimeMillis) 258 assertHasCounts(secondOps!!, 10 * secondChunkCount) 259 260 // Validate the data for the third interval 261 val thirdIntervalBeginMillis = computeIntervalBeginRawMillis(2) 262 val thirdIntervalDurationMillis = computeIntervalDurationMillis(2) 263 val thirdIntervalEndMillis = thirdIntervalBeginMillis + thirdIntervalDurationMillis 264 val thirdOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 265 thirdIntervalBeginMillis, thirdIntervalEndMillis) 266 val thirdChunkCount = secondChunkCount / INTERVAL_COMPRESSION_MULTIPLIER 267 assertHasCounts(thirdOps!!, 10 * thirdChunkCount) 268 269 // Move history in future with the first interval duration 270 runWithShellPermissionIdentity { 271 appOpsManager.offsetHistory(-(2.5f * firstIntervalDurationMillis).toLong()) 272 } 273 274 // Validate the data for the first interval 275 val fourthOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 276 firstIntervalBeginMillis, firstIntervalEndMillis) 277 assertHasCounts(fourthOps!!, 194) 278 279 // Validate the data for the second interval 280 val fifthOps = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 281 secondIntervalBeginMillis, secondIntervalEndMillis) 282 283 assertThat(fifthOps).isNotNull() 284 assertHasCounts(fifthOps!!, 1703) 285 } 286 287 @Test 288 fun testGetHistoricalAggregationOverAttributions() { 289 // Configure historical registry behavior. 290 setHistoryParameters( 291 AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE, 292 SNAPSHOT_INTERVAL_MILLIS, 293 INTERVAL_COMPRESSION_MULTIPLIER) 294 295 setUidMode(OPSTR_REQUEST_DELETE_PACKAGES, uid, AppOpsManager.MODE_ALLOWED) 296 297 UidStateForceActivity.waitForResumed() 298 299 appOpsManager.noteOp(OPSTR_REQUEST_DELETE_PACKAGES, uid, packageName, "firstAttribution", 300 null) 301 appOpsManager.noteOp(OPSTR_REQUEST_DELETE_PACKAGES, uid, packageName, "secondAttribution", 302 null) 303 var memOps: AppOpsManager.HistoricalOps? = null 304 eventually(SNAPSHOT_INTERVAL_MILLIS / 2) { 305 memOps = getHistoricalOps(appOpsManager, uid = uid)!! 306 307 assertThat(memOps!!.getUidOpsAt(0).getPackageOpsAt(0) 308 .getOp(OPSTR_REQUEST_DELETE_PACKAGES)!!.getForegroundAccessCount(OP_FLAGS_ALL)) 309 .isEqualTo(2) 310 assertThat(memOps!!.getUidOpsAt(0).getPackageOpsAt(0) 311 .getAttributedOps("firstAttribution")!!.getOp(OPSTR_REQUEST_DELETE_PACKAGES)!! 312 .getForegroundAccessCount(OP_FLAGS_ALL)).isEqualTo(1) 313 assertThat(memOps!!.getUidOpsAt(0).getPackageOpsAt(0) 314 .getAttributedOps("secondAttribution")!!.getOp(OPSTR_REQUEST_DELETE_PACKAGES)!! 315 .getForegroundAccessCount(OP_FLAGS_ALL)).isEqualTo(1) 316 } 317 318 // Wait until data is on disk and verify no entry got lost 319 Thread.sleep(SNAPSHOT_INTERVAL_MILLIS) 320 321 val diskOps = getHistoricalOps(appOpsManager, uid = uid)!! 322 assertThat(diskOps.getUidOpsAt(0)).isEqualTo(memOps?.getUidOpsAt(0)) 323 } 324 325 private fun testHistoricalAggregationSomeLevelsDeep(depth: Int) { 326 // Configure historical registry behavior. 327 setHistoryParameters( 328 AppOpsManager.HISTORICAL_MODE_ENABLED_PASSIVE, 329 SNAPSHOT_INTERVAL_MILLIS, 330 INTERVAL_COMPRESSION_MULTIPLIER) 331 332 // Add the data to the history 333 val chunk = createDataChunk() 334 val chunkCount = (computeSlotCount(depth + 1) 335 .times(SNAPSHOT_INTERVAL_MILLIS) / chunk.endTimeMillis) 336 for (i in 0 until chunkCount) { 337 addHistoricalOps(chunk) 338 } 339 340 // Validate the data for the full interval 341 val intervalBeginMillis = computeIntervalBeginRawMillis(depth) 342 val intervalEndMillis = computeIntervalBeginRawMillis(depth + 1) 343 val ops = getHistoricalOpsFromDiskRaw(uid, packageName, null /*opNames*/, 344 intervalBeginMillis, intervalEndMillis) 345 val expectedOpCount = ((computeSlotCount(depth + 1) - computeSlotCount(depth)) 346 .times(SNAPSHOT_INTERVAL_MILLIS) / chunk.endTimeMillis) * 10 347 assertHasCounts(ops!!, expectedOpCount) 348 } 349 350 private fun testGetHistoricalPackageOpsForegroundAtDepth(depth: Int) { 351 // Configure historical registry behavior. 352 setHistoryParameters( 353 AppOpsManager.HISTORICAL_MODE_ENABLED_ACTIVE, 354 SNAPSHOT_INTERVAL_MILLIS, 355 INTERVAL_COMPRESSION_MULTIPLIER) 356 357 setUidMode(AppOpsManager.OPSTR_START_FOREGROUND, uid, 358 AppOpsManager.MODE_ALLOWED) 359 setUidMode(AppOpsManager.OPSTR_START_FOREGROUND, 2000, 360 AppOpsManager.MODE_ALLOWED) 361 362 UidStateForceActivity.waitForResumed() 363 364 try { 365 val noteCount = 5 366 367 var beginTimeMillis = 0L 368 var endTimeMillis = 0L 369 370 // Note ops such that we have data at all levels 371 for (d in depth downTo 0) { 372 for (i in 0 until noteCount) { 373 appOpsManager.noteOp(AppOpsManager.OPSTR_START_FOREGROUND, uid, packageName) 374 } 375 376 if (d > 0) { 377 val previousIntervalDuration = computeIntervalDurationMillis(d - 2) 378 val currentIntervalDuration = computeIntervalDurationMillis(d - 1) 379 380 endTimeMillis -= previousIntervalDuration 381 beginTimeMillis -= currentIntervalDuration 382 383 val sleepDurationMillis = currentIntervalDuration / 2 384 SystemClock.sleep(sleepDurationMillis) 385 } 386 } 387 388 val nowMillis = System.currentTimeMillis() 389 if (depth > 0) { 390 beginTimeMillis += nowMillis 391 endTimeMillis += nowMillis 392 } else { 393 beginTimeMillis = nowMillis - SNAPSHOT_INTERVAL_MILLIS 394 endTimeMillis = Long.MAX_VALUE 395 } 396 397 // Get all ops for the package 398 val allOps = getHistoricalOps(appOpsManager, uid, packageName, 399 null, beginTimeMillis, endTimeMillis) 400 401 assertThat(allOps).isNotNull() 402 assertThat(allOps!!.uidCount).isEqualTo(1) 403 assertThat(allOps.beginTimeMillis).isEqualTo(beginTimeMillis) 404 assertThat(allOps.endTimeMillis).isGreaterThan(beginTimeMillis) 405 406 val uidOps = allOps.getUidOpsAt(0) 407 assertThat(uidOps).isNotNull() 408 assertThat(uidOps.uid).isEqualTo(Process.myUid()) 409 assertThat(uidOps.packageCount).isEqualTo(1) 410 411 val packageOps = uidOps.getPackageOpsAt(0) 412 assertThat(packageOps).isNotNull() 413 assertThat(packageOps.packageName).isEqualTo(packageName) 414 assertThat(packageOps.opCount).isEqualTo(1) 415 416 val op = packageOps.getOpAt(0) 417 assertThat(op).isNotNull() 418 assertThat(op.opName).isEqualTo(AppOpsManager.OPSTR_START_FOREGROUND) 419 420 assertThat(op.getForegroundAccessCount(AppOpsManager.OP_FLAGS_ALL)) 421 .isEqualTo(noteCount) 422 assertThat(op.getBackgroundAccessCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0) 423 assertThat(getAccessCount(op, AppOpsManager.UID_STATE_PERSISTENT)).isEqualTo(0) 424 assertThat(getAccessCount(op, AppOpsManager.UID_STATE_TOP)).isEqualTo(noteCount) 425 assertThat(getAccessCount(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION)) 426 .isEqualTo(0) 427 assertThat(getAccessCount(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE)) 428 .isEqualTo(0) 429 assertThat(getAccessCount(op, AppOpsManager.UID_STATE_FOREGROUND)).isEqualTo(0) 430 assertThat(getAccessCount(op, AppOpsManager.UID_STATE_BACKGROUND)).isEqualTo(0) 431 assertThat(getAccessCount(op, AppOpsManager.UID_STATE_CACHED)).isEqualTo(0) 432 433 assertThat(op.getForegroundAccessDuration(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0) 434 assertThat(op.getBackgroundAccessDuration(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0) 435 assertThat(op.getAccessDuration(AppOpsManager.UID_STATE_TOP, 436 AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAGS_ALL)) 437 .isEqualTo(0) 438 assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_PERSISTENT)).isEqualTo(0) 439 assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_TOP)).isEqualTo(0) 440 assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION)) 441 .isEqualTo(0) 442 assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE)) 443 .isEqualTo(0) 444 assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_FOREGROUND)).isEqualTo(0) 445 assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_BACKGROUND)).isEqualTo(0) 446 assertThat(getAccessDuration(op, AppOpsManager.UID_STATE_CACHED)).isEqualTo(0) 447 448 assertThat(op.getForegroundRejectCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0) 449 assertThat(op.getBackgroundRejectCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(0) 450 assertThat(op.getRejectCount(AppOpsManager.UID_STATE_TOP, 451 AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAGS_ALL)) 452 .isEqualTo(0) 453 assertThat(getRejectCount(op, AppOpsManager.UID_STATE_PERSISTENT)).isEqualTo(0) 454 assertThat(getRejectCount(op, AppOpsManager.UID_STATE_TOP)).isEqualTo(0) 455 assertThat(getRejectCount(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE_LOCATION)) 456 .isEqualTo(0) 457 assertThat(getRejectCount(op, AppOpsManager.UID_STATE_FOREGROUND_SERVICE)) 458 .isEqualTo(0) 459 assertThat(getRejectCount(op, AppOpsManager.UID_STATE_FOREGROUND)).isEqualTo(0) 460 assertThat(getRejectCount(op, AppOpsManager.UID_STATE_BACKGROUND)).isEqualTo(0) 461 assertThat(getRejectCount(op, AppOpsManager.UID_STATE_CACHED)).isEqualTo(0) 462 } finally { 463 setUidMode(AppOpsManager.OPSTR_START_FOREGROUND, uid, AppOpsManager.MODE_FOREGROUND) 464 setUidMode(AppOpsManager.OPSTR_START_FOREGROUND, 2000, AppOpsManager.MODE_FOREGROUND) 465 } 466 } 467 468 private fun createDataChunk(): HistoricalOps { 469 val chunk = HistoricalOps(SNAPSHOT_INTERVAL_MILLIS / 4, 470 SNAPSHOT_INTERVAL_MILLIS / 2) 471 chunk.increaseAccessCount(AppOpsManager.OP_START_FOREGROUND, uid, packageName, null, 472 AppOpsManager.UID_STATE_TOP, AppOpsManager.OP_FLAG_SELF, 10) 473 chunk.increaseAccessCount(AppOpsManager.OP_START_FOREGROUND, uid, packageName, null, 474 AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAG_SELF, 10) 475 chunk.increaseRejectCount(AppOpsManager.OP_START_FOREGROUND, uid, packageName, null, 476 AppOpsManager.UID_STATE_TOP, AppOpsManager.OP_FLAG_SELF, 10) 477 chunk.increaseRejectCount(AppOpsManager.OP_START_FOREGROUND, uid, packageName, null, 478 AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAG_SELF, 10) 479 chunk.increaseAccessDuration(AppOpsManager.OP_START_FOREGROUND, uid, packageName, null, 480 AppOpsManager.UID_STATE_TOP, AppOpsManager.OP_FLAG_SELF, 10) 481 chunk.increaseAccessDuration(AppOpsManager.OP_START_FOREGROUND, uid, packageName, null, 482 AppOpsManager.UID_STATE_BACKGROUND, AppOpsManager.OP_FLAG_SELF, 10) 483 return chunk 484 } 485 486 private fun setHistoryParameters( 487 mode: Int, 488 baseSnapshotInterval: Long, 489 compressionStep: Int 490 ) { 491 runWithShellPermissionIdentity { 492 appOpsManager.setHistoryParameters(mode, baseSnapshotInterval, compressionStep) 493 } 494 } 495 496 private fun setUidMode(appOp: String, uid: Int, mode: Int) { 497 runWithShellPermissionIdentity { 498 appOpsManager.setUidMode(appOp, uid, mode) 499 } 500 } 501 502 private fun addHistoricalOps(ops: AppOpsManager.HistoricalOps) { 503 runWithShellPermissionIdentity { 504 appOpsManager.addHistoricalOps(ops) 505 } 506 } 507 508 private fun getHistoricalOps( 509 appOpsManager: AppOpsManager, 510 uid: Int = Process.INVALID_UID, 511 packageName: String? = null, 512 opNames: List<String>? = null, 513 beginTimeMillis: Long = 0, 514 endTimeMillis: Long = Long.MAX_VALUE 515 ): HistoricalOps? { 516 uiAutomation.adoptShellPermissionIdentity() 517 val array = arrayOfNulls<HistoricalOps>(1) 518 val lock = ReentrantLock() 519 val condition = lock.newCondition() 520 try { 521 lock.lock() 522 val request = AppOpsManager.HistoricalOpsRequest.Builder( 523 beginTimeMillis, endTimeMillis) 524 .setUid(uid) 525 .setPackageName(packageName) 526 .setOpNames(opNames?.toList()) 527 .build() 528 appOpsManager.getHistoricalOps(request, context.mainExecutor, Consumer { ops -> 529 array[0] = ops 530 try { 531 lock.lock() 532 condition.signalAll() 533 } finally { 534 lock.unlock() 535 } 536 }) 537 condition.await(5, TimeUnit.SECONDS) 538 return array[0] 539 } finally { 540 lock.unlock() 541 uiAutomation.dropShellPermissionIdentity() 542 } 543 } 544 545 private fun assertHasCounts(ops: HistoricalOps, count: Long) { 546 assertThat(ops).isNotNull() 547 548 if (count <= 0) { 549 assertThat(ops.uidCount).isEqualTo(0) 550 return 551 } 552 553 assertThat(ops.uidCount).isEqualTo(1) 554 555 val uidOps = ops.getUidOpsAt(0) 556 assertThat(uidOps).isNotNull() 557 558 val packageOps = uidOps.getPackageOpsAt(0) 559 assertThat(packageOps).isNotNull() 560 561 val op = packageOps.getOpAt(0) 562 assertThat(op).isNotNull() 563 564 assertThat(op.getForegroundAccessCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count) 565 assertThat(op.getBackgroundAccessCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count) 566 assertThat(op.getForegroundRejectCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count) 567 assertThat(op.getBackgroundRejectCount(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count) 568 assertThat(op.getForegroundAccessDuration(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count) 569 assertThat(op.getBackgroundAccessDuration(AppOpsManager.OP_FLAGS_ALL)).isEqualTo(count) 570 } 571 572 private fun getAccessCount(op: HistoricalOp, uidState: Int): Long { 573 return op.getAccessCount(uidState, uidState, AppOpsManager.OP_FLAGS_ALL) 574 } 575 576 private fun getRejectCount(op: HistoricalOp, uidState: Int): Long { 577 return op.getRejectCount(uidState, uidState, AppOpsManager.OP_FLAGS_ALL) 578 } 579 580 private fun getAccessDuration(op: HistoricalOp, uidState: Int): Long { 581 return op.getAccessDuration(uidState, uidState, AppOpsManager.OP_FLAGS_ALL) 582 } 583 584 private fun getHistoricalOpsFromDiskRaw( 585 uid: Int, 586 packageName: String, 587 opNames: List<String>?, 588 beginTimeMillis: Long, 589 endTimeMillis: Long 590 ): HistoricalOps? { 591 uiAutomation.adoptShellPermissionIdentity() 592 val array = arrayOfNulls<HistoricalOps>(1) 593 val lock = ReentrantLock() 594 val condition = lock.newCondition() 595 try { 596 lock.lock() 597 val request = AppOpsManager.HistoricalOpsRequest.Builder( 598 beginTimeMillis, endTimeMillis) 599 .setUid(uid) 600 .setPackageName(packageName) 601 .setOpNames(opNames?.toList()) 602 .build() 603 appOpsManager.getHistoricalOpsFromDiskRaw(request, context.mainExecutor, 604 Consumer { ops -> 605 array[0] = ops 606 try { 607 lock.lock() 608 condition.signalAll() 609 } finally { 610 lock.unlock() 611 } 612 }) 613 condition.await(5, TimeUnit.SECONDS) 614 return array[0] 615 } finally { 616 lock.unlock() 617 uiAutomation.dropShellPermissionIdentity() 618 } 619 } 620 621 companion object { 622 const val INTERVAL_COMPRESSION_MULTIPLIER = 10 623 const val SNAPSHOT_INTERVAL_MILLIS = 1000L 624 625 val instrumentation get() = InstrumentationRegistry.getInstrumentation() 626 val context get() = instrumentation.context 627 val uiAutomation get() = instrumentation.uiAutomation 628 629 private fun computeIntervalDurationMillis(depth: Int): Long { 630 return Math.pow(INTERVAL_COMPRESSION_MULTIPLIER.toDouble(), 631 (depth + 1).toDouble()).toLong() * SNAPSHOT_INTERVAL_MILLIS 632 } 633 634 private fun computeSlotCount(depth: Int): Int { 635 var count = 0 636 for (i in 1..depth) { 637 count += Math.pow(INTERVAL_COMPRESSION_MULTIPLIER.toDouble(), i.toDouble()).toInt() 638 } 639 return count 640 } 641 642 private fun computeIntervalBeginRawMillis(depth: Int): Long { 643 var beginTimeMillis: Long = 0 644 for (i in 0 until depth + 1) { 645 beginTimeMillis += Math.pow(INTERVAL_COMPRESSION_MULTIPLIER.toDouble(), 646 i.toDouble()).toLong() 647 } 648 return beginTimeMillis * SNAPSHOT_INTERVAL_MILLIS 649 } 650 } 651 } 652