1 /* 2 * Copyright (C) 2023 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.appop; 18 19 import android.annotation.NonNull; 20 import android.app.AppOpsManager; 21 import android.os.UserHandle; 22 import android.util.ArrayMap; 23 import android.util.AtomicFile; 24 import android.util.SparseArray; 25 import android.util.SparseIntArray; 26 27 import com.android.internal.annotations.GuardedBy; 28 import com.android.server.SystemServiceManager; 29 30 import java.io.File; 31 import java.util.Collections; 32 import java.util.Map; 33 34 /** 35 * Provider of legacy app-ops data for new permission subsystem. 36 * 37 * @hide 38 */ 39 public class AppOpMigrationHelperImpl implements AppOpMigrationHelper { 40 private SparseArray<Map<Integer, Map<String, Integer>>> mAppIdAppOpModes = null; 41 private SparseArray<Map<String, Map<String, Integer>>> mPackageAppOpModes = null; 42 private int mVersionAtBoot; 43 44 private final Object mLock = new Object(); 45 46 @Override 47 @GuardedBy("mLock") 48 @NonNull getLegacyAppIdAppOpModes(int userId)49 public Map<Integer, Map<String, Integer>> getLegacyAppIdAppOpModes(int userId) { 50 synchronized (mLock) { 51 if (mAppIdAppOpModes == null) { 52 readLegacyAppOpState(); 53 } 54 } 55 return mAppIdAppOpModes.get(userId, Collections.emptyMap()); 56 } 57 58 @Override 59 @GuardedBy("mLock") 60 @NonNull getLegacyPackageAppOpModes(int userId)61 public Map<String, Map<String, Integer>> getLegacyPackageAppOpModes(int userId) { 62 synchronized (mLock) { 63 if (mPackageAppOpModes == null) { 64 readLegacyAppOpState(); 65 } 66 } 67 return mPackageAppOpModes.get(userId, Collections.emptyMap()); 68 } 69 70 @GuardedBy("mLock") readLegacyAppOpState()71 private void readLegacyAppOpState() { 72 final File systemDir = SystemServiceManager.ensureSystemDir(); 73 AtomicFile appOpFile = new AtomicFile(new File(systemDir, "appops.xml")); 74 75 final SparseArray<SparseIntArray> uidAppOpModes = new SparseArray<>(); 76 final SparseArray<ArrayMap<String, SparseIntArray>> packageAppOpModes = 77 new SparseArray<>(); 78 79 LegacyAppOpStateParser parser = new LegacyAppOpStateParser(); 80 final int version = parser.readState(appOpFile, uidAppOpModes, packageAppOpModes); 81 // -1 No app ops data available 82 // 0 appops.xml exist w/o any version 83 switch (version) { 84 case -2: 85 mVersionAtBoot = -1; 86 break; 87 case -1: 88 mVersionAtBoot = 0; 89 break; 90 default: 91 mVersionAtBoot = version; 92 } 93 mAppIdAppOpModes = getAppIdAppOpModes(uidAppOpModes); 94 mPackageAppOpModes = getPackageAppOpModes(packageAppOpModes); 95 } 96 getAppIdAppOpModes( SparseArray<SparseIntArray> uidAppOpModes)97 private SparseArray<Map<Integer, Map<String, Integer>>> getAppIdAppOpModes( 98 SparseArray<SparseIntArray> uidAppOpModes) { 99 SparseArray<Map<Integer, Map<String, Integer>>> userAppIdAppOpModes = new SparseArray<>(); 100 101 int size = uidAppOpModes.size(); 102 for (int uidIndex = 0; uidIndex < size; uidIndex++) { 103 int uid = uidAppOpModes.keyAt(uidIndex); 104 int userId = UserHandle.getUserId(uid); 105 Map<Integer, Map<String, Integer>> appIdAppOpModes = userAppIdAppOpModes.get(userId); 106 if (appIdAppOpModes == null) { 107 appIdAppOpModes = new ArrayMap<>(); 108 userAppIdAppOpModes.put(userId, appIdAppOpModes); 109 } 110 111 SparseIntArray appOpModes = uidAppOpModes.valueAt(uidIndex); 112 appIdAppOpModes.put(UserHandle.getAppId(uid), getAppOpModesForOpName(appOpModes)); 113 } 114 return userAppIdAppOpModes; 115 } 116 getPackageAppOpModes( SparseArray<ArrayMap<String, SparseIntArray>> legacyPackageAppOpModes)117 private SparseArray<Map<String, Map<String, Integer>>> getPackageAppOpModes( 118 SparseArray<ArrayMap<String, SparseIntArray>> legacyPackageAppOpModes) { 119 SparseArray<Map<String, Map<String, Integer>>> userPackageAppOpModes = new SparseArray<>(); 120 121 int usersSize = legacyPackageAppOpModes.size(); 122 for (int userIndex = 0; userIndex < usersSize; userIndex++) { 123 int userId = legacyPackageAppOpModes.keyAt(userIndex); 124 Map<String, Map<String, Integer>> packageAppOpModes = userPackageAppOpModes.get(userId); 125 if (packageAppOpModes == null) { 126 packageAppOpModes = new ArrayMap<>(); 127 userPackageAppOpModes.put(userId, packageAppOpModes); 128 } 129 130 ArrayMap<String, SparseIntArray> legacyPackagesModes = 131 legacyPackageAppOpModes.valueAt(userIndex); 132 133 int packagesSize = legacyPackagesModes.size(); 134 for (int packageIndex = 0; packageIndex < packagesSize; packageIndex++) { 135 String packageName = legacyPackagesModes.keyAt(packageIndex); 136 SparseIntArray modes = legacyPackagesModes.valueAt(packageIndex); 137 packageAppOpModes.put(packageName, getAppOpModesForOpName(modes)); 138 } 139 } 140 return userPackageAppOpModes; 141 } 142 143 /** 144 * Converts the map from op code -> mode to op name -> mode. 145 */ getAppOpModesForOpName(SparseIntArray appOpCodeModes)146 private Map<String, Integer> getAppOpModesForOpName(SparseIntArray appOpCodeModes) { 147 int modesSize = appOpCodeModes.size(); 148 Map<String, Integer> appOpNameModes = new ArrayMap<>(modesSize); 149 150 for (int modeIndex = 0; modeIndex < modesSize; modeIndex++) { 151 int opCode = appOpCodeModes.keyAt(modeIndex); 152 int opMode = appOpCodeModes.valueAt(modeIndex); 153 appOpNameModes.put(AppOpsManager.opToPublicName(opCode), opMode); 154 } 155 return appOpNameModes; 156 } 157 158 @Override getLegacyAppOpVersion()159 public int getLegacyAppOpVersion() { 160 synchronized (mLock) { 161 if (mAppIdAppOpModes == null || mPackageAppOpModes == null) { 162 readLegacyAppOpState(); 163 } 164 } 165 return mVersionAtBoot; 166 } 167 168 @Override hasLegacyAppOpState()169 public boolean hasLegacyAppOpState() { 170 return getLegacyAppOpVersion() > -1; 171 } 172 } 173