1 /* 2 * Copyright (C) 2021 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.pm.verify.domain; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.annotation.UserIdInt; 22 import android.content.pm.IntentFilterVerificationInfo; 23 import android.content.pm.PackageManager; 24 import android.util.ArrayMap; 25 import android.util.SparseIntArray; 26 27 import com.android.internal.annotations.GuardedBy; 28 import com.android.modules.utils.TypedXmlPullParser; 29 import com.android.modules.utils.TypedXmlSerializer; 30 import com.android.server.pm.SettingsXml; 31 32 import org.xmlpull.v1.XmlPullParserException; 33 34 import java.io.IOException; 35 36 /** 37 * Reads and writes the old {@link android.content.pm.IntentFilterVerificationInfo} so that it can 38 * be migrated in to the new API. Will throw away the state once it's successfully applied so that 39 * eventually there will be no legacy state on the device. 40 * 41 * This attempt is best effort, and if the legacy state is lost that's acceptable. The user setting 42 * in the legacy API may have been set incorrectly because it was never made obvious to the user 43 * what it actually toggled, so there's a strong argument to prevent migration anyways. The user 44 * can just set their preferences again, this time with finer grained control, if the legacy state 45 * gets dropped. 46 */ 47 public class DomainVerificationLegacySettings { 48 49 public static final String TAG_DOMAIN_VERIFICATIONS_LEGACY = "domain-verifications-legacy"; 50 public static final String TAG_USER_STATES = "user-states"; 51 public static final String ATTR_PACKAGE_NAME = "packageName"; 52 public static final String TAG_USER_STATE = "user-state"; 53 public static final String ATTR_USER_ID = "userId"; 54 public static final String ATTR_STATE = "state"; 55 56 @NonNull 57 private final Object mLock = new Object(); 58 59 @NonNull 60 private final ArrayMap<String, LegacyState> mStates = new ArrayMap<>(); 61 add(@onNull String packageName, @NonNull IntentFilterVerificationInfo info)62 public void add(@NonNull String packageName, @NonNull IntentFilterVerificationInfo info) { 63 synchronized (mLock) { 64 getOrCreateStateLocked(packageName).setInfo(info); 65 } 66 } 67 add(@onNull String packageName, @UserIdInt int userId, int state)68 public void add(@NonNull String packageName, @UserIdInt int userId, int state) { 69 synchronized (mLock) { 70 getOrCreateStateLocked(packageName).addUserState(userId, state); 71 } 72 } 73 getUserState(@onNull String packageName, @UserIdInt int userId)74 public int getUserState(@NonNull String packageName, @UserIdInt int userId) { 75 synchronized (mLock) { 76 LegacyState state = mStates.get(packageName); 77 if (state != null) { 78 return state.getUserState(userId); 79 } 80 } 81 return PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED; 82 } 83 84 @Nullable getUserStates(@onNull String packageName)85 public SparseIntArray getUserStates(@NonNull String packageName) { 86 synchronized (mLock) { 87 LegacyState state = mStates.get(packageName); 88 if (state != null) { 89 // Yes, this returns outside of the lock, but we assume that retrieval generally 90 // only happens after all adding has concluded from reading settings. 91 return state.getUserStates(); 92 } 93 } 94 return null; 95 } 96 97 @Nullable remove(@onNull String packageName)98 public IntentFilterVerificationInfo remove(@NonNull String packageName) { 99 synchronized (mLock) { 100 LegacyState state = mStates.get(packageName); 101 if (state != null && !state.isAttached()) { 102 state.markAttached(); 103 return state.getInfo(); 104 } 105 } 106 return null; 107 } 108 109 @GuardedBy("mLock") 110 @NonNull getOrCreateStateLocked(@onNull String packageName)111 private LegacyState getOrCreateStateLocked(@NonNull String packageName) { 112 LegacyState state = mStates.get(packageName); 113 if (state == null) { 114 state = new LegacyState(); 115 mStates.put(packageName, state); 116 } 117 118 return state; 119 } 120 writeSettings(TypedXmlSerializer xmlSerializer)121 public void writeSettings(TypedXmlSerializer xmlSerializer) throws IOException { 122 try (SettingsXml.Serializer serializer = SettingsXml.serializer(xmlSerializer)) { 123 try (SettingsXml.WriteSection ignored = 124 serializer.startSection(TAG_DOMAIN_VERIFICATIONS_LEGACY)) { 125 synchronized (mLock) { 126 final int statesSize = mStates.size(); 127 for (int stateIndex = 0; stateIndex < statesSize; stateIndex++) { 128 final LegacyState state = mStates.valueAt(stateIndex); 129 final SparseIntArray userStates = state.getUserStates(); 130 if (userStates == null) { 131 continue; 132 } 133 134 final String packageName = mStates.keyAt(stateIndex); 135 try (SettingsXml.WriteSection userStatesSection = 136 serializer.startSection(TAG_USER_STATES) 137 .attribute(ATTR_PACKAGE_NAME, packageName)) { 138 final int userStatesSize = userStates.size(); 139 for (int userStateIndex = 0; userStateIndex < userStatesSize; 140 userStateIndex++) { 141 final int userId = userStates.keyAt(userStateIndex); 142 final int userState = userStates.valueAt(userStateIndex); 143 userStatesSection.startSection(TAG_USER_STATE) 144 .attribute(ATTR_USER_ID, userId) 145 .attribute(ATTR_STATE, userState) 146 .finish(); 147 } 148 } 149 } 150 } 151 } 152 } 153 } 154 readSettings(TypedXmlPullParser xmlParser)155 public void readSettings(TypedXmlPullParser xmlParser) 156 throws IOException, XmlPullParserException { 157 final SettingsXml.ChildSection child = SettingsXml.parser(xmlParser).children(); 158 while (child.moveToNext()) { 159 if (TAG_USER_STATES.equals(child.getName())) { 160 readUserStates(child); 161 } 162 } 163 } 164 readUserStates(SettingsXml.ReadSection section)165 private void readUserStates(SettingsXml.ReadSection section) { 166 String packageName = section.getString(ATTR_PACKAGE_NAME); 167 synchronized (mLock) { 168 final LegacyState legacyState = getOrCreateStateLocked(packageName); 169 final SettingsXml.ChildSection child = section.children(); 170 while (child.moveToNext()) { 171 if (TAG_USER_STATE.equals(child.getName())) { 172 readUserState(child, legacyState); 173 } 174 } 175 } 176 } 177 readUserState(SettingsXml.ReadSection section, LegacyState legacyState)178 private void readUserState(SettingsXml.ReadSection section, LegacyState legacyState) { 179 int userId = section.getInt(ATTR_USER_ID); 180 int state = section.getInt(ATTR_STATE); 181 legacyState.addUserState(userId, state); 182 } 183 184 static class LegacyState { 185 @Nullable 186 private IntentFilterVerificationInfo mInfo; 187 188 @Nullable 189 private SparseIntArray mUserStates; 190 191 private boolean attached; 192 193 @Nullable getInfo()194 public IntentFilterVerificationInfo getInfo() { 195 return mInfo; 196 } 197 getUserState(int userId)198 public int getUserState(int userId) { 199 return mUserStates.get(userId, 200 PackageManager.INTENT_FILTER_DOMAIN_VERIFICATION_STATUS_UNDEFINED); 201 } 202 203 @Nullable getUserStates()204 public SparseIntArray getUserStates() { 205 return mUserStates; 206 } 207 setInfo(@onNull IntentFilterVerificationInfo info)208 public void setInfo(@NonNull IntentFilterVerificationInfo info) { 209 mInfo = info; 210 } 211 addUserState(@serIdInt int userId, int state)212 public void addUserState(@UserIdInt int userId, int state) { 213 if (mUserStates == null) { 214 mUserStates = new SparseIntArray(1); 215 } 216 mUserStates.put(userId, state); 217 } 218 isAttached()219 public boolean isAttached() { 220 return attached; 221 } 222 markAttached()223 public void markAttached() { 224 attached = true; 225 } 226 } 227 } 228