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.wifi;
18 
19 import android.annotation.NonNull;
20 import android.util.Log;
21 
22 import com.android.server.wifi.util.WifiConfigStoreEncryptionUtil;
23 import com.android.server.wifi.util.XmlUtil;
24 
25 import org.xmlpull.v1.XmlPullParser;
26 import org.xmlpull.v1.XmlPullParserException;
27 import org.xmlpull.v1.XmlSerializer;
28 
29 import java.io.IOException;
30 import java.util.HashMap;
31 import java.util.Map;
32 
33 /**
34  * This class performs serialization and parsing of XML data block that contain the map of carrier
35  * Wi-Fi offloading settings info.
36  */
37 public class WifiCarrierInfoStoreManagerData implements WifiConfigStore.StoreData {
38     private static final String TAG = "WifiCarrierInfoStoreManagerData";
39     private static final String XML_TAG_SECTION_HEADER =
40             "WifiCarrierInfoStoreManagerDataStores";
41     private static final String XML_TAG_MERGED_CARRIER_NETWORK_OFFLOAD_MAP =
42             "MergedCarrierNetworkOffloadMap";
43     private static final String XML_TAG_UNMERGED_CARRIER_NETWORK_OFFLOAD_MAP =
44             "UnmergedCarrierNetworkOffloadMap";
45 
46     /**
47      * Interface define the data source for the carrier IMSI protection exemption map store data.
48      */
49     public interface DataSource {
50 
51         /**
52          * Retrieve the merged carrier network offload map from the data source to serialize to
53          * disk.
54          */
toSerializeMergedCarrierNetworkOffloadMap()55         Map<Integer, Boolean> toSerializeMergedCarrierNetworkOffloadMap();
56 
57         /**
58          * Retrieve the unmerged carrier network offload map from the data source to serialize to
59          * disk.
60          */
toSerializeUnmergedCarrierNetworkOffloadMap()61         Map<Integer, Boolean> toSerializeUnmergedCarrierNetworkOffloadMap();
62 
63         /**
64          * Should be called when serialize is completed.
65          */
serializeComplete()66         void serializeComplete();
67 
68 
69         /**
70          * Set the merged carrier network offload map in the data source after deserialize them
71          * from disk.
72          */
fromMergedCarrierNetworkOffloadMapDeserialized( Map<Integer, Boolean> carrierOffloadMap)73         void fromMergedCarrierNetworkOffloadMapDeserialized(
74                 Map<Integer, Boolean> carrierOffloadMap);
75 
76         /**
77          * Set the unmerged carrier network offload map in the data source after serializing them
78          * from disk.
79          */
fromUnmergedCarrierNetworkOffloadMapDeserialized( Map<Integer, Boolean> subscriptionOffloadMap)80         void fromUnmergedCarrierNetworkOffloadMapDeserialized(
81                 Map<Integer, Boolean> subscriptionOffloadMap);
82 
83         /**
84          * Clear internal data structure in preparation for user switch or initial store read.
85          */
reset()86         void reset();
87 
88         /**
89          * Indicates whether there is new data to serialize.
90          */
hasNewDataToSerialize()91         boolean hasNewDataToSerialize();
92     }
93 
94     private final DataSource mDataSource;
95 
96     /**
97      * Set the data source fot store data.
98      */
WifiCarrierInfoStoreManagerData(@onNull DataSource dataSource)99     public WifiCarrierInfoStoreManagerData(@NonNull DataSource dataSource) {
100         mDataSource = dataSource;
101     }
102 
103     @Override
serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil)104     public void serializeData(XmlSerializer out, WifiConfigStoreEncryptionUtil encryptionUtil)
105             throws XmlPullParserException, IOException {
106         XmlUtil.writeNextValue(out, XML_TAG_MERGED_CARRIER_NETWORK_OFFLOAD_MAP,
107                 integerMapToStringMap(mDataSource.toSerializeMergedCarrierNetworkOffloadMap()));
108         XmlUtil.writeNextValue(out, XML_TAG_UNMERGED_CARRIER_NETWORK_OFFLOAD_MAP,
109                 integerMapToStringMap(mDataSource.toSerializeUnmergedCarrierNetworkOffloadMap()));
110         mDataSource.serializeComplete();
111     }
112 
113     @Override
deserializeData(XmlPullParser in, int outerTagDepth, int version, WifiConfigStoreEncryptionUtil encryptionUtil)114     public void deserializeData(XmlPullParser in, int outerTagDepth, int version,
115             WifiConfigStoreEncryptionUtil encryptionUtil)
116             throws XmlPullParserException, IOException {
117         mDataSource.reset();
118         if (in != null) {
119             parseWifiCarrierInfoStoreMaps(in, outerTagDepth);
120         }
121     }
122 
parseWifiCarrierInfoStoreMaps(XmlPullParser in, int outerTagDepth)123     private void parseWifiCarrierInfoStoreMaps(XmlPullParser in,
124             int outerTagDepth)
125             throws XmlPullParserException, IOException {
126         while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) {
127             String[] valueName = new String[1];
128             Object value = XmlUtil.readCurrentValue(in, valueName);
129             if (valueName[0] == null) {
130                 throw new XmlPullParserException("Missing value name");
131             }
132             switch (valueName[0]) {
133                 case XML_TAG_MERGED_CARRIER_NETWORK_OFFLOAD_MAP:
134                     if (value instanceof Map) {
135                         mDataSource.fromMergedCarrierNetworkOffloadMapDeserialized(
136                                 stringMapToIntegerMap((Map<String, Boolean>) value));
137                     }
138                     break;
139                 case XML_TAG_UNMERGED_CARRIER_NETWORK_OFFLOAD_MAP:
140                     if (value instanceof Map) {
141                         mDataSource.fromUnmergedCarrierNetworkOffloadMapDeserialized(
142                                 stringMapToIntegerMap((Map<String, Boolean>) value));
143                     }
144                     break;
145                 default:
146                     Log.w(TAG, "Unknown tag under "
147                             + XML_TAG_SECTION_HEADER
148                             + ": " + valueName[0]);
149                     break;
150             }
151         }
152     }
153 
integerMapToStringMap(Map<Integer, Boolean> input)154     private Map<String, Boolean> integerMapToStringMap(Map<Integer, Boolean> input) {
155         Map<String, Boolean> output = new HashMap<>();
156         if (input == null) {
157             return output;
158         }
159         for (Map.Entry<Integer, Boolean> entry : input.entrySet()) {
160             output.put(Integer.toString(entry.getKey()), entry.getValue());
161         }
162         return output;
163     }
164 
stringMapToIntegerMap(Map<String, Boolean> input)165     private Map<Integer, Boolean> stringMapToIntegerMap(Map<String, Boolean> input) {
166         Map<Integer, Boolean> output = new HashMap<>();
167         if (input == null) {
168             return output;
169         }
170         for (Map.Entry<String, Boolean> entry : input.entrySet()) {
171             try {
172                 output.put(Integer.valueOf(entry.getKey()), entry.getValue());
173             } catch (NumberFormatException e) {
174                 Log.e(TAG, "Failed to Integer convert: " + entry.getKey());
175             }
176         }
177         return output;
178     }
179 
180     @Override
resetData()181     public void resetData() {
182         mDataSource.reset();
183     }
184 
185     @Override
hasNewDataToSerialize()186     public boolean hasNewDataToSerialize() {
187         return mDataSource.hasNewDataToSerialize();
188     }
189 
190     @Override
getName()191     public String getName() {
192         return XML_TAG_SECTION_HEADER;
193     }
194 
195     @Override
getStoreFileId()196     public int getStoreFileId() {
197         // User general store.
198         return WifiConfigStore.STORE_FILE_SHARED_GENERAL;
199     }
200 }
201