1 /* 2 * Copyright (C) 2024 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.wifi; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.net.wifi.WifiManager; 22 import android.text.TextUtils; 23 import android.util.ArrayMap; 24 import android.util.Log; 25 26 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; 27 import com.android.server.wifi.util.XmlUtil; 28 29 import org.xmlpull.v1.XmlPullParser; 30 import org.xmlpull.v1.XmlPullParserException; 31 import org.xmlpull.v1.XmlSerializer; 32 33 import java.io.FileDescriptor; 34 import java.io.IOException; 35 import java.io.PrintWriter; 36 import java.util.HashMap; 37 import java.util.Map; 38 39 /** 40 * Store data for storing B2B wifi roaming policies. 41 * These are key (string) / value pairs that are stored in 42 * WifiConfigStore.xml file in a separate section. 43 */ 44 public class WifiRoamingConfigStore { 45 private static final String TAG = "WifiRoamingConfigStore"; 46 private static final int INVALID_ROAMING_MODE = -1; 47 48 // To store roaming policies that are added by the device owner (DO) or 49 // the profile owner of an organization owned device (COPE). 50 private final Map<String, Integer> mDeviceAdminRoamingPolicies = new ArrayMap<>(); 51 // To store roaming policies that are added by non-admins. 52 private final Map<String, Integer> mNonAdminRoamingPolicies = new ArrayMap<>(); 53 private final WifiConfigManager mWifiConfigManager; 54 private boolean mHasNewDataToSerialize = false; 55 WifiRoamingConfigStore(@onNull WifiConfigManager wifiConfigManager, @NonNull WifiConfigStore wifiConfigStore)56 public WifiRoamingConfigStore(@NonNull WifiConfigManager wifiConfigManager, 57 @NonNull WifiConfigStore wifiConfigStore) { 58 mWifiConfigManager = wifiConfigManager; 59 // Register our data store. 60 wifiConfigStore.registerStoreData(new StoreData()); 61 } 62 63 /** 64 * Trigger config store writes in the main wifi service looper's handler. 65 */ triggerSaveToStore()66 private void triggerSaveToStore() { 67 mHasNewDataToSerialize = true; 68 mWifiConfigManager.saveToStore(); 69 } 70 71 /** 72 * Add a roaming policy to the corresponding stored policies. 73 * 74 * @param ssid of the network on which policy to be added. 75 * @param roamingMode denotes roaming mode value configured. 76 * @param isDeviceOwner flag denoting whether API is called by the device owner. 77 */ addRoamingMode(@onNull String ssid, @NonNull int roamingMode, boolean isDeviceOwner)78 public void addRoamingMode(@NonNull String ssid, @NonNull int roamingMode, 79 boolean isDeviceOwner) { 80 if (isDeviceOwner) { 81 mDeviceAdminRoamingPolicies.put(ssid, roamingMode); 82 } else { 83 mNonAdminRoamingPolicies.put(ssid, roamingMode); 84 } 85 triggerSaveToStore(); 86 } 87 88 /** 89 * Remove a roaming policy from the corresponding stored policies. 90 * 91 * @param ssid of the network on which policy to be removed. 92 * @param isDeviceOwner flag denoting whether API is called by the device owner. 93 */ removeRoamingMode(@onNull String ssid, boolean isDeviceOwner)94 public void removeRoamingMode(@NonNull String ssid, boolean isDeviceOwner) { 95 if (isDeviceOwner) { 96 mDeviceAdminRoamingPolicies.remove(ssid); 97 } else { 98 mNonAdminRoamingPolicies.remove(ssid); 99 } 100 triggerSaveToStore(); 101 } 102 103 /** 104 * Retrieve roaming policy/mode for the given network name. 105 * 106 * @param ssid of the network which needs to be queried to fetch policy. 107 * @return roaming mode stored in policy list, 108 * {@value WifiManager#ROAMING_MODE_NORMAL} if the key does not exist. 109 */ getRoamingMode(@onNull String ssid)110 public @NonNull int getRoamingMode(@NonNull String ssid) { 111 int roamingMode; 112 roamingMode = mDeviceAdminRoamingPolicies.getOrDefault(ssid, INVALID_ROAMING_MODE); 113 if (roamingMode == INVALID_ROAMING_MODE) { 114 roamingMode = mNonAdminRoamingPolicies.getOrDefault(ssid, 115 WifiManager.ROAMING_MODE_NORMAL); 116 } 117 return roamingMode; 118 } 119 120 /** 121 * Get all the network roaming policies configured. 122 * 123 * @param isDeviceOwner flag denoting whether API is called by the device owner. 124 * @return Map of corresponding policies for the API caller, 125 * where key is ssid and value is roaming mode/policy configured for that ssid. 126 */ getPerSsidRoamingModes(boolean isDeviceOwner)127 public Map<String, Integer> getPerSsidRoamingModes(boolean isDeviceOwner) { 128 Map<String, Integer> roamingPolicies = new ArrayMap<>(); 129 if (isDeviceOwner) { 130 roamingPolicies.putAll(mDeviceAdminRoamingPolicies); 131 } else { 132 roamingPolicies.putAll(mNonAdminRoamingPolicies); 133 } 134 return roamingPolicies; 135 } 136 137 /** 138 * Dump all roaming policies for debugging. 139 */ dump(FileDescriptor fd, PrintWriter pw, String[] args)140 public void dump(FileDescriptor fd, PrintWriter pw, String[] args) { 141 pw.println(); 142 pw.println("Dump of " + TAG); 143 pw.println("DEVICE_ADMIN_POLICIES"); 144 for (Map.Entry<String, Integer> entry : mDeviceAdminRoamingPolicies.entrySet()) { 145 pw.print(entry.getKey()); 146 pw.print("="); 147 pw.println(entry.getValue()); 148 } 149 pw.println(); 150 pw.println("NON_ADMIN_POLICIES"); 151 for (Map.Entry<String, Integer> entry : mNonAdminRoamingPolicies.entrySet()) { 152 pw.print(entry.getKey()); 153 pw.print("="); 154 pw.println(entry.getValue()); 155 } 156 } 157 158 /** 159 * Store data for persisting the roaming policies data to config store. 160 */ 161 private class StoreData implements WifiConfigStore.StoreData { 162 private static final String XML_TAG_SECTION_HEADER = "RoamingPolicies"; 163 private static final String XML_TAG_DEVICE_ADMIN_POLICIES = "DeviceAdminPolicies"; 164 private static final String XML_TAG_NON_ADMIN_POLICIES = "NonAdminPolicies"; 165 166 @Override serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)167 public void serializeData(XmlSerializer out, 168 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 169 throws XmlPullParserException, IOException { 170 XmlUtil.writeNextValue(out, XML_TAG_DEVICE_ADMIN_POLICIES, mDeviceAdminRoamingPolicies); 171 XmlUtil.writeNextValue(out, XML_TAG_NON_ADMIN_POLICIES, mNonAdminRoamingPolicies); 172 mHasNewDataToSerialize = false; 173 } 174 175 @Override deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)176 public void deserializeData(XmlPullParser in, int outerTagDepth, 177 @WifiConfigStore.Version int version, 178 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 179 throws XmlPullParserException, IOException { 180 if (in == null) { 181 mDeviceAdminRoamingPolicies.clear(); 182 mNonAdminRoamingPolicies.clear(); 183 return; 184 } 185 Map<String, Integer> deviceAdminPolicies = null, nonAdminPolicies = null; 186 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 187 String[] valueName = new String[1]; 188 Object value = XmlUtil.readCurrentValue(in, valueName); 189 if (TextUtils.isEmpty(valueName[0])) { 190 throw new XmlPullParserException("Missing value name"); 191 } 192 switch (valueName[0]) { 193 case XML_TAG_DEVICE_ADMIN_POLICIES: 194 deviceAdminPolicies = (HashMap) value; 195 break; 196 case XML_TAG_NON_ADMIN_POLICIES: 197 nonAdminPolicies = (HashMap) value; 198 break; 199 default: 200 Log.w(TAG, "Ignoring unknown tag under " + XML_TAG_SECTION_HEADER + ": " 201 + valueName[0]); 202 break; 203 } 204 } 205 if (deviceAdminPolicies != null) { 206 mDeviceAdminRoamingPolicies.putAll(deviceAdminPolicies); 207 } 208 if (nonAdminPolicies != null) { 209 mNonAdminRoamingPolicies.putAll(nonAdminPolicies); 210 } 211 } 212 213 @Override resetData()214 public void resetData() { 215 mDeviceAdminRoamingPolicies.clear(); 216 mNonAdminRoamingPolicies.clear(); 217 } 218 219 @Override hasNewDataToSerialize()220 public boolean hasNewDataToSerialize() { 221 return mHasNewDataToSerialize; 222 } 223 224 @Override getName()225 public String getName() { 226 return XML_TAG_SECTION_HEADER; 227 } 228 229 @Override getStoreFileId()230 public @WifiConfigStore.StoreFileId int getStoreFileId() { 231 // Shared general store. 232 return WifiConfigStore.STORE_FILE_SHARED_GENERAL; 233 } 234 } 235 } 236