Merge "TvContract: Add a field for network affiliation to the Channels table"
diff --git a/api/current.txt b/api/current.txt
index a6f0256..0b53039 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -35384,6 +35384,7 @@
method public abstract long getResources();
method public abstract void grant(long);
field public static final long RESOURCE_AUDIO_CAPTURE = 4L; // 0x4L
+ field public static final long RESOURCE_GEOLOCATION = 1L; // 0x1L
field public static final long RESOURCE_PROTECTED_MEDIA_ID = 8L; // 0x8L
field public static final long RESOURCE_VIDEO_CAPTURE = 2L; // 0x2L
}
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index b40a441..f176dfb 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -828,8 +828,8 @@
if (pkg.mCertificates == null) {
pkg.mCertificates = entryCerts;
pkg.mSignatures = convertToSignatures(entryCerts);
- pkg.mSigningKeys = new ArraySet<>();
- for (int i = 0; i < entryCerts.length; i++) {
+ pkg.mSigningKeys = new ArraySet<PublicKey>();
+ for (int i=0; i < entryCerts.length; i++) {
pkg.mSigningKeys.add(entryCerts[i][0].getPublicKey());
}
} else {
@@ -1222,6 +1222,17 @@
if (parsePermissionTree(pkg, res, parser, attrs, outError) == null) {
return null;
}
+ } else if (tagName.equals("upgrade-keyset")) {
+ sa = res.obtainAttributes(attrs,
+ com.android.internal.R.styleable.AndroidManifestUpgradeKeySet);
+ String name = sa.getNonResourceString(
+ com.android.internal.R.styleable.AndroidManifestUpgradeKeySet_name);
+ sa.recycle();
+ if (pkg.mUpgradeKeySets == null) {
+ pkg.mUpgradeKeySets = new ArraySet<String>();
+ }
+ pkg.mUpgradeKeySets.add(name);
+ XmlUtils.skipCurrentTag(parser);
} else if (tagName.equals("uses-permission")) {
if (!parseUsesPermission(pkg, res, parser, attrs, outError)) {
return null;
@@ -1795,7 +1806,7 @@
}
}
- owner.mKeySetMapping = new ArrayMap<String, ArraySet<PublicKey>>();
+ owner.mKeySetMapping = new ArrayMap<String, Set<PublicKey>>();
for (Map.Entry<PublicKey, Set<String>> e : definedKeySets.entrySet()) {
PublicKey key = e.getKey();
Set<String> keySetNames = e.getValue();
@@ -1803,7 +1814,7 @@
if (owner.mKeySetMapping.containsKey(alias)) {
owner.mKeySetMapping.get(alias).add(key);
} else {
- ArraySet<PublicKey> keys = new ArraySet<PublicKey>();
+ Set<PublicKey> keys = new ArraySet<PublicKey>();
keys.add(key);
owner.mKeySetMapping.put(alias, keys);
}
@@ -3795,8 +3806,9 @@
/**
* Data used to feed the KeySetManager
*/
- public ArraySet<PublicKey> mSigningKeys;
- public ArrayMap<String, ArraySet<PublicKey>> mKeySetMapping;
+ public Set<PublicKey> mSigningKeys;
+ public Set<String> mUpgradeKeySets;
+ public Map<String, Set<PublicKey>> mKeySetMapping;
public Package(String packageName) {
this.packageName = packageName;
diff --git a/core/java/android/nfc/cardemulation/AidGroup.java b/core/java/android/nfc/cardemulation/AidGroup.java
index 34568c2..54b517a 100644
--- a/core/java/android/nfc/cardemulation/AidGroup.java
+++ b/core/java/android/nfc/cardemulation/AidGroup.java
@@ -51,7 +51,7 @@
throw new IllegalArgumentException("Too many AIDs in AID group.");
}
for (String aid : aids) {
- if (!ApduServiceInfo.isValidAid(aid)) {
+ if (!CardEmulation.isValidAid(aid)) {
throw new IllegalArgumentException("AID " + aid + " is not a valid AID.");
}
}
diff --git a/core/java/android/nfc/cardemulation/ApduServiceInfo.java b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
index 930cf11..0df87c1 100644
--- a/core/java/android/nfc/cardemulation/ApduServiceInfo.java
+++ b/core/java/android/nfc/cardemulation/ApduServiceInfo.java
@@ -218,7 +218,7 @@
com.android.internal.R.styleable.AidFilter);
String aid = a.getString(com.android.internal.R.styleable.AidFilter_name).
toUpperCase();
- if (isValidAid(aid) && !currentGroup.aids.contains(aid)) {
+ if (CardEmulation.isValidAid(aid) && !currentGroup.aids.contains(aid)) {
currentGroup.aids.add(aid);
} else {
Log.e(TAG, "Ignoring invalid or duplicate aid: " + aid);
@@ -351,40 +351,6 @@
}
}
- /**
- * A valid AID according to ISO/IEC 7816-4:
- * <ul>
- * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
- * <li>Consist of only hex characters
- * <li>Additionally, we allow an asterisk at the end, to indicate
- * a prefix
- * </ul>
- */
- static boolean isValidAid(String aid) {
- if (aid == null)
- return false;
-
- // If a prefix AID, the total length must be odd (even # of AID chars + '*')
- if (aid.endsWith("*") && ((aid.length() % 2) == 0)) {
- Log.e(TAG, "AID " + aid + " is not a valid AID.");
- return false;
- }
-
- // If not a prefix AID, the total length must be even (even # of AID chars)
- if (!aid.endsWith("*") && ((aid.length() % 2) != 0)) {
- Log.e(TAG, "AID " + aid + " is not a valid AID.");
- return false;
- }
-
- // Verify hex characters
- if (!aid.matches("[0-9A-Fa-f]{10,32}\\*?")) {
- Log.e(TAG, "AID " + aid + " is not a valid AID.");
- return false;
- }
-
- return true;
- }
-
@Override
public String toString() {
StringBuilder out = new StringBuilder("ApduService: ");
diff --git a/core/java/android/nfc/cardemulation/CardEmulation.java b/core/java/android/nfc/cardemulation/CardEmulation.java
index 4b9e890..bf248d2 100644
--- a/core/java/android/nfc/cardemulation/CardEmulation.java
+++ b/core/java/android/nfc/cardemulation/CardEmulation.java
@@ -571,8 +571,45 @@
}
}
+ /**
+ * A valid AID according to ISO/IEC 7816-4:
+ * <ul>
+ * <li>Has >= 5 bytes and <=16 bytes (>=10 hex chars and <= 32 hex chars)
+ * <li>Consist of only hex characters
+ * <li>Additionally, we allow an asterisk at the end, to indicate
+ * a prefix
+ * </ul>
+ *
+ * @hide
+ */
+ public static boolean isValidAid(String aid) {
+ if (aid == null)
+ return false;
+
+ // If a prefix AID, the total length must be odd (even # of AID chars + '*')
+ if (aid.endsWith("*") && ((aid.length() % 2) == 0)) {
+ Log.e(TAG, "AID " + aid + " is not a valid AID.");
+ return false;
+ }
+
+ // If not a prefix AID, the total length must be even (even # of AID chars)
+ if (!aid.endsWith("*") && ((aid.length() % 2) != 0)) {
+ Log.e(TAG, "AID " + aid + " is not a valid AID.");
+ return false;
+ }
+
+ // Verify hex characters
+ if (!aid.matches("[0-9A-Fa-f]{10,32}\\*?")) {
+ Log.e(TAG, "AID " + aid + " is not a valid AID.");
+ return false;
+ }
+
+ return true;
+ }
+
void recoverService() {
NfcAdapter adapter = NfcAdapter.getDefaultAdapter(mContext);
sService = adapter.getCardEmulationService();
}
+
}
diff --git a/core/java/android/webkit/PermissionRequest.java b/core/java/android/webkit/PermissionRequest.java
index 231bf2d..0a0507e 100644
--- a/core/java/android/webkit/PermissionRequest.java
+++ b/core/java/android/webkit/PermissionRequest.java
@@ -28,7 +28,6 @@
public interface PermissionRequest {
/**
* Resource belongs to geolocation service.
- * @hide - see b/14668406
*/
public final static long RESOURCE_GEOLOCATION = 1 << 0;
/**
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index fc1d0df..afaf2e9 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -2019,4 +2019,10 @@
<declare-styleable name="KeySet">
<attr name="name" />
</declare-styleable>
+
+ <!-- Associate declared KeySets with upgrading capability -->
+ <declare-styleable name="AndroidManifestUpgradeKeySet" parent="AndroidManifest">
+ <attr name="name" />
+ </declare-styleable>
+
</resources>
diff --git a/core/tests/coretests/apks/keyset/Android.mk b/core/tests/coretests/apks/keyset/Android.mk
new file mode 100644
index 0000000..e44ac6c
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/Android.mk
@@ -0,0 +1,91 @@
+LOCAL_PATH:= $(call my-dir)
+
+#apks signed by keyset_A
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sa_unone
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_MANIFEST_FILE := uNone/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sa_ua
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sa_ub
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sa_uab
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_MANIFEST_FILE := uAB/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sa_ua_ub
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_MANIFEST_FILE := uAuB/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_permdef_sa_unone
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_MANIFEST_FILE := permDef/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_permuse_sa_ua_ub
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_MANIFEST_FILE := permUse/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+#apks signed by keyset_B
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sb_ua
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
+LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sb_ub
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
+LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_permuse_sb_ua_ub
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_B
+LOCAL_MANIFEST_FILE := permUse/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+#apks signed by keyset_A and keyset_B
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sab_ua
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_B
+LOCAL_MANIFEST_FILE := uA/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
+
+#apks signed by keyset_A and unit_test
+include $(CLEAR_VARS)
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+LOCAL_PACKAGE_NAME := keyset_sau_ub
+LOCAL_CERTIFICATE := $(LOCAL_PATH)/../../certs/keyset_A
+LOCAL_ADDITIONAL_CERTIFICATES := $(LOCAL_PATH)/../../certs/keyset_B
+LOCAL_MANIFEST_FILE := uB/AndroidManifest.xml
+include $(FrameworkCoreTests_BUILD_PACKAGE)
\ No newline at end of file
diff --git a/core/tests/coretests/apks/keyset/permDef/AndroidManifest.xml b/core/tests/coretests/apks/keyset/permDef/AndroidManifest.xml
new file mode 100644
index 0000000..8f7ad4a
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/permDef/AndroidManifest.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.keysets_permdef">
+ <application android:hasCode="false">
+ </application>
+ <permission android:description="@string/keyset_perm_desc"
+ android:label="@string/keyset_perm_label"
+ android:name="com.android.frameworks.coretests.keysets_permdef.keyset_perm"
+ android:protectionLevel="signature" />
+</manifest>
diff --git a/core/tests/coretests/apks/keyset/permUse/AndroidManifest.xml b/core/tests/coretests/apks/keyset/permUse/AndroidManifest.xml
new file mode 100644
index 0000000..41a2974
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/permUse/AndroidManifest.xml
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.keysets">
+ <application android:hasCode="false">
+ </application>
+ <uses-permission android:name="com.android.frameworks.coretests.keysets_permdef.keyset_perm" />
+ <keys>
+ <publicKey android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJoN1Nsgqf0V4C/bbN8wo8O2X/S5D76+5Mb9mlIsHkUTUTbHCNk+LxHIUYLm89YbP9zImrV0bUHLUAZUyoMUCiMCAwEAAQ==">
+ <keyset android:name="A" />
+ </publicKey>
+ <publicKey android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMTfQsY8UuXiXmvw/y7Tpr7HoyfAC0nE/8Qdk3ZtEr9asa5qqP0F6xzCI1PGVFV+WLVRwm6FdB9StENL5EKyQFcCAwEAAQ==">
+ <keyset android:name="B" />
+ </publicKey>
+ </keys>
+ <upgrade-keyset android:name="A"/>
+ <upgrade-keyset android:name="B"/>
+</manifest>
diff --git a/core/tests/coretests/apks/keyset/res/values/strings.xml b/core/tests/coretests/apks/keyset/res/values/strings.xml
new file mode 100644
index 0000000..ff99ffa
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/res/values/strings.xml
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+
+<!-- Just need this dummy file to have something to build. -->
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+ <string name="dummy">dummy</string>
+ <string name="keyset_perm_desc">keyset_perm_description</string>
+ <string name="keyset_perm_label">keyset_perm_label</string>
+</resources>
diff --git a/core/tests/coretests/apks/keyset/uA/AndroidManifest.xml b/core/tests/coretests/apks/keyset/uA/AndroidManifest.xml
new file mode 100644
index 0000000..87c420e
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/uA/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.keysets">
+ <application android:hasCode="false">
+ </application>
+ <keys>
+ <publicKey android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJoN1Nsgqf0V4C/bbN8wo8O2X/S5D76+5Mb9mlIsHkUTUTbHCNk+LxHIUYLm89YbP9zImrV0bUHLUAZUyoMUCiMCAwEAAQ==">
+ <keyset android:name="A" />
+ </publicKey>
+ </keys>
+ <upgrade-keyset android:name="A"/>
+</manifest>
diff --git a/core/tests/coretests/apks/keyset/uAB/AndroidManifest.xml b/core/tests/coretests/apks/keyset/uAB/AndroidManifest.xml
new file mode 100644
index 0000000..a65f085
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/uAB/AndroidManifest.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.keysets">
+ <application android:hasCode="false">
+ </application>
+ <keys>
+ <publicKey android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJoN1Nsgqf0V4C/bbN8wo8O2X/S5D76+5Mb9mlIsHkUTUTbHCNk+LxHIUYLm89YbP9zImrV0bUHLUAZUyoMUCiMCAwEAAQ==">
+ <keyset android:name="AB" />
+ </publicKey>
+ <publicKey android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMTfQsY8UuXiXmvw/y7Tpr7HoyfAC0nE/8Qdk3ZtEr9asa5qqP0F6xzCI1PGVFV+WLVRwm6FdB9StENL5EKyQFcCAwEAAQ==">
+ <keyset android:name="AB" />
+ </publicKey>
+ </keys>
+ <upgrade-keyset android:name="AB"/>
+</manifest>
diff --git a/core/tests/coretests/apks/keyset/uAuB/AndroidManifest.xml b/core/tests/coretests/apks/keyset/uAuB/AndroidManifest.xml
new file mode 100644
index 0000000..5b0b864
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/uAuB/AndroidManifest.xml
@@ -0,0 +1,30 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.keysets">
+ <application android:hasCode="false">
+ </application>
+ <keys>
+ <publicKey android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAJoN1Nsgqf0V4C/bbN8wo8O2X/S5D76+5Mb9mlIsHkUTUTbHCNk+LxHIUYLm89YbP9zImrV0bUHLUAZUyoMUCiMCAwEAAQ==">
+ <keyset android:name="A" />
+ </publicKey>
+ <publicKey android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMTfQsY8UuXiXmvw/y7Tpr7HoyfAC0nE/8Qdk3ZtEr9asa5qqP0F6xzCI1PGVFV+WLVRwm6FdB9StENL5EKyQFcCAwEAAQ==">
+ <keyset android:name="B" />
+ </publicKey>
+ </keys>
+ <upgrade-keyset android:name="A"/>
+ <upgrade-keyset android:name="B"/>
+</manifest>
diff --git a/core/tests/coretests/apks/keyset/uB/AndroidManifest.xml b/core/tests/coretests/apks/keyset/uB/AndroidManifest.xml
new file mode 100644
index 0000000..9b89961
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/uB/AndroidManifest.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.keysets">
+ <application android:hasCode="false">
+ </application>
+ <keys>
+ <publicKey android:value="MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBAMTfQsY8UuXiXmvw/y7Tpr7HoyfAC0nE/8Qdk3ZtEr9asa5qqP0F6xzCI1PGVFV+WLVRwm6FdB9StENL5EKyQFcCAwEAAQ==">
+ <keyset android:name="B" />
+ </publicKey>
+ </keys>
+ <upgrade-keyset android:name="B"/>
+</manifest>
diff --git a/core/tests/coretests/apks/keyset/uNone/AndroidManifest.xml b/core/tests/coretests/apks/keyset/uNone/AndroidManifest.xml
new file mode 100644
index 0000000..9c9ef2b
--- /dev/null
+++ b/core/tests/coretests/apks/keyset/uNone/AndroidManifest.xml
@@ -0,0 +1,20 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2010 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.
+-->
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.frameworks.coretests.keysets">
+ <application android:hasCode="false">
+ </application>
+</manifest>
diff --git a/core/tests/coretests/certs/keyset_A.pk8 b/core/tests/coretests/certs/keyset_A.pk8
new file mode 100644
index 0000000..3976b94
--- /dev/null
+++ b/core/tests/coretests/certs/keyset_A.pk8
Binary files differ
diff --git a/core/tests/coretests/certs/keyset_A.x509.pem b/core/tests/coretests/certs/keyset_A.x509.pem
new file mode 100644
index 0000000..0fe334e
--- /dev/null
+++ b/core/tests/coretests/certs/keyset_A.x509.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICKjCCAdQCCQCpDXPnNpO5UjANBgkqhkiG9w0BAQUFADCBmzELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcx
+DzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEYMBYGA1UEAxMPd3d3
+LmV4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNkY2FzaG1hbkBnb29nbGUuY29t
+MB4XDTE0MDQyMTE4MTkwM1oXDTE3MDQyMDE4MTkwM1owgZsxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MQ8w
+DQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxGDAWBgNVBAMTD3d3dy5l
+eGFtcGxlLmNvbTEiMCAGCSqGSIb3DQEJARYTZGNhc2htYW5AZ29vZ2xlLmNvbTBc
+MA0GCSqGSIb3DQEBAQUAA0sAMEgCQQCaDdTbIKn9FeAv22zfMKPDtl/0uQ++vuTG
+/ZpSLB5FE1E2xwjZPi8RyFGC5vPWGz/cyJq1dG1By1AGVMqDFAojAgMBAAEwDQYJ
+KoZIhvcNAQEFBQADQQCPTVDKxVZpxFH6Nm7sxpRplLzxbs/xyGELLIjEBVrgB0CM
+HAxFpPRHDSFpTxGG2mBCSrf+lD2Bf+WiIojx+RLY
+-----END CERTIFICATE-----
diff --git a/core/tests/coretests/certs/keyset_B.pk8 b/core/tests/coretests/certs/keyset_B.pk8
new file mode 100644
index 0000000..a44ebb3
--- /dev/null
+++ b/core/tests/coretests/certs/keyset_B.pk8
Binary files differ
diff --git a/core/tests/coretests/certs/keyset_B.x509.pem b/core/tests/coretests/certs/keyset_B.x509.pem
new file mode 100644
index 0000000..2806de5
--- /dev/null
+++ b/core/tests/coretests/certs/keyset_B.x509.pem
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICKjCCAdQCCQC+5GnAgmYS6DANBgkqhkiG9w0BAQUFADCBmzELMAkGA1UEBhMC
+VVMxEzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcx
+DzANBgNVBAoTBkdvb2dsZTEQMA4GA1UECxMHQW5kcm9pZDEYMBYGA1UEAxMPd3d3
+LmV4YW1wbGUuY29tMSIwIAYJKoZIhvcNAQkBFhNkY2FzaG1hbkBnb29nbGUuY29t
+MB4XDTE0MDQyMTE4MjczM1oXDTE3MDQyMDE4MjczM1owgZsxCzAJBgNVBAYTAlVT
+MRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQHEw1Nb3VudGFpbiBWaWV3MQ8w
+DQYDVQQKEwZHb29nbGUxEDAOBgNVBAsTB0FuZHJvaWQxGDAWBgNVBAMTD3d3dy5l
+eGFtcGxlLmNvbTEiMCAGCSqGSIb3DQEJARYTZGNhc2htYW5AZ29vZ2xlLmNvbTBc
+MA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDE30LGPFLl4l5r8P8u06a+x6MnwAtJxP/E
+HZN2bRK/WrGuaqj9BescwiNTxlRVfli1UcJuhXQfUrRDS+RCskBXAgMBAAEwDQYJ
+KoZIhvcNAQEFBQADQQCYYyur2/sMB88MOhQE8RHNmdO0zEQYAz66z3ctTNqiNsbK
+T9iKj0CT3cjqgfN5ex4onhnoIIPtON7DIHFWke5x
+-----END CERTIFICATE-----
diff --git a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
index 7f41ac1c..0244425 100644
--- a/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
+++ b/core/tests/coretests/src/android/content/pm/PackageManagerTests.java
@@ -61,7 +61,10 @@
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
+import java.util.HashSet;
import java.util.List;
+import java.util.Set;
+
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -3069,6 +3072,262 @@
}
/**
+ * The following tests are related to testing KeySets-based key rotation
+ */
+ /*
+ * Check if an apk which does not specify an upgrade-keyset may be upgraded
+ * by an apk which does
+ */
+ public void testNoKSToUpgradeKS() throws Exception {
+ replaceCerts(R.raw.keyset_sa_unone, R.raw.keyset_sa_ua, true, false, -1);
+ }
+
+ /*
+ * Check if an apk which does specify an upgrade-keyset may be downgraded to
+ * an apk which does not
+ */
+ public void testUpgradeKSToNoKS() throws Exception {
+ replaceCerts(R.raw.keyset_sa_ua, R.raw.keyset_sa_unone, true, false, -1);
+ }
+
+ /*
+ * Check if an apk signed by a key other than the upgrade keyset can update
+ * an app
+ */
+ public void testUpgradeKSWithWrongKey() throws Exception {
+ replaceCerts(R.raw.keyset_sa_ua, R.raw.keyset_sb_ua, true, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ }
+
+ /*
+ * Check if an apk signed by its signing key, which is not an upgrade key,
+ * can upgrade an app.
+ */
+ public void testUpgradeKSWithWrongSigningKey() throws Exception {
+ replaceCerts(R.raw.keyset_sa_ub, R.raw.keyset_sa_ub, true, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ }
+
+ /*
+ * Check if an apk signed by its upgrade key, which is not its signing key,
+ * can upgrade an app.
+ */
+ public void testUpgradeKSWithUpgradeKey() throws Exception {
+ replaceCerts(R.raw.keyset_sa_ub, R.raw.keyset_sb_ub, true, false, -1);
+ }
+ /*
+ * Check if an apk signed by its upgrade key, which is its signing key, can
+ * upgrade an app.
+ */
+ public void testUpgradeKSWithSigningUpgradeKey() throws Exception {
+ replaceCerts(R.raw.keyset_sa_ua, R.raw.keyset_sa_ua, true, false, -1);
+ }
+
+ /*
+ * Check if an apk signed by multiple keys, one of which is its upgrade key,
+ * can upgrade an app.
+ */
+ public void testMultipleUpgradeKSWithUpgradeKey() throws Exception {
+ replaceCerts(R.raw.keyset_sa_ua, R.raw.keyset_sab_ua, true, false, -1);
+ }
+
+ /*
+ * Check if an apk signed by multiple keys, one of which is its signing key,
+ * but none of which is an upgrade key, can upgrade an app.
+ */
+ public void testMultipleUpgradeKSWithSigningKey() throws Exception {
+ replaceCerts(R.raw.keyset_sau_ub, R.raw.keyset_sa_ua, true, true,
+ PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES);
+ }
+
+ /*
+ * Check if an apk which defines multiple (two) upgrade keysets is
+ * upgrade-able by either.
+ */
+ public void testUpgradeKSWithMultipleUpgradeKeySets() throws Exception {
+ replaceCerts(R.raw.keyset_sa_ua_ub, R.raw.keyset_sa_ua, true, false, -1);
+ replaceCerts(R.raw.keyset_sa_ua_ub, R.raw.keyset_sb_ub, true, false, -1);
+ }
+
+ /*
+ * Check if an apk's sigs are changed after upgrading with a non-signing
+ * key.
+ *
+ * TODO: consider checking against hard-coded Signatures in the Sig-tests
+ */
+ public void testSigChangeAfterUpgrade() throws Exception {
+ // install original apk and grab sigs
+ installFromRawResource("tmp.apk", R.raw.keyset_sa_ub,
+ 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ PackageManager pm = getPm();
+ String pkgName = "com.android.frameworks.coretests.keysets";
+ PackageInfo pi = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
+ assertTrue("Package should only have one signature, sig A",
+ pi.signatures.length == 1);
+ String sigBefore = pi.signatures[0].toCharsString();
+ // install apk signed by different upgrade KeySet
+ installFromRawResource("tmp2.apk", R.raw.keyset_sb_ub,
+ PackageManager.INSTALL_REPLACE_EXISTING, false, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ pi = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
+ assertTrue("Package should only have one signature, sig B",
+ pi.signatures.length == 1);
+ String sigAfter = pi.signatures[0].toCharsString();
+ assertFalse("Package signatures did not change after upgrade!",
+ sigBefore.equals(sigAfter));
+ cleanUpInstall(pkgName);
+ }
+
+ /*
+ * Check if an apk's sig is the same after upgrading with a signing
+ * key.
+ */
+ public void testSigSameAfterUpgrade() throws Exception {
+ // install original apk and grab sigs
+ installFromRawResource("tmp.apk", R.raw.keyset_sa_ua,
+ 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ PackageManager pm = getPm();
+ String pkgName = "com.android.frameworks.coretests.keysets";
+ PackageInfo pi = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
+ assertTrue("Package should only have one signature, sig A",
+ pi.signatures.length == 1);
+ String sigBefore = pi.signatures[0].toCharsString();
+ // install apk signed by same upgrade KeySet
+ installFromRawResource("tmp2.apk", R.raw.keyset_sa_ua,
+ PackageManager.INSTALL_REPLACE_EXISTING, false, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ pi = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
+ assertTrue("Package should only have one signature, sig A",
+ pi.signatures.length == 1);
+ String sigAfter = pi.signatures[0].toCharsString();
+ assertTrue("Package signatures changed after upgrade!",
+ sigBefore.equals(sigAfter));
+ cleanUpInstall(pkgName);
+ }
+
+ /*
+ * Check if an apk's sigs are the same after upgrading with an app with
+ * a subset of the original signing keys.
+ */
+ public void testSigRemovedAfterUpgrade() throws Exception {
+ // install original apk and grab sigs
+ installFromRawResource("tmp.apk", R.raw.keyset_sab_ua,
+ 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ PackageManager pm = getPm();
+ String pkgName = "com.android.frameworks.coretests.keysets";
+ PackageInfo pi = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
+ assertTrue("Package should have two signatures, sig A and sig B",
+ pi.signatures.length == 2);
+ Set<String> sigsBefore = new HashSet<String>();
+ for (int i = 0; i < pi.signatures.length; i++) {
+ sigsBefore.add(pi.signatures[i].toCharsString());
+ }
+ // install apk signed subset upgrade KeySet
+ installFromRawResource("tmp2.apk", R.raw.keyset_sa_ua,
+ PackageManager.INSTALL_REPLACE_EXISTING, false, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ pi = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
+ assertTrue("Package should only have one signature, sig A",
+ pi.signatures.length == 1);
+ String sigAfter = pi.signatures[0].toCharsString();
+ assertTrue("Original package signatures did not contain new sig",
+ sigsBefore.contains(sigAfter));
+ cleanUpInstall(pkgName);
+ }
+
+ /*
+ * Check if an apk's sigs are added to after upgrading with an app with
+ * a superset of the original signing keys.
+ */
+ public void testSigAddedAfterUpgrade() throws Exception {
+ // install original apk and grab sigs
+ installFromRawResource("tmp.apk", R.raw.keyset_sa_ua,
+ 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ PackageManager pm = getPm();
+ String pkgName = "com.android.frameworks.coretests.keysets";
+ PackageInfo pi = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
+ assertTrue("Package should only have one signature, sig A",
+ pi.signatures.length == 1);
+ String sigBefore = pi.signatures[0].toCharsString();
+ // install apk signed subset upgrade KeySet
+ installFromRawResource("tmp2.apk", R.raw.keyset_sab_ua,
+ PackageManager.INSTALL_REPLACE_EXISTING, false, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ pi = pm.getPackageInfo(pkgName, PackageManager.GET_SIGNATURES);
+ assertTrue("Package should have two signatures, sig A and sig B",
+ pi.signatures.length == 2);
+ Set<String> sigsAfter = new HashSet<String>();
+ for (int i = 0; i < pi.signatures.length; i++) {
+ sigsAfter.add(pi.signatures[i].toCharsString());
+ }
+ assertTrue("Package signatures did not change after upgrade!",
+ sigsAfter.contains(sigBefore));
+ cleanUpInstall(pkgName);
+ }
+
+ /*
+ * Check if an apk gains signature-level permission after changing to the a
+ * new signature, for which a permission should be granted.
+ */
+ public void testUpgradeSigPermGained() throws Exception {
+ // install apk which defines permission
+ installFromRawResource("permDef.apk", R.raw.keyset_permdef_sa_unone,
+ 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ // install apk which uses permission but does not have sig
+ installFromRawResource("permUse.apk", R.raw.keyset_permuse_sb_ua_ub,
+ 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ // verify that package does not have perm before
+ PackageManager pm = getPm();
+ String permPkgName = "com.android.frameworks.coretests.keysets_permdef";
+ String pkgName = "com.android.frameworks.coretests.keysets";
+ String permName = "com.android.frameworks.coretests.keysets_permdef.keyset_perm";
+ assertFalse("keyset permission granted to app without same signature!",
+ pm.checkPermission(permName, pkgName)
+ == PackageManager.PERMISSION_GRANTED);
+ // upgrade to apk with perm signature
+ installFromRawResource("permUse2.apk", R.raw.keyset_permuse_sa_ua_ub,
+ PackageManager.INSTALL_REPLACE_EXISTING, false, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ assertTrue("keyset permission not granted to app after upgrade to same sig",
+ pm.checkPermission(permName, pkgName)
+ == PackageManager.PERMISSION_GRANTED);
+ cleanUpInstall(permPkgName);
+ cleanUpInstall(pkgName);
+ }
+
+ /*
+ * Check if an apk loses signature-level permission after changing to the a
+ * new signature, from one which a permission should be granted.
+ */
+ public void testUpgradeSigPermLost() throws Exception {
+ // install apk which defines permission
+ installFromRawResource("permDef.apk", R.raw.keyset_permdef_sa_unone,
+ 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ // install apk which uses permission, signed by same sig
+ installFromRawResource("permUse.apk", R.raw.keyset_permuse_sa_ua_ub,
+ 0, false, false, -1, PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+ // verify that package does not have perm before
+ PackageManager pm = getPm();
+ String permPkgName = "com.android.frameworks.coretests.keysets_permdef";
+ String pkgName = "com.android.frameworks.coretests.keysets";
+ String permName = "com.android.frameworks.coretests.keysets_permdef.keyset_perm";
+ assertTrue("keyset permission not granted to app with same sig",
+ pm.checkPermission(permName, pkgName)
+ == PackageManager.PERMISSION_GRANTED);
+ // upgrade to apk without perm signature
+ installFromRawResource("permUse2.apk", R.raw.keyset_permuse_sb_ua_ub,
+ PackageManager.INSTALL_REPLACE_EXISTING, false, false, -1,
+ PackageInfo.INSTALL_LOCATION_UNSPECIFIED);
+
+ assertFalse("keyset permission not revoked from app which upgraded to a "
+ + "different signature",
+ pm.checkPermission(permName, pkgName)
+ == PackageManager.PERMISSION_GRANTED);
+ cleanUpInstall(permPkgName);
+ cleanUpInstall(pkgName);
+ }
+
+ /**
* The following tests are related to testing the checkSignatures api.
*/
private void checkSignatures(int apk1, int apk2, int expMatchResult) throws Exception {
diff --git a/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml b/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml
index 49eba22..0f30be2 100644
--- a/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_flashlight_off.xml
@@ -19,10 +19,16 @@
android:height="64.0dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
android:fill="#4DFFFFFF"
- android:pathData="M3.3,3.0L2.0,4.3l5.0,5.0L7.0,13.0l3.0,0.0l0.0,9.0l3.6,-6.1l4.1,4.1l1.3,-1.3L3.3,3.0zM17.0,10.0l-4.0,0.0l4.0,-8.0L7.0,2.0l0.0,2.2l8.5,8.5L17.0,10.0z"/>
-</vector>
+ android:pathData="M14.708,11.394l14.899,14.9l0.0,-6.771c4.359,-2.353 3.831,-7.489 3.831,-7.489l0.0,-0.64L14.708,11.393998z"/>
+ <path
+ android:fill="#4DFFFFFF"
+ android:pathData="M14.568,4.0l18.87,0.0l0.0,3.917l-18.87,0.0z"/>
+ <path
+ android:fill="#4DFFFFFF"
+ android:pathData="M38.284,39.427l-29.767,-29.766998 -2.4750004,2.4750004 12.351999,12.351 0.0,19.514 11.213001,0.0 0.0,-8.300999 6.2019978,6.2019997z"/>
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml b/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml
index 101ca84..2e9d4013 100644
--- a/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml
+++ b/packages/SystemUI/res/drawable/ic_qs_flashlight_on.xml
@@ -19,10 +19,13 @@
android:height="64.0dp"/>
<viewport
- android:viewportWidth="24.0"
- android:viewportHeight="24.0"/>
+ android:viewportWidth="48.0"
+ android:viewportHeight="48.0"/>
<path
android:fill="#FFFFFFFF"
- android:pathData="M7.0,2.0l0.0,11.0 3.0,0.0 0.0,9.0 7.0,-12.0 -4.0,0.0 4.0,-8.0z"/>
+ android:pathData="M33.438,12.034l0.0,-0.64l-18.87,0.0l0.0,0.64c0.0,0.0 -0.581,5.189 3.826,7.523L18.394,44.0l11.213,0.0L29.606998,19.523C33.966,17.17 33.438,12.034 33.438,12.034zM24.0,27.697c-1.523,0.0 -2.757,-1.234 -2.757,-2.757c0.0,-1.523 1.234,-2.757 2.757,-2.757c1.523,0.0 2.757,1.234 2.757,2.757C26.757,26.462 25.523,27.697 24.0,27.697z"/>
+ <path
+ android:fill="#FFFFFFFF"
+ android:pathData="M14.568,4.0l18.87,0.0l0.0,3.917l-18.87,0.0z"/>
</vector>
diff --git a/services/core/java/com/android/server/pm/KeySetManager.java b/services/core/java/com/android/server/pm/KeySetManagerService.java
similarity index 69%
rename from services/core/java/com/android/server/pm/KeySetManager.java
rename to services/core/java/com/android/server/pm/KeySetManagerService.java
index 1056cd0..96e8f30 100644
--- a/services/core/java/com/android/server/pm/KeySetManager.java
+++ b/services/core/java/com/android/server/pm/KeySetManagerService.java
@@ -19,13 +19,14 @@
import android.content.pm.KeySet;
import android.content.pm.PackageParser;
import android.os.Binder;
+import android.util.ArraySet;
import android.util.Base64;
+import android.util.Slog;
import android.util.LongSparseArray;
import java.io.IOException;
import java.io.PrintWriter;
import java.security.PublicKey;
-import java.util.HashSet;
import java.util.Map;
import java.util.Set;
@@ -36,15 +37,20 @@
/*
* Manages system-wide KeySet state.
*/
-public class KeySetManager {
+public class KeySetManagerService {
- static final String TAG = "KeySetManager";
+ static final String TAG = "KeySetManagerService";
+
+ /* original keysets implementation had no versioning info, so this is the first */
+ public static final int FIRST_VERSION = 1;
+
+ public static final int CURRENT_VERSION = FIRST_VERSION;
/** Sentinel value returned when a {@code KeySet} is not found. */
public static final long KEYSET_NOT_FOUND = -1;
/** Sentinel value returned when public key is not found. */
- private static final long PUBLIC_KEY_NOT_FOUND = -1;
+ protected static final long PUBLIC_KEY_NOT_FOUND = -1;
private final Object mLockObject = new Object();
@@ -52,7 +58,7 @@
private final LongSparseArray<PublicKey> mPublicKeys;
- private final LongSparseArray<Set<Long>> mKeySetMapping;
+ protected final LongSparseArray<Set<Long>> mKeySetMapping;
private final Map<String, PackageSetting> mPackages;
@@ -60,7 +66,7 @@
private static long lastIssuedKeyId = 0;
- public KeySetManager(Map<String, PackageSetting> packages) {
+ public KeySetManagerService(Map<String, PackageSetting> packages) {
mKeySets = new LongSparseArray<KeySet>();
mPublicKeys = new LongSparseArray<PublicKey>();
mKeySetMapping = new LongSparseArray<Set<Long>>();
@@ -100,28 +106,48 @@
public void addDefinedKeySetToPackage(String packageName,
Set<PublicKey> keys, String alias) {
if ((packageName == null) || (keys == null) || (alias == null)) {
- //Log.d(TAG, "Got null argument for a defined keyset, ignoring!");
+ Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
return;
}
synchronized (mLockObject) {
- KeySet ks = addKeySetLocked(keys);
PackageSetting pkg = mPackages.get(packageName);
if (pkg == null) {
throw new NullPointerException("Unknown package");
}
+ // Add to KeySets, then to package
+ KeySet ks = addKeySetLocked(keys);
long id = getIdByKeySetLocked(ks);
pkg.keySetData.addDefinedKeySet(id, alias);
}
}
/**
+ * This informs the system that the given package has defined a KeySet
+ * alias in its manifest to be an upgradeKeySet. This must be called
+ * after all of the defined KeySets have been added.
+ */
+ public void addUpgradeKeySetToPackage(String packageName, String alias) {
+ if ((packageName == null) || (alias == null)) {
+ Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
+ return;
+ }
+ synchronized (mLockObject) {
+ PackageSetting pkg = mPackages.get(packageName);
+ if (pkg == null) {
+ throw new NullPointerException("Unknown package");
+ }
+ pkg.keySetData.addUpgradeKeySet(alias);
+ }
+ }
+
+ /**
* Similar to the above, this informs the system that the given package
* was signed by the provided KeySet.
*/
public void addSigningKeySetToPackage(String packageName,
Set<PublicKey> signingKeys) {
if ((packageName == null) || (signingKeys == null)) {
- //Log.d(TAG, "Got null argument for a signing keyset, ignoring!");
+ Slog.w(TAG, "Got null argument for a signing keyset, ignoring!");
return;
}
synchronized (mLockObject) {
@@ -138,13 +164,13 @@
if (pkg == null) {
throw new NullPointerException("No such package!");
}
- pkg.keySetData.addSigningKeySet(id);
-
- // for each KeySet the package defines which is a subset of
- // the one above, add the KeySet id to the package's signing KeySets
- for (Long keySetID : pkg.keySetData.getDefinedKeySets()) {
+ pkg.keySetData.setProperSigningKeySet(id);
+ // for each KeySet which is a subset of the one above, add the
+ // KeySet id to the package's signing KeySets
+ for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
+ long keySetID = mKeySets.keyAt(keySetIndex);
Set<Long> definedKeys = mKeySetMapping.get(keySetID);
- if (publicKeyIds.contains(definedKeys)) {
+ if (publicKeyIds.containsAll(definedKeys)) {
pkg.keySetData.addSigningKeySet(keySetID);
}
}
@@ -184,10 +210,10 @@
}
/**
- * Fetches the KeySet that a given package refers to by the provided alias.
+ * Fetches the {@link KeySet} that a given package refers to by the provided alias.
*
- * If the package isn't known to us, throws an IllegalArgumentException.
- * Returns null if the alias isn't known to us.
+ * @throws IllegalArgumentException if the package has no keyset data.
+ * @throws NullPointerException if the package is unknown.
*/
public KeySet getKeySetByAliasAndPackageName(String packageName, String alias) {
synchronized (mLockObject) {
@@ -204,12 +230,59 @@
}
/**
+ * Fetches the {@link PublicKey public keys} which belong to the specified
+ * KeySet id.
+ *
+ * Returns {@code null} if the identifier doesn't
+ * identify a {@link KeySet}.
+ */
+ public Set<PublicKey> getPublicKeysFromKeySet(long id) {
+ synchronized (mLockObject) {
+ if(mKeySetMapping.get(id) == null) {
+ return null;
+ }
+ Set<PublicKey> mPubKeys = new ArraySet<PublicKey>();
+ for (long pkId : mKeySetMapping.get(id)) {
+ mPubKeys.add(mPublicKeys.get(pkId));
+ }
+ return mPubKeys;
+ }
+ }
+
+ /**
* Fetches all the known {@link KeySet KeySets} that signed the given
- * package. Returns {@code null} if package is unknown.
+ * package.
+ *
+ * @throws IllegalArgumentException if the package has no keyset data.
+ * @throws NullPointerException if the package is unknown.
*/
public Set<KeySet> getSigningKeySetsByPackageName(String packageName) {
synchronized (mLockObject) {
- Set<KeySet> signingKeySets = new HashSet<KeySet>();
+ Set<KeySet> signingKeySets = new ArraySet<KeySet>();
+ PackageSetting p = mPackages.get(packageName);
+ if (p == null) {
+ throw new NullPointerException("Unknown package");
+ }
+ if (p.keySetData == null || p.keySetData.getSigningKeySets() == null) {
+ throw new IllegalArgumentException("Package has no keySet data");
+ }
+ for (long l : p.keySetData.getSigningKeySets()) {
+ signingKeySets.add(mKeySets.get(l));
+ }
+ return signingKeySets;
+ }
+ }
+
+ /**
+ * Fetches all the known {@link KeySet KeySets} that may upgrade the given
+ * package.
+ *
+ * @throws IllegalArgumentException if the package has no keyset data.
+ * @throws NullPointerException if the package is unknown.
+ */
+ public Set<KeySet> getUpgradeKeySetsByPackageName(String packageName) {
+ synchronized (mLockObject) {
+ Set<KeySet> upgradeKeySets = new ArraySet<KeySet>();
PackageSetting p = mPackages.get(packageName);
if (p == null) {
throw new NullPointerException("Unknown package");
@@ -217,10 +290,12 @@
if (p.keySetData == null) {
throw new IllegalArgumentException("Package has no keySet data");
}
- for (long l : p.keySetData.getSigningKeySets()) {
- signingKeySets.add(mKeySets.get(l));
+ if (p.keySetData.isUsingUpgradeKeySets()) {
+ for (long l : p.keySetData.getUpgradeKeySets()) {
+ upgradeKeySets.add(mKeySets.get(l));
+ }
}
- return signingKeySets;
+ return upgradeKeySets;
}
}
@@ -233,6 +308,9 @@
* If the KeySet isn't known to the system, this adds that and creates the
* mapping to the PublicKeys. If it is known, then it's deduped.
*
+ * If the KeySet isn't known to the system, this adds it to all appropriate
+ * signingKeySets
+ *
* Throws if the provided set is {@code null}.
*/
private KeySet addKeySetLocked(Set<PublicKey> keys) {
@@ -240,7 +318,7 @@
throw new NullPointerException("Provided keys cannot be null");
}
// add each of the keys in the provided set
- Set<Long> addedKeyIds = new HashSet<Long>(keys.size());
+ Set<Long> addedKeyIds = new ArraySet<Long>(keys.size());
for (PublicKey k : keys) {
long id = addPublicKeyLocked(k);
addedKeyIds.add(id);
@@ -260,6 +338,19 @@
mKeySets.put(id, ks);
// add the stable key ids to the mapping
mKeySetMapping.put(id, addedKeyIds);
+ // add this KeySet id to all packages which are signed by it
+ for (String pkgName : mPackages.keySet()) {
+ PackageSetting p = mPackages.get(pkgName);
+ if (p.keySetData != null) {
+ long pProperSigning = p.keySetData.getProperSigningKeySet();
+ if (pProperSigning != PackageKeySetData.KEYSET_UNASSIGNED) {
+ Set<Long> pSigningKeys = mKeySetMapping.get(pProperSigning);
+ if (pSigningKeys.containsAll(addedKeyIds)) {
+ p.keySetData.addSigningKeySet(id);
+ }
+ }
+ }
+ }
// go home
return ks;
}
@@ -299,6 +390,15 @@
/**
* Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
*/
+ protected long getIdForPublicKey(PublicKey k) {
+ synchronized (mLockObject) {
+ return getIdForPublicKeyLocked(k);
+ }
+ }
+
+ /**
+ * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
+ */
private long getIdForPublicKeyLocked(PublicKey k) {
String encodedPublicKey = new String(k.getEncoded());
for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
@@ -330,8 +430,8 @@
public void removeAppKeySetData(String packageName) {
synchronized (mLockObject) {
// Get the package's known keys and KeySets
- Set<Long> deletableKeySets = getKnownKeySetsByPackageNameLocked(packageName);
- Set<Long> deletableKeys = new HashSet<Long>();
+ Set<Long> deletableKeySets = getOriginalKeySetsByPackageNameLocked(packageName);
+ Set<Long> deletableKeys = new ArraySet<Long>();
Set<Long> knownKeys = null;
for (Long ks : deletableKeySets) {
knownKeys = mKeySetMapping.get(ks);
@@ -340,14 +440,14 @@
}
}
- // Now remove the keys and KeySets known to any other package
+ // Now remove the keys and KeySets on which any other package relies
for (String pkgName : mPackages.keySet()) {
if (pkgName.equals(packageName)) {
continue;
}
- Set<Long> knownKeySets = getKnownKeySetsByPackageNameLocked(pkgName);
+ Set<Long> knownKeySets = getOriginalKeySetsByPackageNameLocked(pkgName);
deletableKeySets.removeAll(knownKeySets);
- knownKeys = new HashSet<Long>();
+ knownKeys = new ArraySet<Long>();
for (Long ks : knownKeySets) {
knownKeys = mKeySetMapping.get(ks);
if (knownKeys != null) {
@@ -356,7 +456,7 @@
}
}
- // The remaining keys and KeySets are not known to any other
+ // The remaining keys and KeySets are not relied on by any other
// application and so can be safely deleted.
for (Long ks : deletableKeySets) {
mKeySets.delete(ks);
@@ -366,18 +466,28 @@
mPublicKeys.delete(keyId);
}
- // Now remove them from the KeySets known to each package
+ // Now remove the deleted KeySets from each package's signingKeySets
for (String pkgName : mPackages.keySet()) {
PackageSetting p = mPackages.get(pkgName);
for (Long ks : deletableKeySets) {
p.keySetData.removeSigningKeySet(ks);
- p.keySetData.removeDefinedKeySet(ks);
}
}
+
+ // Finally, remove all KeySets from the original package
+ PackageSetting p = mPackages.get(packageName);
+ clearPackageKeySetDataLocked(p);
}
}
- private Set<Long> getKnownKeySetsByPackageNameLocked(String packageName) {
+ private void clearPackageKeySetDataLocked(PackageSetting p) {
+ p.keySetData.removeAllSigningKeySets();
+ p.keySetData.removeAllUpgradeKeySets();
+ p.keySetData.removeAllDefinedKeySets();
+ return;
+ }
+
+ private Set<Long> getOriginalKeySetsByPackageNameLocked(String packageName) {
PackageSetting p = mPackages.get(packageName);
if (p == null) {
throw new NullPointerException("Unknown package");
@@ -385,12 +495,12 @@
if (p.keySetData == null) {
throw new IllegalArgumentException("Package has no keySet data");
}
- Set<Long> knownKeySets = new HashSet<Long>();
- for (long ks : p.keySetData.getSigningKeySets()) {
- knownKeySets.add(ks);
- }
- for (long ks : p.keySetData.getDefinedKeySets()) {
- knownKeySets.add(ks);
+ Set<Long> knownKeySets = new ArraySet<Long>();
+ knownKeySets.add(p.keySetData.getProperSigningKeySet());
+ if (p.keySetData.isUsingDefinedKeySets()) {
+ for (long ks : p.keySetData.getDefinedKeySets()) {
+ knownKeySets.add(ks);
+ }
}
return knownKeySets;
}
@@ -433,14 +543,16 @@
pw.println("");
}
printedLabel = false;
- for (long keySetId : pkg.keySetData.getDefinedKeySets()) {
- if (!printedLabel) {
- pw.print(" Defined KeySets: ");
- printedLabel = true;
- } else {
- pw.print(", ");
+ if (pkg.keySetData.isUsingDefinedKeySets()) {
+ for (long keySetId : pkg.keySetData.getDefinedKeySets()) {
+ if (!printedLabel) {
+ pw.print(" Defined KeySets: ");
+ printedLabel = true;
+ } else {
+ pw.print(", ");
+ }
+ pw.print(Long.toString(keySetId));
}
- pw.print(Long.toString(keySetId));
}
if (printedLabel) {
pw.println("");
@@ -458,13 +570,29 @@
if (printedLabel) {
pw.println("");
}
+ printedLabel = false;
+ if (pkg.keySetData.isUsingUpgradeKeySets()) {
+ for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
+ if (!printedLabel) {
+ pw.print(" Upgrade KeySets: ");
+ printedLabel = true;
+ } else {
+ pw.print(", ");
+ }
+ pw.print(Long.toString(keySetId));
+ }
+ }
+ if (printedLabel) {
+ pw.println("");
+ }
}
}
}
}
- void writeKeySetManagerLPr(XmlSerializer serializer) throws IOException {
+ void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException {
serializer.startTag(null, "keyset-settings");
+ serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
writePublicKeysLPr(serializer);
writeKeySetsLPr(serializer);
serializer.startTag(null, "lastIssuedKeyId");
@@ -511,7 +639,24 @@
throws XmlPullParserException, IOException {
int type;
long currentKeySetId = 0;
- while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
+ int outerDepth = parser.getDepth();
+ String recordedVersion = parser.getAttributeValue(null, "version");
+ if (recordedVersion == null || Integer.parseInt(recordedVersion) != CURRENT_VERSION) {
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ // Our version is different than the one which generated the old keyset data.
+ // We don't want any of the old data, but we must advance the parser
+ continue;
+ }
+ // The KeySet information read previously from packages.xml is invalid.
+ // Destroy it all.
+ for (PackageSetting p : mPackages.values()) {
+ clearPackageKeySetDataLocked(p);
+ }
+ return;
+ }
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
@@ -520,6 +665,10 @@
readKeysLPw(parser);
} else if (tagName.equals("keysets")) {
readKeySetListLPw(parser);
+ } else if (tagName.equals("lastIssuedKeyId")) {
+ lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
+ } else if (tagName.equals("lastIssuedKeySetId")) {
+ lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
}
}
}
@@ -536,10 +685,6 @@
final String tagName = parser.getName();
if (tagName.equals("public-key")) {
readPublicKeyLPw(parser);
- } else if (tagName.equals("lastIssuedKeyId")) {
- lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
- } else if (tagName.equals("lastIssuedKeySetId")) {
- lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
}
}
}
@@ -558,7 +703,7 @@
if (tagName.equals("keyset")) {
currentKeySetId = readIdentifierLPw(parser);
mKeySets.put(currentKeySetId, new KeySet(new Binder()));
- mKeySetMapping.put(currentKeySetId, new HashSet<Long>());
+ mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
} else if (tagName.equals("key-id")) {
long id = readIdentifierLPw(parser);
mKeySetMapping.get(currentKeySetId).add(id);
diff --git a/services/core/java/com/android/server/pm/PackageKeySetData.java b/services/core/java/com/android/server/pm/PackageKeySetData.java
index ebded28..d470807 100644
--- a/services/core/java/com/android/server/pm/PackageKeySetData.java
+++ b/services/core/java/com/android/server/pm/PackageKeySetData.java
@@ -16,108 +16,137 @@
package com.android.server.pm;
+import com.android.internal.util.ArrayUtils;
+
import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
public class PackageKeySetData {
+ static final long KEYSET_UNASSIGNED = -1;
+
+ /* KeySet containing all signing keys - superset of the others */
+ private long mProperSigningKeySet;
+
private long[] mSigningKeySets;
+ private long[] mUpgradeKeySets;
+
private long[] mDefinedKeySets;
private final Map<String, Long> mKeySetAliases;
PackageKeySetData() {
- mSigningKeySets = new long[0];
- mDefinedKeySets = new long[0];
- mKeySetAliases = new HashMap<String, Long>();
+ mProperSigningKeySet = KEYSET_UNASSIGNED;
+ mKeySetAliases = new HashMap<String, Long>();
}
PackageKeySetData(PackageKeySetData original) {
mSigningKeySets = original.getSigningKeySets().clone();
+ mUpgradeKeySets = original.getUpgradeKeySets().clone();
mDefinedKeySets = original.getDefinedKeySets().clone();
mKeySetAliases = new HashMap<String, Long>();
mKeySetAliases.putAll(original.getAliases());
}
- public void addSigningKeySet(long ks) {
- // deduplicate
- for (long knownKeySet : mSigningKeySets) {
- if (ks == knownKeySet) {
- return;
- }
+ protected void setProperSigningKeySet(long ks) {
+ if (ks == mProperSigningKeySet) {
+
+ /* nothing to change */
+ return;
}
- int end = mSigningKeySets.length;
- mSigningKeySets = Arrays.copyOf(mSigningKeySets, end + 1);
- mSigningKeySets[end] = ks;
+
+ /* otherwise, our current signing keysets are likely invalid */
+ removeAllSigningKeySets();
+ mProperSigningKeySet = ks;
+ addSigningKeySet(ks);
+ return;
}
- public void removeSigningKeySet(long ks) {
- if (packageIsSignedBy(ks)) {
- long[] keysets = new long[mSigningKeySets.length - 1];
- int index = 0;
- for (long signingKeySet : mSigningKeySets) {
- if (signingKeySet != ks) {
- keysets[index] = signingKeySet;
- index += 1;
- }
- }
- mSigningKeySets = keysets;
+ protected long getProperSigningKeySet() {
+ return mProperSigningKeySet;
+ }
+
+ protected void addSigningKeySet(long ks) {
+ mSigningKeySets = ArrayUtils.appendLong(mSigningKeySets, ks);
+ }
+
+ protected void removeSigningKeySet(long ks) {
+ mSigningKeySets = ArrayUtils.removeLong(mSigningKeySets, ks);
+ }
+
+ protected void addUpgradeKeySet(String alias) {
+
+ /* must have previously been defined */
+ Long ks = mKeySetAliases.get(alias);
+ if (ks != null) {
+ mUpgradeKeySets = ArrayUtils.appendLong(mUpgradeKeySets, ks);
+ } else {
+ throw new IllegalArgumentException("Upgrade keyset alias " + alias
+ + "does not refer to a defined keyset alias!");
}
}
- public void addDefinedKeySet(long ks, String alias) {
- // deduplicate
- for (long knownKeySet : mDefinedKeySets) {
- if (ks == knownKeySet) {
- return;
- }
- }
- int end = mDefinedKeySets.length;
- mDefinedKeySets = Arrays.copyOf(mDefinedKeySets, end + 1);
- mDefinedKeySets[end] = ks;
+ /*
+ * Used only when restoring keyset data from persistent storage. Must
+ * correspond to a defined-keyset.
+ */
+ protected void addUpgradeKeySetById(long ks) {
+ mSigningKeySets = ArrayUtils.appendLong(mSigningKeySets, ks);
+ }
+
+ protected void addDefinedKeySet(long ks, String alias) {
+ mDefinedKeySets = ArrayUtils.appendLong(mDefinedKeySets, ks);
mKeySetAliases.put(alias, ks);
}
- public void removeDefinedKeySet(long ks) {
- if (mKeySetAliases.containsValue(ks)) {
- long[] keysets = new long[mDefinedKeySets.length - 1];
- int index = 0;
- for (long definedKeySet : mDefinedKeySets) {
- if (definedKeySet != ks) {
- keysets[index] = definedKeySet;
- index += 1;
- }
- }
- mDefinedKeySets = keysets;
- for (String alias : mKeySetAliases.keySet()) {
- if (mKeySetAliases.get(alias) == ks) {
- mKeySetAliases.remove(alias);
- break;
- }
- }
- }
+ protected void removeAllSigningKeySets() {
+ mProperSigningKeySet = KEYSET_UNASSIGNED;
+ mSigningKeySets = null;
+ return;
}
- public boolean packageIsSignedBy(long ks) {
- for (long signingKeySet : mSigningKeySets) {
- if (ks == signingKeySet) {
- return true;
- }
- }
- return false;
+ protected void removeAllUpgradeKeySets() {
+ mUpgradeKeySets = null;
+ return;
}
- public long[] getSigningKeySets() {
+ protected void removeAllDefinedKeySets() {
+ mDefinedKeySets = null;
+ mKeySetAliases.clear();
+ return;
+ }
+
+ protected boolean packageIsSignedBy(long ks) {
+ return ArrayUtils.contains(mSigningKeySets, ks);
+ }
+
+ protected long[] getSigningKeySets() {
return mSigningKeySets;
}
- public long[] getDefinedKeySets() {
+ protected long[] getUpgradeKeySets() {
+ return mUpgradeKeySets;
+ }
+
+ protected long[] getDefinedKeySets() {
return mDefinedKeySets;
}
- public Map<String, Long> getAliases() {
+ protected Map<String, Long> getAliases() {
return mKeySetAliases;
}
+
+ protected boolean isUsingDefinedKeySets() {
+
+ /* should never be the case that mDefinedKeySets.length == 0 */
+ return (mDefinedKeySets != null && mDefinedKeySets.length > 0);
+ }
+
+ protected boolean isUsingUpgradeKeySets() {
+
+ /* should never be the case that mUpgradeKeySets.length == 0 */
+ return (mUpgradeKeySets != null && mUpgradeKeySets.length > 0);
+ }
}
\ No newline at end of file
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
old mode 100755
new mode 100644
index 9471cff..bc45ae0
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -2814,7 +2814,7 @@
// Migrate the old signatures to the new scheme.
existingSigs.assignSignatures(scannedPkg.mSignatures);
// The new KeySets will be re-added later in the scanning process.
- mSettings.mKeySetManager.removeAppKeySetData(scannedPkg.packageName);
+ mSettings.mKeySetManagerService.removeAppKeySetData(scannedPkg.packageName);
return PackageManager.SIGNATURE_MATCH;
}
return PackageManager.SIGNATURE_NO_MATCH;
@@ -4136,11 +4136,15 @@
&& ps.codePath.equals(srcFile)
&& ps.timeStamp == srcFile.lastModified()
&& !isCompatSignatureUpdateNeeded(pkg)) {
+ long mSigningKeySetId = ps.keySetData.getProperSigningKeySet();
if (ps.signatures.mSignatures != null
- && ps.signatures.mSignatures.length != 0) {
+ && ps.signatures.mSignatures.length != 0
+ && mSigningKeySetId != PackageKeySetData.KEYSET_UNASSIGNED) {
// Optimization: reuse the existing cached certificates
// if the package appears to be unchanged.
pkg.mSignatures = ps.signatures.mSignatures;
+ KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ pkg.mSigningKeys = ksms.getPublicKeysFromKeySet(mSigningKeySetId);
return true;
}
@@ -4411,6 +4415,7 @@
return false;
}
}
+
// Check for shared user signatures
if (pkgSetting.sharedUser != null && pkgSetting.sharedUser.signatures.mSignatures != null) {
// Already existing package. Make sure signatures match
@@ -5103,33 +5108,43 @@
pkg.applicationInfo.uid = pkgSetting.appId;
pkg.mExtras = pkgSetting;
-
- if (!verifySignaturesLP(pkgSetting, pkg)) {
- if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
- return null;
- }
- // The signature has changed, but this package is in the system
- // image... let's recover!
- pkgSetting.signatures.mSignatures = pkg.mSignatures;
- // However... if this package is part of a shared user, but it
- // doesn't match the signature of the shared user, let's fail.
- // What this means is that you can't change the signatures
- // associated with an overall shared user, which doesn't seem all
- // that unreasonable.
- if (pkgSetting.sharedUser != null) {
- if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
- pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
- Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
- mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ if (!pkgSetting.keySetData.isUsingUpgradeKeySets() || pkgSetting.sharedUser != null) {
+ if (!verifySignaturesLP(pkgSetting, pkg)) {
+ if ((parseFlags&PackageParser.PARSE_IS_SYSTEM_DIR) == 0) {
return null;
}
- }
- // File a report about this.
- String msg = "System package " + pkg.packageName
+ // The signature has changed, but this package is in the system
+ // image... let's recover!
+ pkgSetting.signatures.mSignatures = pkg.mSignatures;
+ // However... if this package is part of a shared user, but it
+ // doesn't match the signature of the shared user, let's fail.
+ // What this means is that you can't change the signatures
+ // associated with an overall shared user, which doesn't seem all
+ // that unreasonable.
+ if (pkgSetting.sharedUser != null) {
+ if (compareSignatures(pkgSetting.sharedUser.signatures.mSignatures,
+ pkg.mSignatures) != PackageManager.SIGNATURE_MATCH) {
+ Log.w(TAG, "Signature mismatch for shared user : " + pkgSetting.sharedUser);
+ mLastScanError = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ return null;
+ }
+ }
+ // File a report about this.
+ String msg = "System package " + pkg.packageName
+ " signature changed; retaining data.";
- reportSettingsProblem(Log.WARN, msg);
+ reportSettingsProblem(Log.WARN, msg);
+ }
+ } else {
+ if (!checkUpgradeKeySetLP(pkgSetting, pkg)) {
+ Slog.e(TAG, "Package " + pkg.packageName
+ + " upgrade keys do not match the previously installed version; ");
+ mLastScanError = PackageManager.INSTALL_FAILED_UPDATE_INCOMPATIBLE;
+ return null;
+ } else {
+ // signatures may have changed as result of upgrade
+ pkgSetting.signatures.mSignatures = pkg.mSignatures;
+ }
}
-
// Verify that this new package doesn't have any content providers
// that conflict with existing packages. Only do this if the
// package isn't already installed, since we don't want to break
@@ -5636,16 +5651,24 @@
}
}
- // Add the package's KeySets to the global KeySetManager
- KeySetManager ksm = mSettings.mKeySetManager;
+ // Add the package's KeySets to the global KeySetManagerService
+ KeySetManagerService ksms = mSettings.mKeySetManagerService;
try {
- ksm.addSigningKeySetToPackage(pkg.packageName, pkg.mSigningKeys);
+ // Old KeySetData no longer valid.
+ ksms.removeAppKeySetData(pkg.packageName);
+ ksms.addSigningKeySetToPackage(pkg.packageName, pkg.mSigningKeys);
if (pkg.mKeySetMapping != null) {
- for (Map.Entry<String, ArraySet<PublicKey>> entry :
+ for (Map.Entry<String, Set<PublicKey>> entry :
pkg.mKeySetMapping.entrySet()) {
if (entry.getValue() != null) {
- ksm.addDefinedKeySetToPackage(pkg.packageName,
- entry.getValue(), entry.getKey());
+ ksms.addDefinedKeySetToPackage(pkg.packageName,
+ entry.getValue(), entry.getKey());
+ }
+ }
+ if (pkg.mUpgradeKeySets != null
+ && pkg.mKeySetMapping.keySet().containsAll(pkg.mUpgradeKeySets)) {
+ for (String upgradeAlias : pkg.mUpgradeKeySets) {
+ ksms.addUpgradeKeySetToPackage(pkg.packageName, upgradeAlias);
}
}
}
@@ -9861,10 +9884,28 @@
}
}
+ private boolean checkUpgradeKeySetLP(PackageSetting oldPS, PackageParser.Package newPkg) {
+ // Upgrade keysets are being used. Determine if new package has a superset of the
+ // required keys.
+ long[] upgradeKeySets = oldPS.keySetData.getUpgradeKeySets();
+ KeySetManagerService ksms = mSettings.mKeySetManagerService;
+ Set<Long> newSigningKeyIds = new ArraySet<Long>();
+ for (PublicKey pk : newPkg.mSigningKeys) {
+ newSigningKeyIds.add(ksms.getIdForPublicKey(pk));
+ }
+ //remove PUBLIC_KEY_NOT_FOUND, although not necessary
+ newSigningKeyIds.remove(ksms.PUBLIC_KEY_NOT_FOUND);
+ for (int i = 0; i < upgradeKeySets.length; i++) {
+ if (newSigningKeyIds.containsAll(ksms.mKeySetMapping.get(upgradeKeySets[i]))) {
+ return true;
+ }
+ }
+ return false;
+ }
+
private void replacePackageLI(PackageParser.Package pkg,
int parseFlags, int scanMode, UserHandle user,
String installerPackageName, PackageInstalledInfo res, String abiOverride) {
-
PackageParser.Package oldPackage;
String pkgName = pkg.packageName;
int[] allUsers;
@@ -9874,15 +9915,25 @@
synchronized(mPackages) {
oldPackage = mPackages.get(pkgName);
if (DEBUG_INSTALL) Slog.d(TAG, "replacePackageLI: new=" + pkg + ", old=" + oldPackage);
- if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
+ PackageSetting ps = mSettings.mPackages.get(pkgName);
+ if (ps == null || !ps.keySetData.isUsingUpgradeKeySets() || ps.sharedUser != null) {
+ // default to original signature matching
+ if (compareSignatures(oldPackage.mSignatures, pkg.mSignatures)
!= PackageManager.SIGNATURE_MATCH) {
- Slog.w(TAG, "New package has a different signature: " + pkgName);
- res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
- return;
+ Slog.w(TAG, "New package has a different signature: " + pkgName);
+ res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ return;
+ }
+ } else {
+ if(!checkUpgradeKeySetLP(ps, pkg)) {
+ Slog.w(TAG, "New package not signed by keys specified by upgrade-keysets: "
+ + pkgName);
+ res.returnCode = PackageManager.INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
+ return;
+ }
}
// In case of rollback, remember per-user/profile install state
- PackageSetting ps = mSettings.mPackages.get(pkgName);
allUsers = sUserManager.getUserIds();
perUserInstalled = new boolean[allUsers.length];
for (int i = 0; i < allUsers.length; i++) {
@@ -10636,6 +10687,7 @@
if (deletedPs != null) {
if ((flags&PackageManager.DELETE_KEEP_DATA) == 0) {
if (outInfo != null) {
+ mSettings.mKeySetManagerService.removeAppKeySetData(packageName);
outInfo.removedAppId = mSettings.removePackageLPw(packageName);
}
if (deletedPs != null) {
@@ -10890,7 +10942,6 @@
}
boolean ret = false;
- mSettings.mKeySetManager.removeAppKeySetData(packageName);
if (isSystemApp(ps)) {
if (DEBUG_REMOVE) Slog.d(TAG, "Removing system package:" + ps.name);
// When an updated system application is deleted we delete the existing resources as well and
@@ -12271,7 +12322,7 @@
}
if (!checkin && dumpState.isDumping(DumpState.DUMP_KEYSETS)) {
- mSettings.mKeySetManager.dump(pw, packageName, dumpState);
+ mSettings.mKeySetManagerService.dump(pw, packageName, dumpState);
}
if (dumpState.isDumping(DumpState.DUMP_PACKAGES)) {
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 1867ff3..4304dee 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -244,7 +244,7 @@
private final File mSystemDir;
- public final KeySetManager mKeySetManager = new KeySetManager(mPackages);
+ public final KeySetManagerService mKeySetManagerService = new KeySetManagerService(mPackages);
// A mapping of (sourceUserId, targetUserId, packageNames) for forwarding the intents of a
// package.
@@ -1721,7 +1721,7 @@
}
}
- mKeySetManager.writeKeySetManagerLPr(serializer);
+ mKeySetManagerService.writeKeySetManagerServiceLPr(serializer);
serializer.endTag(null, "packages");
@@ -1936,6 +1936,7 @@
}
writeSigningKeySetsLPr(serializer, pkg.keySetData);
+ writeUpgradeKeySetsLPr(serializer, pkg.keySetData);
writeKeySetAliasesLPr(serializer, pkg.keySetData);
serializer.endTag(null, "package");
@@ -1943,10 +1944,23 @@
void writeSigningKeySetsLPr(XmlSerializer serializer,
PackageKeySetData data) throws IOException {
- for (long id : data.getSigningKeySets()) {
- serializer.startTag(null, "signing-keyset");
- serializer.attribute(null, "identifier", Long.toString(id));
- serializer.endTag(null, "signing-keyset");
+ if (data.getSigningKeySets() != null) {
+ for (long id : data.getSigningKeySets()) {
+ serializer.startTag(null, "signing-keyset");
+ serializer.attribute(null, "identifier", Long.toString(id));
+ serializer.endTag(null, "signing-keyset");
+ }
+ }
+ }
+
+ void writeUpgradeKeySetsLPr(XmlSerializer serializer,
+ PackageKeySetData data) throws IOException {
+ if (data.isUsingUpgradeKeySets()) {
+ for (long id : data.getUpgradeKeySets()) {
+ serializer.startTag(null, "upgrade-keyset");
+ serializer.attribute(null, "identifier", Long.toString(id));
+ serializer.endTag(null, "upgrade-keyset");
+ }
}
}
@@ -2157,7 +2171,7 @@
final String enforcement = parser.getAttributeValue(null, ATTR_ENFORCEMENT);
mReadExternalStorageEnforced = "1".equals(enforcement);
} else if (tagName.equals("keyset-settings")) {
- mKeySetManager.readKeySetsLPw(parser);
+ mKeySetManagerService.readKeySetsLPw(parser);
} else {
Slog.w(PackageManagerService.TAG, "Unknown element under <packages>: "
+ parser.getName());
@@ -2893,8 +2907,9 @@
} else if (tagName.equals("signing-keyset")) {
long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
packageSetting.keySetData.addSigningKeySet(id);
- if (false) Slog.d(TAG, "Adding signing keyset " + Long.toString(id)
- + " to " + name);
+ } else if (tagName.equals("upgrade-keyset")) {
+ long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
+ packageSetting.keySetData.addUpgradeKeySetById(id);
} else if (tagName.equals("defined-keyset")) {
long id = Long.parseLong(parser.getAttributeValue(null, "identifier"));
String alias = parser.getAttributeValue(null, "alias");