hotspot2: add support for complete PerProviderSubscription/Policy subtree am: 2d7af45e93
am: 01e738a040
Change-Id: Ic35247930e4c7a99c5408593287926adcc1be8b9
This commit is contained in:
@@ -18,6 +18,7 @@ package android.net.wifi.hotspot2;
|
||||
|
||||
import android.net.wifi.hotspot2.pps.Credential;
|
||||
import android.net.wifi.hotspot2.pps.HomeSP;
|
||||
import android.net.wifi.hotspot2.pps.Policy;
|
||||
import android.os.Parcelable;
|
||||
import android.os.Parcel;
|
||||
|
||||
@@ -28,13 +29,12 @@ import android.os.Parcel;
|
||||
* For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
|
||||
* Release 2 Technical Specification.
|
||||
*
|
||||
* Currently, only HomeSP and Credential subtrees are supported.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class PasspointConfiguration implements Parcelable {
|
||||
public HomeSP homeSp = null;
|
||||
public Credential credential = null;
|
||||
public Policy policy = null;
|
||||
|
||||
/**
|
||||
* Constructor for creating PasspointConfiguration with default values.
|
||||
@@ -54,6 +54,9 @@ public final class PasspointConfiguration implements Parcelable {
|
||||
if (source.credential != null) {
|
||||
credential = new Credential(source.credential);
|
||||
}
|
||||
if (source.policy != null) {
|
||||
policy = new Policy(source.policy);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,6 +69,7 @@ public final class PasspointConfiguration implements Parcelable {
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeParcelable(homeSp, flags);
|
||||
dest.writeParcelable(credential, flags);
|
||||
dest.writeParcelable(policy, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -77,9 +81,10 @@ public final class PasspointConfiguration implements Parcelable {
|
||||
return false;
|
||||
}
|
||||
PasspointConfiguration that = (PasspointConfiguration) thatObject;
|
||||
return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp)) &&
|
||||
(credential == null ? that.credential == null :
|
||||
credential.equals(that.credential));
|
||||
return (homeSp == null ? that.homeSp == null : homeSp.equals(that.homeSp))
|
||||
&& (credential == null ? that.credential == null :
|
||||
credential.equals(that.credential))
|
||||
&& (policy == null) ? that.policy == null : policy.equals(that.policy);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -94,6 +99,9 @@ public final class PasspointConfiguration implements Parcelable {
|
||||
if (credential == null || !credential.validate()) {
|
||||
return false;
|
||||
}
|
||||
if (policy != null && !policy.validate()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -104,6 +112,7 @@ public final class PasspointConfiguration implements Parcelable {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.homeSp = in.readParcelable(null);
|
||||
config.credential = in.readParcelable(null);
|
||||
config.policy = in.readParcelable(null);
|
||||
return config;
|
||||
}
|
||||
@Override
|
||||
|
||||
@@ -19,6 +19,8 @@ package android.net.wifi.hotspot2.omadm;
|
||||
import android.net.wifi.hotspot2.PasspointConfiguration;
|
||||
import android.net.wifi.hotspot2.pps.Credential;
|
||||
import android.net.wifi.hotspot2.pps.HomeSP;
|
||||
import android.net.wifi.hotspot2.pps.Policy;
|
||||
import android.net.wifi.hotspot2.pps.UpdateParameter;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
@@ -168,12 +170,39 @@ public final class PPSMOParser {
|
||||
private static final String NODE_INNER_METHOD = "InnerMethod";
|
||||
private static final String NODE_DIGITAL_CERTIFICATE = "DigitalCertificate";
|
||||
private static final String NODE_CERTIFICATE_TYPE = "CertificateType";
|
||||
private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256FingerPrint";
|
||||
private static final String NODE_CERT_SHA256_FINGERPRINT = "CertSHA256Fingerprint";
|
||||
private static final String NODE_REALM = "Realm";
|
||||
private static final String NODE_SIM = "SIM";
|
||||
private static final String NODE_SIM_IMSI = "IMSI";
|
||||
private static final String NODE_CHECK_AAA_SERVER_CERT_STATUS = "CheckAAAServerCertStatus";
|
||||
|
||||
/**
|
||||
* Fields under Policy subtree.
|
||||
*/
|
||||
private static final String NODE_POLICY = "Policy";
|
||||
private static final String NODE_PREFERRED_ROAMING_PARTNER_LIST =
|
||||
"PreferredRoamingPartnerList";
|
||||
private static final String NODE_FQDN_MATCH = "FQDN_Match";
|
||||
private static final String NODE_PRIORITY = "Priority";
|
||||
private static final String NODE_COUNTRY = "Country";
|
||||
private static final String NODE_MIN_BACKHAUL_THRESHOLD = "MinBackhaulThreshold";
|
||||
private static final String NODE_NETWORK_TYPE = "NetworkType";
|
||||
private static final String NODE_DOWNLINK_BANDWIDTH = "DLBandwidth";
|
||||
private static final String NODE_UPLINK_BANDWIDTH = "ULBandwidth";
|
||||
private static final String NODE_POLICY_UPDATE = "PolicyUpdate";
|
||||
private static final String NODE_UPDATE_INTERVAL = "UpdateInterval";
|
||||
private static final String NODE_UPDATE_METHOD = "UpdateMethod";
|
||||
private static final String NODE_RESTRICTION = "Restriction";
|
||||
private static final String NODE_URI = "URI";
|
||||
private static final String NODE_TRUST_ROOT = "TrustRoot";
|
||||
private static final String NODE_CERT_URL = "CertURL";
|
||||
private static final String NODE_SP_EXCLUSION_LIST = "SPExclusionList";
|
||||
private static final String NODE_REQUIRED_PROTO_PORT_TUPLE = "RequiredProtoPortTuple";
|
||||
private static final String NODE_IP_PROTOCOL = "IPProtocol";
|
||||
private static final String NODE_PORT_NUMBER = "PortNumber";
|
||||
private static final String NODE_MAXIMUM_BSS_LOAD_VALUE = "MaximumBSSLoadValue";
|
||||
private static final String NODE_OTHER = "Other";
|
||||
|
||||
/**
|
||||
* URN (Unique Resource Name) for PerProviderSubscription Management Object Tree.
|
||||
*/
|
||||
@@ -551,6 +580,9 @@ public final class PPSMOParser {
|
||||
case NODE_CREDENTIAL:
|
||||
config.credential = parseCredential(child);
|
||||
break;
|
||||
case NODE_POLICY:
|
||||
config.policy = parsePolicy(child);
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node: " + child.getName());
|
||||
}
|
||||
@@ -998,6 +1030,425 @@ public final class PPSMOParser {
|
||||
return simCred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the PerProviderSubscription/Policy subtree
|
||||
* @return {@link Policy}
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static Policy parsePolicy(PPSNode node) throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for Policy");
|
||||
}
|
||||
|
||||
Policy policy = new Policy();
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
switch (child.getName()) {
|
||||
case NODE_PREFERRED_ROAMING_PARTNER_LIST:
|
||||
policy.preferredRoamingPartnerList = parsePreferredRoamingPartnerList(child);
|
||||
break;
|
||||
case NODE_MIN_BACKHAUL_THRESHOLD:
|
||||
parseMinBackhaulThreshold(child, policy);
|
||||
break;
|
||||
case NODE_POLICY_UPDATE:
|
||||
policy.policyUpdate = parseUpdateParameter(child);
|
||||
break;
|
||||
case NODE_SP_EXCLUSION_LIST:
|
||||
policy.excludedSsidList = parseSpExclusionList(child);
|
||||
break;
|
||||
case NODE_REQUIRED_PROTO_PORT_TUPLE:
|
||||
policy.requiredProtoPortMap = parseRequiredProtoPortTuple(child);
|
||||
break;
|
||||
case NODE_MAXIMUM_BSS_LOAD_VALUE:
|
||||
policy.maximumBssLoadValue = parseInteger(getPpsNodeValue(child));
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node under Policy: " + child.getName());
|
||||
}
|
||||
}
|
||||
return policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList
|
||||
* subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the
|
||||
* PerProviderSubscription/Policy/PreferredRoamingPartnerList subtree
|
||||
* @return List of {@link Policy#RoamingPartner}
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static List<Policy.RoamingPartner> parsePreferredRoamingPartnerList(PPSNode node)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for PreferredRoamingPartnerList");
|
||||
}
|
||||
List<Policy.RoamingPartner> partnerList = new ArrayList<>();
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
partnerList.add(parsePreferredRoamingPartner(child));
|
||||
}
|
||||
return partnerList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+>
|
||||
* subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the
|
||||
* PerProviderSubscription/Policy/PreferredRoamingPartnerList/<X+> subtree
|
||||
* @return {@link Policy#RoamingPartner}
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static Policy.RoamingPartner parsePreferredRoamingPartner(PPSNode node)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for PreferredRoamingPartner "
|
||||
+ "instance");
|
||||
}
|
||||
|
||||
Policy.RoamingPartner roamingPartner = new Policy.RoamingPartner();
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
switch (child.getName()) {
|
||||
case NODE_FQDN_MATCH:
|
||||
// FQDN_Match field is in the format of "[FQDN],[MatchInfo]", where [MatchInfo]
|
||||
// is either "exactMatch" for exact match of FQDN or "includeSubdomains" for
|
||||
// matching all FQDNs with the same sub-domain.
|
||||
String fqdnMatch = getPpsNodeValue(child);
|
||||
String[] fqdnMatchArray = fqdnMatch.split(",");
|
||||
if (fqdnMatchArray.length != 2) {
|
||||
throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch);
|
||||
}
|
||||
roamingPartner.fqdn = fqdnMatchArray[0];
|
||||
if (TextUtils.equals(fqdnMatchArray[1], "exactMatch")) {
|
||||
roamingPartner.fqdnExactMatch = true;
|
||||
} else if (TextUtils.equals(fqdnMatchArray[1], "includeSubdomains")) {
|
||||
roamingPartner.fqdnExactMatch = false;
|
||||
} else {
|
||||
throw new ParsingException("Invalid FQDN_Match: " + fqdnMatch);
|
||||
}
|
||||
break;
|
||||
case NODE_PRIORITY:
|
||||
roamingPartner.priority = parseInteger(getPpsNodeValue(child));
|
||||
break;
|
||||
case NODE_COUNTRY:
|
||||
roamingPartner.countries = getPpsNodeValue(child);
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node under PreferredRoamingPartnerList "
|
||||
+ "instance " + child.getName());
|
||||
}
|
||||
}
|
||||
return roamingPartner;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold subtree
|
||||
* into the given policy.
|
||||
*
|
||||
* @param node PPSNode representing the root of the
|
||||
* PerProviderSubscription/Policy/MinBackhaulThreshold subtree
|
||||
* @param policy The policy to store the MinBackhualThreshold configuration
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static void parseMinBackhaulThreshold(PPSNode node, Policy policy)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for MinBackhaulThreshold");
|
||||
}
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
parseMinBackhaulThresholdInstance(child, policy);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree
|
||||
* into the given policy.
|
||||
*
|
||||
* @param node PPSNode representing the root of the
|
||||
* PerProviderSubscription/Policy/MinBackhaulThreshold/<X+> subtree
|
||||
* @param policy The policy to store the MinBackhaulThreshold configuration
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static void parseMinBackhaulThresholdInstance(PPSNode node, Policy policy)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for MinBackhaulThreshold instance");
|
||||
}
|
||||
String networkType = null;
|
||||
long downlinkBandwidth = Long.MIN_VALUE;
|
||||
long uplinkBandwidth = Long.MIN_VALUE;
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
switch (child.getName()) {
|
||||
case NODE_NETWORK_TYPE:
|
||||
networkType = getPpsNodeValue(child);
|
||||
break;
|
||||
case NODE_DOWNLINK_BANDWIDTH:
|
||||
try {
|
||||
downlinkBandwidth = Long.parseLong(getPpsNodeValue(child));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParsingException("Invalid value for downlink bandwidth: "
|
||||
+ getPpsNodeValue(child));
|
||||
}
|
||||
break;
|
||||
case NODE_UPLINK_BANDWIDTH:
|
||||
try {
|
||||
uplinkBandwidth = Long.parseLong(getPpsNodeValue(child));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParsingException("Invalid value for downlink bandwidth: "
|
||||
+ getPpsNodeValue(child));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node under MinBackhaulThreshold instance "
|
||||
+ child.getName());
|
||||
}
|
||||
}
|
||||
if (networkType == null) {
|
||||
throw new ParsingException("Missing NetworkType field");
|
||||
}
|
||||
|
||||
if (TextUtils.equals(networkType, "home")) {
|
||||
policy.minHomeDownlinkBandwidth = downlinkBandwidth;
|
||||
policy.minHomeUplinkBandwidth = uplinkBandwidth;
|
||||
} else if (TextUtils.equals(networkType, "roaming")) {
|
||||
policy.minRoamingDownlinkBandwidth = downlinkBandwidth;
|
||||
policy.minRoamingUplinkBandwidth = uplinkBandwidth;
|
||||
} else {
|
||||
throw new ParsingException("Invalid network type: " + networkType);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse update parameters. This contained configurations from either
|
||||
* PerProviderSubscription/Policy/PolicyUpdate or PerProviderSubscription/SubscriptionUpdate
|
||||
* subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the PerProviderSubscription/Policy/PolicyUpdate
|
||||
* or PerProviderSubscription/SubscriptionUpdate subtree
|
||||
* @return {@link UpdateParameter}
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static UpdateParameter parseUpdateParameter(PPSNode node)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for Update Parameters");
|
||||
}
|
||||
|
||||
UpdateParameter updateParam = new UpdateParameter();
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
switch(child.getName()) {
|
||||
case NODE_UPDATE_INTERVAL:
|
||||
try {
|
||||
updateParam.updateIntervalInMinutes =
|
||||
Long.parseLong(getPpsNodeValue(child));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new ParsingException("Invalid value for update interval: "
|
||||
+ getPpsNodeValue(child));
|
||||
}
|
||||
break;
|
||||
case NODE_UPDATE_METHOD:
|
||||
updateParam.updateMethod = getPpsNodeValue(child);
|
||||
break;
|
||||
case NODE_RESTRICTION:
|
||||
updateParam.restriction = getPpsNodeValue(child);
|
||||
break;
|
||||
case NODE_URI:
|
||||
updateParam.serverUri = getPpsNodeValue(child);
|
||||
break;
|
||||
case NODE_USERNAME_PASSWORD:
|
||||
Pair<String, String> usernamePassword = parseUpdateUserCredential(child);
|
||||
updateParam.username = usernamePassword.first;
|
||||
updateParam.base64EncodedPassword = usernamePassword.second;
|
||||
break;
|
||||
case NODE_TRUST_ROOT:
|
||||
Pair<String, byte[]> trustRoot = parseUpdateTrustRoot(child);
|
||||
updateParam.trustRootCertUrl = trustRoot.first;
|
||||
updateParam.trustRootCertSha256Fingerprint = trustRoot.second;
|
||||
break;
|
||||
case NODE_OTHER:
|
||||
Log.d(TAG, "Ignore unsupported paramter: " + child.getName());
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node under Update Parameters: "
|
||||
+ child.getName());
|
||||
}
|
||||
}
|
||||
return updateParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse username and password parameters associated with policy or subscription update.
|
||||
* This contained configurations under either
|
||||
* PerProviderSubscription/Policy/PolicyUpdate/UsernamePassword or
|
||||
* PerProviderSubscription/SubscriptionUpdate/UsernamePassword subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the UsernamePassword subtree
|
||||
* @return Pair of username and password
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static Pair<String, String> parseUpdateUserCredential(PPSNode node)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for UsernamePassword");
|
||||
}
|
||||
|
||||
String username = null;
|
||||
String password = null;
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
switch (child.getName()) {
|
||||
case NODE_USERNAME:
|
||||
username = getPpsNodeValue(child);
|
||||
break;
|
||||
case NODE_PASSWORD:
|
||||
password = getPpsNodeValue(child);
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node under UsernamePassword: "
|
||||
+ child.getName());
|
||||
}
|
||||
}
|
||||
return Pair.create(username, password);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse the trust root parameters associated with policy or subscription update.
|
||||
* This contained configurations under either
|
||||
* PerProviderSubscription/Policy/PolicyUpdate/TrustRoot or
|
||||
* PerProviderSubscription/SubscriptionUpdate/TrustRoot subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the TrustRoot subtree
|
||||
* @return Pair of Certificate URL and fingerprint
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static Pair<String, byte[]> parseUpdateTrustRoot(PPSNode node)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for TrustRoot");
|
||||
}
|
||||
|
||||
String certUrl = null;
|
||||
byte[] certFingerprint = null;
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
switch (child.getName()) {
|
||||
case NODE_CERT_URL:
|
||||
certUrl = getPpsNodeValue(child);
|
||||
break;
|
||||
case NODE_CERT_SHA256_FINGERPRINT:
|
||||
certFingerprint = parseHexString(getPpsNodeValue(child));
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node under TrustRoot: "
|
||||
+ child.getName());
|
||||
}
|
||||
}
|
||||
return Pair.create(certUrl, certFingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy/SPExclusionList subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the
|
||||
* PerProviderSubscription/Policy/SPExclusionList subtree
|
||||
* @return Array of excluded SSIDs
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static String[] parseSpExclusionList(PPSNode node) throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for SPExclusionList");
|
||||
}
|
||||
List<String> ssidList = new ArrayList<>();
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
ssidList.add(parseSpExclusionInstance(child));
|
||||
}
|
||||
return ssidList.toArray(new String[ssidList.size()]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy/SPExclusionList/<X+> subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the
|
||||
* PerProviderSubscription/Policy/SPExclusionList/<X+> subtree
|
||||
* @return String
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static String parseSpExclusionInstance(PPSNode node) throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for SPExclusion instance");
|
||||
}
|
||||
String ssid = null;
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
switch (child.getName()) {
|
||||
case NODE_SSID:
|
||||
ssid = getPpsNodeValue(child);
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node under SPExclusion instance");
|
||||
}
|
||||
}
|
||||
return ssid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the
|
||||
* PerProviderSubscription/Policy/RequiredProtoPortTuple subtree
|
||||
* @return Map of IP Protocol to Port Number tuples
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static Map<Integer, String> parseRequiredProtoPortTuple(PPSNode node)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple");
|
||||
}
|
||||
Map<Integer, String> protoPortTupleMap = new HashMap<>();
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
Pair<Integer, String> protoPortTuple = parseProtoPortTuple(child);
|
||||
protoPortTupleMap.put(protoPortTuple.first, protoPortTuple.second);
|
||||
}
|
||||
return protoPortTupleMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse configurations under PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+>
|
||||
* subtree.
|
||||
*
|
||||
* @param node PPSNode representing the root of the
|
||||
* PerProviderSubscription/Policy/RequiredProtoPortTuple/<X+> subtree
|
||||
* @return Pair of IP Protocol to Port Number tuple
|
||||
* @throws ParsingException
|
||||
*/
|
||||
private static Pair<Integer, String> parseProtoPortTuple(PPSNode node)
|
||||
throws ParsingException {
|
||||
if (node.isLeaf()) {
|
||||
throw new ParsingException("Leaf node not expected for RequiredProtoPortTuple "
|
||||
+ "instance");
|
||||
}
|
||||
int proto = Integer.MIN_VALUE;
|
||||
String ports = null;
|
||||
for (PPSNode child : node.getChildren()) {
|
||||
switch (child.getName()) {
|
||||
case NODE_IP_PROTOCOL:
|
||||
proto = parseInteger(getPpsNodeValue(child));
|
||||
break;
|
||||
case NODE_PORT_NUMBER:
|
||||
ports = getPpsNodeValue(child);
|
||||
break;
|
||||
default:
|
||||
throw new ParsingException("Unknown node under RequiredProtoPortTuple instance"
|
||||
+ child.getName());
|
||||
}
|
||||
}
|
||||
if (proto == Integer.MIN_VALUE) {
|
||||
throw new ParsingException("Missing IPProtocol field");
|
||||
}
|
||||
if (ports == null) {
|
||||
throw new ParsingException("Missing PortNumber field");
|
||||
}
|
||||
return Pair.create(proto, ports);
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert a hex string to a byte array.
|
||||
*
|
||||
|
||||
19
wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
Normal file
19
wifi/java/android/net/wifi/hotspot2/pps/Policy.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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 android.net.wifi.hotspot2.pps;
|
||||
|
||||
parcelable Policy;
|
||||
452
wifi/java/android/net/wifi/hotspot2/pps/Policy.java
Normal file
452
wifi/java/android/net/wifi/hotspot2/pps/Policy.java
Normal file
@@ -0,0 +1,452 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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 android.net.wifi.hotspot2.pps;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Class representing Policy subtree in PerProviderSubscription (PPS)
|
||||
* Management Object (MO) tree.
|
||||
*
|
||||
* The Policy specifies additional criteria for Passpoint network selections, such as preferred
|
||||
* roaming partner, minimum backhaul bandwidth, and etc. It also provides the meta data for
|
||||
* updating the policy.
|
||||
*
|
||||
* For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
|
||||
* Release 2 Technical Specification.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class Policy implements Parcelable {
|
||||
private static final String TAG = "Policy";
|
||||
|
||||
/**
|
||||
* Default priority for preferred roaming partner.
|
||||
*/
|
||||
public static final int PREFERRED_ROAMING_PARTNER_DEFAULT_PRIORITY = 128;
|
||||
|
||||
/**
|
||||
* Maximum number of SSIDs in the exclusion list.
|
||||
*/
|
||||
private static final int MAX_EXCLUSION_SSIDS = 128;
|
||||
|
||||
/**
|
||||
* Maximum byte for SSID.
|
||||
*/
|
||||
private static final int MAX_SSID_BYTES = 32;
|
||||
|
||||
/**
|
||||
* Maximum bytes for port string in {@link #requiredProtoPortMap}.
|
||||
*/
|
||||
private static final int MAX_PORT_STRING_BYTES = 64;
|
||||
|
||||
/**
|
||||
* Integer value used for indicating null value in the Parcel.
|
||||
*/
|
||||
private static final int NULL_VALUE = -1;
|
||||
|
||||
/**
|
||||
* Minimum available downlink/uplink bandwidth (in kilobits per second) required when
|
||||
* selecting a network from home providers.
|
||||
*
|
||||
* The bandwidth is calculated as the LinkSpeed * (1 – LinkLoad/255), where LinkSpeed
|
||||
* and LinkLoad parameters are drawn from the WAN Metrics ANQP element at that hotspot.
|
||||
*
|
||||
* Using Long.MIN_VALUE to indicate unset value.
|
||||
*/
|
||||
public long minHomeDownlinkBandwidth = Long.MIN_VALUE;
|
||||
public long minHomeUplinkBandwidth = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* Minimum available downlink/uplink bandwidth (in kilobits per second) required when
|
||||
* selecting a network from roaming providers.
|
||||
*
|
||||
* The bandwidth is calculated as the LinkSpeed * (1 – LinkLoad/255), where LinkSpeed
|
||||
* and LinkLoad parameters are drawn from the WAN Metrics ANQP element at that hotspot.
|
||||
*
|
||||
* Using Long.MIN_VALUE to indicate unset value.
|
||||
*/
|
||||
public long minRoamingDownlinkBandwidth = Long.MIN_VALUE;
|
||||
public long minRoamingUplinkBandwidth = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* List of SSIDs that are not preferred by the Home SP.
|
||||
*/
|
||||
public String[] excludedSsidList = null;
|
||||
|
||||
/**
|
||||
* List of IP protocol and port number required by one or more operator supported application.
|
||||
* The port string contained one or more port numbers delimited by ",".
|
||||
*/
|
||||
public Map<Integer, String> requiredProtoPortMap = null;
|
||||
|
||||
/**
|
||||
* This specifies the maximum acceptable BSS load policy. This is used to prevent device
|
||||
* from joining an AP whose channel is overly congested with traffic.
|
||||
* Using Integer.MIN_VALUE to indicate unset value.
|
||||
*/
|
||||
public int maximumBssLoadValue = Integer.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* Policy associated with a roaming provider. This specifies a priority associated
|
||||
* with a roaming provider for given list of countries.
|
||||
*
|
||||
* Contains field under PerProviderSubscription/Policy/PreferredRoamingPartnerList.
|
||||
*/
|
||||
public static final class RoamingPartner implements Parcelable {
|
||||
/**
|
||||
* FQDN of the roaming partner.
|
||||
*/
|
||||
public String fqdn = null;
|
||||
|
||||
/**
|
||||
* Flag indicating the exact match of FQDN is required for FQDN matching.
|
||||
*
|
||||
* When this flag is set to false, sub-domain matching is used. For example, when
|
||||
* {@link #fqdn} s set to "example.com", "host.example.com" would be a match.
|
||||
*/
|
||||
public boolean fqdnExactMatch = false;
|
||||
|
||||
/**
|
||||
* Priority associated with this roaming partner policy.
|
||||
*/
|
||||
public int priority = PREFERRED_ROAMING_PARTNER_DEFAULT_PRIORITY;
|
||||
|
||||
/**
|
||||
* A string contained One or more, comma delimited (i.e., ",") ISO/IEC 3166-1 two
|
||||
* character country strings or the country-independent value, "*".
|
||||
*/
|
||||
public String countries = null;
|
||||
|
||||
public RoamingPartner() {}
|
||||
|
||||
public RoamingPartner(RoamingPartner source) {
|
||||
if (source != null) {
|
||||
fqdn = source.fqdn;
|
||||
fqdnExactMatch = source.fqdnExactMatch;
|
||||
priority = source.priority;
|
||||
countries = source.countries;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeString(fqdn);
|
||||
dest.writeInt(fqdnExactMatch ? 1 : 0);
|
||||
dest.writeInt(priority);
|
||||
dest.writeString(countries);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object thatObject) {
|
||||
if (this == thatObject) {
|
||||
return true;
|
||||
}
|
||||
if (!(thatObject instanceof RoamingPartner)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RoamingPartner that = (RoamingPartner) thatObject;
|
||||
return TextUtils.equals(fqdn, that.fqdn)
|
||||
&& fqdnExactMatch == that.fqdnExactMatch
|
||||
&& priority == that.priority
|
||||
&& TextUtils.equals(countries, that.countries);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate RoamingParnter data.
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
public boolean validate() {
|
||||
if (TextUtils.isEmpty(fqdn)) {
|
||||
Log.d(TAG, "Missing FQDN");
|
||||
return false;
|
||||
}
|
||||
if (TextUtils.isEmpty(countries)) {
|
||||
Log.d(TAG, "Missing countries");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<RoamingPartner> CREATOR =
|
||||
new Creator<RoamingPartner>() {
|
||||
@Override
|
||||
public RoamingPartner createFromParcel(Parcel in) {
|
||||
RoamingPartner roamingPartner = new RoamingPartner();
|
||||
roamingPartner.fqdn = in.readString();
|
||||
roamingPartner.fqdnExactMatch = in.readInt() != 0;
|
||||
roamingPartner.priority = in.readInt();
|
||||
roamingPartner.countries = in.readString();
|
||||
return roamingPartner;
|
||||
}
|
||||
|
||||
@Override
|
||||
public RoamingPartner[] newArray(int size) {
|
||||
return new RoamingPartner[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
public List<RoamingPartner> preferredRoamingPartnerList = null;
|
||||
|
||||
/**
|
||||
* Meta data used for policy update.
|
||||
*/
|
||||
public UpdateParameter policyUpdate = null;
|
||||
|
||||
/**
|
||||
* Constructor for creating Policy with default values.
|
||||
*/
|
||||
public Policy() {}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @param source The source to copy from
|
||||
*/
|
||||
public Policy(Policy source) {
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
minHomeDownlinkBandwidth = source.minHomeDownlinkBandwidth;
|
||||
minHomeUplinkBandwidth = source.minHomeUplinkBandwidth;
|
||||
minRoamingDownlinkBandwidth = source.minRoamingDownlinkBandwidth;
|
||||
minRoamingUplinkBandwidth = source.minRoamingUplinkBandwidth;
|
||||
maximumBssLoadValue = source.maximumBssLoadValue;
|
||||
if (source.excludedSsidList != null) {
|
||||
excludedSsidList = Arrays.copyOf(source.excludedSsidList,
|
||||
source.excludedSsidList.length);
|
||||
}
|
||||
if (source.requiredProtoPortMap != null) {
|
||||
requiredProtoPortMap = Collections.unmodifiableMap(source.requiredProtoPortMap);
|
||||
}
|
||||
if (source.preferredRoamingPartnerList != null) {
|
||||
preferredRoamingPartnerList = Collections.unmodifiableList(
|
||||
source.preferredRoamingPartnerList);
|
||||
}
|
||||
if (source.policyUpdate != null) {
|
||||
policyUpdate = new UpdateParameter(source.policyUpdate);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(minHomeDownlinkBandwidth);
|
||||
dest.writeLong(minHomeUplinkBandwidth);
|
||||
dest.writeLong(minRoamingDownlinkBandwidth);
|
||||
dest.writeLong(minRoamingUplinkBandwidth);
|
||||
dest.writeStringArray(excludedSsidList);
|
||||
writeProtoPortMap(dest, requiredProtoPortMap);
|
||||
dest.writeInt(maximumBssLoadValue);
|
||||
writeRoamingPartnerList(dest, flags, preferredRoamingPartnerList);
|
||||
dest.writeParcelable(policyUpdate, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object thatObject) {
|
||||
if (this == thatObject) {
|
||||
return true;
|
||||
}
|
||||
if (!(thatObject instanceof Policy)) {
|
||||
return false;
|
||||
}
|
||||
Policy that = (Policy) thatObject;
|
||||
|
||||
return minHomeDownlinkBandwidth == that.minHomeDownlinkBandwidth
|
||||
&& minHomeUplinkBandwidth == that.minHomeUplinkBandwidth
|
||||
&& minRoamingDownlinkBandwidth == that.minRoamingDownlinkBandwidth
|
||||
&& minRoamingUplinkBandwidth == that.minRoamingUplinkBandwidth
|
||||
&& Arrays.equals(excludedSsidList, that.excludedSsidList)
|
||||
&& (requiredProtoPortMap == null) ? that.requiredProtoPortMap == null
|
||||
: requiredProtoPortMap.equals(that.requiredProtoPortMap)
|
||||
&& maximumBssLoadValue == that.maximumBssLoadValue
|
||||
&& (preferredRoamingPartnerList == null) ? that.preferredRoamingPartnerList == null
|
||||
: preferredRoamingPartnerList.equals(that.preferredRoamingPartnerList)
|
||||
&& (policyUpdate == null) ? that.policyUpdate == null
|
||||
: policyUpdate.equals(that.policyUpdate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate Policy data.
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
public boolean validate() {
|
||||
if (policyUpdate == null) {
|
||||
Log.d(TAG, "PolicyUpdate not specified");
|
||||
return false;
|
||||
}
|
||||
if (!policyUpdate.validate()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Validate SSID exclusion list.
|
||||
if (excludedSsidList != null) {
|
||||
if (excludedSsidList.length > MAX_EXCLUSION_SSIDS) {
|
||||
Log.d(TAG, "SSID exclusion list size exceeded the max: "
|
||||
+ excludedSsidList.length);
|
||||
return false;
|
||||
}
|
||||
for (String ssid : excludedSsidList) {
|
||||
if (ssid.getBytes(StandardCharsets.UTF_8).length > MAX_SSID_BYTES) {
|
||||
Log.d(TAG, "Invalid SSID: " + ssid);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Validate required protocol to port map.
|
||||
if (requiredProtoPortMap != null) {
|
||||
for (Map.Entry<Integer, String> entry : requiredProtoPortMap.entrySet()) {
|
||||
String portNumber = entry.getValue();
|
||||
if (portNumber.getBytes(StandardCharsets.UTF_8).length > MAX_PORT_STRING_BYTES) {
|
||||
Log.d(TAG, "PortNumber string bytes exceeded the max: " + portNumber);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Validate preferred roaming partner list.
|
||||
if (preferredRoamingPartnerList != null) {
|
||||
for (RoamingPartner partner : preferredRoamingPartnerList) {
|
||||
if (!partner.validate()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<Policy> CREATOR =
|
||||
new Creator<Policy>() {
|
||||
@Override
|
||||
public Policy createFromParcel(Parcel in) {
|
||||
Policy policy = new Policy();
|
||||
policy.minHomeDownlinkBandwidth = in.readLong();
|
||||
policy.minHomeUplinkBandwidth = in.readLong();
|
||||
policy.minRoamingDownlinkBandwidth = in.readLong();
|
||||
policy.minRoamingUplinkBandwidth = in.readLong();
|
||||
policy.excludedSsidList = in.createStringArray();
|
||||
policy.requiredProtoPortMap = readProtoPortMap(in);
|
||||
policy.maximumBssLoadValue = in.readInt();
|
||||
policy.preferredRoamingPartnerList = readRoamingPartnerList(in);
|
||||
policy.policyUpdate = in.readParcelable(null);
|
||||
return policy;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Policy[] newArray(int size) {
|
||||
return new Policy[size];
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for reading IP Protocol to Port Number map from a Parcel.
|
||||
*
|
||||
* @param in The Parcel to read from
|
||||
* @return Map of IP protocol to port number
|
||||
*/
|
||||
private Map<Integer, String> readProtoPortMap(Parcel in) {
|
||||
int size = in.readInt();
|
||||
if (size == NULL_VALUE) {
|
||||
return null;
|
||||
}
|
||||
Map<Integer, String> protoPortMap = new HashMap<>(size);
|
||||
for (int i = 0; i < size; i++) {
|
||||
int key = in.readInt();
|
||||
String value = in.readString();
|
||||
protoPortMap.put(key, value);
|
||||
}
|
||||
return protoPortMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for reading roaming partner list from a Parcel.
|
||||
*
|
||||
* @param in The Parcel to read from
|
||||
* @return List of roaming partners
|
||||
*/
|
||||
private List<RoamingPartner> readRoamingPartnerList(Parcel in) {
|
||||
int size = in.readInt();
|
||||
if (size == NULL_VALUE) {
|
||||
return null;
|
||||
}
|
||||
List<RoamingPartner> partnerList = new ArrayList<>();
|
||||
for (int i = 0; i < size; i++) {
|
||||
partnerList.add(in.readParcelable(null));
|
||||
}
|
||||
return partnerList;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Helper function for writing IP Protocol to Port Number map to a Parcel.
|
||||
*
|
||||
* @param dest The Parcel to write to
|
||||
* @param protoPortMap The map to write
|
||||
*/
|
||||
private static void writeProtoPortMap(Parcel dest, Map<Integer, String> protoPortMap) {
|
||||
if (protoPortMap == null) {
|
||||
dest.writeInt(NULL_VALUE);
|
||||
return;
|
||||
}
|
||||
dest.writeInt(protoPortMap.size());
|
||||
for (Map.Entry<Integer, String> entry : protoPortMap.entrySet()) {
|
||||
dest.writeInt(entry.getKey());
|
||||
dest.writeString(entry.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for writing roaming partner list to a Parcel.
|
||||
*
|
||||
* @param dest The Parcel to write to
|
||||
* @param flags The flag about how the object should be written
|
||||
* @param partnerList The partner list to write
|
||||
*/
|
||||
private static void writeRoamingPartnerList(Parcel dest, int flags,
|
||||
List<RoamingPartner> partnerList) {
|
||||
if (partnerList == null) {
|
||||
dest.writeInt(NULL_VALUE);
|
||||
return;
|
||||
}
|
||||
dest.writeInt(partnerList.size());
|
||||
for (RoamingPartner partner : partnerList) {
|
||||
dest.writeParcelable(partner, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
19
wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
Normal file
19
wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.aidl
Normal file
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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 android.net.wifi.hotspot2.pps;
|
||||
|
||||
parcelable UpdateParameter;
|
||||
303
wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
Normal file
303
wifi/java/android/net/wifi/hotspot2/pps/UpdateParameter.java
Normal file
@@ -0,0 +1,303 @@
|
||||
/**
|
||||
* Copyright (c) 2017, 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 android.net.wifi.hotspot2.pps;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Base64;
|
||||
import android.util.Log;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* Class representing configuration parameters for subscription or policy update in
|
||||
* PerProviderSubscription (PPS) Management Object (MO) tree. This is used by both
|
||||
* PerProviderSubscription/Policy/PolicyUpdate and PerProviderSubscription/SubscriptionUpdate
|
||||
* subtree.
|
||||
*
|
||||
* For more info, refer to Hotspot 2.0 PPS MO defined in section 9.1 of the Hotspot 2.0
|
||||
* Release 2 Technical Specification.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class UpdateParameter implements Parcelable {
|
||||
private static final String TAG = "UpdateParameter";
|
||||
|
||||
/**
|
||||
* Value indicating policy update is not applicable. Thus, never check with policy server
|
||||
* for updates.
|
||||
*/
|
||||
public static final long UPDATE_CHECK_INTERVAL_NEVER = 0xFFFFFFFFL;
|
||||
|
||||
/**
|
||||
* Valid string for UpdateMethod.
|
||||
*/
|
||||
public static final String UPDATE_METHOD_OMADM = "OMA-DM-ClientInitiated";
|
||||
public static final String UPDATE_METHOD_SSP = "SSP-ClientInitiated";
|
||||
|
||||
/**
|
||||
* Valid string for Restriction.
|
||||
*/
|
||||
public static final String UPDATE_RESTRICTION_HOMESP = "HomeSP";
|
||||
public static final String UPDATE_RESTRICTION_ROAMING_PARTNER = "RoamingPartner";
|
||||
public static final String UPDATE_RESTRICTION_UNRESTRICTED = "Unrestricted";
|
||||
|
||||
/**
|
||||
* Maximum bytes for URI string.
|
||||
*/
|
||||
private static final int MAX_URI_BYTES = 1023;
|
||||
|
||||
/**
|
||||
* Maximum bytes for URI string.
|
||||
*/
|
||||
private static final int MAX_URL_BYTES = 1023;
|
||||
|
||||
/**
|
||||
* Maximum bytes for username.
|
||||
*/
|
||||
private static final int MAX_USERNAME_BYTES = 63;
|
||||
|
||||
/**
|
||||
* Maximum bytes for password.
|
||||
*/
|
||||
private static final int MAX_PASSWORD_BYTES = 255;
|
||||
|
||||
/**
|
||||
* Number of bytes for certificate SHA-256 fingerprint byte array.
|
||||
*/
|
||||
private static final int CERTIFICATE_SHA256_BYTES = 32;
|
||||
|
||||
/**
|
||||
* This specifies how often the mobile device shall check with policy server for updates.
|
||||
*
|
||||
* Using Long.MIN_VALUE to indicate unset value.
|
||||
*/
|
||||
public long updateIntervalInMinutes = Long.MIN_VALUE;
|
||||
|
||||
/**
|
||||
* The method used to update the policy. Permitted values are "OMA-DM-ClientInitiated"
|
||||
* and "SPP-ClientInitiated".
|
||||
*/
|
||||
public String updateMethod = null;
|
||||
|
||||
/**
|
||||
* This specifies the hotspots at which the subscription update is permitted. Permitted
|
||||
* values are "HomeSP", "RoamingPartner", or "Unrestricted";
|
||||
*/
|
||||
public String restriction = null;
|
||||
|
||||
/**
|
||||
* The URI of the update server.
|
||||
*/
|
||||
public String serverUri = null;
|
||||
|
||||
/**
|
||||
* Username used to authenticate with the policy server.
|
||||
*/
|
||||
public String username = null;
|
||||
|
||||
/**
|
||||
* Base64 encoded password used to authenticate with the policy server.
|
||||
*/
|
||||
public String base64EncodedPassword = null;
|
||||
|
||||
/**
|
||||
* HTTPS URL for retrieving certificate for trust root. The trust root is used to validate
|
||||
* policy server's identity.
|
||||
*/
|
||||
public String trustRootCertUrl = null;
|
||||
|
||||
/**
|
||||
* SHA-256 fingerprint of the certificate located at {@link #trustRootCertUrl}
|
||||
*/
|
||||
public byte[] trustRootCertSha256Fingerprint = null;
|
||||
|
||||
/**
|
||||
* Constructor for creating Policy with default values.
|
||||
*/
|
||||
public UpdateParameter() {}
|
||||
|
||||
/**
|
||||
* Copy constructor.
|
||||
*
|
||||
* @param source The source to copy from
|
||||
*/
|
||||
public UpdateParameter(UpdateParameter source) {
|
||||
if (source == null) {
|
||||
return;
|
||||
}
|
||||
updateIntervalInMinutes = source.updateIntervalInMinutes;
|
||||
updateMethod = source.updateMethod;
|
||||
restriction = source.restriction;
|
||||
serverUri = source.serverUri;
|
||||
username = source.username;
|
||||
base64EncodedPassword = source.base64EncodedPassword;
|
||||
trustRootCertUrl = source.trustRootCertUrl;
|
||||
if (source.trustRootCertSha256Fingerprint != null) {
|
||||
trustRootCertSha256Fingerprint = Arrays.copyOf(source.trustRootCertSha256Fingerprint,
|
||||
source.trustRootCertSha256Fingerprint.length);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeLong(updateIntervalInMinutes);
|
||||
dest.writeString(updateMethod);
|
||||
dest.writeString(restriction);
|
||||
dest.writeString(serverUri);
|
||||
dest.writeString(username);
|
||||
dest.writeString(base64EncodedPassword);
|
||||
dest.writeString(trustRootCertUrl);
|
||||
dest.writeByteArray(trustRootCertSha256Fingerprint);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object thatObject) {
|
||||
if (this == thatObject) {
|
||||
return true;
|
||||
}
|
||||
if (!(thatObject instanceof UpdateParameter)) {
|
||||
return false;
|
||||
}
|
||||
UpdateParameter that = (UpdateParameter) thatObject;
|
||||
|
||||
return updateIntervalInMinutes == that.updateIntervalInMinutes
|
||||
&& TextUtils.equals(updateMethod, that.updateMethod)
|
||||
&& TextUtils.equals(restriction, that.restriction)
|
||||
&& TextUtils.equals(serverUri, that.serverUri)
|
||||
&& TextUtils.equals(username, that.username)
|
||||
&& TextUtils.equals(base64EncodedPassword, that.base64EncodedPassword)
|
||||
&& TextUtils.equals(trustRootCertUrl, that.trustRootCertUrl)
|
||||
&& Arrays.equals(trustRootCertSha256Fingerprint,
|
||||
that.trustRootCertSha256Fingerprint);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate UpdateParameter data.
|
||||
*
|
||||
* @return true on success
|
||||
*/
|
||||
public boolean validate() {
|
||||
if (updateIntervalInMinutes == Long.MIN_VALUE) {
|
||||
Log.d(TAG, "Update interval not specified");
|
||||
return false;
|
||||
}
|
||||
// Update not applicable.
|
||||
if (updateIntervalInMinutes == UPDATE_CHECK_INTERVAL_NEVER) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!TextUtils.equals(updateMethod, UPDATE_METHOD_OMADM)
|
||||
&& !TextUtils.equals(updateMethod, UPDATE_METHOD_SSP)) {
|
||||
Log.d(TAG, "Unknown update method: " + updateMethod);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!TextUtils.equals(restriction, UPDATE_RESTRICTION_HOMESP)
|
||||
&& !TextUtils.equals(restriction, UPDATE_RESTRICTION_ROAMING_PARTNER)
|
||||
&& !TextUtils.equals(restriction, UPDATE_RESTRICTION_UNRESTRICTED)) {
|
||||
Log.d(TAG, "Unknown restriction: " + restriction);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(serverUri)) {
|
||||
Log.d(TAG, "Missing update server URI");
|
||||
return false;
|
||||
}
|
||||
if (serverUri.getBytes(StandardCharsets.UTF_8).length > MAX_URI_BYTES) {
|
||||
Log.d(TAG, "URI bytes exceeded the max: "
|
||||
+ serverUri.getBytes(StandardCharsets.UTF_8).length);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(username)) {
|
||||
Log.d(TAG, "Missing username");
|
||||
return false;
|
||||
}
|
||||
if (username.getBytes(StandardCharsets.UTF_8).length > MAX_USERNAME_BYTES) {
|
||||
Log.d(TAG, "Username bytes exceeded the max: "
|
||||
+ username.getBytes(StandardCharsets.UTF_8).length);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(base64EncodedPassword)) {
|
||||
Log.d(TAG, "Missing username");
|
||||
return false;
|
||||
}
|
||||
if (base64EncodedPassword.getBytes(StandardCharsets.UTF_8).length > MAX_PASSWORD_BYTES) {
|
||||
Log.d(TAG, "Password bytes exceeded the max: "
|
||||
+ base64EncodedPassword.getBytes(StandardCharsets.UTF_8).length);
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
Base64.decode(base64EncodedPassword, Base64.DEFAULT);
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.d(TAG, "Invalid encoding for password: " + base64EncodedPassword);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (TextUtils.isEmpty(trustRootCertUrl)) {
|
||||
Log.d(TAG, "Missing trust root certificate URL");
|
||||
return false;
|
||||
}
|
||||
if (trustRootCertUrl.getBytes(StandardCharsets.UTF_8).length > MAX_URL_BYTES) {
|
||||
Log.d(TAG, "Trust root cert URL bytes exceeded the max: "
|
||||
+ trustRootCertUrl.getBytes(StandardCharsets.UTF_8).length);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (trustRootCertSha256Fingerprint == null) {
|
||||
Log.d(TAG, "Missing trust root certificate SHA-256 fingerprint");
|
||||
return false;
|
||||
}
|
||||
if (trustRootCertSha256Fingerprint.length != CERTIFICATE_SHA256_BYTES) {
|
||||
Log.d(TAG, "Incorrect size of trust root certificate SHA-256 fingerprint: "
|
||||
+ trustRootCertSha256Fingerprint.length);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static final Creator<UpdateParameter> CREATOR =
|
||||
new Creator<UpdateParameter>() {
|
||||
@Override
|
||||
public UpdateParameter createFromParcel(Parcel in) {
|
||||
UpdateParameter updateParam = new UpdateParameter();
|
||||
updateParam.updateIntervalInMinutes = in.readLong();
|
||||
updateParam.updateMethod = in.readString();
|
||||
updateParam.restriction = in.readString();
|
||||
updateParam.serverUri = in.readString();
|
||||
updateParam.username = in.readString();
|
||||
updateParam.base64EncodedPassword = in.readString();
|
||||
updateParam.trustRootCertUrl = in.readString();
|
||||
updateParam.trustRootCertSha256Fingerprint = in.createByteArray();
|
||||
return updateParam;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UpdateParameter[] newArray(int size) {
|
||||
return new UpdateParameter[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -42,7 +42,7 @@ V1UrQ2lBZ0lDQWdJQ0FnSUNBOFRtOWtaVDRLSUNBZ0lDQWdJQ0FnSUNBZ1BFNXZaR1ZPWVcxbApQ
|
||||
a05sY25ScFptbGpZWFJsVkhsd1pUd3ZUbTlrWlU1aGJXVStDaUFnSUNBZ0lDQWdJQ0FnSUR4V1lX
|
||||
eDFaVDU0TlRBNWRqTThMMVpoCmJIVmxQZ29nSUNBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lD
|
||||
QWdJQ0FnUEU1dlpHVStDaUFnSUNBZ0lDQWdJQ0FnSUR4T2IyUmwKVG1GdFpUNURaWEowVTBoQk1q
|
||||
VTJSbWx1WjJWeVVISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
|
||||
VTJSbWx1WjJWeWNISnBiblE4TDA1dlpHVk9ZVzFsUGdvZ0lDQWdJQ0FnSUNBZ0lDQThWbUZzZFdV
|
||||
KwpNV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpGbU1XWXhaakZtTVdZeFpqRm1NV1l4WmpG
|
||||
bU1XWXhaakZtTVdZeFpqRm1NV1l4ClpqRm1NV1l4Wmp3dlZtRnNkV1UrQ2lBZ0lDQWdJQ0FnSUNB
|
||||
OEwwNXZaR1UrQ2lBZ0lDQWdJQ0FnUEM5T2IyUmxQZ29nSUNBZ0lDQWcKSUR4T2IyUmxQZ29nSUNB
|
||||
|
||||
@@ -35,7 +35,7 @@ ICAgPC9Ob2RlPgogICAgICAgIDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPkRpZ2l0YWxDZXJ0
|
||||
aWZpY2F0ZTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9kZT4KICAgICAgICAgICAgPE5vZGVOYW1l
|
||||
PkNlcnRpZmljYXRlVHlwZTwvTm9kZU5hbWU+CiAgICAgICAgICAgIDxWYWx1ZT54NTA5djM8L1Zh
|
||||
bHVlPgogICAgICAgICAgPC9Ob2RlPgogICAgICAgICAgPE5vZGU+CiAgICAgICAgICAgIDxOb2Rl
|
||||
TmFtZT5DZXJ0U0hBMjU2RmluZ2VyUHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
|
||||
TmFtZT5DZXJ0U0hBMjU2RmluZ2VycHJpbnQ8L05vZGVOYW1lPgogICAgICAgICAgICA8VmFsdWU+
|
||||
MWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYxZjFmMWYx
|
||||
ZjFmMWYxZjwvVmFsdWU+CiAgICAgICAgICA8L05vZGU+CiAgICAgICAgPC9Ob2RlPgogICAgICAg
|
||||
IDxOb2RlPgogICAgICAgICAgPE5vZGVOYW1lPlNJTTwvTm9kZU5hbWU+CiAgICAgICAgICA8Tm9k
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
<Value>x509v3</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>CertSHA256FingerPrint</NodeName>
|
||||
<NodeName>CertSHA256Fingerprint</NodeName>
|
||||
<Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
@@ -159,6 +159,144 @@
|
||||
</Node>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>Policy</NodeName>
|
||||
<Node>
|
||||
<NodeName>PreferredRoamingPartnerList</NodeName>
|
||||
<Node>
|
||||
<NodeName>p001</NodeName>
|
||||
<Node>
|
||||
<NodeName>FQDN_Match</NodeName>
|
||||
<Value>test1.fqdn.com,exactMatch</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>Priority</NodeName>
|
||||
<Value>127</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>Country</NodeName>
|
||||
<Value>us,fr</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>p002</NodeName>
|
||||
<Node>
|
||||
<NodeName>FQDN_Match</NodeName>
|
||||
<Value>test2.fqdn.com,includeSubdomains</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>Priority</NodeName>
|
||||
<Value>200</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>Country</NodeName>
|
||||
<Value>*</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>MinBackhaulThreshold</NodeName>
|
||||
<Node>
|
||||
<NodeName>m001</NodeName>
|
||||
<Node>
|
||||
<NodeName>NetworkType</NodeName>
|
||||
<Value>home</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>DLBandwidth</NodeName>
|
||||
<Value>23412</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>ULBandwidth</NodeName>
|
||||
<Value>9823</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>m002</NodeName>
|
||||
<Node>
|
||||
<NodeName>NetworkType</NodeName>
|
||||
<Value>roaming</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>DLBandwidth</NodeName>
|
||||
<Value>9271</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>ULBandwidth</NodeName>
|
||||
<Value>2315</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>PolicyUpdate</NodeName>
|
||||
<Node>
|
||||
<NodeName>UpdateInterval</NodeName>
|
||||
<Value>120</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>UpdateMethod</NodeName>
|
||||
<Value>OMA-DM-ClientInitiated</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>Restriction</NodeName>
|
||||
<Value>HomeSP</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>URI</NodeName>
|
||||
<Value>policy.update.com</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>UsernamePassword</NodeName>
|
||||
<Node>
|
||||
<NodeName>Username</NodeName>
|
||||
<Value>updateUser</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>Password</NodeName>
|
||||
<Value>updatePass</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>TrustRoot</NodeName>
|
||||
<Node>
|
||||
<NodeName>CertURL</NodeName>
|
||||
<Value>update.cert.com</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>CertSHA256Fingerprint</NodeName>
|
||||
<Value>1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f1f</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>SPExclusionList</NodeName>
|
||||
<Node>
|
||||
<NodeName>s001</NodeName>
|
||||
<Node>
|
||||
<NodeName>SSID</NodeName>
|
||||
<Value>excludeSSID</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>RequiredProtoPortTuple</NodeName>
|
||||
<Node>
|
||||
<NodeName>r001</NodeName>
|
||||
<Node>
|
||||
<NodeName>IPProtocol</NodeName>
|
||||
<Value>12</Value>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>PortNumber</NodeName>
|
||||
<Value>34,92,234</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
</Node>
|
||||
<Node>
|
||||
<NodeName>MaximumBSSLoadValue</NodeName>
|
||||
<Value>23</Value>
|
||||
</Node>
|
||||
</Node>
|
||||
</Node>
|
||||
</Node>
|
||||
</MgmtTree>
|
||||
|
||||
@@ -22,11 +22,17 @@ import static org.junit.Assert.assertTrue;
|
||||
import android.net.wifi.EAPConstants;
|
||||
import android.net.wifi.hotspot2.pps.Credential;
|
||||
import android.net.wifi.hotspot2.pps.HomeSP;
|
||||
import android.net.wifi.hotspot2.pps.Policy;
|
||||
import android.net.wifi.hotspot2.pps.UpdateParameter;
|
||||
import android.os.Parcel;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link android.net.wifi.hotspot2.PasspointConfiguration}.
|
||||
*/
|
||||
@@ -65,6 +71,64 @@ public class PasspointConfigurationTest {
|
||||
return cred;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for creating a {@link Policy} for testing.
|
||||
*
|
||||
* @return {@link Policy}
|
||||
*/
|
||||
private static Policy createPolicy() {
|
||||
Policy policy = new Policy();
|
||||
policy.minHomeDownlinkBandwidth = 123;
|
||||
policy.minHomeUplinkBandwidth = 345;
|
||||
policy.minRoamingDownlinkBandwidth = 567;
|
||||
policy.minRoamingUplinkBandwidth = 789;
|
||||
policy.maximumBssLoadValue = 12;
|
||||
policy.excludedSsidList = new String[] {"ssid1", "ssid2"};
|
||||
policy.requiredProtoPortMap = new HashMap<>();
|
||||
policy.requiredProtoPortMap.put(12, "23,342,123");
|
||||
policy.requiredProtoPortMap.put(23, "789,372,1235");
|
||||
|
||||
policy.preferredRoamingPartnerList = new ArrayList<>();
|
||||
Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
|
||||
partner1.fqdn = "partner1.com";
|
||||
partner1.fqdnExactMatch = true;
|
||||
partner1.priority = 12;
|
||||
partner1.countries = "us,jp";
|
||||
Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
|
||||
partner2.fqdn = "partner2.com";
|
||||
partner2.fqdnExactMatch = false;
|
||||
partner2.priority = 42;
|
||||
partner2.countries = "ca,fr";
|
||||
policy.preferredRoamingPartnerList.add(partner1);
|
||||
policy.preferredRoamingPartnerList.add(partner2);
|
||||
|
||||
policy.policyUpdate = new UpdateParameter();
|
||||
policy.policyUpdate.updateIntervalInMinutes = 1712;
|
||||
policy.policyUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_OMADM;
|
||||
policy.policyUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_HOMESP;
|
||||
policy.policyUpdate.serverUri = "policy.update.com";
|
||||
policy.policyUpdate.username = "username";
|
||||
policy.policyUpdate.base64EncodedPassword =
|
||||
Base64.encodeToString("password".getBytes(), Base64.DEFAULT);
|
||||
policy.policyUpdate.trustRootCertUrl = "trust.cert.com";
|
||||
policy.policyUpdate.trustRootCertSha256Fingerprint = new byte[32];
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for creating a {@link PasspointConfiguration} for testing.
|
||||
*
|
||||
* @return {@link PasspointConfiguration}
|
||||
*/
|
||||
private static PasspointConfiguration createConfig() {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.homeSp = createHomeSp();
|
||||
config.credential = createCredential();
|
||||
config.policy = createPolicy();
|
||||
return config;
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel write and read consistency for the given configuration.
|
||||
*
|
||||
@@ -92,39 +156,48 @@ public class PasspointConfigurationTest {
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a configuration that contained both HomeSP and Credential.
|
||||
* Verify parcel read/write for a configuration that contained the full configuration.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithHomeSPAndCredential() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.homeSp = createHomeSp();
|
||||
config.credential = createCredential();
|
||||
public void verifyParcelWithFullConfiguration() throws Exception {
|
||||
verifyParcel(createConfig());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a configuration that doesn't contain HomeSP.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithoutHomeSP() throws Exception {
|
||||
PasspointConfiguration config = createConfig();
|
||||
config.homeSp = null;
|
||||
verifyParcel(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a configuration that contained only HomeSP.
|
||||
* Verify parcel read/write for a configuration that doesn't contain Credential.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithHomeSPOnly() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.homeSp = createHomeSp();
|
||||
public void verifyParcelWithoutCredential() throws Exception {
|
||||
PasspointConfiguration config = createConfig();
|
||||
config.credential = null;
|
||||
verifyParcel(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a configuration that contained only Credential.
|
||||
* Verify parcel read/write for a configuration that doesn't contain Policy.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithCredentialOnly() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.credential = createCredential();
|
||||
public void verifyParcelWithoutPolicy() throws Exception {
|
||||
PasspointConfiguration config = createConfig();
|
||||
config.policy = null;
|
||||
verifyParcel(config);
|
||||
}
|
||||
|
||||
@@ -139,6 +212,17 @@ public class PasspointConfigurationTest {
|
||||
assertFalse(config.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a configuration contained all fields is valid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateFullConfig() throws Exception {
|
||||
PasspointConfiguration config = createConfig();
|
||||
assertTrue(config.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a configuration without Credential is invalid.
|
||||
*
|
||||
@@ -146,33 +230,33 @@ public class PasspointConfigurationTest {
|
||||
*/
|
||||
@Test
|
||||
public void validateConfigWithoutCredential() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.homeSp = createHomeSp();
|
||||
PasspointConfiguration config = createConfig();
|
||||
config.credential = null;
|
||||
assertFalse(config.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a a configuration without HomeSP is invalid.
|
||||
* Verify that a configuration without HomeSP is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateConfigWithoutHomeSp() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.credential = createCredential();
|
||||
PasspointConfiguration config = createConfig();
|
||||
config.homeSp = null;
|
||||
assertFalse(config.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify a valid configuration.
|
||||
* Verify that a configuration without Policy is valid, since Policy configurations
|
||||
* are optional (applied for Hotspot 2.0 Release only).
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateValidConfig() throws Exception {
|
||||
PasspointConfiguration config = new PasspointConfiguration();
|
||||
config.homeSp = createHomeSp();
|
||||
config.credential = createCredential();
|
||||
public void validateConfigWithoutPolicy() throws Exception {
|
||||
PasspointConfiguration config = createConfig();
|
||||
config.policy = null;
|
||||
assertTrue(config.validate());
|
||||
}
|
||||
|
||||
@@ -195,9 +279,7 @@ public class PasspointConfigurationTest {
|
||||
*/
|
||||
@Test
|
||||
public void validateCopyConstructorWithValidSource() throws Exception {
|
||||
PasspointConfiguration sourceConfig = new PasspointConfiguration();
|
||||
sourceConfig.homeSp = createHomeSp();
|
||||
sourceConfig.credential = createCredential();
|
||||
PasspointConfiguration sourceConfig = createConfig();
|
||||
PasspointConfiguration copyConfig = new PasspointConfiguration(sourceConfig);
|
||||
assertTrue(copyConfig.equals(sourceConfig));
|
||||
}
|
||||
|
||||
@@ -23,7 +23,10 @@ import android.net.wifi.hotspot2.omadm.PPSMOParser;
|
||||
import android.net.wifi.hotspot2.PasspointConfiguration;
|
||||
import android.net.wifi.hotspot2.pps.Credential;
|
||||
import android.net.wifi.hotspot2.pps.HomeSP;
|
||||
import android.net.wifi.hotspot2.pps.Policy;
|
||||
import android.net.wifi.hotspot2.pps.UpdateParameter;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
@@ -33,6 +36,7 @@ import java.io.InputStream;
|
||||
import java.io.InputStreamReader;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
|
||||
@@ -118,6 +122,41 @@ public class PPSMOParserTest {
|
||||
config.credential.simCredential = new Credential.SimCredential();
|
||||
config.credential.simCredential.imsi = "imsi";
|
||||
config.credential.simCredential.eapType = 24;
|
||||
|
||||
// Policy configuration.
|
||||
config.policy = new Policy();
|
||||
config.policy.preferredRoamingPartnerList = new ArrayList<>();
|
||||
Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
|
||||
partner1.fqdn = "test1.fqdn.com";
|
||||
partner1.fqdnExactMatch = true;
|
||||
partner1.priority = 127;
|
||||
partner1.countries = "us,fr";
|
||||
Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
|
||||
partner2.fqdn = "test2.fqdn.com";
|
||||
partner2.fqdnExactMatch = false;
|
||||
partner2.priority = 200;
|
||||
partner2.countries = "*";
|
||||
config.policy.preferredRoamingPartnerList.add(partner1);
|
||||
config.policy.preferredRoamingPartnerList.add(partner2);
|
||||
config.policy.minHomeDownlinkBandwidth = 23412;
|
||||
config.policy.minHomeUplinkBandwidth = 9823;
|
||||
config.policy.minRoamingDownlinkBandwidth = 9271;
|
||||
config.policy.minRoamingUplinkBandwidth = 2315;
|
||||
config.policy.excludedSsidList = new String[] {"excludeSSID"};
|
||||
config.policy.requiredProtoPortMap = new HashMap<>();
|
||||
config.policy.requiredProtoPortMap.put(12, "34,92,234");
|
||||
config.policy.maximumBssLoadValue = 23;
|
||||
config.policy.policyUpdate = new UpdateParameter();
|
||||
config.policy.policyUpdate.updateIntervalInMinutes = 120;
|
||||
config.policy.policyUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_OMADM;
|
||||
config.policy.policyUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_HOMESP;
|
||||
config.policy.policyUpdate.serverUri = "policy.update.com";
|
||||
config.policy.policyUpdate.username = "updateUser";
|
||||
config.policy.policyUpdate.base64EncodedPassword = "updatePass";
|
||||
config.policy.policyUpdate.trustRootCertUrl = "update.cert.com";
|
||||
config.policy.policyUpdate.trustRootCertSha256Fingerprint = new byte[32];
|
||||
Arrays.fill(config.policy.policyUpdate.trustRootCertSha256Fingerprint, (byte) 0x1f);
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
|
||||
304
wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
Normal file
304
wifi/tests/src/android/net/wifi/hotspot2/pps/PolicyTest.java
Normal file
@@ -0,0 +1,304 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.wifi.hotspot2.pps;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link android.net.wifi.hotspot2.pps.Policy}.
|
||||
*/
|
||||
@SmallTest
|
||||
public class PolicyTest {
|
||||
private static final int MAX_NUMBER_OF_EXCLUDED_SSIDS = 128;
|
||||
private static final int MAX_SSID_BYTES = 32;
|
||||
private static final int MAX_PORT_STRING_BYTES = 64;
|
||||
|
||||
/**
|
||||
* Helper function for creating a {@link Policy} for testing.
|
||||
*
|
||||
* @return {@link Policy}
|
||||
*/
|
||||
private static Policy createPolicy() {
|
||||
Policy policy = new Policy();
|
||||
policy.minHomeDownlinkBandwidth = 123;
|
||||
policy.minHomeUplinkBandwidth = 345;
|
||||
policy.minRoamingDownlinkBandwidth = 567;
|
||||
policy.minRoamingUplinkBandwidth = 789;
|
||||
policy.excludedSsidList = new String[] {"ssid1", "ssid2"};
|
||||
policy.requiredProtoPortMap = new HashMap<>();
|
||||
policy.requiredProtoPortMap.put(12, "23,342,123");
|
||||
policy.requiredProtoPortMap.put(23, "789,372,1235");
|
||||
policy.maximumBssLoadValue = 12;
|
||||
|
||||
policy.preferredRoamingPartnerList = new ArrayList<>();
|
||||
Policy.RoamingPartner partner1 = new Policy.RoamingPartner();
|
||||
partner1.fqdn = "partner1.com";
|
||||
partner1.fqdnExactMatch = true;
|
||||
partner1.priority = 12;
|
||||
partner1.countries = "us,jp";
|
||||
Policy.RoamingPartner partner2 = new Policy.RoamingPartner();
|
||||
partner2.fqdn = "partner2.com";
|
||||
partner2.fqdnExactMatch = false;
|
||||
partner2.priority = 42;
|
||||
partner2.countries = "ca,fr";
|
||||
policy.preferredRoamingPartnerList.add(partner1);
|
||||
policy.preferredRoamingPartnerList.add(partner2);
|
||||
|
||||
policy.policyUpdate = new UpdateParameter();
|
||||
policy.policyUpdate.updateIntervalInMinutes = 1712;
|
||||
policy.policyUpdate.updateMethod = UpdateParameter.UPDATE_METHOD_OMADM;
|
||||
policy.policyUpdate.restriction = UpdateParameter.UPDATE_RESTRICTION_HOMESP;
|
||||
policy.policyUpdate.serverUri = "policy.update.com";
|
||||
policy.policyUpdate.username = "username";
|
||||
policy.policyUpdate.base64EncodedPassword =
|
||||
Base64.encodeToString("password".getBytes(), Base64.DEFAULT);
|
||||
policy.policyUpdate.trustRootCertUrl = "trust.cert.com";
|
||||
policy.policyUpdate.trustRootCertSha256Fingerprint = new byte[32];
|
||||
|
||||
return policy;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for verifying Policy after parcel write then read.
|
||||
* @param policyToWrite
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void verifyParcel(Policy policyToWrite) throws Exception {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
policyToWrite.writeToParcel(parcel, 0);
|
||||
|
||||
parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
|
||||
Policy policyFromRead = Policy.CREATOR.createFromParcel(parcel);
|
||||
assertTrue(policyFromRead.equals(policyToWrite));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for an empty Policy.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithEmptyPolicy() throws Exception {
|
||||
verifyParcel(new Policy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a Policy with all fields set.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithFullPolicy() throws Exception {
|
||||
verifyParcel(createPolicy());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a Policy without protocol port map.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithoutProtoPortMap() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
policy.requiredProtoPortMap = null;
|
||||
verifyParcel(policy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a Policy without preferred roaming partner list.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithoutPreferredRoamingPartnerList() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
policy.preferredRoamingPartnerList = null;
|
||||
verifyParcel(policy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a Policy without policy update parameters.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithoutPolicyUpdate() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
policy.policyUpdate = null;
|
||||
verifyParcel(policy);
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that policy created using copy constructor with null source should be the same
|
||||
* as the policy created using default constructor.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyCopyConstructionWithNullSource() throws Exception {
|
||||
Policy copyPolicy = new Policy(null);
|
||||
Policy defaultPolicy = new Policy();
|
||||
assertTrue(defaultPolicy.equals(copyPolicy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that policy created using copy constructor with a valid source should be the
|
||||
* same as the source.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyCopyConstructionWithFullPolicy() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
Policy copyPolicy = new Policy(policy);
|
||||
assertTrue(policy.equals(copyPolicy));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a default policy (with no informatio) is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithDefault() throws Exception {
|
||||
Policy policy = new Policy();
|
||||
assertFalse(policy.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a policy created using {@link #createPolicy} is valid, since all fields are
|
||||
* filled in with valid values.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithFullPolicy() throws Exception {
|
||||
assertTrue(createPolicy().validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a policy without policy update parameters is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithoutPolicyUpdate() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
policy.policyUpdate = null;
|
||||
assertFalse(policy.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a policy with invalid policy update parameters is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithInvalidPolicyUpdate() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
policy.policyUpdate = new UpdateParameter();
|
||||
assertFalse(policy.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a policy with a preferred roaming partner with FQDN not specified is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithRoamingPartnerWithoutFQDN() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
Policy.RoamingPartner partner = new Policy.RoamingPartner();
|
||||
partner.fqdnExactMatch = true;
|
||||
partner.priority = 12;
|
||||
partner.countries = "us,jp";
|
||||
policy.preferredRoamingPartnerList.add(partner);
|
||||
assertFalse(policy.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a policy with a preferred roaming partner with countries not specified is
|
||||
* invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithRoamingPartnerWithoutCountries() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
Policy.RoamingPartner partner = new Policy.RoamingPartner();
|
||||
partner.fqdn = "test.com";
|
||||
partner.fqdnExactMatch = true;
|
||||
partner.priority = 12;
|
||||
policy.preferredRoamingPartnerList.add(partner);
|
||||
assertFalse(policy.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a policy with a proto-port tuple that contains an invalid port string is
|
||||
* invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithInvalidPortStringInProtoPortMap() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
byte[] rawPortBytes = new byte[MAX_PORT_STRING_BYTES + 1];
|
||||
policy.requiredProtoPortMap.put(324, new String(rawPortBytes, StandardCharsets.UTF_8));
|
||||
assertFalse(policy.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a policy with number of excluded SSIDs exceeded the max is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithSsidExclusionListSizeExceededMax() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
policy.excludedSsidList = new String[MAX_NUMBER_OF_EXCLUDED_SSIDS + 1];
|
||||
Arrays.fill(policy.excludedSsidList, "ssid");
|
||||
assertFalse(policy.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a policy with an invalid SSID in the excluded SSID list is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithInvalidSsid() throws Exception {
|
||||
Policy policy = createPolicy();
|
||||
byte[] rawSsidBytes = new byte[MAX_SSID_BYTES + 1];
|
||||
Arrays.fill(rawSsidBytes, (byte) 'a');
|
||||
policy.excludedSsidList = new String[] {new String(rawSsidBytes, StandardCharsets.UTF_8)};
|
||||
assertFalse(policy.validate());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,348 @@
|
||||
/*
|
||||
* Copyright (C) 2017 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 android.net.wifi.hotspot2.pps;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import android.os.Parcel;
|
||||
import android.test.suitebuilder.annotation.SmallTest;
|
||||
import android.util.Base64;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Unit tests for {@link android.net.wifi.hotspot2.pps.UpdateParameter}.
|
||||
*/
|
||||
@SmallTest
|
||||
public class UpdateParameterTest {
|
||||
private static final int MAX_URI_BYTES = 1023;
|
||||
private static final int MAX_URL_BYTES = 1023;
|
||||
private static final int MAX_USERNAME_BYTES = 63;
|
||||
private static final int MAX_PASSWORD_BYTES = 255;
|
||||
private static final int CERTIFICATE_SHA256_BYTES = 32;
|
||||
|
||||
/**
|
||||
* Helper function for creating a {@link UpdateParameter} for testing.
|
||||
*
|
||||
* @return {@link UpdateParameter}
|
||||
*/
|
||||
private static UpdateParameter createUpdateParameter() {
|
||||
UpdateParameter updateParam = new UpdateParameter();
|
||||
updateParam.updateIntervalInMinutes = 1712;
|
||||
updateParam.updateMethod = UpdateParameter.UPDATE_METHOD_OMADM;
|
||||
updateParam.restriction = UpdateParameter.UPDATE_RESTRICTION_HOMESP;
|
||||
updateParam.serverUri = "server.pdate.com";
|
||||
updateParam.username = "username";
|
||||
updateParam.base64EncodedPassword =
|
||||
Base64.encodeToString("password".getBytes(), Base64.DEFAULT);
|
||||
updateParam.trustRootCertUrl = "trust.cert.com";
|
||||
updateParam.trustRootCertSha256Fingerprint = new byte[32];
|
||||
return updateParam;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function for verifying UpdateParameter after parcel write then read.
|
||||
* @param paramToWrite The UpdateParamter to verify
|
||||
* @throws Exception
|
||||
*/
|
||||
private static void verifyParcel(UpdateParameter paramToWrite) throws Exception {
|
||||
Parcel parcel = Parcel.obtain();
|
||||
paramToWrite.writeToParcel(parcel, 0);
|
||||
|
||||
parcel.setDataPosition(0); // Rewind data position back to the beginning for read.
|
||||
UpdateParameter paramFromRead = UpdateParameter.CREATOR.createFromParcel(parcel);
|
||||
assertTrue(paramFromRead.equals(paramToWrite));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for an empty UpdateParameter.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithEmptyUpdateParameter() throws Exception {
|
||||
verifyParcel(new UpdateParameter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify parcel read/write for a UpdateParameter with all fields set.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyParcelWithFullUpdateParameter() throws Exception {
|
||||
verifyParcel(createUpdateParameter());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that UpdateParameter created using copy constructor with null source should be the
|
||||
* same as the UpdateParameter created using default constructor.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyCopyConstructionWithNullSource() throws Exception {
|
||||
UpdateParameter copyParam = new UpdateParameter(null);
|
||||
UpdateParameter defaultParam = new UpdateParameter();
|
||||
assertTrue(defaultParam.equals(copyParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that UpdateParameter created using copy constructor with a valid source should be the
|
||||
* same as the source.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void verifyCopyConstructionWithFullUpdateParameter() throws Exception {
|
||||
UpdateParameter origParam = createUpdateParameter();
|
||||
UpdateParameter copyParam = new UpdateParameter(origParam);
|
||||
assertTrue(origParam.equals(copyParam));
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that a default UpdateParameter is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithDefault() throws Exception {
|
||||
UpdateParameter updateParam = new UpdateParameter();
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter created using {@link #createUpdateParameter} is valid,
|
||||
* since all fields are filled in with valid values.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithFullPolicy() throws Exception {
|
||||
assertTrue(createUpdateParameter().validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with an unknown update method is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithUnknowMethod() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.updateMethod = "adsfasd";
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with an unknown restriction is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithUnknowRestriction() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.restriction = "adsfasd";
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with an username exceeding maximum size is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithUsernameExceedingMaxSize() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
byte[] rawUsernameBytes = new byte[MAX_USERNAME_BYTES + 1];
|
||||
Arrays.fill(rawUsernameBytes, (byte) 'a');
|
||||
updateParam.username = new String(rawUsernameBytes, StandardCharsets.UTF_8);
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with an empty username is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithEmptyUsername() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.username = null;
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with a password exceeding maximum size is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithPasswordExceedingMaxSize() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
byte[] rawPasswordBytes = new byte[MAX_PASSWORD_BYTES + 1];
|
||||
Arrays.fill(rawPasswordBytes, (byte) 'a');
|
||||
updateParam.base64EncodedPassword = new String(rawPasswordBytes, StandardCharsets.UTF_8);
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with an empty password is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithEmptyPassword() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.base64EncodedPassword = null;
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with a Base64 encoded password that contained invalid padding
|
||||
* is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithPasswordContainedInvalidPadding() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.base64EncodedPassword = updateParam.base64EncodedPassword + "=";
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter without trust root certificate URL is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithoutTrustRootCertUrl() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.trustRootCertUrl = null;
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with invalid trust root certificate URL is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithInvalidTrustRootCertUrl() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
byte[] rawUrlBytes = new byte[MAX_URL_BYTES + 1];
|
||||
Arrays.fill(rawUrlBytes, (byte) 'a');
|
||||
updateParam.trustRootCertUrl = new String(rawUrlBytes, StandardCharsets.UTF_8);
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter without trust root certificate SHA-256 fingerprint is
|
||||
* invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithouttrustRootCertSha256Fingerprint() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.trustRootCertSha256Fingerprint = null;
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with an incorrect size trust root certificate SHA-256
|
||||
* fingerprint is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithInvalidtrustRootCertSha256Fingerprint() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.trustRootCertSha256Fingerprint = new byte[CERTIFICATE_SHA256_BYTES + 1];
|
||||
assertFalse(updateParam.validate());
|
||||
|
||||
updateParam.trustRootCertSha256Fingerprint = new byte[CERTIFICATE_SHA256_BYTES - 1];
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter without server URI is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithoutServerUri() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.serverUri = null;
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with an invalid server URI is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validatePolicyWithInvalidServerUri() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
byte[] rawUriBytes = new byte[MAX_URI_BYTES + 1];
|
||||
Arrays.fill(rawUriBytes, (byte) 'a');
|
||||
updateParam.serverUri = new String(rawUriBytes, StandardCharsets.UTF_8);
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with update interval set to "never" will not perform
|
||||
* validation on other parameters, since update is not applicable in this case.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithNoServerCheck() throws Exception {
|
||||
UpdateParameter updateParam = new UpdateParameter();
|
||||
updateParam.updateIntervalInMinutes = UpdateParameter.UPDATE_CHECK_INTERVAL_NEVER;
|
||||
updateParam.username = null;
|
||||
updateParam.base64EncodedPassword = null;
|
||||
updateParam.updateMethod = null;
|
||||
updateParam.restriction = null;
|
||||
updateParam.serverUri = null;
|
||||
updateParam.trustRootCertUrl = null;
|
||||
updateParam.trustRootCertSha256Fingerprint = null;
|
||||
assertTrue(updateParam.validate());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verify that an UpdateParameter with unset update interval is invalid.
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
@Test
|
||||
public void validateUpdateParameterWithoutUpdateInterval() throws Exception {
|
||||
UpdateParameter updateParam = createUpdateParameter();
|
||||
updateParam.updateIntervalInMinutes = Long.MIN_VALUE;
|
||||
assertFalse(updateParam.validate());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user