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 package android.packageinstaller.nopermission.cts 17 18 import android.app.AppOpsManager.MODE_ALLOWED 19 import android.app.PendingIntent 20 import android.content.BroadcastReceiver 21 import android.content.Context 22 import android.content.Intent 23 import android.content.IntentFilter 24 import android.content.pm.PackageInstaller 25 import android.content.pm.PackageInstaller.EXTRA_STATUS 26 import android.content.pm.PackageInstaller.STATUS_FAILURE_INVALID 27 import android.os.Build 28 import android.platform.test.annotations.AppModeFull 29 import androidx.test.InstrumentationRegistry 30 import androidx.test.filters.MediumTest 31 import androidx.test.runner.AndroidJUnit4 32 import android.support.test.uiautomator.By 33 import android.support.test.uiautomator.UiDevice 34 import android.support.test.uiautomator.Until 35 import androidx.core.content.FileProvider 36 import com.android.compatibility.common.util.AppOpsUtils 37 import org.junit.After 38 import org.junit.Assert.assertFalse 39 import org.junit.Assert.assertTrue 40 import org.junit.Before 41 import org.junit.Test 42 import org.junit.runner.RunWith 43 import java.io.File 44 import java.lang.IllegalArgumentException 45 46 private const val TEST_APK_NAME = "CtsEmptyTestApp.apk" 47 private const val TEST_APK_PACKAGE_NAME = "android.packageinstaller.emptytestapp.cts" 48 private const val TEST_APK_EXTERNAL_LOCATION = "/data/local/tmp/cts/nopermission" 49 private const val CONTENT_AUTHORITY = "android.packageinstaller.nopermission.cts.fileprovider" 50 private const val PACKAGE_INSTALLER_PACKAGE_NAME = "com.android.packageinstaller" 51 private const val INSTALL_CONFIRM_TEXT_ID = "install_confirm_question" 52 private const val WM_DISMISS_KEYGUARD_COMMAND = "wm dismiss-keyguard" 53 54 private const val ACTION = "NoPermissionTests.install_cb" 55 56 private const val WAIT_FOR_UI_TIMEOUT = 5000L 57 private const val APP_OP_STR = "REQUEST_INSTALL_PACKAGES" 58 59 @RunWith(AndroidJUnit4::class) 60 @MediumTest 61 @AppModeFull 62 class NoPermissionTests { 63 private var context = InstrumentationRegistry.getTargetContext() 64 private var pm = context.packageManager 65 private var packageName = context.packageName 66 private var apkFile = File(context.filesDir, TEST_APK_NAME) 67 private var uiDevice = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()) 68 69 private val receiver = object : BroadcastReceiver() { 70 override fun onReceive(context: Context, intent: Intent) { 71 val status = intent.getIntExtra(EXTRA_STATUS, STATUS_FAILURE_INVALID) 72 73 if (status == PackageInstaller.STATUS_PENDING_USER_ACTION) { 74 val activityIntent = intent.getParcelableExtra<Intent>(Intent.EXTRA_INTENT) 75 activityIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK) 76 context.startActivity(activityIntent) 77 } 78 } 79 } 80 81 @Before 82 fun wakeUpScreen() { 83 if (!uiDevice.isScreenOn) { 84 uiDevice.wakeUp() 85 } 86 uiDevice.executeShellCommand(WM_DISMISS_KEYGUARD_COMMAND) 87 } 88 89 @Before 90 fun copyTestApk() { 91 File(TEST_APK_EXTERNAL_LOCATION, TEST_APK_NAME).copyTo(target = apkFile, overwrite = true) 92 } 93 94 @Before 95 fun allowToInstallPackages() { 96 // To make sure no other blocking dialogs appear 97 AppOpsUtils.setOpMode(context.packageName, APP_OP_STR, MODE_ALLOWED) 98 } 99 100 @Before 101 fun registerInstallResultReceiver() { 102 context.registerReceiver(receiver, IntentFilter(ACTION)) 103 } 104 105 @Before 106 fun waitForUIIdle() { 107 uiDevice.waitForIdle() 108 } 109 110 private fun launchPackageInstallerViaIntent() { 111 val intent = Intent(Intent.ACTION_INSTALL_PACKAGE) 112 intent.data = FileProvider.getUriForFile(context, CONTENT_AUTHORITY, apkFile) 113 intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION or Intent.FLAG_ACTIVITY_NEW_TASK 114 context.startActivity(intent) 115 } 116 117 private fun launchPackageInstallerViaSession() { 118 val pi = pm.packageInstaller 119 120 // Create session 121 val sessionId = pi.createSession(PackageInstaller.SessionParams( 122 PackageInstaller.SessionParams.MODE_FULL_INSTALL)) 123 val session = pi.openSession(sessionId)!! 124 125 // Write data to session 126 File(TEST_APK_EXTERNAL_LOCATION, TEST_APK_NAME).inputStream().use { fileOnDisk -> 127 session.openWrite(TEST_APK_NAME, 0, -1).use { sessionFile -> 128 fileOnDisk.copyTo(sessionFile) 129 } 130 } 131 132 // Commit session 133 val pendingIntent = PendingIntent.getBroadcast(context, 0, Intent(ACTION), 134 PendingIntent.FLAG_UPDATE_CURRENT) 135 session.commit(pendingIntent.intentSender) 136 } 137 138 private fun assertInstallSucceeded(errorMessage: String) { 139 val selector = By.res(PACKAGE_INSTALLER_PACKAGE_NAME, INSTALL_CONFIRM_TEXT_ID) 140 assertTrue(errorMessage, uiDevice.wait(Until.hasObject(selector), WAIT_FOR_UI_TIMEOUT)) 141 uiDevice.pressBack() 142 } 143 144 private fun assertInstallFailed(errorMessage: String) { 145 val selector = By.res(PACKAGE_INSTALLER_PACKAGE_NAME, INSTALL_CONFIRM_TEXT_ID) 146 assertFalse(errorMessage, uiDevice.wait(Until.hasObject(selector), WAIT_FOR_UI_TIMEOUT)) 147 uiDevice.pressBack() 148 } 149 150 @Test 151 fun noPermissionsTestIntent() { 152 launchPackageInstallerViaIntent() 153 154 if (pm.getPackageInfo(packageName, 0).applicationInfo.targetSdkVersion 155 >= Build.VERSION_CODES.O) { 156 assertInstallFailed("Package Installer UI should not appear") 157 } else { 158 assertInstallSucceeded("Package Installer UI should appear") 159 } 160 } 161 162 @Test 163 fun noPermissionsTestSession() { 164 launchPackageInstallerViaSession() 165 166 if (pm.getPackageInfo(packageName, 0).applicationInfo.targetSdkVersion 167 >= Build.VERSION_CODES.O) { 168 assertInstallFailed("Package Installer UI should not appear") 169 } else { 170 assertInstallSucceeded("Package Installer UI should appear") 171 } 172 } 173 174 @After 175 fun unregisterInstallResultReceiver() { 176 try { 177 context.unregisterReceiver(receiver) 178 } catch (ignored: IllegalArgumentException) { 179 } 180 } 181 182 @After 183 fun uninstallTestPackage() { 184 uiDevice.executeShellCommand("pm uninstall $TEST_APK_PACKAGE_NAME") 185 } 186 } 187