1 /* 2 * Copyright (C) 2014 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.permission.cts; 18 19 import static android.app.AppOpsManager.MODE_ALLOWED; 20 import static android.app.AppOpsManager.MODE_DEFAULT; 21 import static android.app.AppOpsManager.MODE_ERRORED; 22 import static android.app.AppOpsManager.MODE_IGNORED; 23 import static android.app.AppOpsManager.OPSTR_READ_CALENDAR; 24 import static android.app.AppOpsManager.OPSTR_READ_SMS; 25 import static android.app.AppOpsManager.OPSTR_RECORD_AUDIO; 26 import static com.android.compatibility.common.util.AppOpsUtils.allowedOperationLogged; 27 import static com.android.compatibility.common.util.AppOpsUtils.rejectedOperationLogged; 28 import static com.android.compatibility.common.util.AppOpsUtils.setOpMode; 29 30 import static org.mockito.Mockito.mock; 31 import static org.mockito.Mockito.reset; 32 import static org.mockito.Mockito.timeout; 33 import static org.mockito.Mockito.verify; 34 import static org.mockito.Mockito.verifyZeroInteractions; 35 36 import android.Manifest.permission; 37 import android.app.AppOpsManager; 38 import android.app.AppOpsManager.OnOpChangedListener; 39 import android.content.Context; 40 import android.os.Process; 41 import android.test.InstrumentationTestCase; 42 import android.test.suitebuilder.annotation.SmallTest; 43 44 import com.android.compatibility.common.util.AppOpsUtils; 45 46 import java.util.HashMap; 47 import java.util.HashSet; 48 import java.util.Map; 49 import java.util.Set; 50 51 public class AppOpsTest extends InstrumentationTestCase { 52 // Notifying OnOpChangedListener callbacks is an async operation, so we define a timeout. 53 private static final int MODE_WATCHER_TIMEOUT_MS = 5000; 54 55 private AppOpsManager mAppOps; 56 private Context mContext; 57 private String mOpPackageName; 58 private int mMyUid; 59 60 // These permissions and opStrs must map to the same op codes. 61 private static Map<String, String> permissionToOpStr = new HashMap<>(); 62 63 static { permissionToOpStr.put(permission.ACCESS_COARSE_LOCATION, AppOpsManager.OPSTR_COARSE_LOCATION)64 permissionToOpStr.put(permission.ACCESS_COARSE_LOCATION, 65 AppOpsManager.OPSTR_COARSE_LOCATION); permissionToOpStr.put(permission.ACCESS_FINE_LOCATION, AppOpsManager.OPSTR_FINE_LOCATION)66 permissionToOpStr.put(permission.ACCESS_FINE_LOCATION, AppOpsManager.OPSTR_FINE_LOCATION); permissionToOpStr.put(permission.READ_CONTACTS, AppOpsManager.OPSTR_READ_CONTACTS)67 permissionToOpStr.put(permission.READ_CONTACTS, AppOpsManager.OPSTR_READ_CONTACTS); permissionToOpStr.put(permission.WRITE_CONTACTS, AppOpsManager.OPSTR_WRITE_CONTACTS)68 permissionToOpStr.put(permission.WRITE_CONTACTS, AppOpsManager.OPSTR_WRITE_CONTACTS); permissionToOpStr.put(permission.READ_CALL_LOG, AppOpsManager.OPSTR_READ_CALL_LOG)69 permissionToOpStr.put(permission.READ_CALL_LOG, AppOpsManager.OPSTR_READ_CALL_LOG); permissionToOpStr.put(permission.WRITE_CALL_LOG, AppOpsManager.OPSTR_WRITE_CALL_LOG)70 permissionToOpStr.put(permission.WRITE_CALL_LOG, AppOpsManager.OPSTR_WRITE_CALL_LOG); permissionToOpStr.put(permission.READ_CALENDAR, AppOpsManager.OPSTR_READ_CALENDAR)71 permissionToOpStr.put(permission.READ_CALENDAR, AppOpsManager.OPSTR_READ_CALENDAR); permissionToOpStr.put(permission.WRITE_CALENDAR, AppOpsManager.OPSTR_WRITE_CALENDAR)72 permissionToOpStr.put(permission.WRITE_CALENDAR, AppOpsManager.OPSTR_WRITE_CALENDAR); permissionToOpStr.put(permission.CALL_PHONE, AppOpsManager.OPSTR_CALL_PHONE)73 permissionToOpStr.put(permission.CALL_PHONE, AppOpsManager.OPSTR_CALL_PHONE); permissionToOpStr.put(permission.READ_SMS, AppOpsManager.OPSTR_READ_SMS)74 permissionToOpStr.put(permission.READ_SMS, AppOpsManager.OPSTR_READ_SMS); permissionToOpStr.put(permission.RECEIVE_SMS, AppOpsManager.OPSTR_RECEIVE_SMS)75 permissionToOpStr.put(permission.RECEIVE_SMS, AppOpsManager.OPSTR_RECEIVE_SMS); permissionToOpStr.put(permission.RECEIVE_MMS, AppOpsManager.OPSTR_RECEIVE_MMS)76 permissionToOpStr.put(permission.RECEIVE_MMS, AppOpsManager.OPSTR_RECEIVE_MMS); permissionToOpStr.put(permission.RECEIVE_WAP_PUSH, AppOpsManager.OPSTR_RECEIVE_WAP_PUSH)77 permissionToOpStr.put(permission.RECEIVE_WAP_PUSH, AppOpsManager.OPSTR_RECEIVE_WAP_PUSH); permissionToOpStr.put(permission.SEND_SMS, AppOpsManager.OPSTR_SEND_SMS)78 permissionToOpStr.put(permission.SEND_SMS, AppOpsManager.OPSTR_SEND_SMS); permissionToOpStr.put(permission.READ_SMS, AppOpsManager.OPSTR_READ_SMS)79 permissionToOpStr.put(permission.READ_SMS, AppOpsManager.OPSTR_READ_SMS); permissionToOpStr.put(permission.WRITE_SETTINGS, AppOpsManager.OPSTR_WRITE_SETTINGS)80 permissionToOpStr.put(permission.WRITE_SETTINGS, AppOpsManager.OPSTR_WRITE_SETTINGS); permissionToOpStr.put(permission.SYSTEM_ALERT_WINDOW, AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW)81 permissionToOpStr.put(permission.SYSTEM_ALERT_WINDOW, 82 AppOpsManager.OPSTR_SYSTEM_ALERT_WINDOW); permissionToOpStr.put(permission.ACCESS_NOTIFICATIONS, AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS)83 permissionToOpStr.put(permission.ACCESS_NOTIFICATIONS, 84 AppOpsManager.OPSTR_ACCESS_NOTIFICATIONS); permissionToOpStr.put(permission.CAMERA, AppOpsManager.OPSTR_CAMERA)85 permissionToOpStr.put(permission.CAMERA, AppOpsManager.OPSTR_CAMERA); permissionToOpStr.put(permission.RECORD_AUDIO, AppOpsManager.OPSTR_RECORD_AUDIO)86 permissionToOpStr.put(permission.RECORD_AUDIO, AppOpsManager.OPSTR_RECORD_AUDIO); permissionToOpStr.put(permission.READ_PHONE_STATE, AppOpsManager.OPSTR_READ_PHONE_STATE)87 permissionToOpStr.put(permission.READ_PHONE_STATE, AppOpsManager.OPSTR_READ_PHONE_STATE); permissionToOpStr.put(permission.ADD_VOICEMAIL, AppOpsManager.OPSTR_ADD_VOICEMAIL)88 permissionToOpStr.put(permission.ADD_VOICEMAIL, AppOpsManager.OPSTR_ADD_VOICEMAIL); permissionToOpStr.put(permission.USE_SIP, AppOpsManager.OPSTR_USE_SIP)89 permissionToOpStr.put(permission.USE_SIP, AppOpsManager.OPSTR_USE_SIP); permissionToOpStr.put(permission.PROCESS_OUTGOING_CALLS, AppOpsManager.OPSTR_PROCESS_OUTGOING_CALLS)90 permissionToOpStr.put(permission.PROCESS_OUTGOING_CALLS, 91 AppOpsManager.OPSTR_PROCESS_OUTGOING_CALLS); permissionToOpStr.put(permission.BODY_SENSORS, AppOpsManager.OPSTR_BODY_SENSORS)92 permissionToOpStr.put(permission.BODY_SENSORS, AppOpsManager.OPSTR_BODY_SENSORS); permissionToOpStr.put(permission.READ_CELL_BROADCASTS, AppOpsManager.OPSTR_READ_CELL_BROADCASTS)93 permissionToOpStr.put(permission.READ_CELL_BROADCASTS, 94 AppOpsManager.OPSTR_READ_CELL_BROADCASTS); permissionToOpStr.put(permission.READ_EXTERNAL_STORAGE, AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE)95 permissionToOpStr.put(permission.READ_EXTERNAL_STORAGE, 96 AppOpsManager.OPSTR_READ_EXTERNAL_STORAGE); permissionToOpStr.put(permission.WRITE_EXTERNAL_STORAGE, AppOpsManager.OPSTR_WRITE_EXTERNAL_STORAGE)97 permissionToOpStr.put(permission.WRITE_EXTERNAL_STORAGE, 98 AppOpsManager.OPSTR_WRITE_EXTERNAL_STORAGE); 99 } 100 101 @Override setUp()102 protected void setUp() throws Exception { 103 super.setUp(); 104 mContext = getInstrumentation().getContext(); 105 mAppOps = (AppOpsManager) mContext.getSystemService(Context.APP_OPS_SERVICE); 106 mOpPackageName = mContext.getOpPackageName(); 107 mMyUid = Process.myUid(); 108 assertNotNull(mAppOps); 109 110 // Reset app ops state for this test package to the system default. 111 AppOpsUtils.reset(mOpPackageName); 112 } 113 testNoteOpAndCheckOp()114 public void testNoteOpAndCheckOp() throws Exception { 115 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ALLOWED); 116 assertEquals(MODE_ALLOWED, mAppOps.noteOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 117 assertEquals(MODE_ALLOWED, mAppOps.noteOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 118 assertEquals(MODE_ALLOWED, mAppOps.checkOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 119 assertEquals(MODE_ALLOWED, mAppOps.checkOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 120 121 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_IGNORED); 122 assertEquals(MODE_IGNORED, mAppOps.noteOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 123 assertEquals(MODE_IGNORED, mAppOps.noteOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 124 assertEquals(MODE_IGNORED, mAppOps.checkOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 125 assertEquals(MODE_IGNORED, mAppOps.checkOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 126 127 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_DEFAULT); 128 assertEquals(MODE_DEFAULT, mAppOps.noteOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 129 assertEquals(MODE_DEFAULT, mAppOps.noteOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 130 assertEquals(MODE_DEFAULT, mAppOps.checkOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 131 assertEquals(MODE_DEFAULT, mAppOps.checkOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 132 133 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ERRORED); 134 assertEquals(MODE_ERRORED, mAppOps.noteOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 135 assertEquals(MODE_ERRORED, mAppOps.checkOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 136 try { 137 mAppOps.noteOp(OPSTR_READ_SMS, mMyUid, mOpPackageName); 138 fail("SecurityException expected"); 139 } catch (SecurityException expected) { 140 } 141 try { 142 mAppOps.checkOp(OPSTR_READ_SMS, mMyUid, mOpPackageName); 143 fail("SecurityException expected"); 144 } catch (SecurityException expected) { 145 } 146 } 147 testStartOpAndFinishOp()148 public void testStartOpAndFinishOp() throws Exception { 149 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ALLOWED); 150 assertEquals(MODE_ALLOWED, mAppOps.startOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 151 mAppOps.finishOp(OPSTR_READ_SMS, mMyUid, mOpPackageName); 152 assertEquals(MODE_ALLOWED, mAppOps.startOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 153 mAppOps.finishOp(OPSTR_READ_SMS, mMyUid, mOpPackageName); 154 155 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_IGNORED); 156 assertEquals(MODE_IGNORED, mAppOps.startOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 157 assertEquals(MODE_IGNORED, mAppOps.startOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 158 159 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_DEFAULT); 160 assertEquals(MODE_DEFAULT, mAppOps.startOp(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 161 assertEquals(MODE_DEFAULT, mAppOps.startOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 162 163 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ERRORED); 164 assertEquals(MODE_ERRORED, mAppOps.startOpNoThrow(OPSTR_READ_SMS, mMyUid, mOpPackageName)); 165 try { 166 mAppOps.startOp(OPSTR_READ_SMS, mMyUid, mOpPackageName); 167 fail("SecurityException expected"); 168 } catch (SecurityException expected) { 169 } 170 } 171 testCheckPackagePassesCheck()172 public void testCheckPackagePassesCheck() throws Exception { 173 mAppOps.checkPackage(mMyUid, mOpPackageName); 174 mAppOps.checkPackage(Process.SYSTEM_UID, "android"); 175 } 176 testCheckPackageDoesntPassCheck()177 public void testCheckPackageDoesntPassCheck() throws Exception { 178 try { 179 // Package name doesn't match UID. 180 mAppOps.checkPackage(Process.SYSTEM_UID, mOpPackageName); 181 fail("SecurityException expected"); 182 } catch (SecurityException expected) { 183 } 184 185 try { 186 // Package name doesn't match UID. 187 mAppOps.checkPackage(mMyUid, "android"); 188 fail("SecurityException expected"); 189 } catch (SecurityException expected) { 190 } 191 192 try { 193 // Package name missing 194 mAppOps.checkPackage(mMyUid, ""); 195 fail("SecurityException expected"); 196 } catch (SecurityException expected) { 197 } 198 } 199 testWatchingMode()200 public void testWatchingMode() throws Exception { 201 OnOpChangedListener watcher = mock(OnOpChangedListener.class); 202 try { 203 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ALLOWED); 204 205 mAppOps.startWatchingMode(OPSTR_READ_SMS, mOpPackageName, watcher); 206 207 // Make a change to the app op's mode. 208 reset(watcher); 209 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ERRORED); 210 verify(watcher, timeout(MODE_WATCHER_TIMEOUT_MS)) 211 .onOpChanged(OPSTR_READ_SMS, mOpPackageName); 212 213 // Make another change to the app op's mode. 214 reset(watcher); 215 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ALLOWED); 216 verify(watcher, timeout(MODE_WATCHER_TIMEOUT_MS)) 217 .onOpChanged(OPSTR_READ_SMS, mOpPackageName); 218 219 // Set mode to the same value as before - expect no call to the listener. 220 reset(watcher); 221 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ALLOWED); 222 verifyZeroInteractions(watcher); 223 224 mAppOps.stopWatchingMode(watcher); 225 226 // Make a change to the app op's mode. Since we already stopped watching the mode, the 227 // listener shouldn't be called. 228 reset(watcher); 229 setOpMode(mOpPackageName, OPSTR_READ_SMS, MODE_ERRORED); 230 verifyZeroInteractions(watcher); 231 } finally { 232 // Clean up registered watcher. 233 mAppOps.stopWatchingMode(watcher); 234 } 235 } 236 237 @SmallTest testAllOpsHaveOpString()238 public void testAllOpsHaveOpString() { 239 Set<String> opStrs = new HashSet<>(); 240 for (String opStr : AppOpsManager.getOpStrs()) { 241 assertNotNull("Each app op must have an operation string defined", opStr); 242 opStrs.add(opStr); 243 } 244 assertEquals("Not all op strings are unique", AppOpsManager._NUM_OP, opStrs.size()); 245 } 246 247 @SmallTest testOpCodesUnique()248 public void testOpCodesUnique() { 249 String[] opStrs = AppOpsManager.getOpStrs(); 250 Set<Integer> opCodes = new HashSet<>(); 251 for (String opStr : opStrs) { 252 opCodes.add(AppOpsManager.strOpToOp(opStr)); 253 } 254 assertEquals("Not all app op codes are unique", opStrs.length, opCodes.size()); 255 } 256 257 @SmallTest testPermissionMapping()258 public void testPermissionMapping() { 259 for (String permission : permissionToOpStr.keySet()) { 260 testPermissionMapping(permission, permissionToOpStr.get(permission)); 261 } 262 } 263 testPermissionMapping(String permission, String opStr)264 private void testPermissionMapping(String permission, String opStr) { 265 // Do the public value => internal op code lookups. 266 String mappedOpStr = AppOpsManager.permissionToOp(permission); 267 assertEquals(mappedOpStr, opStr); 268 int mappedOpCode = AppOpsManager.permissionToOpCode(permission); 269 int mappedOpCode2 = AppOpsManager.strOpToOp(opStr); 270 assertEquals(mappedOpCode, mappedOpCode2); 271 272 // Do the internal op code => public value lookup (reverse lookup). 273 String permissionMappedBack = AppOpsManager.opToPermission(mappedOpCode); 274 assertEquals(permission, permissionMappedBack); 275 } 276 277 /** 278 * Test that the app can not change the app op mode for itself. 279 */ 280 @SmallTest testCantSetModeForSelf()281 public void testCantSetModeForSelf() { 282 try { 283 int writeSmsOp = AppOpsManager.permissionToOpCode("android.permission.WRITE_SMS"); 284 mAppOps.setMode(writeSmsOp, mMyUid, mOpPackageName, AppOpsManager.MODE_ALLOWED); 285 fail("Was able to set mode for self"); 286 } catch (SecurityException expected) { 287 } 288 } 289 290 @SmallTest testGetOpsForPackage_opsAreLogged()291 public void testGetOpsForPackage_opsAreLogged() throws Exception { 292 // This test checks if operations get logged by the system. It needs to start with a clean 293 // slate, i.e. these ops can't have been logged previously for this test package. The reason 294 // is that there's no API for clearing the app op logs before a test run. However, the op 295 // logs are cleared when this test package is reinstalled between test runs. To make sure 296 // that other test methods in this class don't affect this test method, here we use 297 // operations that are not used by any other test cases. 298 String mustNotBeLogged = "Operation mustn't be logged before the test runs"; 299 assertFalse(mustNotBeLogged, allowedOperationLogged(mOpPackageName, OPSTR_RECORD_AUDIO)); 300 assertFalse(mustNotBeLogged, allowedOperationLogged(mOpPackageName, OPSTR_READ_CALENDAR)); 301 302 setOpMode(mOpPackageName, OPSTR_RECORD_AUDIO, MODE_ALLOWED); 303 setOpMode(mOpPackageName, OPSTR_READ_CALENDAR, MODE_ERRORED); 304 305 // Note an op that's allowed. 306 mAppOps.noteOp(OPSTR_RECORD_AUDIO, mMyUid, mOpPackageName); 307 String mustBeLogged = "Operation must be logged"; 308 assertTrue(mustBeLogged, allowedOperationLogged(mOpPackageName, OPSTR_RECORD_AUDIO)); 309 310 // Note another op that's not allowed. 311 mAppOps.noteOpNoThrow(OPSTR_READ_CALENDAR, mMyUid, mOpPackageName); 312 assertTrue(mustBeLogged, allowedOperationLogged(mOpPackageName, OPSTR_RECORD_AUDIO)); 313 assertTrue(mustBeLogged, rejectedOperationLogged(mOpPackageName, OPSTR_READ_CALENDAR)); 314 } 315 } 316