diff options
author | Roshan Pius <rpius@google.com> | 2019-01-16 16:24:02 -0800 |
---|---|---|
committer | Roshan Pius <rpius@google.com> | 2019-01-18 08:02:25 -0800 |
commit | e9b9e8526f976a8942711d546547de6b8c286220 (patch) | |
tree | 568a2a0825f3ace8ea91104a21447ba6853e46de /service/java/com | |
parent | 812bc06ef69c687f0a440449273ad78d46da15e0 (diff) | |
download | android_frameworks_opt_net_wifi-e9b9e8526f976a8942711d546547de6b8c286220.tar.gz android_frameworks_opt_net_wifi-e9b9e8526f976a8942711d546547de6b8c286220.tar.bz2 android_frameworks_opt_net_wifi-e9b9e8526f976a8942711d546547de6b8c286220.zip |
WifiNetworkFactory: Persist user approvals
Persist the list of approved access points for each app.
Bug: 122658039
Test: ./frameworks/opt/net/wifi/tests/wifitests/runtests.sh
Test: act.py -c wifi_manager.config -tb dut-name -tc WifiNetworkRequestTest
Test: act.py -c wifi_manager.config -tb dut-name -tc WifiNetworkRequestTest
:test_connect_to_wpa_psk_2g_which_is_already_approved
Change-Id: Iec0450ccadf04c3168088b456bb33ed6a786ac8e
Diffstat (limited to 'service/java/com')
3 files changed, 340 insertions, 4 deletions
diff --git a/service/java/com/android/server/wifi/NetworkRequestStoreData.java b/service/java/com/android/server/wifi/NetworkRequestStoreData.java new file mode 100644 index 000000000..b74e64423 --- /dev/null +++ b/service/java/com/android/server/wifi/NetworkRequestStoreData.java @@ -0,0 +1,279 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.android.server.wifi; + +import android.net.MacAddress; +import android.util.Log; + +import com.android.server.wifi.WifiNetworkFactory.AccessPoint; +import com.android.server.wifi.util.XmlUtil; +import com.android.server.wifi.util.XmlUtil.WifiConfigurationXmlUtil; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; +import org.xmlpull.v1.XmlSerializer; + +import java.io.IOException; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Set; + +/** + * This class performs serialization and parsing of XML data block that contain the list of WiFi + * network request approvals. + */ +public class NetworkRequestStoreData implements WifiConfigStore.StoreData { + private static final String TAG = "NetworkRequestStoreData"; + + private static final String XML_TAG_SECTION_HEADER_NETWORK_REQUEST_MAP = + "NetworkRequestMap"; + private static final String XML_TAG_SECTION_HEADER_APPROVED_ACCESS_POINTS_PER_APP = + "ApprovedAccessPointsPerApp"; + private static final String XML_TAG_REQUESTOR_PACKAGE_NAME = "RequestorPackageName"; + private static final String XML_TAG_SECTION_HEADER_ACCESS_POINT = "AccessPoint"; + private static final String XML_TAG_ACCESS_POINT_SSID = WifiConfigurationXmlUtil.XML_TAG_SSID; + private static final String XML_TAG_ACCESS_POINT_BSSID = WifiConfigurationXmlUtil.XML_TAG_BSSID; + private static final String XML_TAG_ACCESS_POINT_NETWORK_TYPE = "NetworkType"; + + /** + * Interface define the data source for the network requests store data. + */ + public interface DataSource { + /** + * Retrieve the approved access points from the data source to serialize them to disk. + * + * @return Map of package name to a set of {@link AccessPoint} + */ + Map<String, Set<AccessPoint>> toSerialize(); + + /** + * Set the approved access points in the data source after serializing them from disk. + * + * @param approvedAccessPoints Map of package name to {@link AccessPoint} + */ + void fromDeserialized(Map<String, Set<AccessPoint>> approvedAccessPoints); + + /** + * Clear internal data structure in preparation for user switch or initial store read. + */ + void reset(); + + /** + * Indicates whether there is new data to serialize. + */ + boolean hasNewDataToSerialize(); + } + + private final DataSource mDataSource; + + public NetworkRequestStoreData(DataSource dataSource) { + mDataSource = dataSource; + } + + @Override + public void serializeData(XmlSerializer out) + throws XmlPullParserException, IOException { + serializeApprovedAccessPointsMap(out, mDataSource.toSerialize()); + } + + @Override + public void deserializeData(XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException { + // Ignore empty reads. + if (in == null) { + return; + } + mDataSource.fromDeserialized(parseApprovedAccessPointsMap(in, outerTagDepth)); + } + + @Override + public void resetData() { + mDataSource.reset(); + } + + @Override + public boolean hasNewDataToSerialize() { + return mDataSource.hasNewDataToSerialize(); + } + + @Override + public String getName() { + return XML_TAG_SECTION_HEADER_NETWORK_REQUEST_MAP; + } + + @Override + public @WifiConfigStore.StoreFileId int getStoreFileId() { + return WifiConfigStore.STORE_FILE_USER_GENERAL; + } + + /** + * Serialize the map of package name to approved access points to an output stream in XML + * format. + * + * @throws XmlPullParserException + * @throws IOException + */ + private void serializeApprovedAccessPointsMap( + XmlSerializer out, final Map<String, Set<AccessPoint>> approvedAccessPointsMap) + throws XmlPullParserException, IOException { + if (approvedAccessPointsMap == null) { + return; + } + for (Entry<String, Set<AccessPoint>> entry : approvedAccessPointsMap.entrySet()) { + String packageName = entry.getKey(); + XmlUtil.writeNextSectionStart(out, + XML_TAG_SECTION_HEADER_APPROVED_ACCESS_POINTS_PER_APP); + XmlUtil.writeNextValue(out, XML_TAG_REQUESTOR_PACKAGE_NAME, packageName); + serializeApprovedAccessPoints(out, entry.getValue()); + XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_APPROVED_ACCESS_POINTS_PER_APP); + } + } + + /** + * Serialize the set of approved access points to an output stream in XML format. + * + * @throws XmlPullParserException + * @throws IOException + */ + private void serializeApprovedAccessPoints( + XmlSerializer out, final Set<AccessPoint> approvedAccessPoints) + throws XmlPullParserException, IOException { + for (AccessPoint approvedAccessPoint : approvedAccessPoints) { + serializeApprovedAccessPoint(out, approvedAccessPoint); + } + } + + /** + * Serialize a {@link AccessPoint} to an output stream in XML format. + * + * @throws XmlPullParserException + * @throws IOException + */ + private void serializeApprovedAccessPoint(XmlSerializer out, + AccessPoint approvedAccessPoint) + throws XmlPullParserException, IOException { + XmlUtil.writeNextSectionStart(out, XML_TAG_SECTION_HEADER_ACCESS_POINT); + XmlUtil.writeNextValue(out, XML_TAG_ACCESS_POINT_SSID, approvedAccessPoint.ssid); + XmlUtil.writeNextValue(out, XML_TAG_ACCESS_POINT_BSSID, + approvedAccessPoint.bssid.toString()); + XmlUtil.writeNextValue(out, XML_TAG_ACCESS_POINT_NETWORK_TYPE, + approvedAccessPoint.networkType); + XmlUtil.writeNextSectionEnd(out, XML_TAG_SECTION_HEADER_ACCESS_POINT); + } + + /** + * Parse a map of package name to approved access point from an input stream in XML format. + * + * @throws XmlPullParserException + * @throws IOException + */ + private Map<String, Set<AccessPoint>> parseApprovedAccessPointsMap(XmlPullParser in, + int outerTagDepth) + throws XmlPullParserException, IOException { + Map<String, Set<AccessPoint>> approvedAccessPointsMap = new HashMap<>(); + while (XmlUtil.gotoNextSectionWithNameOrEnd( + in, XML_TAG_SECTION_HEADER_APPROVED_ACCESS_POINTS_PER_APP, outerTagDepth)) { + // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are + // fatal and should abort the entire loading process. + try { + String packageName = + (String) XmlUtil.readNextValueWithName(in, XML_TAG_REQUESTOR_PACKAGE_NAME); + Set<AccessPoint> approvedAccessPoints = + parseApprovedAccessPoints(in, outerTagDepth + 1); + approvedAccessPointsMap.put(packageName, approvedAccessPoints); + } catch (RuntimeException e) { + // Failed to parse this network, skip it. + Log.e(TAG, "Failed to parse network suggestion. Skipping...", e); + } + } + return approvedAccessPointsMap; + } + + /** + * Parse a set of approved access points from an input stream in XML format. + * + * @throws XmlPullParserException + * @throws IOException + */ + private Set<AccessPoint> parseApprovedAccessPoints(XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException { + Set<AccessPoint> approvedAccessPoints = new HashSet<>(); + while (XmlUtil.gotoNextSectionWithNameOrEnd( + in, XML_TAG_SECTION_HEADER_ACCESS_POINT, outerTagDepth)) { + // Try/catch only runtime exceptions (like illegal args), any XML/IO exceptions are + // fatal and should abort the entire loading process. + try { + AccessPoint approvedAccessPoint = + parseApprovedAccessPoint(in, outerTagDepth + 1); + approvedAccessPoints.add(approvedAccessPoint); + } catch (RuntimeException e) { + // Failed to parse this network, skip it. + Log.e(TAG, "Failed to parse network suggestion. Skipping...", e); + } + } + return approvedAccessPoints; + } + + /** + * Parse a {@link AccessPoint} from an input stream in XML format. + * + * @throws XmlPullParserException + * @throws IOException + */ + private AccessPoint parseApprovedAccessPoint(XmlPullParser in, int outerTagDepth) + throws XmlPullParserException, IOException { + String ssid = null; + MacAddress bssid = null; + int networkType = -1; + + // Loop through and parse out all the elements from the stream within this section. + while (!XmlUtil.isNextSectionEnd(in, outerTagDepth)) { + String[] valueName = new String[1]; + Object value = XmlUtil.readCurrentValue(in, valueName); + if (valueName[0] == null) { + throw new XmlPullParserException("Missing value name"); + } + switch (valueName[0]) { + case XML_TAG_ACCESS_POINT_SSID: + ssid = (String) value; + break; + case XML_TAG_ACCESS_POINT_BSSID: + bssid = MacAddress.fromString((String) value); + break; + case XML_TAG_ACCESS_POINT_NETWORK_TYPE: + networkType = (int) value; + break; + default: + throw new XmlPullParserException( + "Unknown value name found: " + valueName[0]); + } + } + if (ssid == null) { + throw new XmlPullParserException("XML parsing of ssid failed"); + } + if (bssid == null) { + throw new XmlPullParserException("XML parsing of bssid failed"); + } + if (networkType == -1) { + throw new XmlPullParserException("XML parsing of network type failed"); + } + return new AccessPoint(ssid, bssid, networkType); + } +} + diff --git a/service/java/com/android/server/wifi/WifiInjector.java b/service/java/com/android/server/wifi/WifiInjector.java index 2954608ee..92d1fce1d 100644 --- a/service/java/com/android/server/wifi/WifiInjector.java +++ b/service/java/com/android/server/wifi/WifiInjector.java @@ -593,7 +593,15 @@ public class WifiInjector { (ActivityManager) mContext.getSystemService(Context.ACTIVITY_SERVICE), (AlarmManager) mContext.getSystemService(Context.ALARM_SERVICE), mClock, this, wifiConnectivityManager, mWifiConfigManager, - mWifiPermissionsUtil); + mWifiConfigStore, mWifiPermissionsUtil); + } + + /** + * Construct an instance of {@link NetworkRequestStoreData}. + */ + public NetworkRequestStoreData makeNetworkRequestStoreData( + NetworkRequestStoreData.DataSource dataSource) { + return new NetworkRequestStoreData(dataSource); } /** diff --git a/service/java/com/android/server/wifi/WifiNetworkFactory.java b/service/java/com/android/server/wifi/WifiNetworkFactory.java index 0552d2c90..ce83a6d5e 100644 --- a/service/java/com/android/server/wifi/WifiNetworkFactory.java +++ b/service/java/com/android/server/wifi/WifiNetworkFactory.java @@ -67,7 +67,6 @@ import java.util.Map; import java.util.Objects; import java.util.Set; - /** * Network factory to handle trusted wifi network requests. */ @@ -98,6 +97,7 @@ public class WifiNetworkFactory extends NetworkFactory { private final WifiInjector mWifiInjector; private final WifiConnectivityManager mWifiConnectivityManager; private final WifiConfigManager mWifiConfigManager; + private final WifiConfigStore mWifiConfigStore; private final WifiPermissionsUtil mWifiPermissionsUtil; private final WifiScanner.ScanSettings mScanSettings; private final NetworkFactoryScanListener mScanListener; @@ -128,11 +128,16 @@ public class WifiNetworkFactory extends NetworkFactory { private boolean mConnectionTimeoutSet = false; private boolean mIsPeriodicScanPaused = false; private boolean mWifiEnabled = false; + /** + * Indicates that we have new data to serialize. + */ + private boolean mHasNewDataToSerialize = false; /** * Helper class to store an access point that the user previously approved for a specific app. + * TODO(b/123014687): Move to a common util class. */ - private static class AccessPoint { + public static class AccessPoint { public final String ssid; public final MacAddress bssid; public final @NetworkType int networkType; @@ -310,12 +315,39 @@ public class WifiNetworkFactory extends NetworkFactory { return true; }; + /** + * Module to interact with the wifi config store. + */ + private class NetworkRequestDataSource implements NetworkRequestStoreData.DataSource { + @Override + public Map<String, Set<AccessPoint>> toSerialize() { + // Clear the flag after writing to disk. + mHasNewDataToSerialize = false; + return mUserApprovedAccessPointMap; + } + + @Override + public void fromDeserialized(Map<String, Set<AccessPoint>> approvedAccessPointMap) { + mUserApprovedAccessPointMap.putAll(approvedAccessPointMap); + } + + @Override + public void reset() { + mUserApprovedAccessPointMap.clear(); + } + + @Override + public boolean hasNewDataToSerialize() { + return mHasNewDataToSerialize; + } + } public WifiNetworkFactory(Looper looper, Context context, NetworkCapabilities nc, ActivityManager activityManager, AlarmManager alarmManager, Clock clock, WifiInjector wifiInjector, WifiConnectivityManager connectivityManager, WifiConfigManager configManager, + WifiConfigStore configStore, WifiPermissionsUtil wifiPermissionsUtil) { super(looper, context, TAG, nc); mContext = context; @@ -326,6 +358,7 @@ public class WifiNetworkFactory extends NetworkFactory { mWifiInjector = wifiInjector; mWifiConnectivityManager = connectivityManager; mWifiConfigManager = configManager; + mWifiConfigStore = configStore; mWifiPermissionsUtil = wifiPermissionsUtil; // Create the scan settings. mScanSettings = new WifiScanner.ScanSettings(); @@ -338,9 +371,21 @@ public class WifiNetworkFactory extends NetworkFactory { mRegisteredCallbacks = new ExternalCallbackTracker<INetworkRequestMatchCallback>(mHandler); mSrcMessenger = new Messenger(new Handler(looper, mNetworkConnectionTriggerCallback)); + // register the data store for serializing/deserializing data. + configStore.registerStoreData( + wifiInjector.makeNetworkRequestStoreData(new NetworkRequestDataSource())); + setScoreFilter(SCORE_FILTER); } + private void saveToStore() { + // Set the flag to let WifiConfigStore that we have new data to write. + mHasNewDataToSerialize = true; + if (!mWifiConfigManager.saveToStore(true)) { + Log.w(TAG, "Failed to save to store"); + } + } + /** * Enable verbose logging. */ @@ -549,6 +594,7 @@ public class WifiNetworkFactory extends NetworkFactory { super.dump(fd, pw, args); pw.println(TAG + ": mGenericConnectionReqCount " + mGenericConnectionReqCount); pw.println(TAG + ": mActiveSpecificNetworkRequest " + mActiveSpecificNetworkRequest); + pw.println(TAG + ": mUserApprovedAccessPointMap " + mUserApprovedAccessPointMap); } /** @@ -1061,6 +1107,8 @@ public class WifiNetworkFactory extends NetworkFactory { newUserApprovedAccessPoints.add(approvedAccessPoint); } } + if (newUserApprovedAccessPoints.isEmpty()) return; + String requestorPackageName = mContext.getPackageManager().getNameForUid( mActiveSpecificNetworkRequestSpecifier.requestorUid); Set<AccessPoint> approvedAccessPoints = @@ -1069,11 +1117,12 @@ public class WifiNetworkFactory extends NetworkFactory { approvedAccessPoints = new HashSet<>(); mUserApprovedAccessPointMap.put(requestorPackageName, approvedAccessPoints); } - approvedAccessPoints.addAll(newUserApprovedAccessPoints); if (mVerboseLoggingEnabled) { Log.v(TAG, "Adding " + newUserApprovedAccessPoints + " to user approved access point for " + requestorPackageName); } + approvedAccessPoints.addAll(newUserApprovedAccessPoints); + saveToStore(); } private String getSimplePackageName(@NonNull String origPackageName) { |