summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/pm/dex/DexLogger.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java166
2 files changed, 179 insertions, 6 deletions
diff --git a/services/core/java/com/android/server/pm/dex/DexLogger.java b/services/core/java/com/android/server/pm/dex/DexLogger.java
index c7bbf1cbc5c6..88d9e52ccf51 100644
--- a/services/core/java/com/android/server/pm/dex/DexLogger.java
+++ b/services/core/java/com/android/server/pm/dex/DexLogger.java
@@ -27,6 +27,7 @@ import android.util.PackageUtils;
import android.util.Slog;
import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
import com.android.server.pm.Installer;
import com.android.server.pm.Installer.InstallerException;
@@ -57,10 +58,11 @@ public class DexLogger implements DexManager.Listener {
return new DexLogger(pms, installer, installLock);
}
- private DexLogger(IPackageManager pms, Installer installer, Object installLock) {
- mPackageManager = pms;
- mInstaller = installer;
- mInstallLock = installLock;
+ @VisibleForTesting
+ /*package*/ DexLogger(IPackageManager pms, Installer installer, Object installLock) {
+ mPackageManager = pms;
+ mInstaller = installer;
+ mInstallLock = installLock;
}
/**
@@ -92,7 +94,7 @@ public class DexLogger implements DexManager.Listener {
message = message + ' ' + ByteStringUtils.toHexString(hash);
}
- EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, ownerUid, message);
+ writeDclEvent(ownerUid, message);
if (dexUseInfo.isUsedByOtherApps()) {
Set<String> otherPackages = dexUseInfo.getLoadingPackages();
@@ -109,8 +111,13 @@ public class DexLogger implements DexManager.Listener {
}
}
for (int otherUid : otherUids) {
- EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, otherUid, message);
+ writeDclEvent(otherUid, message);
}
}
}
+
+ @VisibleForTesting
+ /*package*/ void writeDclEvent(int uid, String message) {
+ EventLog.writeEvent(SNET_TAG, DCL_SUBTAG, uid, message);
+ }
}
diff --git a/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java b/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
new file mode 100644
index 000000000000..bf8d4056ee55
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/pm/dex/DexLoggerTests.java
@@ -0,0 +1,166 @@
+/*
+ * 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 android.content.pm.ApplicationInfo;
+import android.content.pm.IPackageManager;
+import android.content.pm.PackageInfo;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.os.storage.StorageManager;
+
+import com.android.server.pm.Installer;
+import com.android.server.pm.Installer.InstallerException;
+
+import com.google.common.collect.ArrayListMultimap;
+import com.google.common.collect.ListMultimap;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.junit.MockitoJUnit;
+import org.mockito.junit.MockitoRule;
+import org.mockito.quality.Strictness;
+
+import java.util.Arrays;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.doReturn;
+import static org.mockito.Mockito.doThrow;
+
+import static com.android.server.pm.dex.PackageDexUsage.PackageUseInfo;
+import static com.android.server.pm.dex.PackageDexUsage.DexUseInfo;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class DexLoggerTests {
+ private static final String PACKAGE_NAME = "package.name";
+ private static final String VOLUME_UUID = "volUuid";
+ private static final String DEX_PATH = "/bar/foo.jar";
+ private static final int STORAGE_FLAGS = StorageManager.FLAG_STORAGE_DE;
+ private static final int OWNER_UID = 43;
+ private static final int OWNER_USER_ID = 44;
+
+ // Obtained via: echo -n "foo.jar" | sha256sum
+ private static final String DEX_FILENAME_HASH =
+ "91D7B844D7CC9673748FF057D8DC83972280FC28537D381AA42015A9CF214B9F";
+
+ private static final byte[] CONTENT_HASH_BYTES = new byte[] {
+ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
+ 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32
+ };
+ private static final String CONTENT_HASH =
+ "0102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F20";
+
+ @Rule public MockitoRule mockito = MockitoJUnit.rule().strictness(Strictness.STRICT_STUBS);
+
+ @Mock IPackageManager mPM;
+ @Mock Installer mInstaller;
+ private final Object mInstallLock = new Object();
+
+ private DexManager.Listener mListener;
+
+ private final ListMultimap<Integer, String> mMessagesForUid = ArrayListMultimap.create();
+
+ @Before
+ public void setup() {
+ // For test purposes capture log messages as well as sending to the event log.
+ mListener = new DexLogger(mPM, mInstaller, mInstallLock) {
+ @Override
+ void writeDclEvent(int uid, String message) {
+ super.writeDclEvent(uid, message);
+ mMessagesForUid.put(uid, message);
+ }
+ };
+ }
+
+ @Test
+ public void testSingleAppWithFileHash() throws Exception {
+ doReturn(CONTENT_HASH_BYTES).when(mInstaller).hashSecondaryDexFile(
+ DEX_PATH, PACKAGE_NAME, OWNER_UID, VOLUME_UUID, STORAGE_FLAGS);
+
+ runOnReconcile();
+
+ assertThat(mMessagesForUid.keySet()).containsExactly(OWNER_UID);
+ String expectedMessage = DEX_FILENAME_HASH + " " + CONTENT_HASH;
+ assertThat(mMessagesForUid).containsEntry(OWNER_UID, expectedMessage);
+ }
+
+ @Test
+ public void testSingleAppNoFileHash() throws Exception {
+ doReturn(new byte[] { }).when(mInstaller).hashSecondaryDexFile(
+ DEX_PATH, PACKAGE_NAME, OWNER_UID, VOLUME_UUID, STORAGE_FLAGS);
+
+ runOnReconcile();
+
+ assertThat(mMessagesForUid.keySet()).containsExactly(OWNER_UID);
+ assertThat(mMessagesForUid).containsEntry(OWNER_UID, DEX_FILENAME_HASH);
+ }
+
+ @Test
+ public void testSingleAppHashFails() throws Exception {
+ doThrow(new InstallerException("Testing failure")).when(mInstaller).hashSecondaryDexFile(
+ DEX_PATH, PACKAGE_NAME, OWNER_UID, VOLUME_UUID, STORAGE_FLAGS);
+
+ runOnReconcile();
+
+ assertThat(mMessagesForUid).isEmpty();
+ }
+
+ @Test
+ public void testOtherApps() throws Exception {
+ doReturn(CONTENT_HASH_BYTES).when(mInstaller).hashSecondaryDexFile(
+ DEX_PATH, PACKAGE_NAME, OWNER_UID, VOLUME_UUID, STORAGE_FLAGS);
+
+ // Simulate three packages from two different UIDs
+ String packageName1 = "other1.package.name";
+ String packageName2 = "other2.package.name";
+ String packageName3 = "other3.package.name";
+ int uid1 = 1001;
+ int uid2 = 1002;
+
+ doReturn(uid1).when(mPM).getPackageUid(packageName1, 0, OWNER_USER_ID);
+ doReturn(uid2).when(mPM).getPackageUid(packageName2, 0, OWNER_USER_ID);
+ doReturn(uid1).when(mPM).getPackageUid(packageName3, 0, OWNER_USER_ID);
+
+ runOnReconcile(packageName1, packageName2, packageName3);
+
+ assertThat(mMessagesForUid.keySet()).containsExactly(OWNER_UID, uid1, uid2);
+
+ String expectedMessage = DEX_FILENAME_HASH + " " + CONTENT_HASH;
+ assertThat(mMessagesForUid).containsEntry(OWNER_UID, expectedMessage);
+ assertThat(mMessagesForUid).containsEntry(uid1, expectedMessage);
+ assertThat(mMessagesForUid).containsEntry(uid2, expectedMessage);
+ }
+
+ private void runOnReconcile(String... otherPackageNames) {
+ ApplicationInfo appInfo = new ApplicationInfo();
+ appInfo.packageName = PACKAGE_NAME;
+ appInfo.volumeUuid = VOLUME_UUID;
+ appInfo.uid = OWNER_UID;
+
+ boolean isUsedByOtherApps = otherPackageNames.length > 0;
+ DexUseInfo dexUseInfo = new DexUseInfo(
+ isUsedByOtherApps, OWNER_USER_ID, /* classLoaderContext */ null, /* loaderIsa */ null);
+ dexUseInfo.getLoadingPackages().addAll(Arrays.asList(otherPackageNames));
+
+ mListener.onReconcileSecondaryDexFile(appInfo, dexUseInfo, DEX_PATH, STORAGE_FLAGS);
+ }
+}