1*795d594fSAndroid Build Coastguard Worker /* 2*795d594fSAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project 3*795d594fSAndroid Build Coastguard Worker * 4*795d594fSAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License"); 5*795d594fSAndroid Build Coastguard Worker * you may not use this file except in compliance with the License. 6*795d594fSAndroid Build Coastguard Worker * You may obtain a copy of the License at 7*795d594fSAndroid Build Coastguard Worker * 8*795d594fSAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0 9*795d594fSAndroid Build Coastguard Worker * 10*795d594fSAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software 11*795d594fSAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS, 12*795d594fSAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13*795d594fSAndroid Build Coastguard Worker * See the License for the specific language governing permissions and 14*795d594fSAndroid Build Coastguard Worker * limitations under the License. 15*795d594fSAndroid Build Coastguard Worker */ 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker import java.io.File; 18*795d594fSAndroid Build Coastguard Worker import java.lang.reflect.Method; 19*795d594fSAndroid Build Coastguard Worker import java.util.Base64; 20*795d594fSAndroid Build Coastguard Worker 21*795d594fSAndroid Build Coastguard Worker public class Main { main(String[] args)22*795d594fSAndroid Build Coastguard Worker public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException { 23*795d594fSAndroid Build Coastguard Worker System.loadLibrary(args[0]); 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard Worker // Run the initialization routine. This will enable hidden API checks in 26*795d594fSAndroid Build Coastguard Worker // the runtime, in case they are not enabled by default. 27*795d594fSAndroid Build Coastguard Worker init(); 28*795d594fSAndroid Build Coastguard Worker 29*795d594fSAndroid Build Coastguard Worker // Load the '-ex' APK and attach it to the boot class path. 30*795d594fSAndroid Build Coastguard Worker appendToBootClassLoader(DEX_EXTRA, /* isCorePlatform */ false); 31*795d594fSAndroid Build Coastguard Worker 32*795d594fSAndroid Build Coastguard Worker // All test classes contain just methods named "foo" with different return types 33*795d594fSAndroid Build Coastguard Worker // and access flags. Check that: 34*795d594fSAndroid Build Coastguard Worker // (a) only the non-hidden ones are returned from getDeclaredMethods 35*795d594fSAndroid Build Coastguard Worker // (they have return types Number and Double), and 36*795d594fSAndroid Build Coastguard Worker // (b) getDeclaredMethod picks virtual/non-synthetic methods over direct/synthetic 37*795d594fSAndroid Build Coastguard Worker // (the right one always has return type Number). 38*795d594fSAndroid Build Coastguard Worker Class<?> covariantClass = Class.forName(JAVA_CLASS_NAME, true, BOOT_CLASS_LOADER); 39*795d594fSAndroid Build Coastguard Worker checkMethodList(covariantClass, /* expectedLength= */ 1); 40*795d594fSAndroid Build Coastguard Worker checkMethod(covariantClass); 41*795d594fSAndroid Build Coastguard Worker 42*795d594fSAndroid Build Coastguard Worker String[] classes = new String[] { 43*795d594fSAndroid Build Coastguard Worker "VirtualMethods", 44*795d594fSAndroid Build Coastguard Worker "DirectMethods", 45*795d594fSAndroid Build Coastguard Worker "SyntheticMethods", 46*795d594fSAndroid Build Coastguard Worker "NonSyntheticMethods" 47*795d594fSAndroid Build Coastguard Worker }; 48*795d594fSAndroid Build Coastguard Worker for (String className : classes) { 49*795d594fSAndroid Build Coastguard Worker Class<?> klass = Class.forName(className, true, BOOT_CLASS_LOADER); 50*795d594fSAndroid Build Coastguard Worker checkMethodList(klass, /* expectedLength= */ 2); 51*795d594fSAndroid Build Coastguard Worker checkMethod(klass); 52*795d594fSAndroid Build Coastguard Worker } 53*795d594fSAndroid Build Coastguard Worker } 54*795d594fSAndroid Build Coastguard Worker checkMethodList(Class<?> klass, int expectedLength)55*795d594fSAndroid Build Coastguard Worker private static void checkMethodList(Class<?> klass, int expectedLength) { 56*795d594fSAndroid Build Coastguard Worker String className = klass.getName(); 57*795d594fSAndroid Build Coastguard Worker Method[] methods = klass.getDeclaredMethods(); 58*795d594fSAndroid Build Coastguard Worker if (methods.length != expectedLength) { 59*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(className + ": expected " + expectedLength + 60*795d594fSAndroid Build Coastguard Worker " declared method(s), got " + methods.length); 61*795d594fSAndroid Build Coastguard Worker } 62*795d594fSAndroid Build Coastguard Worker boolean hasNumberReturnType = false; 63*795d594fSAndroid Build Coastguard Worker boolean hasDoubleReturnType = false; 64*795d594fSAndroid Build Coastguard Worker for (Method method : methods) { 65*795d594fSAndroid Build Coastguard Worker if (!METHOD_NAME.equals(method.getName())) { 66*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(className + ": expected declared method name: \"" + METHOD_NAME + 67*795d594fSAndroid Build Coastguard Worker "\", got: \"" + method.getName() + "\""); 68*795d594fSAndroid Build Coastguard Worker } 69*795d594fSAndroid Build Coastguard Worker if (Number.class == method.getReturnType()) { 70*795d594fSAndroid Build Coastguard Worker hasNumberReturnType = true; 71*795d594fSAndroid Build Coastguard Worker } else if (Double.class == method.getReturnType()) { 72*795d594fSAndroid Build Coastguard Worker hasDoubleReturnType = true; 73*795d594fSAndroid Build Coastguard Worker } 74*795d594fSAndroid Build Coastguard Worker } 75*795d594fSAndroid Build Coastguard Worker if (methods.length >= 1 && !hasNumberReturnType) { 76*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(className + ": expected a method with return type \"Number\""); 77*795d594fSAndroid Build Coastguard Worker } 78*795d594fSAndroid Build Coastguard Worker if (methods.length >= 2 && !hasDoubleReturnType) { 79*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(className + ": expected a method with return type \"Double\""); 80*795d594fSAndroid Build Coastguard Worker } 81*795d594fSAndroid Build Coastguard Worker } 82*795d594fSAndroid Build Coastguard Worker checkMethod(Class<?> klass)83*795d594fSAndroid Build Coastguard Worker private static void checkMethod(Class<?> klass) throws NoSuchMethodException { 84*795d594fSAndroid Build Coastguard Worker String className = klass.getName(); 85*795d594fSAndroid Build Coastguard Worker Method method = klass.getDeclaredMethod(METHOD_NAME); 86*795d594fSAndroid Build Coastguard Worker if (!METHOD_NAME.equals(method.getName())) { 87*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(className + ": expected declared method name: \"" + METHOD_NAME + 88*795d594fSAndroid Build Coastguard Worker "\", got: \"" + method.getName() + "\""); 89*795d594fSAndroid Build Coastguard Worker } else if (Number.class != method.getReturnType()) { 90*795d594fSAndroid Build Coastguard Worker throw new RuntimeException(className + ": expected method return type: \"Number\", got \"" + 91*795d594fSAndroid Build Coastguard Worker method.getReturnType().toString() + "\""); 92*795d594fSAndroid Build Coastguard Worker } 93*795d594fSAndroid Build Coastguard Worker } 94*795d594fSAndroid Build Coastguard Worker 95*795d594fSAndroid Build Coastguard Worker private static final String DEX_EXTRA = new File(System.getenv("DEX_LOCATION"), 96*795d594fSAndroid Build Coastguard Worker "690-hiddenapi-same-name-methods-ex.jar").getAbsolutePath(); 97*795d594fSAndroid Build Coastguard Worker 98*795d594fSAndroid Build Coastguard Worker private static ClassLoader BOOT_CLASS_LOADER = Object.class.getClassLoader(); 99*795d594fSAndroid Build Coastguard Worker 100*795d594fSAndroid Build Coastguard Worker private static final String JAVA_CLASS_NAME = "SpecificClass"; 101*795d594fSAndroid Build Coastguard Worker private static final String METHOD_NAME = "foo"; 102*795d594fSAndroid Build Coastguard Worker 103*795d594fSAndroid Build Coastguard Worker // Native functions. Note that these are implemented in 674-hiddenapi/hiddenapi.cc. appendToBootClassLoader(String dexPath, boolean isCorePlatform)104*795d594fSAndroid Build Coastguard Worker private static native void appendToBootClassLoader(String dexPath, boolean isCorePlatform); init()105*795d594fSAndroid Build Coastguard Worker private static native void init(); 106*795d594fSAndroid Build Coastguard Worker } 107