1 /* 2 * Copyright (C) 2016 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package art; 18 19 import java.lang.reflect.InvocationTargetException; 20 import java.lang.reflect.Method; 21 import java.util.Base64; 22 23 public class Test984 { 24 25 static class Transform { 26 // This method must be 'static' so that when we try to invoke it through a j.l.r.Method we will 27 // simply use the jmethodID directly and not do any lookup in any receiver object. sayHi(Runnable r)28 public static void sayHi(Runnable r) { 29 System.out.println("hello"); 30 r.run(); 31 System.out.println("goodbye"); 32 } 33 } 34 // static class Transform { 35 // public static void sayHi(Runnable r) { 36 // System.out.println("Hello - Transformed"); 37 // r.run(); 38 // System.out.println("Goodbye - Transformed"); 39 // } 40 // } 41 private static final byte[] CLASS_BYTES = Base64.getDecoder().decode( 42 "yv66vgAAADQAKAoACAARCQASABMIABQKABUAFgsAFwAYCAAZBwAbBwAeAQAGPGluaXQ+AQADKClW" + 43 "AQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEABXNheUhpAQAXKExqYXZhL2xhbmcvUnVubmFibGU7" + 44 "KVYBAApTb3VyY2VGaWxlAQAMVGVzdDk4NC5qYXZhDAAJAAoHAB8MACAAIQEAE0hlbGxvIC0gVHJh" + 45 "bnNmb3JtZWQHACIMACMAJAcAJQwAJgAKAQAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkBwAnAQAVYXJ0" + 46 "L1Rlc3Q5ODQkVHJhbnNmb3JtAQAJVHJhbnNmb3JtAQAMSW5uZXJDbGFzc2VzAQAQamF2YS9sYW5n" + 47 "L09iamVjdAEAEGphdmEvbGFuZy9TeXN0ZW0BAANvdXQBABVMamF2YS9pby9QcmludFN0cmVhbTsB" + 48 "ABNqYXZhL2lvL1ByaW50U3RyZWFtAQAHcHJpbnRsbgEAFShMamF2YS9sYW5nL1N0cmluZzspVgEA" + 49 "EmphdmEvbGFuZy9SdW5uYWJsZQEAA3J1bgEAC2FydC9UZXN0OTg0ACAABwAIAAAAAAACAAAACQAK" + 50 "AAEACwAAAB0AAQABAAAABSq3AAGxAAAAAQAMAAAABgABAAAABQAJAA0ADgABAAsAAAA7AAIAAQAA" + 51 "ABeyAAISA7YABCq5AAUBALIAAhIGtgAEsQAAAAEADAAAABIABAAAAAcACAAIAA4ACQAWAAoAAgAP" + 52 "AAAAAgAQAB0AAAAKAAEABwAaABwACA=="); 53 private static final byte[] DEX_BYTES = Base64.getDecoder().decode( 54 "ZGV4CjAzNQB/mxSMAAAAAAAAAAAAAAAAAAAAAAAAAAA8BAAAcAAAAHhWNBIAAAAAAAAAAHgDAAAX" + 55 "AAAAcAAAAAoAAADMAAAAAwAAAPQAAAABAAAAGAEAAAUAAAAgAQAAAQAAAEgBAADUAgAAaAEAAGgB" + 56 "AABwAQAAhwEAAJwBAAC1AQAAxAEAAOgBAAAIAgAAHwIAADMCAABJAgAAXQIAAHECAAB/AgAAigIA" + 57 "AI0CAACRAgAAngIAAKQCAACpAgAAsgIAALcCAAC+AgAAAwAAAAQAAAAFAAAABgAAAAcAAAAIAAAA" + 58 "CQAAAAoAAAALAAAADgAAAA4AAAAJAAAAAAAAAA8AAAAJAAAAyAIAAA8AAAAJAAAA0AIAAAgABAAS" + 59 "AAAAAAAAAAAAAAAAAAEAFQAAAAQAAgATAAAABQAAAAAAAAAGAAAAFAAAAAAAAAAAAAAABQAAAAAA" + 60 "AAAMAAAAaAMAADwDAAAAAAAABjxpbml0PgAVR29vZGJ5ZSAtIFRyYW5zZm9ybWVkABNIZWxsbyAt" + 61 "IFRyYW5zZm9ybWVkABdMYXJ0L1Rlc3Q5ODQkVHJhbnNmb3JtOwANTGFydC9UZXN0OTg0OwAiTGRh" + 62 "bHZpay9hbm5vdGF0aW9uL0VuY2xvc2luZ0NsYXNzOwAeTGRhbHZpay9hbm5vdGF0aW9uL0lubmVy" + 63 "Q2xhc3M7ABVMamF2YS9pby9QcmludFN0cmVhbTsAEkxqYXZhL2xhbmcvT2JqZWN0OwAUTGphdmEv" + 64 "bGFuZy9SdW5uYWJsZTsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AAxU" + 65 "ZXN0OTg0LmphdmEACVRyYW5zZm9ybQABVgACVkwAC2FjY2Vzc0ZsYWdzAARuYW1lAANvdXQAB3By" + 66 "aW50bG4AA3J1bgAFc2F5SGkABXZhbHVlAAAAAAEAAAAGAAAAAQAAAAcAAAAFAAcOAAcBAAcOAQgP" + 67 "AQMPAQgPAAEAAQABAAAA2AIAAAQAAABwEAMAAAAOAAMAAQACAAAA3QIAABQAAABiAAAAGwECAAAA" + 68 "biACABAAchAEAAIAYgAAABsBAQAAAG4gAgAQAA4AAAACAACAgATsBQEJhAYAAAICARYYAQIDAhAE" + 69 "CBEXDQACAAAATAMAAFIDAABcAwAAAAAAAAAAAAAAAAAAEAAAAAAAAAABAAAAAAAAAAEAAAAXAAAA" + 70 "cAAAAAIAAAAKAAAAzAAAAAMAAAADAAAA9AAAAAQAAAABAAAAGAEAAAUAAAAFAAAAIAEAAAYAAAAB" + 71 "AAAASAEAAAIgAAAXAAAAaAEAAAEQAAACAAAAyAIAAAMgAAACAAAA2AIAAAEgAAACAAAA7AIAAAAg" + 72 "AAABAAAAPAMAAAQgAAACAAAATAMAAAMQAAABAAAAXAMAAAYgAAABAAAAaAMAAAAQAAABAAAAeAMA" + 73 "AA=="); 74 run()75 public static void run() { 76 doTest(); 77 } 78 79 // The Method that holds an obsolete method pointer. We will fill it in by getting a jmethodID 80 // from a stack with an obsolete method in it. There should be no other ways to obtain an obsolete 81 // jmethodID in ART without unsafe casts. 82 public static Method obsolete_method = null; 83 doTest()84 public static void doTest() { 85 // Capture the obsolete method. 86 // 87 // NB The obsolete method must be direct so that we will not look in the receiver type to get 88 // the actual method. 89 Transform.sayHi(() -> { 90 System.out.println("transforming calling function"); 91 Redefinition.doCommonClassRedefinition(Transform.class, CLASS_BYTES, DEX_BYTES); 92 System.out.println("Retrieving obsolete method from current stack"); 93 // This should get the obsolete sayHi method (as the only obsolete method on the current 94 // threads stack). 95 Test984.obsolete_method = getFirstObsoleteMethod984(); 96 }); 97 98 // Prove we did actually redefine something. 99 System.out.println("Invoking redefined version of method."); 100 Transform.sayHi(() -> { System.out.println("Not doing anything here"); }); 101 102 System.out.println("invoking obsolete method"); 103 try { 104 obsolete_method.invoke(null, (Runnable)() -> { 105 throw new Error("Unexpected code running from invoke of obsolete method!"); 106 }); 107 throw new Error("Running obsolete method did not throw exception"); 108 } catch (Throwable e) { 109 // On newer RI InternalError has been replaced by InvocationTargetException. 110 if (e instanceof InternalError || e.getCause() instanceof InternalError || 111 e instanceof InvocationTargetException || 112 e.getCause() instanceof InvocationTargetException) { 113 System.out.println("Caught expected error from attempting to invoke an obsolete method."); 114 } else { 115 System.out.println("Unexpected error type for calling obsolete method! Expected either " 116 + "an InternalError or something that is caused by an InternalError."); 117 throw new Error("Unexpected error caught: ", e); 118 } 119 } 120 } 121 122 // Gets the first obsolete method on the current threads stack (NB only looks through the first 30 123 // stack frames). getFirstObsoleteMethod984()124 private static native Method getFirstObsoleteMethod984(); 125 } 126