package com.ensoftcorp.open.android.essentials.permissions.mappings; import java.util.ArrayList; import java.util.List; import com.ensoftcorp.atlas.core.db.graph.Edge; import com.ensoftcorp.atlas.core.db.graph.Graph; import com.ensoftcorp.atlas.core.db.graph.GraphElement; import com.ensoftcorp.atlas.core.db.graph.GraphElement.EdgeDirection; import com.ensoftcorp.atlas.core.db.graph.GraphElement.NodeDirection; import com.ensoftcorp.atlas.core.db.graph.Node; import com.ensoftcorp.atlas.core.db.set.AtlasSet; import com.ensoftcorp.atlas.core.query.Attr; import com.ensoftcorp.atlas.core.query.Q; import com.ensoftcorp.atlas.core.xcsg.XCSG; import com.ensoftcorp.atlas.java.core.script.Common; /** * A helper class for applying Permission protected API method tags * @author Yuqing Chen, Jon Mathews, Ben Holland, Zach Lones */ public class PermissionUtils { /** * A method which find the methods matching the name, declarative structure, and parameters * Tag the matched methods with corresponding permission tag. * <p> * <ul> * <li>Expected format is based on PScout mappings. * <li>Class names are essentially the binary names. * <li>Constructors are always named <init>. * </ul> * * @param context * A context from which to start searching * * @param packageName * The package containing the class(es) and method * * @param className * The type name, essentially the binary name (unqualified) * * @param parameters * fully qualified parameter type names of the method * @param tag * a set of tags to apply to the method * * @return the GraphElement, or null if method could not be found */ public static GraphElement tagMethod(Q context, String packageName, String className, String methodName, String[] parameters, String... tags) { Q methods; // Get all methods with the same name to methodName //if method is constructor, compare to input classNames if (methodName.equals("<init>")){ methods = Common.universe().selectNode(XCSG.name, className).nodesTaggedWithAny(XCSG.Constructor); } else { // FIXME: technically, this search must exclude constructors. XCSG // will have dedicated tags for non-constructors, which will be // faster than using Q.difference(). In the meantime, this corner // case is not affecting PScout mappings. methods = Common.universe().selectNode(XCSG.name, methodName).nodesTaggedWithAll(XCSG.Method); } //find methods nodes with matched parameter type names List<Q> allParamTypeNodes = new ArrayList<Q>(); for (String parameter : parameters){ String elementTypeName = parameter; Q paramTypeNode; //the array dimension of parameter type's array type int arrayDim = 0; if (parameter.contains("[]")){ //get element type name for comparing elementTypeName = parameter.substring(0, parameter.indexOf("[")); //count array dimension for (int i=0; i<parameter.length(); i++){ if (parameter.charAt(i) == '['){ arrayDim++; } } } // match parameter type names paramTypeNode = Common.universe().selectNode(Attr.Node.BINARY_NAME, elementTypeName); //if array type exists, use the array type to represent type node if (arrayDim !=0){ paramTypeNode = Common.universe().reverseStep(paramTypeNode).nodesTaggedWithAll(XCSG.ArrayType).selectNode(XCSG.Java.arrayTypeDimension, new Integer(arrayDim)); } if (paramTypeNode.eval().nodes().size()!=0){ allParamTypeNodes.add(paramTypeNode); } } //use public methods from Common to get matched methods methods = Common.signature(methods, allParamTypeNodes); //Get nodes representing selected methods AtlasSet<Node> nodes = methods.eval().nodes(); for (Node node : nodes){ //get the parent of the method node GraphElement parent = null; AtlasSet<Edge> es = Graph.U.edges(node, NodeDirection.IN); for (Edge e : es) { if (e.tags().contains(XCSG.Contains)) { parent = e.getNode(EdgeDirection.FROM); break; } } // compare parent binary name to input qualified class name // if binary name not available, skip it if (parent == null){ continue; } else if (parent.attr().get(Attr.Node.BINARY_NAME) == null){ continue; } else if (parent.attr().get(Attr.Node.BINARY_NAME).equals(packageName + "." + className)){ for(String tag : tags){ node.tags().add(tag); } return node; } } return null; } /** * A method to return the method given the universe as a context * * @param packageName * The package containing the class(es) and method * @param className * A String containing the classes going from outermost class to * innermost class delimited by $ Assume anonymous inner classes * start with a number and non-anonymous classes do not. * @param methodName * name of the method * @param parameters * array containing fully qualified name of parameter types for the method * @param tags * a set of tags to apply to the method * @return */ public static GraphElement tagMethod(String packageName, String className, String methodName, String[] parameters, String... tags) { return tagMethod(Common.universe(), packageName, className, methodName, parameters, tags); } }