1 /* 2 * Copyright (C) 2019 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 com.android.preload.check; 18 19 import dalvik.system.DexFile; 20 21 import java.io.BufferedInputStream; 22 import java.io.BufferedOutputStream; 23 import java.io.File; 24 import java.io.FileOutputStream; 25 import java.lang.reflect.Field; 26 import java.lang.reflect.Method; 27 import java.net.URL; 28 import java.util.ArrayList; 29 import java.util.Collection; 30 import java.util.List; 31 32 public class Util { 33 private static Field statusField; 34 35 static { 36 try { 37 Class<?> klass = Class.class; 38 statusField = klass.getDeclaredField("status"); 39 statusField.setAccessible(true); 40 } catch (Throwable t) { 41 throw new RuntimeException(t); 42 } 43 // Reset the framework's kill handler. 44 Thread.setDefaultUncaughtExceptionHandler(null); 45 } 46 getBootDexFiles()47 public static Collection<DexFile> getBootDexFiles() throws Exception { 48 Class<?> vmClassLoaderClass = Class.forName("java.lang.VMClassLoader"); 49 Method getResources = vmClassLoaderClass.getDeclaredMethod("getResources", String.class); 50 getResources.setAccessible(true); 51 ArrayList<DexFile> res = new ArrayList<>(); 52 for (int i = 1;; i++) { 53 try { 54 String name = "classes" + (i > 1 ? String.valueOf(i) : "") + ".dex"; 55 @SuppressWarnings("unchecked") 56 List<URL> urls = (List<URL>) getResources.invoke(null, name); 57 if (urls.isEmpty()) { 58 break; 59 } 60 for (URL url : urls) { 61 // Make temp copy, so we can use public API. Would be nice to use in-memory, but 62 // those are unstable. 63 String tmp = "/data/local/tmp/tmp.dex"; 64 try (BufferedInputStream in = new BufferedInputStream(url.openStream()); 65 BufferedOutputStream out = new BufferedOutputStream( 66 new FileOutputStream(tmp))) { 67 byte[] buf = new byte[4096]; 68 for (;;) { 69 int r = in.read(buf); 70 if (r == -1) { 71 break; 72 } 73 out.write(buf, 0, r); 74 } 75 } 76 try { 77 res.add(new DexFile(tmp)); 78 } catch (Exception dexError) { 79 dexError.printStackTrace(System.out); 80 } 81 new File(tmp).delete(); 82 } 83 } catch (Exception ignored) { 84 break; 85 } 86 } 87 return res; 88 } 89 isInitialized(Class<?> klass)90 public static boolean isInitialized(Class<?> klass) throws Exception { 91 Object val = statusField.get(klass); 92 if (val == null || !(val instanceof Integer)) { 93 throw new IllegalStateException(String.valueOf(val)); 94 } 95 int intVal = (int)val; 96 intVal = (intVal >> (32-4)) & 0xf; 97 return intVal >= 14; 98 } 99 assertTrue(boolean val, String msg)100 public static void assertTrue(boolean val, String msg) { 101 if (!val) { 102 throw new RuntimeException(msg); 103 } 104 } 105 assertInitializedState(String className, boolean expected, ClassLoader loader)106 public static void assertInitializedState(String className, boolean expected, 107 ClassLoader loader) { 108 boolean initialized; 109 try { 110 Class<?> klass = Class.forName(className, /* initialize */ false, loader); 111 initialized = isInitialized(klass); 112 } catch (Throwable t) { 113 throw new RuntimeException(t); 114 } 115 assertTrue(expected == initialized, className); 116 } 117 assertNotInitialized(String className, ClassLoader loader)118 public static void assertNotInitialized(String className, ClassLoader loader) { 119 assertInitializedState(className, false, loader); 120 } 121 assertInitialized(String className, ClassLoader loader)122 public static void assertInitialized(String className, ClassLoader loader) { 123 assertInitializedState(className, true, loader); 124 } 125 } 126