1 /* <lambda>null2 * Copyright (C) 2020 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.appops2.cts 18 19 import android.app.AppOpsManager 20 import android.app.AppOpsManager.OnOpNotedCallback 21 import android.app.AppOpsManager.permissionToOp 22 import android.app.AsyncNotedAppOp 23 import android.app.PendingIntent 24 import android.app.SyncNotedAppOp 25 import android.app.appops.cts.eventually 26 import android.content.BroadcastReceiver 27 import android.content.Context 28 import android.content.Intent 29 import android.content.Intent.FLAG_ACTIVITY_CLEAR_TASK 30 import android.content.Intent.FLAG_ACTIVITY_NEW_TASK 31 import android.content.IntentFilter 32 import android.content.pm.PackageInstaller.EXTRA_STATUS 33 import android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID 34 import android.content.pm.PackageInstaller.STATUS_PENDING_USER_ACTION 35 import android.content.pm.PackageInstaller.SessionParams 36 import android.content.pm.PackageInstaller.SessionParams.MODE_FULL_INSTALL 37 import android.platform.test.annotations.AppModeFull 38 import androidx.test.platform.app.InstrumentationRegistry 39 import com.google.common.truth.Truth.assertThat 40 import org.junit.After 41 import org.junit.Before 42 import org.junit.Test 43 import java.io.File 44 import java.util.concurrent.Executor 45 46 private const val TEST_ATTRIBUTION_TAG = "testAttribution" 47 48 @AppModeFull(reason = "Test relies on other app to connect to. Instant apps can't see other apps") 49 class AppOpsLoggingTest { 50 private val context = InstrumentationRegistry.getInstrumentation().targetContext 51 private val appOpsManager = context.getSystemService(AppOpsManager::class.java)!! 52 53 // Collected note-op calls inside of this process 54 private val noted = mutableListOf<Pair<SyncNotedAppOp, Array<StackTraceElement>>>() 55 private val selfNoted = mutableListOf<Pair<SyncNotedAppOp, Array<StackTraceElement>>>() 56 private val asyncNoted = mutableListOf<AsyncNotedAppOp>() 57 58 @Before 59 fun setNotedAppOpsCollectorAndClearCollectedNoteOps() { 60 setNotedAppOpsCollector() 61 clearCollectedNotedOps() 62 } 63 64 private fun clearCollectedNotedOps() { 65 noted.clear() 66 selfNoted.clear() 67 asyncNoted.clear() 68 } 69 70 private fun setNotedAppOpsCollector() { 71 appOpsManager.setOnOpNotedCallback(Executor { it.run() }, 72 object : OnOpNotedCallback() { 73 override fun onNoted(op: SyncNotedAppOp) { 74 noted.add(op to Throwable().stackTrace) 75 } 76 77 override fun onSelfNoted(op: SyncNotedAppOp) { 78 selfNoted.add(op to Throwable().stackTrace) 79 } 80 81 override fun onAsyncNoted(asyncOp: AsyncNotedAppOp) { 82 asyncNoted.add(asyncOp) 83 } 84 }) 85 } 86 87 /** 88 * Realistic end-to-end test for requesting to install a package 89 */ 90 @Test 91 fun requestInstall() { 92 val pi = context.createAttributionContext(TEST_ATTRIBUTION_TAG).packageManager 93 .packageInstaller 94 val sessionId = pi.createSession(SessionParams(MODE_FULL_INSTALL)) 95 96 val session = pi.openSession(sessionId) 97 try { 98 // Write apk data to session 99 File("/data/local/tmp/cts/appops2/CtsAppToBlame1.apk") 100 .inputStream().use { fileOnDisk -> 101 session.openWrite("base.apk", 0, -1).use { sessionFile -> 102 fileOnDisk.copyTo(sessionFile) 103 } 104 } 105 106 val installAction = context.packageName + ".install_cb" 107 context.registerReceiver(object : BroadcastReceiver() { 108 override fun onReceive(ignored: Context?, intent: Intent) { 109 if (intent.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID) 110 != STATUS_PENDING_USER_ACTION) { 111 return 112 } 113 114 // Start package install request UI (should trigger REQUEST_INSTALL_PACKAGES) 115 val activityIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT) 116 activityIntent!!.addFlags( 117 FLAG_ACTIVITY_CLEAR_TASK or FLAG_ACTIVITY_NEW_TASK) 118 context.startActivity(activityIntent) 119 } 120 }, IntentFilter(installAction), Context.RECEIVER_EXPORTED) 121 122 // Commit session (should trigger installAction receiver) 123 session.commit(PendingIntent.getBroadcast(context, 0, 124 Intent(installAction).setPackage(context.packageName), 125 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE).intentSender) 126 127 eventually { 128 assertThat(asyncNoted[0].op).isEqualTo( 129 permissionToOp(android.Manifest.permission.REQUEST_INSTALL_PACKAGES)) 130 assertThat(asyncNoted[0].attributionTag).isEqualTo(TEST_ATTRIBUTION_TAG) 131 } 132 } finally { 133 session.abandon() 134 } 135 } 136 137 @After 138 fun removeNotedAppOpsCollector() { 139 appOpsManager.setOnOpNotedCallback(null, null) 140 } 141 } 142