1*795d594fSAndroid Build Coastguard Worker#!/usr/bin/python3 2*795d594fSAndroid Build Coastguard Worker# 3*795d594fSAndroid Build Coastguard Worker# Copyright (C) 2015 The Android Open Source Project 4*795d594fSAndroid Build Coastguard Worker# 5*795d594fSAndroid Build Coastguard Worker# Licensed under the Apache License, Version 2.0 (the "License"); 6*795d594fSAndroid Build Coastguard Worker# you may not use this file except in compliance with the License. 7*795d594fSAndroid Build Coastguard Worker# You may obtain a copy of the License at 8*795d594fSAndroid Build Coastguard Worker# 9*795d594fSAndroid Build Coastguard Worker# http://www.apache.org/licenses/LICENSE-2.0 10*795d594fSAndroid Build Coastguard Worker# 11*795d594fSAndroid Build Coastguard Worker# Unless required by applicable law or agreed to in writing, software 12*795d594fSAndroid Build Coastguard Worker# distributed under the License is distributed on an "AS IS" BASIS, 13*795d594fSAndroid Build Coastguard Worker# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14*795d594fSAndroid Build Coastguard Worker# See the License for the specific language governing permissions and 15*795d594fSAndroid Build Coastguard Worker# limitations under the License. 16*795d594fSAndroid Build Coastguard Worker 17*795d594fSAndroid Build Coastguard Worker""" 18*795d594fSAndroid Build Coastguard WorkerGenerate Smali test files for test 967. 19*795d594fSAndroid Build Coastguard Worker""" 20*795d594fSAndroid Build Coastguard Worker 21*795d594fSAndroid Build Coastguard Workerimport os 22*795d594fSAndroid Build Coastguard Workerimport sys 23*795d594fSAndroid Build Coastguard Workerfrom pathlib import Path 24*795d594fSAndroid Build Coastguard Worker 25*795d594fSAndroid Build Coastguard WorkerBUILD_TOP = os.getenv("ANDROID_BUILD_TOP") 26*795d594fSAndroid Build Coastguard Workerif BUILD_TOP is None: 27*795d594fSAndroid Build Coastguard Worker print("ANDROID_BUILD_TOP not set. Please run build/envsetup.sh", file=sys.stderr) 28*795d594fSAndroid Build Coastguard Worker sys.exit(1) 29*795d594fSAndroid Build Coastguard Worker 30*795d594fSAndroid Build Coastguard Worker# Allow us to import utils and mixins. 31*795d594fSAndroid Build Coastguard Workersys.path.append(str(Path(BUILD_TOP)/"art"/"test"/"utils"/"python")) 32*795d594fSAndroid Build Coastguard Worker 33*795d594fSAndroid Build Coastguard Workerfrom testgen.utils import get_copyright, subtree_sizes, gensym, filter_blanks 34*795d594fSAndroid Build Coastguard Workerimport testgen.mixins as mixins 35*795d594fSAndroid Build Coastguard Worker 36*795d594fSAndroid Build Coastguard Workerfrom enum import Enum 37*795d594fSAndroid Build Coastguard Workerfrom functools import total_ordering 38*795d594fSAndroid Build Coastguard Workerimport itertools 39*795d594fSAndroid Build Coastguard Workerimport string 40*795d594fSAndroid Build Coastguard Worker 41*795d594fSAndroid Build Coastguard Worker# The max depth the type tree can have. 42*795d594fSAndroid Build Coastguard WorkerMAX_IFACE_DEPTH = 3 43*795d594fSAndroid Build Coastguard Worker 44*795d594fSAndroid Build Coastguard Workerclass MainClass(mixins.DumpMixin, mixins.Named, mixins.SmaliFileMixin): 45*795d594fSAndroid Build Coastguard Worker """ 46*795d594fSAndroid Build Coastguard Worker A Main.smali file containing the Main class and the main function. It will run 47*795d594fSAndroid Build Coastguard Worker all the test functions we have. 48*795d594fSAndroid Build Coastguard Worker """ 49*795d594fSAndroid Build Coastguard Worker 50*795d594fSAndroid Build Coastguard Worker MAIN_CLASS_TEMPLATE = """{copyright} 51*795d594fSAndroid Build Coastguard Worker 52*795d594fSAndroid Build Coastguard Worker.class public LMain; 53*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object; 54*795d594fSAndroid Build Coastguard Worker 55*795d594fSAndroid Build Coastguard Worker# class Main {{ 56*795d594fSAndroid Build Coastguard Worker 57*795d594fSAndroid Build Coastguard Worker.method public constructor <init>()V 58*795d594fSAndroid Build Coastguard Worker .registers 1 59*795d594fSAndroid Build Coastguard Worker invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V 60*795d594fSAndroid Build Coastguard Worker return-void 61*795d594fSAndroid Build Coastguard Worker.end method 62*795d594fSAndroid Build Coastguard Worker 63*795d594fSAndroid Build Coastguard Worker{test_funcs} 64*795d594fSAndroid Build Coastguard Worker 65*795d594fSAndroid Build Coastguard Worker{main_func} 66*795d594fSAndroid Build Coastguard Worker 67*795d594fSAndroid Build Coastguard Worker# }} 68*795d594fSAndroid Build Coastguard Worker""" 69*795d594fSAndroid Build Coastguard Worker 70*795d594fSAndroid Build Coastguard Worker MAIN_FUNCTION_TEMPLATE = """ 71*795d594fSAndroid Build Coastguard Worker# public static void main(String[] args) {{ 72*795d594fSAndroid Build Coastguard Worker.method public static main([Ljava/lang/String;)V 73*795d594fSAndroid Build Coastguard Worker .locals 0 74*795d594fSAndroid Build Coastguard Worker 75*795d594fSAndroid Build Coastguard Worker {test_group_invoke} 76*795d594fSAndroid Build Coastguard Worker 77*795d594fSAndroid Build Coastguard Worker return-void 78*795d594fSAndroid Build Coastguard Worker.end method 79*795d594fSAndroid Build Coastguard Worker# }} 80*795d594fSAndroid Build Coastguard Worker""" 81*795d594fSAndroid Build Coastguard Worker 82*795d594fSAndroid Build Coastguard Worker TEST_GROUP_INVOKE_TEMPLATE = """ 83*795d594fSAndroid Build Coastguard Worker# {test_name}(); 84*795d594fSAndroid Build Coastguard Worker invoke-static {{}}, {test_name}()V 85*795d594fSAndroid Build Coastguard Worker""" 86*795d594fSAndroid Build Coastguard Worker 87*795d594fSAndroid Build Coastguard Worker def __init__(self): 88*795d594fSAndroid Build Coastguard Worker """ 89*795d594fSAndroid Build Coastguard Worker Initialize this MainClass. We start out with no tests. 90*795d594fSAndroid Build Coastguard Worker """ 91*795d594fSAndroid Build Coastguard Worker self.tests = set() 92*795d594fSAndroid Build Coastguard Worker 93*795d594fSAndroid Build Coastguard Worker def get_expected(self): 94*795d594fSAndroid Build Coastguard Worker """ 95*795d594fSAndroid Build Coastguard Worker Get the expected output of this test. 96*795d594fSAndroid Build Coastguard Worker """ 97*795d594fSAndroid Build Coastguard Worker all_tests = sorted(self.tests) 98*795d594fSAndroid Build Coastguard Worker return filter_blanks("\n".join(a.get_expected() for a in all_tests)) 99*795d594fSAndroid Build Coastguard Worker 100*795d594fSAndroid Build Coastguard Worker def add_test(self, ty): 101*795d594fSAndroid Build Coastguard Worker """ 102*795d594fSAndroid Build Coastguard Worker Add a test for the concrete type 'ty' 103*795d594fSAndroid Build Coastguard Worker """ 104*795d594fSAndroid Build Coastguard Worker self.tests.add(Func(ty)) 105*795d594fSAndroid Build Coastguard Worker 106*795d594fSAndroid Build Coastguard Worker def get_name(self): 107*795d594fSAndroid Build Coastguard Worker """ 108*795d594fSAndroid Build Coastguard Worker Get the name of this class 109*795d594fSAndroid Build Coastguard Worker """ 110*795d594fSAndroid Build Coastguard Worker return "Main" 111*795d594fSAndroid Build Coastguard Worker 112*795d594fSAndroid Build Coastguard Worker def __str__(self): 113*795d594fSAndroid Build Coastguard Worker """ 114*795d594fSAndroid Build Coastguard Worker Print the MainClass smali code. 115*795d594fSAndroid Build Coastguard Worker """ 116*795d594fSAndroid Build Coastguard Worker all_tests = sorted(self.tests) 117*795d594fSAndroid Build Coastguard Worker test_invoke = "" 118*795d594fSAndroid Build Coastguard Worker test_funcs = "" 119*795d594fSAndroid Build Coastguard Worker for t in all_tests: 120*795d594fSAndroid Build Coastguard Worker test_funcs += str(t) 121*795d594fSAndroid Build Coastguard Worker for t in all_tests: 122*795d594fSAndroid Build Coastguard Worker test_invoke += self.TEST_GROUP_INVOKE_TEMPLATE.format(test_name=t.get_name()) 123*795d594fSAndroid Build Coastguard Worker main_func = self.MAIN_FUNCTION_TEMPLATE.format(test_group_invoke=test_invoke) 124*795d594fSAndroid Build Coastguard Worker 125*795d594fSAndroid Build Coastguard Worker return self.MAIN_CLASS_TEMPLATE.format(copyright = get_copyright("smali"), 126*795d594fSAndroid Build Coastguard Worker test_funcs = test_funcs, 127*795d594fSAndroid Build Coastguard Worker main_func = main_func) 128*795d594fSAndroid Build Coastguard Worker 129*795d594fSAndroid Build Coastguard Workerclass Func(mixins.Named, mixins.NameComparableMixin): 130*795d594fSAndroid Build Coastguard Worker """ 131*795d594fSAndroid Build Coastguard Worker A function that tests the functionality of a concrete type. Should only be 132*795d594fSAndroid Build Coastguard Worker constructed by MainClass.add_test. 133*795d594fSAndroid Build Coastguard Worker """ 134*795d594fSAndroid Build Coastguard Worker 135*795d594fSAndroid Build Coastguard Worker TEST_FUNCTION_TEMPLATE = """ 136*795d594fSAndroid Build Coastguard Worker# public static void {fname}() {{ 137*795d594fSAndroid Build Coastguard Worker# {farg} v = null; 138*795d594fSAndroid Build Coastguard Worker# try {{ 139*795d594fSAndroid Build Coastguard Worker# v = new {farg}(); 140*795d594fSAndroid Build Coastguard Worker# }} catch (Throwable e) {{ 141*795d594fSAndroid Build Coastguard Worker# System.out.println("Unexpected error occurred which creating {farg} instance"); 142*795d594fSAndroid Build Coastguard Worker# e.printStackTrace(System.out); 143*795d594fSAndroid Build Coastguard Worker# return; 144*795d594fSAndroid Build Coastguard Worker# }} 145*795d594fSAndroid Build Coastguard Worker# try {{ 146*795d594fSAndroid Build Coastguard Worker# System.out.printf("{tree} calls %s\\n", v.getName()); 147*795d594fSAndroid Build Coastguard Worker# return; 148*795d594fSAndroid Build Coastguard Worker# }} catch (AbstractMethodError e) {{ 149*795d594fSAndroid Build Coastguard Worker# System.out.println("{tree} threw AbstractMethodError"); 150*795d594fSAndroid Build Coastguard Worker# }} catch (NoSuchMethodError e) {{ 151*795d594fSAndroid Build Coastguard Worker# System.out.println("{tree} threw NoSuchMethodError"); 152*795d594fSAndroid Build Coastguard Worker# }} catch (IncompatibleClassChangeError e) {{ 153*795d594fSAndroid Build Coastguard Worker# System.out.println("{tree} threw IncompatibleClassChangeError"); 154*795d594fSAndroid Build Coastguard Worker# }} catch (Throwable e) {{ 155*795d594fSAndroid Build Coastguard Worker# e.printStackTrace(System.out); 156*795d594fSAndroid Build Coastguard Worker# return; 157*795d594fSAndroid Build Coastguard Worker# }} 158*795d594fSAndroid Build Coastguard Worker# }} 159*795d594fSAndroid Build Coastguard Worker.method public static {fname}()V 160*795d594fSAndroid Build Coastguard Worker .locals 7 161*795d594fSAndroid Build Coastguard Worker sget-object v4, Ljava/lang/System;->out:Ljava/io/PrintStream; 162*795d594fSAndroid Build Coastguard Worker 163*795d594fSAndroid Build Coastguard Worker :new_{fname}_try_start 164*795d594fSAndroid Build Coastguard Worker new-instance v0, L{farg}; 165*795d594fSAndroid Build Coastguard Worker invoke-direct {{v0}}, L{farg};-><init>()V 166*795d594fSAndroid Build Coastguard Worker goto :call_{fname}_try_start 167*795d594fSAndroid Build Coastguard Worker :new_{fname}_try_end 168*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/Throwable; {{:new_{fname}_try_start .. :new_{fname}_try_end}} :new_error_{fname}_start 169*795d594fSAndroid Build Coastguard Worker :new_error_{fname}_start 170*795d594fSAndroid Build Coastguard Worker move-exception v6 171*795d594fSAndroid Build Coastguard Worker const-string v5, "Unexpected error occurred which creating {farg} instance" 172*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 173*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v6,v4}}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V 174*795d594fSAndroid Build Coastguard Worker return-void 175*795d594fSAndroid Build Coastguard Worker :call_{fname}_try_start 176*795d594fSAndroid Build Coastguard Worker const/4 v1, 1 177*795d594fSAndroid Build Coastguard Worker new-array v2,v1, [Ljava/lang/Object; 178*795d594fSAndroid Build Coastguard Worker const/4 v1, 0 179*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v0}}, L{farg};->getName()Ljava/lang/String; 180*795d594fSAndroid Build Coastguard Worker move-result-object v3 181*795d594fSAndroid Build Coastguard Worker aput-object v3,v2,v1 182*795d594fSAndroid Build Coastguard Worker 183*795d594fSAndroid Build Coastguard Worker const-string v5, "{tree} calls %s\\n" 184*795d594fSAndroid Build Coastguard Worker 185*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v4,v5,v2}}, Ljava/io/PrintStream;->printf(Ljava/lang/String;[Ljava/lang/Object;)Ljava/io/PrintStream; 186*795d594fSAndroid Build Coastguard Worker return-void 187*795d594fSAndroid Build Coastguard Worker :call_{fname}_try_end 188*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/AbstractMethodError; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :AME_{fname}_start 189*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/NoSuchMethodError; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :NSME_{fname}_start 190*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/IncompatibleClassChangeError; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :ICCE_{fname}_start 191*795d594fSAndroid Build Coastguard Worker .catch Ljava/lang/Throwable; {{:call_{fname}_try_start .. :call_{fname}_try_end}} :error_{fname}_start 192*795d594fSAndroid Build Coastguard Worker :AME_{fname}_start 193*795d594fSAndroid Build Coastguard Worker const-string v5, "{tree} threw AbstractMethodError" 194*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 195*795d594fSAndroid Build Coastguard Worker return-void 196*795d594fSAndroid Build Coastguard Worker :NSME_{fname}_start 197*795d594fSAndroid Build Coastguard Worker const-string v5, "{tree} threw NoSuchMethodError" 198*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 199*795d594fSAndroid Build Coastguard Worker return-void 200*795d594fSAndroid Build Coastguard Worker :ICCE_{fname}_start 201*795d594fSAndroid Build Coastguard Worker const-string v5, "{tree} threw IncompatibleClassChangeError" 202*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v4,v5}}, Ljava/io/PrintStream;->println(Ljava/lang/Object;)V 203*795d594fSAndroid Build Coastguard Worker return-void 204*795d594fSAndroid Build Coastguard Worker :error_{fname}_start 205*795d594fSAndroid Build Coastguard Worker move-exception v6 206*795d594fSAndroid Build Coastguard Worker invoke-virtual {{v6,v4}}, Ljava/lang/Throwable;->printStackTrace(Ljava/io/PrintStream;)V 207*795d594fSAndroid Build Coastguard Worker return-void 208*795d594fSAndroid Build Coastguard Worker.end method 209*795d594fSAndroid Build Coastguard Worker""" 210*795d594fSAndroid Build Coastguard Worker 211*795d594fSAndroid Build Coastguard Worker NSME_RESULT_TEMPLATE = "{tree} threw NoSuchMethodError" 212*795d594fSAndroid Build Coastguard Worker ICCE_RESULT_TEMPLATE = "{tree} threw IncompatibleClassChangeError" 213*795d594fSAndroid Build Coastguard Worker AME_RESULT_TEMPLATE = "{tree} threw AbstractMethodError" 214*795d594fSAndroid Build Coastguard Worker NORMAL_RESULT_TEMPLATE = "{tree} calls {result}" 215*795d594fSAndroid Build Coastguard Worker 216*795d594fSAndroid Build Coastguard Worker def __init__(self, farg): 217*795d594fSAndroid Build Coastguard Worker """ 218*795d594fSAndroid Build Coastguard Worker Initialize a test function for the given argument 219*795d594fSAndroid Build Coastguard Worker """ 220*795d594fSAndroid Build Coastguard Worker self.farg = farg 221*795d594fSAndroid Build Coastguard Worker 222*795d594fSAndroid Build Coastguard Worker def get_expected(self): 223*795d594fSAndroid Build Coastguard Worker """ 224*795d594fSAndroid Build Coastguard Worker Get the expected output calling this function. 225*795d594fSAndroid Build Coastguard Worker """ 226*795d594fSAndroid Build Coastguard Worker exp = self.farg.get_called() 227*795d594fSAndroid Build Coastguard Worker if exp.is_empty(): 228*795d594fSAndroid Build Coastguard Worker return self.NSME_RESULT_TEMPLATE.format(tree = self.farg.get_tree()) 229*795d594fSAndroid Build Coastguard Worker elif exp.is_abstract(): 230*795d594fSAndroid Build Coastguard Worker return self.AME_RESULT_TEMPLATE.format(tree = self.farg.get_tree()) 231*795d594fSAndroid Build Coastguard Worker elif exp.is_conflict(): 232*795d594fSAndroid Build Coastguard Worker return self.ICCE_RESULT_TEMPLATE.format(tree = self.farg.get_tree()) 233*795d594fSAndroid Build Coastguard Worker else: 234*795d594fSAndroid Build Coastguard Worker assert exp.is_default() 235*795d594fSAndroid Build Coastguard Worker return self.NORMAL_RESULT_TEMPLATE.format(tree = self.farg.get_tree(), 236*795d594fSAndroid Build Coastguard Worker result = exp.get_tree()) 237*795d594fSAndroid Build Coastguard Worker 238*795d594fSAndroid Build Coastguard Worker def get_name(self): 239*795d594fSAndroid Build Coastguard Worker """ 240*795d594fSAndroid Build Coastguard Worker Get the name of this function 241*795d594fSAndroid Build Coastguard Worker """ 242*795d594fSAndroid Build Coastguard Worker return "TEST_FUNC_{}".format(self.farg.get_name()) 243*795d594fSAndroid Build Coastguard Worker 244*795d594fSAndroid Build Coastguard Worker def __str__(self): 245*795d594fSAndroid Build Coastguard Worker """ 246*795d594fSAndroid Build Coastguard Worker Print the smali code of this function. 247*795d594fSAndroid Build Coastguard Worker """ 248*795d594fSAndroid Build Coastguard Worker return self.TEST_FUNCTION_TEMPLATE.format(tree = self.farg.get_tree(), 249*795d594fSAndroid Build Coastguard Worker fname = self.get_name(), 250*795d594fSAndroid Build Coastguard Worker farg = self.farg.get_name()) 251*795d594fSAndroid Build Coastguard Worker 252*795d594fSAndroid Build Coastguard Workerclass TestClass(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): 253*795d594fSAndroid Build Coastguard Worker """ 254*795d594fSAndroid Build Coastguard Worker A class that will be instantiated to test default method resolution order. 255*795d594fSAndroid Build Coastguard Worker """ 256*795d594fSAndroid Build Coastguard Worker 257*795d594fSAndroid Build Coastguard Worker TEST_CLASS_TEMPLATE = """{copyright} 258*795d594fSAndroid Build Coastguard Worker 259*795d594fSAndroid Build Coastguard Worker.class public L{class_name}; 260*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object; 261*795d594fSAndroid Build Coastguard Worker.implements L{iface_name}; 262*795d594fSAndroid Build Coastguard Worker 263*795d594fSAndroid Build Coastguard Worker# public class {class_name} implements {iface_name} {{ 264*795d594fSAndroid Build Coastguard Worker 265*795d594fSAndroid Build Coastguard Worker.method public constructor <init>()V 266*795d594fSAndroid Build Coastguard Worker .registers 1 267*795d594fSAndroid Build Coastguard Worker invoke-direct {{p0}}, Ljava/lang/Object;-><init>()V 268*795d594fSAndroid Build Coastguard Worker return-void 269*795d594fSAndroid Build Coastguard Worker.end method 270*795d594fSAndroid Build Coastguard Worker 271*795d594fSAndroid Build Coastguard Worker{funcs} 272*795d594fSAndroid Build Coastguard Worker 273*795d594fSAndroid Build Coastguard Worker# }} 274*795d594fSAndroid Build Coastguard Worker""" 275*795d594fSAndroid Build Coastguard Worker 276*795d594fSAndroid Build Coastguard Worker def __init__(self, iface): 277*795d594fSAndroid Build Coastguard Worker """ 278*795d594fSAndroid Build Coastguard Worker Initialize this test class which implements the given interface 279*795d594fSAndroid Build Coastguard Worker """ 280*795d594fSAndroid Build Coastguard Worker self.iface = iface 281*795d594fSAndroid Build Coastguard Worker self.class_name = "CLASS_"+gensym() 282*795d594fSAndroid Build Coastguard Worker 283*795d594fSAndroid Build Coastguard Worker def get_name(self): 284*795d594fSAndroid Build Coastguard Worker """ 285*795d594fSAndroid Build Coastguard Worker Get the name of this class 286*795d594fSAndroid Build Coastguard Worker """ 287*795d594fSAndroid Build Coastguard Worker return self.class_name 288*795d594fSAndroid Build Coastguard Worker 289*795d594fSAndroid Build Coastguard Worker def get_tree(self): 290*795d594fSAndroid Build Coastguard Worker """ 291*795d594fSAndroid Build Coastguard Worker Print out a representation of the type tree of this class 292*795d594fSAndroid Build Coastguard Worker """ 293*795d594fSAndroid Build Coastguard Worker return "[{class_name} {iface_tree}]".format(class_name = self.class_name, 294*795d594fSAndroid Build Coastguard Worker iface_tree = self.iface.get_tree()) 295*795d594fSAndroid Build Coastguard Worker 296*795d594fSAndroid Build Coastguard Worker def __iter__(self): 297*795d594fSAndroid Build Coastguard Worker """ 298*795d594fSAndroid Build Coastguard Worker Step through all interfaces implemented transitively by this class 299*795d594fSAndroid Build Coastguard Worker """ 300*795d594fSAndroid Build Coastguard Worker yield self.iface 301*795d594fSAndroid Build Coastguard Worker yield from self.iface 302*795d594fSAndroid Build Coastguard Worker 303*795d594fSAndroid Build Coastguard Worker def get_called(self): 304*795d594fSAndroid Build Coastguard Worker """ 305*795d594fSAndroid Build Coastguard Worker Returns the interface that will be called when the method on this class is invoked or 306*795d594fSAndroid Build Coastguard Worker CONFLICT_TYPE if there is no interface that will be called. 307*795d594fSAndroid Build Coastguard Worker """ 308*795d594fSAndroid Build Coastguard Worker return self.iface.get_called() 309*795d594fSAndroid Build Coastguard Worker 310*795d594fSAndroid Build Coastguard Worker def __str__(self): 311*795d594fSAndroid Build Coastguard Worker """ 312*795d594fSAndroid Build Coastguard Worker Print the smali code of this class. 313*795d594fSAndroid Build Coastguard Worker """ 314*795d594fSAndroid Build Coastguard Worker return self.TEST_CLASS_TEMPLATE.format(copyright = get_copyright('smali'), 315*795d594fSAndroid Build Coastguard Worker iface_name = self.iface.get_name(), 316*795d594fSAndroid Build Coastguard Worker tree = self.get_tree(), 317*795d594fSAndroid Build Coastguard Worker class_name = self.class_name, 318*795d594fSAndroid Build Coastguard Worker funcs = "") 319*795d594fSAndroid Build Coastguard Worker 320*795d594fSAndroid Build Coastguard Workerclass InterfaceType(Enum): 321*795d594fSAndroid Build Coastguard Worker """ 322*795d594fSAndroid Build Coastguard Worker An enumeration of all the different types of interfaces we can have. 323*795d594fSAndroid Build Coastguard Worker 324*795d594fSAndroid Build Coastguard Worker default: It has a default method 325*795d594fSAndroid Build Coastguard Worker abstract: It has a method declared but not defined 326*795d594fSAndroid Build Coastguard Worker empty: It does not have the method 327*795d594fSAndroid Build Coastguard Worker """ 328*795d594fSAndroid Build Coastguard Worker default = 0 329*795d594fSAndroid Build Coastguard Worker abstract = 1 330*795d594fSAndroid Build Coastguard Worker empty = 2 331*795d594fSAndroid Build Coastguard Worker 332*795d594fSAndroid Build Coastguard Worker def get_suffix(self): 333*795d594fSAndroid Build Coastguard Worker if self == InterfaceType.default: 334*795d594fSAndroid Build Coastguard Worker return "_DEFAULT" 335*795d594fSAndroid Build Coastguard Worker elif self == InterfaceType.abstract: 336*795d594fSAndroid Build Coastguard Worker return "_ABSTRACT" 337*795d594fSAndroid Build Coastguard Worker elif self == InterfaceType.empty: 338*795d594fSAndroid Build Coastguard Worker return "_EMPTY" 339*795d594fSAndroid Build Coastguard Worker else: 340*795d594fSAndroid Build Coastguard Worker raise TypeError("Interface type had illegal value.") 341*795d594fSAndroid Build Coastguard Worker 342*795d594fSAndroid Build Coastguard Workerclass ConflictInterface: 343*795d594fSAndroid Build Coastguard Worker """ 344*795d594fSAndroid Build Coastguard Worker A singleton representing a conflict of default methods. 345*795d594fSAndroid Build Coastguard Worker """ 346*795d594fSAndroid Build Coastguard Worker 347*795d594fSAndroid Build Coastguard Worker def is_conflict(self): 348*795d594fSAndroid Build Coastguard Worker """ 349*795d594fSAndroid Build Coastguard Worker Returns true if this is a conflict interface and calling the method on this interface will 350*795d594fSAndroid Build Coastguard Worker result in an IncompatibleClassChangeError. 351*795d594fSAndroid Build Coastguard Worker """ 352*795d594fSAndroid Build Coastguard Worker return True 353*795d594fSAndroid Build Coastguard Worker 354*795d594fSAndroid Build Coastguard Worker def is_abstract(self): 355*795d594fSAndroid Build Coastguard Worker """ 356*795d594fSAndroid Build Coastguard Worker Returns true if this is an abstract interface and calling the method on this interface will 357*795d594fSAndroid Build Coastguard Worker result in an AbstractMethodError. 358*795d594fSAndroid Build Coastguard Worker """ 359*795d594fSAndroid Build Coastguard Worker return False 360*795d594fSAndroid Build Coastguard Worker 361*795d594fSAndroid Build Coastguard Worker def is_empty(self): 362*795d594fSAndroid Build Coastguard Worker """ 363*795d594fSAndroid Build Coastguard Worker Returns true if this is an abstract interface and calling the method on this interface will 364*795d594fSAndroid Build Coastguard Worker result in a NoSuchMethodError. 365*795d594fSAndroid Build Coastguard Worker """ 366*795d594fSAndroid Build Coastguard Worker return False 367*795d594fSAndroid Build Coastguard Worker 368*795d594fSAndroid Build Coastguard Worker def is_default(self): 369*795d594fSAndroid Build Coastguard Worker """ 370*795d594fSAndroid Build Coastguard Worker Returns true if this is a default interface and calling the method on this interface will 371*795d594fSAndroid Build Coastguard Worker result in a method actually being called. 372*795d594fSAndroid Build Coastguard Worker """ 373*795d594fSAndroid Build Coastguard Worker return False 374*795d594fSAndroid Build Coastguard Worker 375*795d594fSAndroid Build Coastguard WorkerCONFLICT_TYPE = ConflictInterface() 376*795d594fSAndroid Build Coastguard Worker 377*795d594fSAndroid Build Coastguard Workerclass TestInterface(mixins.DumpMixin, mixins.Named, mixins.NameComparableMixin, mixins.SmaliFileMixin): 378*795d594fSAndroid Build Coastguard Worker """ 379*795d594fSAndroid Build Coastguard Worker An interface that will be used to test default method resolution order. 380*795d594fSAndroid Build Coastguard Worker """ 381*795d594fSAndroid Build Coastguard Worker 382*795d594fSAndroid Build Coastguard Worker TEST_INTERFACE_TEMPLATE = """{copyright} 383*795d594fSAndroid Build Coastguard Worker.class public abstract interface L{class_name}; 384*795d594fSAndroid Build Coastguard Worker.super Ljava/lang/Object; 385*795d594fSAndroid Build Coastguard Worker{implements_spec} 386*795d594fSAndroid Build Coastguard Worker 387*795d594fSAndroid Build Coastguard Worker# public interface {class_name} {extends} {ifaces} {{ 388*795d594fSAndroid Build Coastguard Worker 389*795d594fSAndroid Build Coastguard Worker{funcs} 390*795d594fSAndroid Build Coastguard Worker 391*795d594fSAndroid Build Coastguard Worker# }} 392*795d594fSAndroid Build Coastguard Worker""" 393*795d594fSAndroid Build Coastguard Worker 394*795d594fSAndroid Build Coastguard Worker DEFAULT_FUNC_TEMPLATE = """ 395*795d594fSAndroid Build Coastguard Worker# public default String getName() {{ 396*795d594fSAndroid Build Coastguard Worker# return "{tree}"; 397*795d594fSAndroid Build Coastguard Worker# }} 398*795d594fSAndroid Build Coastguard Worker.method public getName()Ljava/lang/String; 399*795d594fSAndroid Build Coastguard Worker .locals 1 400*795d594fSAndroid Build Coastguard Worker const-string v0, "{tree}" 401*795d594fSAndroid Build Coastguard Worker return-object v0 402*795d594fSAndroid Build Coastguard Worker.end method 403*795d594fSAndroid Build Coastguard Worker""" 404*795d594fSAndroid Build Coastguard Worker 405*795d594fSAndroid Build Coastguard Worker ABSTRACT_FUNC_TEMPLATE = """ 406*795d594fSAndroid Build Coastguard Worker# public String getName(); 407*795d594fSAndroid Build Coastguard Worker.method public abstract getName()Ljava/lang/String; 408*795d594fSAndroid Build Coastguard Worker.end method 409*795d594fSAndroid Build Coastguard Worker""" 410*795d594fSAndroid Build Coastguard Worker 411*795d594fSAndroid Build Coastguard Worker EMPTY_FUNC_TEMPLATE = """""" 412*795d594fSAndroid Build Coastguard Worker 413*795d594fSAndroid Build Coastguard Worker IMPLEMENTS_TEMPLATE = """ 414*795d594fSAndroid Build Coastguard Worker.implements L{iface_name}; 415*795d594fSAndroid Build Coastguard Worker""" 416*795d594fSAndroid Build Coastguard Worker 417*795d594fSAndroid Build Coastguard Worker def __init__(self, ifaces, iface_type, full_name = None): 418*795d594fSAndroid Build Coastguard Worker """ 419*795d594fSAndroid Build Coastguard Worker Initialize interface with the given super-interfaces 420*795d594fSAndroid Build Coastguard Worker """ 421*795d594fSAndroid Build Coastguard Worker self.ifaces = sorted(ifaces) 422*795d594fSAndroid Build Coastguard Worker self.iface_type = iface_type 423*795d594fSAndroid Build Coastguard Worker if full_name is None: 424*795d594fSAndroid Build Coastguard Worker end = self.iface_type.get_suffix() 425*795d594fSAndroid Build Coastguard Worker self.class_name = "INTERFACE_"+gensym()+end 426*795d594fSAndroid Build Coastguard Worker else: 427*795d594fSAndroid Build Coastguard Worker self.class_name = full_name 428*795d594fSAndroid Build Coastguard Worker 429*795d594fSAndroid Build Coastguard Worker def get_specific_version(self, v): 430*795d594fSAndroid Build Coastguard Worker """ 431*795d594fSAndroid Build Coastguard Worker Returns a copy of this interface of the given type for use in partial compilation. 432*795d594fSAndroid Build Coastguard Worker """ 433*795d594fSAndroid Build Coastguard Worker return TestInterface(self.ifaces, v, full_name = self.class_name) 434*795d594fSAndroid Build Coastguard Worker 435*795d594fSAndroid Build Coastguard Worker def get_super_types(self): 436*795d594fSAndroid Build Coastguard Worker """ 437*795d594fSAndroid Build Coastguard Worker Returns a set of all the supertypes of this interface 438*795d594fSAndroid Build Coastguard Worker """ 439*795d594fSAndroid Build Coastguard Worker return set(i2 for i2 in self) 440*795d594fSAndroid Build Coastguard Worker 441*795d594fSAndroid Build Coastguard Worker def is_conflict(self): 442*795d594fSAndroid Build Coastguard Worker """ 443*795d594fSAndroid Build Coastguard Worker Returns true if this is a conflict interface and calling the method on this interface will 444*795d594fSAndroid Build Coastguard Worker result in an IncompatibleClassChangeError. 445*795d594fSAndroid Build Coastguard Worker """ 446*795d594fSAndroid Build Coastguard Worker return False 447*795d594fSAndroid Build Coastguard Worker 448*795d594fSAndroid Build Coastguard Worker def is_abstract(self): 449*795d594fSAndroid Build Coastguard Worker """ 450*795d594fSAndroid Build Coastguard Worker Returns true if this is an abstract interface and calling the method on this interface will 451*795d594fSAndroid Build Coastguard Worker result in an AbstractMethodError. 452*795d594fSAndroid Build Coastguard Worker """ 453*795d594fSAndroid Build Coastguard Worker return self.iface_type == InterfaceType.abstract 454*795d594fSAndroid Build Coastguard Worker 455*795d594fSAndroid Build Coastguard Worker def is_empty(self): 456*795d594fSAndroid Build Coastguard Worker """ 457*795d594fSAndroid Build Coastguard Worker Returns true if this is an abstract interface and calling the method on this interface will 458*795d594fSAndroid Build Coastguard Worker result in a NoSuchMethodError. 459*795d594fSAndroid Build Coastguard Worker """ 460*795d594fSAndroid Build Coastguard Worker return self.iface_type == InterfaceType.empty 461*795d594fSAndroid Build Coastguard Worker 462*795d594fSAndroid Build Coastguard Worker def is_default(self): 463*795d594fSAndroid Build Coastguard Worker """ 464*795d594fSAndroid Build Coastguard Worker Returns true if this is a default interface and calling the method on this interface will 465*795d594fSAndroid Build Coastguard Worker result in a method actually being called. 466*795d594fSAndroid Build Coastguard Worker """ 467*795d594fSAndroid Build Coastguard Worker return self.iface_type == InterfaceType.default 468*795d594fSAndroid Build Coastguard Worker 469*795d594fSAndroid Build Coastguard Worker def get_called(self): 470*795d594fSAndroid Build Coastguard Worker """ 471*795d594fSAndroid Build Coastguard Worker Returns the interface that will be called when the method on this class is invoked or 472*795d594fSAndroid Build Coastguard Worker CONFLICT_TYPE if there is no interface that will be called. 473*795d594fSAndroid Build Coastguard Worker """ 474*795d594fSAndroid Build Coastguard Worker if not self.is_empty() or len(self.ifaces) == 0: 475*795d594fSAndroid Build Coastguard Worker return self 476*795d594fSAndroid Build Coastguard Worker else: 477*795d594fSAndroid Build Coastguard Worker best = self 478*795d594fSAndroid Build Coastguard Worker for super_iface in self.ifaces: 479*795d594fSAndroid Build Coastguard Worker super_best = super_iface.get_called() 480*795d594fSAndroid Build Coastguard Worker if super_best.is_conflict(): 481*795d594fSAndroid Build Coastguard Worker return CONFLICT_TYPE 482*795d594fSAndroid Build Coastguard Worker elif best.is_default(): 483*795d594fSAndroid Build Coastguard Worker if super_best.is_default(): 484*795d594fSAndroid Build Coastguard Worker return CONFLICT_TYPE 485*795d594fSAndroid Build Coastguard Worker elif best.is_abstract(): 486*795d594fSAndroid Build Coastguard Worker if super_best.is_default(): 487*795d594fSAndroid Build Coastguard Worker best = super_best 488*795d594fSAndroid Build Coastguard Worker else: 489*795d594fSAndroid Build Coastguard Worker assert best.is_empty() 490*795d594fSAndroid Build Coastguard Worker best = super_best 491*795d594fSAndroid Build Coastguard Worker return best 492*795d594fSAndroid Build Coastguard Worker 493*795d594fSAndroid Build Coastguard Worker def get_name(self): 494*795d594fSAndroid Build Coastguard Worker """ 495*795d594fSAndroid Build Coastguard Worker Get the name of this class 496*795d594fSAndroid Build Coastguard Worker """ 497*795d594fSAndroid Build Coastguard Worker return self.class_name 498*795d594fSAndroid Build Coastguard Worker 499*795d594fSAndroid Build Coastguard Worker def get_tree(self): 500*795d594fSAndroid Build Coastguard Worker """ 501*795d594fSAndroid Build Coastguard Worker Print out a representation of the type tree of this class 502*795d594fSAndroid Build Coastguard Worker """ 503*795d594fSAndroid Build Coastguard Worker return "[{class_name} {iftree}]".format(class_name = self.get_name(), 504*795d594fSAndroid Build Coastguard Worker iftree = print_tree(self.ifaces)) 505*795d594fSAndroid Build Coastguard Worker 506*795d594fSAndroid Build Coastguard Worker def __iter__(self): 507*795d594fSAndroid Build Coastguard Worker """ 508*795d594fSAndroid Build Coastguard Worker Performs depth-first traversal of the interface tree this interface is the 509*795d594fSAndroid Build Coastguard Worker root of. Does not filter out repeats. 510*795d594fSAndroid Build Coastguard Worker """ 511*795d594fSAndroid Build Coastguard Worker for i in self.ifaces: 512*795d594fSAndroid Build Coastguard Worker yield i 513*795d594fSAndroid Build Coastguard Worker yield from i 514*795d594fSAndroid Build Coastguard Worker 515*795d594fSAndroid Build Coastguard Worker def __str__(self): 516*795d594fSAndroid Build Coastguard Worker """ 517*795d594fSAndroid Build Coastguard Worker Print the smali code of this interface. 518*795d594fSAndroid Build Coastguard Worker """ 519*795d594fSAndroid Build Coastguard Worker s_ifaces = " " 520*795d594fSAndroid Build Coastguard Worker j_ifaces = " " 521*795d594fSAndroid Build Coastguard Worker for i in self.ifaces: 522*795d594fSAndroid Build Coastguard Worker s_ifaces += self.IMPLEMENTS_TEMPLATE.format(iface_name = i.get_name()) 523*795d594fSAndroid Build Coastguard Worker j_ifaces += " {},".format(i.get_name()) 524*795d594fSAndroid Build Coastguard Worker j_ifaces = j_ifaces[0:-1] 525*795d594fSAndroid Build Coastguard Worker if self.is_default(): 526*795d594fSAndroid Build Coastguard Worker funcs = self.DEFAULT_FUNC_TEMPLATE.format(tree = self.get_tree()) 527*795d594fSAndroid Build Coastguard Worker elif self.is_abstract(): 528*795d594fSAndroid Build Coastguard Worker funcs = self.ABSTRACT_FUNC_TEMPLATE.format() 529*795d594fSAndroid Build Coastguard Worker else: 530*795d594fSAndroid Build Coastguard Worker funcs = "" 531*795d594fSAndroid Build Coastguard Worker return self.TEST_INTERFACE_TEMPLATE.format(copyright = get_copyright('smali'), 532*795d594fSAndroid Build Coastguard Worker implements_spec = s_ifaces, 533*795d594fSAndroid Build Coastguard Worker extends = "extends" if len(self.ifaces) else "", 534*795d594fSAndroid Build Coastguard Worker ifaces = j_ifaces, 535*795d594fSAndroid Build Coastguard Worker funcs = funcs, 536*795d594fSAndroid Build Coastguard Worker tree = self.get_tree(), 537*795d594fSAndroid Build Coastguard Worker class_name = self.class_name) 538*795d594fSAndroid Build Coastguard Worker 539*795d594fSAndroid Build Coastguard Workerdef print_tree(ifaces): 540*795d594fSAndroid Build Coastguard Worker """ 541*795d594fSAndroid Build Coastguard Worker Prints a list of iface trees 542*795d594fSAndroid Build Coastguard Worker """ 543*795d594fSAndroid Build Coastguard Worker return " ".join(i.get_tree() for i in ifaces) 544*795d594fSAndroid Build Coastguard Worker 545*795d594fSAndroid Build Coastguard Worker# The deduplicated output of subtree_sizes for each size up to 546*795d594fSAndroid Build Coastguard Worker# MAX_LEAF_IFACE_PER_OBJECT. 547*795d594fSAndroid Build Coastguard WorkerSUBTREES = [set(tuple(sorted(l)) for l in subtree_sizes(i)) 548*795d594fSAndroid Build Coastguard Worker for i in range(MAX_IFACE_DEPTH + 1)] 549*795d594fSAndroid Build Coastguard Worker 550*795d594fSAndroid Build Coastguard Workerdef create_test_classes(): 551*795d594fSAndroid Build Coastguard Worker """ 552*795d594fSAndroid Build Coastguard Worker Yield all the test classes with the different interface trees 553*795d594fSAndroid Build Coastguard Worker """ 554*795d594fSAndroid Build Coastguard Worker for num in range(1, MAX_IFACE_DEPTH + 1): 555*795d594fSAndroid Build Coastguard Worker for iface in create_interface_trees(num): 556*795d594fSAndroid Build Coastguard Worker yield TestClass(iface) 557*795d594fSAndroid Build Coastguard Worker 558*795d594fSAndroid Build Coastguard Workerdef create_interface_trees(num): 559*795d594fSAndroid Build Coastguard Worker """ 560*795d594fSAndroid Build Coastguard Worker Yield all the interface trees up to 'num' depth. 561*795d594fSAndroid Build Coastguard Worker """ 562*795d594fSAndroid Build Coastguard Worker if num == 0: 563*795d594fSAndroid Build Coastguard Worker for iftype in InterfaceType: 564*795d594fSAndroid Build Coastguard Worker yield TestInterface(tuple(), iftype) 565*795d594fSAndroid Build Coastguard Worker return 566*795d594fSAndroid Build Coastguard Worker for split in SUBTREES[num]: 567*795d594fSAndroid Build Coastguard Worker ifaces = [] 568*795d594fSAndroid Build Coastguard Worker for sub in split: 569*795d594fSAndroid Build Coastguard Worker ifaces.append(list(create_interface_trees(sub))) 570*795d594fSAndroid Build Coastguard Worker yield TestInterface(tuple(), InterfaceType.default) 571*795d594fSAndroid Build Coastguard Worker for supers in itertools.product(*ifaces): 572*795d594fSAndroid Build Coastguard Worker for iftype in InterfaceType: 573*795d594fSAndroid Build Coastguard Worker if iftype == InterfaceType.default: 574*795d594fSAndroid Build Coastguard Worker # We can just stop at defaults. We have other tests that a default can override an 575*795d594fSAndroid Build Coastguard Worker # abstract and this cuts down on the number of cases significantly, improving speed of 576*795d594fSAndroid Build Coastguard Worker # this test. 577*795d594fSAndroid Build Coastguard Worker continue 578*795d594fSAndroid Build Coastguard Worker yield TestInterface(supers, iftype) 579*795d594fSAndroid Build Coastguard Worker 580*795d594fSAndroid Build Coastguard Workerdef create_all_test_files(): 581*795d594fSAndroid Build Coastguard Worker """ 582*795d594fSAndroid Build Coastguard Worker Creates all the objects representing the files in this test. They just need to 583*795d594fSAndroid Build Coastguard Worker be dumped. 584*795d594fSAndroid Build Coastguard Worker """ 585*795d594fSAndroid Build Coastguard Worker mc = MainClass() 586*795d594fSAndroid Build Coastguard Worker classes = {mc} 587*795d594fSAndroid Build Coastguard Worker for clazz in create_test_classes(): 588*795d594fSAndroid Build Coastguard Worker classes.add(clazz) 589*795d594fSAndroid Build Coastguard Worker for i in clazz: 590*795d594fSAndroid Build Coastguard Worker classes.add(i) 591*795d594fSAndroid Build Coastguard Worker mc.add_test(clazz) 592*795d594fSAndroid Build Coastguard Worker return mc, classes 593*795d594fSAndroid Build Coastguard Worker 594*795d594fSAndroid Build Coastguard Workerdef main(argv): 595*795d594fSAndroid Build Coastguard Worker smali_dir = Path(argv[1]) 596*795d594fSAndroid Build Coastguard Worker if not smali_dir.exists() or not smali_dir.is_dir(): 597*795d594fSAndroid Build Coastguard Worker print("{} is not a valid smali dir".format(smali_dir), file=sys.stderr) 598*795d594fSAndroid Build Coastguard Worker sys.exit(1) 599*795d594fSAndroid Build Coastguard Worker expected_txt = Path(argv[2]) 600*795d594fSAndroid Build Coastguard Worker mainclass, all_files = create_all_test_files() 601*795d594fSAndroid Build Coastguard Worker with expected_txt.open('w') as out: 602*795d594fSAndroid Build Coastguard Worker print(mainclass.get_expected(), file=out) 603*795d594fSAndroid Build Coastguard Worker for f in all_files: 604*795d594fSAndroid Build Coastguard Worker f.dump(smali_dir) 605*795d594fSAndroid Build Coastguard Worker 606*795d594fSAndroid Build Coastguard Workerif __name__ == '__main__': 607*795d594fSAndroid Build Coastguard Worker main(sys.argv) 608