diff options
author | Andreas Gampe <agampe@google.com> | 2019-04-16 14:49:42 -0700 |
---|---|---|
committer | Andreas Gampe <agampe@google.com> | 2019-04-16 14:52:14 -0700 |
commit | bb621f2df4740f43c31c62916f33085f54036f0e (patch) | |
tree | c3eee02945be325346f65bbbaeeff2ebbde6bd80 /tools/preload-check | |
parent | bc17e4b328a4ce1146c7b23798c7aa7f03ee0c6d (diff) |
PreloadCheck: Add support for regex checking
Add some reflection hackery to retrieve boot classpath dex files. This
requires unstripped jars. Then use DexFile APIs to retrieve all classes,
and run a check if the given regular exception matches.
Use the new infrastructure to check that NoPreloadHolder classes are
not initialized.
Test: atest --test-mapping frameworks/base/tools/preload-check
Change-Id: Ic19e950647e5827d3c3ec4a7109553f39be7f43a
Diffstat (limited to 'tools/preload-check')
3 files changed, 122 insertions, 2 deletions
diff --git a/tools/preload-check/device/src/com/android/preload/check/NotInitializedRegex.java b/tools/preload-check/device/src/com/android/preload/check/NotInitializedRegex.java new file mode 100644 index 000000000000..261024b030f0 --- /dev/null +++ b/tools/preload-check/device/src/com/android/preload/check/NotInitializedRegex.java @@ -0,0 +1,58 @@ +/* + * Copyright (C) 2019 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. + */ + +package com.android.preload.check; + +import dalvik.system.DexFile; + +import java.util.Collection; +import java.util.Enumeration; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +public class NotInitializedRegex { + public static void main(String[] args) throws Exception { + Matcher m = Pattern.compile(args[0]).matcher(""); + boolean requiresMatch = args.length > 1 ? Boolean.parseBoolean(args[1]) : false; + + Collection<DexFile> dexFiles = Util.getBootDexFiles(); + int matched = 0, notMatched = 0; + for (DexFile dexFile : dexFiles) { + Enumeration<String> entries = dexFile.entries(); + while (entries.hasMoreElements()) { + String entry = entries.nextElement(); + m.reset(entry); + if (m.matches()) { + System.out.println(entry + ": match"); + matched++; + check(entry); + } else { + System.out.println(entry + ": no match"); + notMatched++; + } + } + } + System.out.println("Matched: " + matched + " Not-Matched: " + notMatched); + if (requiresMatch && matched == 0) { + throw new RuntimeException("Did not find match"); + } + System.out.println("OK"); + } + + private static void check(String name) { + Util.assertNotInitialized(name, null); + } +} diff --git a/tools/preload-check/device/src/com/android/preload/check/Util.java b/tools/preload-check/device/src/com/android/preload/check/Util.java index 662f67ac0bd6..19cc5abf6f4d 100644 --- a/tools/preload-check/device/src/com/android/preload/check/Util.java +++ b/tools/preload-check/device/src/com/android/preload/check/Util.java @@ -16,7 +16,18 @@ package com.android.preload.check; +import dalvik.system.DexFile; + +import java.io.BufferedInputStream; +import java.io.BufferedOutputStream; +import java.io.File; +import java.io.FileOutputStream; import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.net.URL; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; public class Util { private static Field statusField; @@ -31,6 +42,49 @@ public class Util { } } + public static Collection<DexFile> getBootDexFiles() throws Exception { + Class<?> vmClassLoaderClass = Class.forName("java.lang.VMClassLoader"); + Method getResources = vmClassLoaderClass.getDeclaredMethod("getResources", String.class); + getResources.setAccessible(true); + LinkedList<DexFile> res = new LinkedList<>(); + for (int i = 1;; i++) { + try { + String name = "classes" + (i > 1 ? String.valueOf(i) : "") + ".dex"; + @SuppressWarnings("unchecked") + List<URL> urls = (List<URL>) getResources.invoke(null, name); + if (urls.isEmpty()) { + break; + } + for (URL url : urls) { + // Make temp copy, so we can use public API. Would be nice to use in-memory, but + // those are unstable. + String tmp = "/data/local/tmp/tmp.dex"; + try (BufferedInputStream in = new BufferedInputStream(url.openStream()); + BufferedOutputStream out = new BufferedOutputStream( + new FileOutputStream(tmp))) { + byte[] buf = new byte[4096]; + for (;;) { + int r = in.read(buf); + if (r == -1) { + break; + } + out.write(buf, 0, r); + } + } + try { + res.add(new DexFile(tmp)); + } catch (Exception dexError) { + dexError.printStackTrace(System.out); + } + new File(tmp).delete(); + } + } catch (Exception ignored) { + break; + } + } + return res; + } + public static boolean isInitialized(Class<?> klass) throws Exception { Object val = statusField.get(klass); if (val == null || !(val instanceof Integer)) { diff --git a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java index 1fde40252939..00fd414e3ee2 100644 --- a/tools/preload-check/src/com/android/preload/check/PreloadCheck.java +++ b/tools/preload-check/src/com/android/preload/check/PreloadCheck.java @@ -16,7 +16,7 @@ package com.android.preload.check; -import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; import com.android.tradefed.device.ITestDevice; import com.android.tradefed.testtype.DeviceJUnit4ClassRunner; @@ -97,6 +97,14 @@ public class PreloadCheck implements IDeviceTest { } } + /** + * Test the classes ending in NoPreloadHolder are not initialized. + */ + @Test + public void testNoPreloadHolder() throws Exception { + run("com.android.preload.check.NotInitializedRegex", ".*NoPreloadHolder$", "true"); + } + private void run(String cmd, String... args) throws Exception { StringBuilder sb = new StringBuilder(); sb.append("app_process ") @@ -107,7 +115,7 @@ public class PreloadCheck implements IDeviceTest { sb.append(' ').append(escape(arg)); } String res = mTestDevice.executeShellCommand(sb.toString()); - assertEquals(sb.toString(), "OK", res.trim()); + assertTrue(sb.toString() + "\n===\n" + res, res.trim().endsWith("OK")); } private static String escape(String input) { |