SdkUtil.java revision fead9ca09b117136b35bc5bf137340a754f9eddd
197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar/* 297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Copyright (C) 2015 The Android Open Source Project 397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Licensed under the Apache License, Version 2.0 (the "License"); 497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * you may not use this file except in compliance with the License. 597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * You may obtain a copy of the License at 697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * http://www.apache.org/licenses/LICENSE-2.0 797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Unless required by applicable law or agreed to in writing, software 897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * distributed under the License is distributed on an "AS IS" BASIS, 997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 1097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * See the License for the specific language governing permissions and 1197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * limitations under the License. 1297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar */ 1397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 14fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountpackage android.databinding.tool.reflection; 1597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 1697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport com.google.common.base.Preconditions; 17fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount 1897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport org.w3c.dom.Document; 1997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport org.w3c.dom.Node; 2097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport org.w3c.dom.NodeList; 21fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount 22fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mountimport android.databinding.tool.util.L; 23fead9ca09b117136b35bc5bf137340a754f9edddGeorge Mount 2497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.io.File; 2597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.util.HashMap; 2697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport java.util.Map; 2797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 2897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport javax.xml.parsers.DocumentBuilder; 2997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport javax.xml.parsers.DocumentBuilderFactory; 3097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport javax.xml.xpath.XPath; 3197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport javax.xml.xpath.XPathExpressionException; 3297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarimport javax.xml.xpath.XPathFactory; 3397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 3497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar/** 3597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Class that is used for SDK related stuff. 3697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * <p> 3797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar * Must be initialized with the sdk location to work properly 3897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar */ 3997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyarpublic class SdkUtil { 4097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 4197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar static File mSdkPath; 4297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 4397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar static ApiChecker mApiChecker; 4497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 4597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar static int mMinSdk; 4697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 4797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public static void initialize(int minSdk, File sdkPath) { 4897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mSdkPath = sdkPath; 4997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mMinSdk = minSdk; 5097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mApiChecker = new ApiChecker(new File(sdkPath.getAbsolutePath() 5197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar + "/platform-tools/api/api-versions.xml")); 5297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar L.d("SdkUtil init, minSdk: %s", minSdk); 5397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 5497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 5597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public static int getMinApi(ModelClass modelClass) { 5697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return mApiChecker.getMinApi(modelClass.getJniDescription(), null); 5797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 5897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 5997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public static int getMinApi(ModelMethod modelMethod) { 6097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar ModelClass declaringClass = modelMethod.getDeclaringClass(); 6197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar Preconditions.checkNotNull(mApiChecker, "should've initialized api checker"); 6297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar while (declaringClass != null) { 6397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar String classDesc = declaringClass.getJniDescription(); 6497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar String methodDesc = modelMethod.getJniDescription(); 6597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar int result = mApiChecker.getMinApi(classDesc, methodDesc); 6697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar L.d("checking method api for %s, class:%s method:%s. result: %d", modelMethod.getName(), 6797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar classDesc, methodDesc, result); 6897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (result > 1) { 6997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return result; 7097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 7197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar declaringClass = declaringClass.getSuperclass(); 7297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 7397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return 1; 7497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 7597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 7697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private static class ApiChecker { 7797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 78895b618d9c6e3deb56465d0759cda57f50c46214Yigit Boyar private Map<String, Integer> mFullLookup = new HashMap<String, Integer>(); 7997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 8097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private Document mDoc; 8197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 8297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private XPath mXPath; 8397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 8497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public ApiChecker(File apiFile) { 8597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar try { 8697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 8797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar DocumentBuilder builder = factory.newDocumentBuilder(); 8897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mDoc = builder.parse(apiFile); 8997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar XPathFactory xPathFactory = XPathFactory.newInstance(); 9097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mXPath = xPathFactory.newXPath(); 9197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar buildFullLookup(); 9297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } catch (Throwable t) { 9397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar L.e(t, "cannot load api descriptions from %s", apiFile); 9497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 9597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 9697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 9797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private void buildFullLookup() throws XPathExpressionException { 9897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar NodeList allClasses = mDoc.getChildNodes().item(0).getChildNodes(); 9997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar for (int j = 0; j < allClasses.getLength(); j++) { 10097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar Node node = allClasses.item(j); 10197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (node.getNodeType() != Node.ELEMENT_NODE || !"class" 10297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar .equals(node.getNodeName())) { 10397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar continue; 10497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 10597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar //L.d("checking node %s", node.getAttributes().getNamedItem("name").getNodeValue()); 10697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar int classSince = getSince(node); 10797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar String classDesc = node.getAttributes().getNamedItem("name").getNodeValue(); 10897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 10997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar final NodeList childNodes = node.getChildNodes(); 11097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar for (int i = 0; i < childNodes.getLength(); i++) { 11197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar Node child = childNodes.item(i); 11297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (child.getNodeType() != Node.ELEMENT_NODE || !"method" 11397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar .equals(child.getNodeName())) { 11497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar continue; 11597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 11697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar int methodSince = getSince(child); 11797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar int since = Math.max(classSince, methodSince); 11897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (since > SdkUtil.mMinSdk) { 11997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar String methodDesc = child.getAttributes().getNamedItem("name") 12097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar .getNodeValue(); 12197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar String key = cacheKey(classDesc, methodDesc); 12297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar mFullLookup.put(key, since); 12397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 12497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 12597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 12697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 12797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 12897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar public int getMinApi(String classDesc, String methodOrFieldDesc) { 12997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (mDoc == null || mXPath == null) { 13097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return 1; 13197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 13297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (classDesc == null || classDesc.isEmpty()) { 13397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return 1; 13497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 13597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar final String key = cacheKey(classDesc, methodOrFieldDesc); 13697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar Integer since = mFullLookup.get(key); 13797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return since == null ? 1 : since; 13897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 13997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 14097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private static String cacheKey(String classDesc, String methodOrFieldDesc) { 14197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return classDesc + "~" + methodOrFieldDesc; 14297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 14397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 14497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar private static int getSince(Node node) { 14597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar final Node since = node.getAttributes().getNamedItem("since"); 14697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (since != null) { 14797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar final String nodeValue = since.getNodeValue(); 14897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar if (nodeValue != null && !nodeValue.isEmpty()) { 14997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar try { 15097d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return Integer.parseInt(nodeValue); 15197d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } catch (Throwable t) { 15297d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 15397d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 15497d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 15597d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar 15697d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar return 1; 15797d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 15897d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar } 15997d6ddf47f4ff1abb3ed5201ce5232163f5325b1Yigit Boyar} 160