1 /* 2 * 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 com.android.server.location.injector; 18 19 import android.location.util.identity.CallerIdentity; 20 import android.util.SparseArray; 21 22 import com.android.internal.util.Preconditions; 23 24 import java.util.HashMap; 25 26 /** 27 * Version of AppOpsHelper for testing. All app ops are allowed until notified otherwise. 28 */ 29 public class FakeAppOpsHelper extends AppOpsHelper { 30 31 private static class AppOp { AppOp()32 AppOp() {} 33 boolean mAllowed = true; 34 boolean mStarted = false; 35 int mNoteCount = 0; 36 } 37 38 private final HashMap<String, SparseArray<AppOp>> mAppOps; 39 FakeAppOpsHelper()40 public FakeAppOpsHelper() { 41 mAppOps = new HashMap<>(); 42 } 43 setAppOpAllowed(int appOp, String packageName, boolean allowed)44 public void setAppOpAllowed(int appOp, String packageName, boolean allowed) { 45 AppOp myAppOp = getOp(packageName, appOp); 46 myAppOp.mAllowed = allowed; 47 notifyAppOpChanged(packageName); 48 } 49 isAppOpStarted(int appOp, String packageName)50 public boolean isAppOpStarted(int appOp, String packageName) { 51 AppOp myAppOp = getOp(packageName, appOp); 52 return myAppOp.mStarted; 53 } 54 getAppOpNoteCount(int appOp, String packageName)55 public int getAppOpNoteCount(int appOp, String packageName) { 56 AppOp myAppOp = getOp(packageName, appOp); 57 return myAppOp.mNoteCount; 58 } 59 60 @Override startOpNoThrow(int appOp, CallerIdentity callerIdentity)61 public boolean startOpNoThrow(int appOp, CallerIdentity callerIdentity) { 62 AppOp myAppOp = getOp(callerIdentity.getPackageName(), appOp); 63 if (!myAppOp.mAllowed) { 64 return false; 65 } 66 Preconditions.checkState(!myAppOp.mStarted); 67 myAppOp.mStarted = true; 68 return true; 69 } 70 71 @Override finishOp(int appOp, CallerIdentity callerIdentity)72 public void finishOp(int appOp, CallerIdentity callerIdentity) { 73 AppOp myAppOp = getOp(callerIdentity.getPackageName(), appOp); 74 Preconditions.checkState(myAppOp.mStarted); 75 myAppOp.mStarted = false; 76 } 77 78 @Override checkOpNoThrow(int appOp, CallerIdentity callerIdentity)79 public boolean checkOpNoThrow(int appOp, CallerIdentity callerIdentity) { 80 AppOp myAppOp = getOp(callerIdentity.getPackageName(), appOp); 81 return myAppOp.mAllowed; 82 } 83 84 @Override noteOp(int appOp, CallerIdentity callerIdentity)85 public boolean noteOp(int appOp, CallerIdentity callerIdentity) { 86 if (!noteOpNoThrow(appOp, callerIdentity)) { 87 throw new SecurityException( 88 "noteOp not allowed for op " + appOp + " and caller " + callerIdentity); 89 } 90 91 return true; 92 } 93 94 @Override noteOpNoThrow(int appOp, CallerIdentity callerIdentity)95 public boolean noteOpNoThrow(int appOp, CallerIdentity callerIdentity) { 96 AppOp myAppOp = getOp(callerIdentity.getPackageName(), appOp); 97 if (!myAppOp.mAllowed) { 98 return false; 99 } 100 myAppOp.mNoteCount++; 101 return true; 102 } 103 getOp(String packageName, int appOp)104 private AppOp getOp(String packageName, int appOp) { 105 SparseArray<AppOp> ops = mAppOps.get(packageName); 106 if (ops == null) { 107 ops = new SparseArray<>(); 108 mAppOps.put(packageName, ops); 109 } 110 111 AppOp myAppOp; 112 if (ops.contains(appOp)) { 113 myAppOp = ops.get(appOp); 114 } else { 115 myAppOp = new AppOp(); 116 ops.put(appOp, myAppOp); 117 } 118 119 return myAppOp; 120 } 121 } 122