diff options
author | Jan Nordqvist <jannq@google.com> | 2016-02-13 02:12:36 +0000 |
---|---|---|
committer | Android Partner Code Review <android-gerrit-partner@google.com> | 2016-02-13 02:12:37 +0000 |
commit | 1a12bb76143efa4c86e17bf1a14e6c19a21e747b (patch) | |
tree | f9a69700b7f670d62c02aa7da7be0c1b9afbea3b /service | |
parent | ed514c84aae008d245679f05c9dbcd7e71f126f8 (diff) | |
parent | c9b88562541a0c2acd60d0a01ac1e182e73c79f9 (diff) |
Merge "Fixed incorrect XML serialization of MO Tree." into mm-wireless-dev
Diffstat (limited to 'service')
9 files changed, 187 insertions, 49 deletions
diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/MOTree.java b/service/java/com/android/server/wifi/hotspot2/omadm/MOTree.java index 99683adca..63541eec8 100644 --- a/service/java/com/android/server/wifi/hotspot2/omadm/MOTree.java +++ b/service/java/com/android/server/wifi/hotspot2/omadm/MOTree.java @@ -2,6 +2,7 @@ package com.android.server.wifi.hotspot2.omadm; import org.xml.sax.SAXException; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -40,27 +41,35 @@ public class MOTree { mUrn = urn; mDtdRev = dtdRev; - mRoot = new OMAConstructed(null, MgmtTreeTag, null); + mRoot = new ManagementTreeRoot(node, dtdRev); for (XMLNode child : node.getChildren()) { buildNode(mRoot, child); } } - public MOTree(String urn, String rev, OMAConstructed root) throws IOException { + public MOTree(String urn, String rev, OMAConstructed root) { mUrn = urn; mDtdRev = rev; mRoot = root; } - public static MOTree buildMgmtTree(String urn, String rev, OMAConstructed root) throws IOException { + /** + * Build a Passpoint OMA-DM Management Object tree object. + * @param urn The URN for the tree. + * @param rev The DTD revision for the tree. + * @param root The OMA-DM tree root, in all practical cases the PerProviderSubscription + * node. + * @return an MOTree object + */ + public static MOTree buildMgmtTree(String urn, String rev, OMAConstructed root) { OMAConstructed realRoot; switch (urn) { case OMAConstants.PPS_URN: case OMAConstants.DevInfoURN: case OMAConstants.DevDetailURN: case OMAConstants.DevDetailXURN: - realRoot = new OMAConstructed(null, MgmtTreeTag, urn, "xmlns", OMAConstants.SyncML); + realRoot = new ManagementTreeRoot(OMAConstants.OMAVersion); realRoot.addChild(root); return new MOTree(urn, rev, realRoot); default: @@ -232,7 +241,7 @@ public class MOTree { for (; ; ) { int octet = in.read(); if (octet < 0) { - return null; + throw new FileNotFoundException(); } else if (octet > ' ') { tree.append((char) octet); strip = false; @@ -258,11 +267,7 @@ public class MOTree { public String toXml() { StringBuilder sb = new StringBuilder(); - - sb.append('<').append(MgmtTreeTag).append(">\n"); - sb.append("<VerDTD>").append(mDtdRev).append("</VerDTD>\n"); mRoot.toXml(sb); - sb.append("</").append(MgmtTreeTag).append(">\n"); return sb.toString(); } } diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/ManagementTreeRoot.java b/service/java/com/android/server/wifi/hotspot2/omadm/ManagementTreeRoot.java new file mode 100644 index 000000000..83a8dc834 --- /dev/null +++ b/service/java/com/android/server/wifi/hotspot2/omadm/ManagementTreeRoot.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2016 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.hotspot2.omadm; + +import java.util.Map; + +/** + * A specialized OMAConstructed OMA-DM node used as the MgmtTree root node in Passpoint + * management trees. + */ +public class ManagementTreeRoot extends OMAConstructed { + private final String mDtdRev; + + public ManagementTreeRoot(XMLNode node, String dtdRev) { + super(null, MOTree.MgmtTreeTag, null, new MultiValueMap<OMANode>(), + node.getTextualAttributes()); + mDtdRev = dtdRev; + } + + public ManagementTreeRoot(String dtdRev) { + super(null, MOTree.MgmtTreeTag, null, "xmlns", OMAConstants.SyncML); + mDtdRev = dtdRev; + } + + @Override + public void toXml(StringBuilder sb) { + sb.append('<').append(MOTree.MgmtTreeTag); + if (getAttributes() != null && !getAttributes().isEmpty()) { + for (Map.Entry<String, String> avp : getAttributes().entrySet()) { + sb.append(' ').append(avp.getKey()).append("=\"") + .append(escape(avp.getValue())).append('"'); + } + } + sb.append(">\n"); + + sb.append('<').append(OMAConstants.SyncMLVersionTag) + .append('>').append(mDtdRev) + .append("</").append(OMAConstants.SyncMLVersionTag).append(">\n"); + for (OMANode child : getChildren()) { + child.toXml(sb); + } + sb.append("</").append(MOTree.MgmtTreeTag).append(">\n"); + } +} diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/NodeAttribute.java b/service/java/com/android/server/wifi/hotspot2/omadm/NodeAttribute.java index 1fc1adf7a..87ded86da 100644 --- a/service/java/com/android/server/wifi/hotspot2/omadm/NodeAttribute.java +++ b/service/java/com/android/server/wifi/hotspot2/omadm/NodeAttribute.java @@ -24,6 +24,19 @@ public class NodeAttribute { } @Override + public boolean equals(Object thatObject) { + if (this == thatObject) { + return true; + } + if (thatObject == null || getClass() != thatObject.getClass()) { + return false; + } + + NodeAttribute that = (NodeAttribute) thatObject; + return mName.equals(that.mName) && mType.equals(that.mType) && mValue.equals(that.mValue); + } + + @Override public String toString() { return String.format("%s (%s) = '%s'", mName, mType, mValue); } diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/OMAConstructed.java b/service/java/com/android/server/wifi/hotspot2/omadm/OMAConstructed.java index 10b159f5c..c0e4c66dd 100644 --- a/service/java/com/android/server/wifi/hotspot2/omadm/OMAConstructed.java +++ b/service/java/com/android/server/wifi/hotspot2/omadm/OMAConstructed.java @@ -15,7 +15,7 @@ public class OMAConstructed extends OMANode { this(parent, name, context, new MultiValueMap<OMANode>(), buildAttributes(avps)); } - private OMAConstructed(OMAConstructed parent, String name, String context, + protected OMAConstructed(OMAConstructed parent, String name, String context, MultiValueMap<OMANode> children, Map<String, String> avps) { super(parent, name, context, avps); mChildren = children; diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/OMANode.java b/service/java/com/android/server/wifi/hotspot2/omadm/OMANode.java index ff0c7e32e..fbb607561 100644 --- a/service/java/com/android/server/wifi/hotspot2/omadm/OMANode.java +++ b/service/java/com/android/server/wifi/hotspot2/omadm/OMANode.java @@ -16,6 +16,16 @@ public abstract class OMANode { private final String mContext; private final Map<String, String> mAttributes; + private static final Map<Character, String> sEscapes = new HashMap<>(); + + static { + sEscapes.put('"', """); + sEscapes.put('\'', "'"); + sEscapes.put('<', "<"); + sEscapes.put('>', ">"); + sEscapes.put('&', "&"); + } + protected OMANode(OMAConstructed parent, String name, String context, Map<String, String> avps) { mParent = parent; mName = name; @@ -66,6 +76,25 @@ public abstract class OMANode { return sb.toString(); } + /** + * Perform escaping of special XML characters + * @param s the raw string + * @return a "XML clean" representation + */ + public static String escape(String s) { + StringBuilder sb = new StringBuilder(s.length()); + for (int n = 0; n < s.length(); n++) { + char ch = s.charAt(n); + String escape = sEscapes.get(ch); + if (escape != null) { + sb.append(escape); + } else { + sb.append(ch); + } + } + return sb.toString(); + } + public abstract OMANode reparent(OMAConstructed parent); public abstract String getScalarValue(Iterator<String> path) throws OMAException; @@ -93,7 +122,8 @@ public abstract class OMANode { sb.append('<').append(MOTree.NodeTag); if (mAttributes != null && !mAttributes.isEmpty()) { for (Map.Entry<String, String> avp : mAttributes.entrySet()) { - sb.append(' ').append(avp.getKey()).append("=\"").append(avp.getValue()).append('"'); + sb.append(' ').append(avp.getKey()).append("=\"") + .append(escape(avp.getValue())).append('"'); } } sb.append(">\n"); diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java b/service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java index 2669a302d..cbcd81d16 100644 --- a/service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java +++ b/service/java/com/android/server/wifi/hotspot2/omadm/OMAParser.java @@ -35,6 +35,10 @@ public class OMAParser extends DefaultHandler { } } + public XMLNode getRoot() { + return mRoot; + } + @Override public void startElement(String uri, String localName, String qName, Attributes attributes) throws SAXException { diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/OMAScalar.java b/service/java/com/android/server/wifi/hotspot2/omadm/OMAScalar.java index c8a3f9846..86740ac1c 100644 --- a/service/java/com/android/server/wifi/hotspot2/omadm/OMAScalar.java +++ b/service/java/com/android/server/wifi/hotspot2/omadm/OMAScalar.java @@ -1,7 +1,5 @@ package com.android.server.wifi.hotspot2.omadm; -import android.util.Log; - import java.io.IOException; import java.io.OutputStream; import java.util.Collection; @@ -83,7 +81,7 @@ public class OMAScalar extends OMANode { @Override public void fillPayload(StringBuilder sb) { sb.append('<').append(MOTree.ValueTag).append('>'); - sb.append(mValue); + sb.append(escape(mValue)); sb.append("</").append(MOTree.ValueTag).append(">\n"); } } diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java b/service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java index f26e83cbf..e967212e7 100644 --- a/service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java +++ b/service/java/com/android/server/wifi/hotspot2/omadm/PasspointManagementObjectManager.java @@ -143,7 +143,7 @@ public class PasspointManagementObjectManager { "unrestricted", UpdateInfo.UpdateRestriction.Unrestricted); } - private static void setSelections(String key, Object ... pairs) { + private static void setSelections(String key, Object... pairs) { Map<String, Object> kvp = new HashMap<>(); sSelectionMap.put(key, kvp); for (int n = 0; n < pairs.length; n += 2) { @@ -161,10 +161,6 @@ public class PasspointManagementObjectManager { mSPs = new HashMap<>(); } - public File getPpsFile() { - return mPpsFile; - } - public boolean isEnabled() { return mEnabled; } @@ -184,9 +180,11 @@ public class PasspointManagementObjectManager { } try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) { - MOTree moTree = MOTree.unmarshal(in); mSPs.clear(); - if (moTree == null) { + MOTree moTree; + try { + moTree = MOTree.unmarshal(in); + } catch (FileNotFoundException fnfe) { return Collections.emptyList(); // Empty file } @@ -227,6 +225,7 @@ public class PasspointManagementObjectManager { /** * R1 *only* addSP method. + * * @param homeSP * @throws IOException */ @@ -282,6 +281,7 @@ public class PasspointManagementObjectManager { /** * Add an SP sub-tree. mo must be PPS with an immediate instance child (e.g. Cred01) and an * optional UpdateIdentifier, + * * @param mo The new MO * @throws IOException */ @@ -306,7 +306,7 @@ public class PasspointManagementObjectManager { if (instance != null) { String nodeFqdn = getString(instance.getListValue(FQDNPath.iterator())); if (fqdn.equalsIgnoreCase(nodeFqdn)) { - return (OMAConstructed) node; + return (OMAConstructed) node; // targetTree is rooted at the PPS } } @@ -329,7 +329,7 @@ public class PasspointManagementObjectManager { Log.d(Utils.hs2LogTag(getClass()), "modifying SP: " + mods); MOTree moTree; int ppsMods = 0; - int updateIdentifier = 0; + int updateIdentifier; try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) { moTree = MOTree.unmarshal(in); // moTree is PPS/?/provider-data @@ -367,7 +367,7 @@ public class PasspointManagementObjectManager { for (OMANode newNode : modRoot.getChildren()) { // newNode is something like Credential // current is the same existing node - OMANode old = current.getParent().replaceNode(current, newNode); + current.getParent().replaceNode(current, newNode); ppsMods++; } } @@ -447,17 +447,8 @@ public class PasspointManagementObjectManager { } return MOTree.buildMgmtTree(OMAConstants.PPS_URN, OMAConstants.OMAVersion, target).toXml(); - } - } - - public MOTree getMOTree(HomeSP homeSP) throws IOException { - try (BufferedInputStream in = new BufferedInputStream(new FileInputStream(mPpsFile))) { - MOTree moTree = MOTree.unmarshal(in); - OMAConstructed target = findTargetTree(moTree, homeSP.getFQDN()); - if (target == null) { - throw new IOException("Can't find " + homeSP.getFQDN() + " in MO tree"); - } - return MOTree.buildMgmtTree(OMAConstants.PPS_URN, OMAConstants.OMAVersion, target); + } catch (FileNotFoundException fnfe) { + return null; } } @@ -469,20 +460,6 @@ public class PasspointManagementObjectManager { } } - private static String fqdnList(Collection<HomeSP> sps) { - StringBuilder sb = new StringBuilder(); - boolean first = true; - for (HomeSP sp : sps) { - if (first) { - first = false; - } else { - sb.append(", "); - } - sb.append(sp.getFQDN()); - } - return sb.toString(); - } - private static OMANode buildHomeSPTree(HomeSP homeSP, OMAConstructed root, int instanceID) throws IOException { OMANode providerSubNode = root.addChild(getInstanceString(instanceID), diff --git a/service/java/com/android/server/wifi/hotspot2/omadm/XMLNode.java b/service/java/com/android/server/wifi/hotspot2/omadm/XMLNode.java index 3fa54a20a..76b7076df 100644 --- a/service/java/com/android/server/wifi/hotspot2/omadm/XMLNode.java +++ b/service/java/com/android/server/wifi/hotspot2/omadm/XMLNode.java @@ -9,6 +9,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -67,6 +68,46 @@ public class XMLNode { mTextBuilder = new StringBuilder(); } + @Override + public boolean equals(Object thatObject) { + if (thatObject == this) { + return true; + } else if (thatObject.getClass() != XMLNode.class) { + return false; + } + + XMLNode that = (XMLNode) thatObject; + if (!getTag().equals(that.getTag()) + || mAttributes.size() != that.mAttributes.size() + || mChildren.size() != that.mChildren.size()) { + return false; + } + + for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) { + if (!entry.getValue().equals(that.mAttributes.get(entry.getKey()))) { + return false; + } + } + + List<XMLNode> cloneOfThat = new ArrayList<>(that.mChildren); + for (XMLNode child : mChildren) { + Iterator<XMLNode> thatChildren = cloneOfThat.iterator(); + boolean found = false; + while (thatChildren.hasNext()) { + XMLNode thatChild = thatChildren.next(); + if (child.equals(thatChild)) { + found = true; + thatChildren.remove(); + break; + } + } + if (!found) { + return false; + } + } + return true; + } + public void setText(String text) { mText = text; mTextBuilder = null; @@ -152,6 +193,18 @@ public class XMLNode { return Collections.unmodifiableMap(mAttributes); } + /** + * Get the attributes of this node as a map of attribute name to attribute value. + * @return The attribute mapping. + */ + public Map<String, String> getTextualAttributes() { + Map<String, String> map = new HashMap<>(mAttributes.size()); + for (Map.Entry<String, NodeAttribute> entry : mAttributes.entrySet()) { + map.put(entry.getKey(), entry.getValue().getValue()); + } + return map; + } + public String getAttributeValue(String name) { NodeAttribute nodeAttribute = mAttributes.get(name); return nodeAttribute != null ? nodeAttribute.getValue() : null; |