diff options
Diffstat (limited to 'tests/DexLoggerIntegrationTests/src')
-rw-r--r-- | tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java | 22 | ||||
-rw-r--r-- | tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java | 154 |
2 files changed, 176 insertions, 0 deletions
diff --git a/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java b/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java new file mode 100644 index 000000000000..e995a26ea5c9 --- /dev/null +++ b/tests/DexLoggerIntegrationTests/src/com/android/dcl/Simple.java @@ -0,0 +1,22 @@ +/* + * Copyright 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. + */ + +package com.android.dcl; + +/** Dummy class which is built into a jar purely so we can pass it to DexClassLoader. */ +public final class Simple { + public Simple() {} +} diff --git a/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java new file mode 100644 index 000000000000..d8b3b2086335 --- /dev/null +++ b/tests/DexLoggerIntegrationTests/src/com/android/server/pm/dex/DexLoggerIntegrationTests.java @@ -0,0 +1,154 @@ +/* + * Copyright 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. + */ + +package com.android.server.pm.dex; + +import static com.google.common.truth.Truth.assertThat; + +import android.content.Context; +import android.support.test.InstrumentationRegistry; +import android.support.test.filters.LargeTest; +import android.util.EventLog; +import dalvik.system.DexClassLoader; + +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.JUnit4; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.InputStream; +import java.io.OutputStream; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Formatter; +import java.util.List; + +/** + * Integration tests for {@link com.android.server.pm.dex.DexLogger}. + * + * The setup for the test dynamically loads code in a jar extracted + * from our assets (a secondary dex file). + * + * We then use adb to trigger secondary dex file reconcilation (and + * wait for it to complete). As a side-effect of this DexLogger should + * be notified of the file and should log the hash of the file's name + * and content. We verify that this message appears in the event log. + * + * Run with "atest DexLoggerIntegrationTests". + */ +@LargeTest +@RunWith(JUnit4.class) +public final class DexLoggerIntegrationTests { + + private static final String PACKAGE_NAME = "com.android.frameworks.dexloggertest"; + + // Event log tag used for SNET related events + private static final int SNET_TAG = 0x534e4554; + // Subtag used to distinguish dynamic code loading events + private static final String DCL_SUBTAG = "dcl"; + + // Obtained via "echo -n copied.jar | sha256sum" + private static final String EXPECTED_NAME_HASH = + "1B6C71DB26F36582867432CCA12FB6A517470C9F9AABE9198DD4C5C030D6DC0C"; + + private static String expectedContentHash; + + @BeforeClass + public static void setUpAll() throws Exception { + Context context = InstrumentationRegistry.getTargetContext(); + MessageDigest hasher = MessageDigest.getInstance("SHA-256"); + + // Copy the jar from our Java resources to a private data directory + File privateCopy = new File(context.getDir("jars", Context.MODE_PRIVATE), "copied.jar"); + Class<?> thisClass = DexLoggerIntegrationTests.class; + try (InputStream input = thisClass.getResourceAsStream("/javalib.jar"); + OutputStream output = new FileOutputStream(privateCopy)) { + byte[] buffer = new byte[1024]; + while (true) { + int numRead = input.read(buffer); + if (numRead < 0) { + break; + } + output.write(buffer, 0, numRead); + hasher.update(buffer, 0, numRead); + } + } + + // Remember the SHA-256 of the file content to check that it is the same as + // the value we see logged. + Formatter formatter = new Formatter(); + for (byte b : hasher.digest()) { + formatter.format("%02X", b); + } + expectedContentHash = formatter.toString(); + + // Feed the jar to a class loader and make sure it contains what we expect. + ClassLoader loader = + new DexClassLoader( + privateCopy.toString(), null, null, context.getClass().getClassLoader()); + loader.loadClass("com.android.dcl.Simple"); + } + + @Test + public void testDexLoggerReconcileGeneratesEvents() throws Exception { + int[] tagList = new int[] { SNET_TAG }; + List<EventLog.Event> events = new ArrayList<>(); + + // There may already be events in the event log - figure out the most recent one + EventLog.readEvents(tagList, events); + long previousEventNanos = + events.isEmpty() ? 0 : events.get(events.size() - 1).getTimeNanos(); + events.clear(); + + Process process = Runtime.getRuntime().exec( + "cmd package reconcile-secondary-dex-files " + PACKAGE_NAME); + int exitCode = process.waitFor(); + assertThat(exitCode).isEqualTo(0); + + int myUid = android.os.Process.myUid(); + String expectedMessage = EXPECTED_NAME_HASH + " " + expectedContentHash; + + EventLog.readEvents(tagList, events); + boolean found = false; + for (EventLog.Event event : events) { + if (event.getTimeNanos() <= previousEventNanos) { + continue; + } + Object[] data = (Object[]) event.getData(); + + // We only care about DCL events that we generated. + String subTag = (String) data[0]; + if (!DCL_SUBTAG.equals(subTag)) { + continue; + } + int uid = (int) data[1]; + if (uid != myUid) { + continue; + } + + String message = (String) data[2]; + assertThat(message).isEqualTo(expectedMessage); + found = true; + } + + assertThat(found).isTrue(); + } +} |