| /* |
| * Copyright (C) 2017 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| import java.util.Arrays; |
| import java.lang.reflect.Executable; |
| import java.lang.reflect.Method; |
| import java.util.Base64; |
| import art.Breakpoint; |
| import art.Redefinition; |
| |
| public class Main { |
| static class Transform { |
| public void sayHi() { |
| System.out.println("Hello"); |
| } |
| } |
| |
| /** |
| * base64 encoded class/dex file for |
| * class Transform { |
| * public void sayHi() { |
| * System.out.println("Goodbye"); |
| * } |
| * } |
| */ |
| private static final byte[] DEX_BYTES = Base64.getDecoder().decode( |
| "ZGV4CjAzNQA7jFommHUzfbuvjq/I2cDcwdjqQk6KPfqYAwAAcAAAAHhWNBIAAAAAAAAAANQCAAAU" + |
| "AAAAcAAAAAkAAADAAAAAAgAAAOQAAAABAAAA/AAAAAQAAAAEAQAAAQAAACQBAABUAgAARAEAAJ4B" + |
| "AACmAQAArwEAAMEBAADJAQAA7QEAAA0CAAAkAgAAOAIAAEwCAABgAgAAawIAAHYCAAB5AgAAfQIA" + |
| "AIoCAACQAgAAlQIAAJ4CAAClAgAAAgAAAAMAAAAEAAAABQAAAAYAAAAHAAAACAAAAAkAAAAMAAAA" + |
| "DAAAAAgAAAAAAAAADQAAAAgAAACYAQAABwAEABAAAAAAAAAAAAAAAAAAAAASAAAABAABABEAAAAF" + |
| "AAAAAAAAAAAAAAAAAAAABQAAAAAAAAAKAAAAiAEAAMYCAAAAAAAAAgAAALcCAAC9AgAAAQABAAEA" + |
| "AACsAgAABAAAAHAQAwAAAA4AAwABAAIAAACxAgAACAAAAGIAAAAaAQEAbiACABAADgBEAQAAAAAA" + |
| "AAAAAAAAAAAAAQAAAAYABjxpbml0PgAHR29vZGJ5ZQAQTE1haW4kVHJhbnNmb3JtOwAGTE1haW47" + |
| "ACJMZGFsdmlrL2Fubm90YXRpb24vRW5jbG9zaW5nQ2xhc3M7AB5MZGFsdmlrL2Fubm90YXRpb24v" + |
| "SW5uZXJDbGFzczsAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwASTGphdmEvbGFuZy9PYmplY3Q7ABJM" + |
| "amF2YS9sYW5nL1N0cmluZzsAEkxqYXZhL2xhbmcvU3lzdGVtOwAJTWFpbi5qYXZhAAlUcmFuc2Zv" + |
| "cm0AAVYAAlZMAAthY2Nlc3NGbGFncwAEbmFtZQADb3V0AAdwcmludGxuAAVzYXlIaQAFdmFsdWUA" + |
| "EgAHDgAUAAcOeAACAgETGAECAwIOBAgPFwsAAAEBAICABNACAQHoAhAAAAAAAAAAAQAAAAAAAAAB" + |
| "AAAAFAAAAHAAAAACAAAACQAAAMAAAAADAAAAAgAAAOQAAAAEAAAAAQAAAPwAAAAFAAAABAAAAAQB" + |
| "AAAGAAAAAQAAACQBAAADEAAAAQAAAEQBAAABIAAAAgAAAFABAAAGIAAAAQAAAIgBAAABEAAAAQAA" + |
| "AJgBAAACIAAAFAAAAJ4BAAADIAAAAgAAAKwCAAAEIAAAAgAAALcCAAAAIAAAAQAAAMYCAAAAEAAA" + |
| "AQAAANQCAAA="); |
| |
| public static void notifyBreakpointReached(Thread thr, Executable e, long loc) { |
| System.out.println( |
| "\tBreakpoint reached: " + e + " @ line=" + Breakpoint.locationToLine(e, loc)); |
| } |
| |
| public static void check(boolean b, String msg) { |
| if (!b) { |
| throw new Error("FAILED: " + msg); |
| } |
| } |
| public static void main(String[] args) throws Exception { |
| System.loadLibrary(args[0]); |
| // Set up breakpoints |
| Breakpoint.stopBreakpointWatch(Thread.currentThread()); |
| Breakpoint.startBreakpointWatch( |
| Main.class, |
| Main.class.getDeclaredMethod( |
| "notifyBreakpointReached", Thread.class, Executable.class, Long.TYPE), |
| Thread.currentThread()); |
| |
| Method targetMethod = Transform.class.getDeclaredMethod("sayHi"); |
| Transform t = new Transform(); |
| check(isInterpretOnly() || !isMethodDeoptimized(targetMethod), |
| "method should not be deoptimized"); |
| t.sayHi(); |
| |
| // Set a breakpoint at the start of the function. |
| Breakpoint.setBreakpoint(targetMethod, 0); |
| check(isInterpretOnly() || isMethodDeoptimized(targetMethod), |
| "method should be deoptimized"); |
| t.sayHi(); |
| |
| System.out.println("Redefining transform!"); |
| Redefinition.doCommonClassRedefinition(Transform.class, new byte[0], DEX_BYTES); |
| check(isInterpretOnly() || !isMethodDeoptimized(targetMethod), |
| "method should not be deoptimized"); |
| t.sayHi(); |
| |
| Breakpoint.setBreakpoint(targetMethod, 0); |
| check(isInterpretOnly() || isMethodDeoptimized(targetMethod), |
| "method should be deoptimized"); |
| t.sayHi(); |
| } |
| |
| static native boolean isMethodDeoptimized(Method m); |
| static native boolean isInterpretOnly(); |
| } |