Add device side mainline module detection
Bug: 142286159
Test: make sts
Test: make cts/apps/MainlineModuleDetector
Test: install MainlineModule Detector and trigger intent
Test: make cts
Test: run cts with the detection logic temporarily applied
Change-Id: Ib0cd61b007274a7ab18ac0be035c1e9a332392bd
diff --git a/apps/MainlineModuleDetector/Android.mk b/apps/MainlineModuleDetector/Android.mk
index b99f8f7..5b8e316 100644
--- a/apps/MainlineModuleDetector/Android.mk
+++ b/apps/MainlineModuleDetector/Android.mk
@@ -1,5 +1,5 @@
#
-# Copyright (C) 2018 The Android Open Source Project
+# 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.
@@ -21,6 +21,8 @@
LOCAL_MODULE_PATH := $(TARGET_OUT_DATA_APPS)
+LOCAL_STATIC_JAVA_LIBRARIES := compatibility-device-util-axt
+
LOCAL_SRC_FILES := $(call all-java-files-under, src)
LOCAL_PACKAGE_NAME := MainlineModuleDetector
diff --git a/apps/MainlineModuleDetector/AndroidManifest.xml b/apps/MainlineModuleDetector/AndroidManifest.xml
index 9a36cc6..4cc8f8c 100644
--- a/apps/MainlineModuleDetector/AndroidManifest.xml
+++ b/apps/MainlineModuleDetector/AndroidManifest.xml
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2018 The Android Open Source Project
+<!-- 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.
diff --git a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
index 5e473d6..01c02c7 100644
--- a/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
+++ b/apps/MainlineModuleDetector/src/com/android/cts/mainlinemoduledetector/MainlineModuleDetector.java
@@ -1,14 +1,28 @@
+/*
+ * 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.cts.mainlinemoduledetector;
import android.app.Activity;
-import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
-import android.os.Build;
import android.os.Bundle;
import android.util.Log;
-import java.security.MessageDigest;
-import java.util.EnumSet;
+import com.android.compatibility.common.util.mainline.MainlineModule;
+import com.android.compatibility.common.util.mainline.ModuleDetector;
+
import java.util.HashSet;
import java.util.Set;
@@ -16,143 +30,20 @@
private static final String LOG_TAG = "MainlineModuleDetector";
- private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
-
- enum ModuleType {
- APEX,
- APK
- }
-
- enum MainlineModule {
- // Security
- MEDIA_SOFTWARE_CODEC("com.google.android.media.swcodec",
- true, ModuleType.APEX,
- "0C:2B:13:87:6D:E5:6A:E6:4E:D1:DE:93:42:2A:8A:3F:EA:6F:34:C0:FC:5D:7D:A1:BD:CF:EF"
- + ":C1:A7:B7:C9:1D"),
- MEDIA("com.google.android.media",
- true, ModuleType.APEX,
- "16:C1:5C:FA:15:D0:FD:D0:7E:BE:CB:5A:76:6B:40:8B:05:DD:92:7E:1F:3A:DD:C5:AB:F6:8E"
- + ":E8:B9:98:F9:FD"),
- DNS_RESOLVER("com.google.android.resolv",
- true, ModuleType.APEX,
- "EC:82:21:76:5E:4F:7E:2C:6D:8D:0F:0C:E9:BD:82:5B:98:BE:D2:0C:07:2C:C6:C8:08:DD:E4"
- + ":68:5F:EB:A6:FF"),
- CONSCRYPT("com.google.android.conscrypt",
- true, ModuleType.APEX,
- "8C:5D:A9:10:E6:11:21:B9:D6:E0:3B:42:D3:20:6A:7D:AD:29:DD:C1:63:AE:CD:4B:8E:E9:3F"
- + ":D3:83:79:CA:2A"),
- // Privacy
- PERMISSION_CONTROLLER("com.google.android.permissioncontroller",
- false, ModuleType.APK,
- "89:DF:B5:04:7E:E0:19:29:C2:18:4D:68:EF:49:64:F2:A9:0A:F1:24:C3:23:38:28:B8:F6:40"
- + ":D9:E6:C0:0F:83"),
- ANDROID_SERVICES("com.google.android.ext.services",
- false, ModuleType.APK,
- "18:46:05:09:5B:E6:CA:22:D0:55:F3:4E:FA:F0:13:44:FD:3A:B3:B5:63:8C:30:62:76:10:EE"
- + ":AE:8A:26:0B:29"),
- DOCUMENTS_UI("com.google.android.documentsui",
- true, ModuleType.APK,
- "9A:4B:85:34:44:86:EC:F5:1F:F8:05:EB:9D:23:17:97:79:BE:B7:EC:81:91:93:5A:CA:67:F0"
- + ":F4:09:02:52:97"),
- // Consistency
- TZDATA("com.google.android.tzdata",
- true, ModuleType.APEX,
- "55:93:DD:78:CB:26:EC:9B:00:59:2A:6A:F5:94:E4:16:1F:FD:B5:E9:F3:71:A7:43:54:5F:93"
- + ":F2:A0:F6:53:89"),
- NETWORK_STACK("com.google.android.networkstack",
- true, ModuleType.APK,
- "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
- + ":F6:0B:F6:2C:1E"),
- CAPTIVE_PORTAL_LOGIN("com.google.android.captiveportallogin",
- true, ModuleType.APK,
- "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
- + ":F6:0B:F6:2C:1E"),
- NETWORK_PERMISSION_CONFIGURATION("com.google.android.networkstack.permissionconfig",
- true, ModuleType.APK,
- "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
- + ":F6:0B:F6:2C:1E"),
- MODULE_METADATA("com.google.android.modulemetadata",
- true, ModuleType.APK,
- "BF:62:23:1E:28:F0:85:42:75:5C:F3:3C:9D:D8:3C:5D:1D:0F:A3:20:64:50:EF:BC:4C:3F:F3"
- + ":D5:FD:A0:33:0F"),
- ;
-
- String packageName;
- boolean isPlayUpdated;
- ModuleType moduleType;
- String certSHA256;
-
- MainlineModule(String packageName, boolean isPlayUpdated, ModuleType moduleType,
- String certSHA256) {
- this.packageName = packageName;
- this.isPlayUpdated = isPlayUpdated;
- this.moduleType = moduleType;
- this.certSHA256 = certSHA256;
- }
- }
-
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
try {
- String modules = String.join(",", getPlayManagedModules());
- Log.i(LOG_TAG, "Play managed modules are: <" + modules + ">");
+ PackageManager pm = getApplicationContext().getPackageManager();
+ Set<MainlineModule> modules = ModuleDetector.getPlayManagedModules(pm);
+ Set<String> moduleNames = new HashSet<>();
+ for (MainlineModule module : modules) {
+ moduleNames.add(module.packageName);
+ }
+ Log.i(LOG_TAG, "Play managed modules are: <" + String.join(",", moduleNames) + ">");
} catch (Exception e) {
Log.e(LOG_TAG, "Failed to retrieve modules.", e);
}
this.finish();
}
-
- private Set<String> getPlayManagedModules() throws Exception {
- Set<String> playManagedModules = new HashSet<>();
-
- PackageManager pm = getApplicationContext().getPackageManager();
-
- Set<String> packages = new HashSet<>();
- for (PackageInfo info : pm.getInstalledPackages(0)) {
- packages.add(info.packageName);
- }
- for (PackageInfo info : pm.getInstalledPackages(PackageManager.MATCH_APEX)) {
- packages.add(info.packageName);
- }
-
- for (MainlineModule module : EnumSet.allOf(MainlineModule.class)) {
- if (module.isPlayUpdated && packages.contains(module.packageName)
- && module.certSHA256.equals(getSignatureDigest(module))) {
- playManagedModules.add(module.packageName);
- }
- }
- return playManagedModules;
- }
-
- private String getSignatureDigest(MainlineModule module) throws Exception {
- PackageManager pm = getApplicationContext().getPackageManager();
- int flag = PackageManager.GET_SIGNING_CERTIFICATES;
- if (module.moduleType == ModuleType.APEX) {
- flag |= PackageManager.MATCH_APEX;
- }
-
- PackageInfo packageInfo = pm.getPackageInfo(module.packageName, flag);
- MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
- messageDigest.update(packageInfo.signingInfo.getApkContentsSigners()[0].toByteArray());
-
- final byte[] digest = messageDigest.digest();
- final int digestLength = digest.length;
- final int charCount = 3 * digestLength - 1;
-
- final char[] chars = new char[charCount];
- for (int i = 0; i < digestLength; i++) {
- final int byteHex = digest[i] & 0xFF;
- chars[i * 3] = HEX_ARRAY[byteHex >>> 4];
- chars[i * 3 + 1] = HEX_ARRAY[byteHex & 0x0F];
- if (i < digestLength - 1) {
- chars[i * 3 + 2] = ':';
- }
- }
-
- String ret = new String(chars);
- Log.d(LOG_TAG, "Module: " + module.packageName + " has signature: " + ret);
- return ret;
- }
-
}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java
new file mode 100644
index 0000000..b34242e
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/MainlineModule.java
@@ -0,0 +1,87 @@
+/*
+ * 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.compatibility.common.util.mainline;
+
+/**
+ * Enum containing metadata for mainline modules.
+ */
+public enum MainlineModule {
+ // Security
+ MEDIA_SOFTWARE_CODEC("com.google.android.media.swcodec",
+ true, ModuleType.APEX,
+ "0C:2B:13:87:6D:E5:6A:E6:4E:D1:DE:93:42:2A:8A:3F:EA:6F:34:C0:FC:5D:7D:A1:BD:CF:EF"
+ + ":C1:A7:B7:C9:1D"),
+ MEDIA("com.google.android.media",
+ true, ModuleType.APEX,
+ "16:C1:5C:FA:15:D0:FD:D0:7E:BE:CB:5A:76:6B:40:8B:05:DD:92:7E:1F:3A:DD:C5:AB:F6:8E"
+ + ":E8:B9:98:F9:FD"),
+ DNS_RESOLVER("com.google.android.resolv",
+ true, ModuleType.APEX,
+ "EC:82:21:76:5E:4F:7E:2C:6D:8D:0F:0C:E9:BD:82:5B:98:BE:D2:0C:07:2C:C6:C8:08:DD:E4"
+ + ":68:5F:EB:A6:FF"),
+ CONSCRYPT("com.google.android.conscrypt",
+ true, ModuleType.APEX,
+ "8C:5D:A9:10:E6:11:21:B9:D6:E0:3B:42:D3:20:6A:7D:AD:29:DD:C1:63:AE:CD:4B:8E:E9:3F"
+ + ":D3:83:79:CA:2A"),
+ // Privacy
+ PERMISSION_CONTROLLER("com.google.android.permissioncontroller",
+ false, ModuleType.APK,
+ "89:DF:B5:04:7E:E0:19:29:C2:18:4D:68:EF:49:64:F2:A9:0A:F1:24:C3:23:38:28:B8:F6:40"
+ + ":D9:E6:C0:0F:83"),
+ ANDROID_SERVICES("com.google.android.ext.services",
+ false, ModuleType.APK,
+ "18:46:05:09:5B:E6:CA:22:D0:55:F3:4E:FA:F0:13:44:FD:3A:B3:B5:63:8C:30:62:76:10:EE"
+ + ":AE:8A:26:0B:29"),
+ DOCUMENTS_UI("com.google.android.documentsui",
+ true, ModuleType.APK,
+ "9A:4B:85:34:44:86:EC:F5:1F:F8:05:EB:9D:23:17:97:79:BE:B7:EC:81:91:93:5A:CA:67:F0"
+ + ":F4:09:02:52:97"),
+ // Consistency
+ TZDATA("com.google.android.tzdata",
+ true, ModuleType.APEX,
+ "55:93:DD:78:CB:26:EC:9B:00:59:2A:6A:F5:94:E4:16:1F:FD:B5:E9:F3:71:A7:43:54:5F:93"
+ + ":F2:A0:F6:53:89"),
+ NETWORK_STACK("com.google.android.networkstack",
+ true, ModuleType.APK,
+ "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+ + ":F6:0B:F6:2C:1E"),
+ CAPTIVE_PORTAL_LOGIN("com.google.android.captiveportallogin",
+ true, ModuleType.APK,
+ "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+ + ":F6:0B:F6:2C:1E"),
+ NETWORK_PERMISSION_CONFIGURATION("com.google.android.networkstack.permissionconfig",
+ true, ModuleType.APK,
+ "5F:A4:22:12:AD:40:3E:22:DD:6E:FE:75:F3:F3:11:84:05:1F:EF:74:4C:0B:05:BE:5C:73:ED"
+ + ":F6:0B:F6:2C:1E"),
+ MODULE_METADATA("com.google.android.modulemetadata",
+ true, ModuleType.APK,
+ "BF:62:23:1E:28:F0:85:42:75:5C:F3:3C:9D:D8:3C:5D:1D:0F:A3:20:64:50:EF:BC:4C:3F:F3"
+ + ":D5:FD:A0:33:0F"),
+ ;
+
+ public final String packageName;
+ public final boolean isPlayUpdated;
+ public final ModuleType moduleType;
+ public final String certSHA256;
+
+ MainlineModule(String packageName, boolean isPlayUpdated, ModuleType moduleType,
+ String certSHA256) {
+ this.packageName = packageName;
+ this.isPlayUpdated = isPlayUpdated;
+ this.moduleType = moduleType;
+ this.certSHA256 = certSHA256;
+ }
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleDetector.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleDetector.java
new file mode 100644
index 0000000..11b467d
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleDetector.java
@@ -0,0 +1,108 @@
+/*
+ * 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.compatibility.common.util.mainline;
+
+import android.content.pm.PackageInfo;
+import android.content.pm.PackageManager;
+import android.util.Log;
+
+import java.security.MessageDigest;
+import java.util.EnumSet;
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * Detects mainline modules.
+ */
+public class ModuleDetector {
+ private static final String LOG_TAG = "MainlineModuleDetector";
+
+ private static final char[] HEX_ARRAY = "0123456789ABCDEF".toCharArray();
+
+ /**
+ * Return true if a module is play managed.
+ *
+ * Example of skipping a test based on mainline modules:
+ * <pre>
+ * @Test
+ * public void testPocCVE_1234_5678() throws Exception {
+ * if(!ModuleDetector.moduleIsPlayManaged(
+ * getInstrumentation().getContext().getPackageManager(),
+ * MainlineModule.MEDIA_SOFTWARE_CODEC)) {
+ * doStagefrightTest(R.raw.cve_2018_5882);
+ * }
+ * }
+ * </pre>
+ */
+ public static boolean moduleIsPlayManaged(PackageManager pm, MainlineModule module)
+ throws Exception {
+ return getPlayManagedModules(pm).contains(module);
+ }
+
+
+ /**
+ * Return all play managed mainline modules.
+ */
+ public static Set<MainlineModule> getPlayManagedModules(PackageManager pm) throws Exception {
+ Set<MainlineModule> playManagedModules = new HashSet<>();
+
+ Set<String> packages = new HashSet<>();
+ for (PackageInfo info : pm.getInstalledPackages(0)) {
+ packages.add(info.packageName);
+ }
+ for (PackageInfo info : pm.getInstalledPackages(PackageManager.MATCH_APEX)) {
+ packages.add(info.packageName);
+ }
+
+ for (MainlineModule module : EnumSet.allOf(MainlineModule.class)) {
+ if (module.isPlayUpdated && packages.contains(module.packageName)
+ && module.certSHA256.equals(getSignatureDigest(pm, module))) {
+ playManagedModules.add(module);
+ }
+ }
+ return playManagedModules;
+ }
+
+ private static String getSignatureDigest(PackageManager pm, MainlineModule module)
+ throws Exception {
+ int flag = PackageManager.GET_SIGNING_CERTIFICATES;
+ if (module.moduleType == ModuleType.APEX) {
+ flag |= PackageManager.MATCH_APEX;
+ }
+
+ PackageInfo packageInfo = pm.getPackageInfo(module.packageName, flag);
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA256");
+ messageDigest.update(packageInfo.signingInfo.getApkContentsSigners()[0].toByteArray());
+
+ final byte[] digest = messageDigest.digest();
+ final int digestLength = digest.length;
+ final int charCount = 3 * digestLength - 1;
+
+ final char[] chars = new char[charCount];
+ for (int i = 0; i < digestLength; i++) {
+ final int byteHex = digest[i] & 0xFF;
+ chars[i * 3] = HEX_ARRAY[byteHex >>> 4];
+ chars[i * 3 + 1] = HEX_ARRAY[byteHex & 0x0F];
+ if (i < digestLength - 1) {
+ chars[i * 3 + 2] = ':';
+ }
+ }
+
+ String ret = new String(chars);
+ Log.d(LOG_TAG, "Module: " + module.packageName + " has signature: " + ret);
+ return ret;
+ }
+}
diff --git a/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleType.java b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleType.java
new file mode 100644
index 0000000..b50d62c
--- /dev/null
+++ b/common/device-side/util-axt/src/com/android/compatibility/common/util/mainline/ModuleType.java
@@ -0,0 +1,24 @@
+/*
+ * 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.compatibility.common.util.mainline;
+
+/**
+ * File type of mainline module.
+ */
+public enum ModuleType {
+ APEX,
+ APK
+}