1 /* 2 * Copyright 2017 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.Nullable; 20 import android.util.ArraySet; 21 import android.util.Log; 22 23 import com.android.server.wifi.WifiConfigStore.StoreData; 24 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil; 25 import com.android.server.wifi.util.XmlUtil; 26 27 import org.xmlpull.v1.XmlPullParser; 28 import org.xmlpull.v1.XmlPullParserException; 29 import org.xmlpull.v1.XmlSerializer; 30 31 import java.io.IOException; 32 import java.util.Collections; 33 import java.util.Set; 34 35 /** 36 * Config store data for Wifi Wake. 37 */ 38 public class WakeupConfigStoreData implements StoreData { 39 private static final String TAG = "WakeupConfigStoreData"; 40 41 private static final String XML_TAG_FEATURE_STATE_SECTION = "FeatureState"; 42 private static final String XML_TAG_IS_ACTIVE = "IsActive"; 43 private static final String XML_TAG_IS_ONBOARDED = "IsOnboarded"; 44 private static final String XML_TAG_NOTIFICATIONS_SHOWN = "NotificationsShown"; 45 private static final String XML_TAG_NETWORK_SECTION = "Network"; 46 private static final String XML_TAG_SSID = "SSID"; 47 private static final String XML_TAG_SECURITY = "Security"; 48 49 private final DataSource<Boolean> mIsActiveDataSource; 50 private final DataSource<Boolean> mIsOnboardedDataSource; 51 private final DataSource<Integer> mNotificationsDataSource; 52 private final DataSource<Set<ScanResultMatchInfo>> mNetworkDataSource; 53 private boolean mHasBeenRead = false; 54 55 /** 56 * Interface defining a data source for the store data. 57 * 58 * @param <T> Type of data source 59 */ 60 public interface DataSource<T> { 61 /** 62 * Returns the data from the data source. 63 */ getData()64 T getData(); 65 66 /** 67 * Updates the data in the data source. 68 * 69 * @param data Data retrieved from the store 70 */ setData(T data)71 void setData(T data); 72 } 73 74 /** 75 * Creates the config store data with its data sources. 76 * 77 * @param isActiveDataSource Data source for isActive 78 * @param networkDataSource Data source for the locked network list 79 */ WakeupConfigStoreData( DataSource<Boolean> isActiveDataSource, DataSource<Boolean> isOnboardedDataSource, DataSource<Integer> notificationsDataSource, DataSource<Set<ScanResultMatchInfo>> networkDataSource)80 public WakeupConfigStoreData( 81 DataSource<Boolean> isActiveDataSource, 82 DataSource<Boolean> isOnboardedDataSource, 83 DataSource<Integer> notificationsDataSource, 84 DataSource<Set<ScanResultMatchInfo>> networkDataSource) { 85 mIsActiveDataSource = isActiveDataSource; 86 mIsOnboardedDataSource = isOnboardedDataSource; 87 mNotificationsDataSource = notificationsDataSource; 88 mNetworkDataSource = networkDataSource; 89 } 90 91 /** 92 * Returns whether the user store has been read. 93 */ hasBeenRead()94 public boolean hasBeenRead() { 95 return mHasBeenRead; 96 } 97 98 @Override serializeData(XmlSerializer out, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)99 public void serializeData(XmlSerializer out, 100 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 101 throws XmlPullParserException, IOException { 102 writeFeatureState(out); 103 104 for (ScanResultMatchInfo scanResultMatchInfo : mNetworkDataSource.getData()) { 105 writeNetwork(out, scanResultMatchInfo); 106 } 107 } 108 109 /** 110 * Writes the current state of Wifi Wake to an XML output stream. 111 * 112 * @param out XML output stream 113 * @throws XmlPullParserException 114 * @throws IOException 115 */ writeFeatureState(XmlSerializer out)116 private void writeFeatureState(XmlSerializer out) 117 throws IOException, XmlPullParserException { 118 XmlUtil.writeNextSectionStart(out, XML_TAG_FEATURE_STATE_SECTION); 119 120 XmlUtil.writeNextValue(out, XML_TAG_IS_ACTIVE, mIsActiveDataSource.getData()); 121 XmlUtil.writeNextValue(out, XML_TAG_IS_ONBOARDED, mIsOnboardedDataSource.getData()); 122 XmlUtil.writeNextValue(out, XML_TAG_NOTIFICATIONS_SHOWN, 123 mNotificationsDataSource.getData()); 124 125 XmlUtil.writeNextSectionEnd(out, XML_TAG_FEATURE_STATE_SECTION); 126 } 127 128 /** 129 * Writes a {@link ScanResultMatchInfo} to an XML output stream. 130 * 131 * @param out XML output stream 132 * @param scanResultMatchInfo The ScanResultMatchInfo to serialize 133 * @throws XmlPullParserException 134 * @throws IOException 135 */ writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo)136 private void writeNetwork(XmlSerializer out, ScanResultMatchInfo scanResultMatchInfo) 137 throws XmlPullParserException, IOException { 138 XmlUtil.writeNextSectionStart(out, XML_TAG_NETWORK_SECTION); 139 140 XmlUtil.writeNextValue(out, XML_TAG_SSID, scanResultMatchInfo.networkSsid); 141 XmlUtil.writeNextValue(out, XML_TAG_SECURITY, scanResultMatchInfo.networkType); 142 143 XmlUtil.writeNextSectionEnd(out, XML_TAG_NETWORK_SECTION); 144 } 145 146 @Override deserializeData(XmlPullParser in, int outerTagDepth, @WifiConfigStore.Version int version, @Nullable WifiConfigStoreEncryptionUtil encryptionUtil)147 public void deserializeData(XmlPullParser in, int outerTagDepth, 148 @WifiConfigStore.Version int version, 149 @Nullable WifiConfigStoreEncryptionUtil encryptionUtil) 150 throws XmlPullParserException, IOException { 151 if (!mHasBeenRead) { 152 Log.d(TAG, "WifiWake user data has been read"); 153 mHasBeenRead = true; 154 } 155 // Ignore empty reads. 156 if (in == null) { 157 return; 158 } 159 160 Set<ScanResultMatchInfo> networks = new ArraySet<>(); 161 162 String[] headerName = new String[1]; 163 while (XmlUtil.gotoNextSectionOrEnd(in, headerName, outerTagDepth)) { 164 switch (headerName[0]) { 165 case XML_TAG_FEATURE_STATE_SECTION: 166 parseFeatureState(in, outerTagDepth + 1); 167 break; 168 case XML_TAG_NETWORK_SECTION: 169 networks.add(parseNetwork(in, outerTagDepth + 1)); 170 break; 171 } 172 } 173 174 mNetworkDataSource.setData(networks); 175 } 176 177 /** 178 * Parses the state of Wifi Wake from an XML input stream and sets the respective data sources. 179 * 180 * @param in XML input stream 181 * @param outerTagDepth XML tag depth of the containing section 182 * @throws IOException 183 * @throws XmlPullParserException 184 */ parseFeatureState(XmlPullParser in, int outerTagDepth)185 private void parseFeatureState(XmlPullParser in, int outerTagDepth) 186 throws IOException, XmlPullParserException { 187 boolean isActive = false; 188 boolean isOnboarded = false; 189 int notificationsShown = 0; 190 191 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 192 String[] valueName = new String[1]; 193 Object value = XmlUtil.readCurrentValue(in, valueName); 194 if (valueName[0] == null) { 195 throw new XmlPullParserException("Missing value name"); 196 } 197 switch (valueName[0]) { 198 case XML_TAG_IS_ACTIVE: 199 isActive = (Boolean) value; 200 break; 201 case XML_TAG_IS_ONBOARDED: 202 isOnboarded = (Boolean) value; 203 break; 204 case XML_TAG_NOTIFICATIONS_SHOWN: 205 notificationsShown = (Integer) value; 206 break; 207 default: 208 throw new XmlPullParserException("Unknown value found: " + valueName[0]); 209 } 210 } 211 212 mIsActiveDataSource.setData(isActive); 213 mIsOnboardedDataSource.setData(isOnboarded); 214 mNotificationsDataSource.setData(notificationsShown); 215 } 216 217 /** 218 * Parses a {@link ScanResultMatchInfo} from an XML input stream. 219 * 220 * @param in XML input stream 221 * @param outerTagDepth XML tag depth of the containing section 222 * @return The {@link ScanResultMatchInfo} 223 * @throws IOException 224 * @throws XmlPullParserException 225 */ parseNetwork(XmlPullParser in, int outerTagDepth)226 private ScanResultMatchInfo parseNetwork(XmlPullParser in, int outerTagDepth) 227 throws IOException, XmlPullParserException { 228 ScanResultMatchInfo scanResultMatchInfo = new ScanResultMatchInfo(); 229 while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { 230 String[] valueName = new String[1]; 231 Object value = XmlUtil.readCurrentValue(in, valueName); 232 if (valueName[0] == null) { 233 throw new XmlPullParserException("Missing value name"); 234 } 235 switch (valueName[0]) { 236 case XML_TAG_SSID: 237 scanResultMatchInfo.networkSsid = (String) value; 238 break; 239 case XML_TAG_SECURITY: 240 scanResultMatchInfo.networkType = (int) value; 241 break; 242 default: 243 throw new XmlPullParserException("Unknown tag under " + TAG + ": " 244 + valueName[0]); 245 } 246 } 247 248 return scanResultMatchInfo; 249 } 250 251 @Override resetData()252 public void resetData() { 253 mNetworkDataSource.setData(Collections.emptySet()); 254 mIsActiveDataSource.setData(false); 255 mIsOnboardedDataSource.setData(false); 256 mNotificationsDataSource.setData(0); 257 } 258 259 @Override hasNewDataToSerialize()260 public boolean hasNewDataToSerialize() { 261 // always persist. 262 return true; 263 } 264 265 @Override getName()266 public String getName() { 267 return TAG; 268 } 269 270 @Override getStoreFileId()271 public @WifiConfigStore.StoreFileId int getStoreFileId() { 272 // Shared general store. 273 return WifiConfigStore.STORE_FILE_USER_GENERAL; 274 } 275 } 276