| /* |
| * Copyright (C) 2013 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; |
| |
| 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.Map; |
| import java.util.Set; |
| |
| import org.xmlpull.v1.XmlPullParser; |
| import org.xmlpull.v1.XmlPullParserException; |
| import org.xmlpull.v1.XmlSerializer; |
| |
| /* |
| * Manages system-wide KeySet state. |
| */ |
| public class KeySetManagerService { |
| |
| 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. */ |
| protected static final long PUBLIC_KEY_NOT_FOUND = -1; |
| |
| private final LongSparseArray<KeySetHandle> mKeySets; |
| |
| private final LongSparseArray<PublicKey> mPublicKeys; |
| |
| protected final LongSparseArray<ArraySet<Long>> mKeySetMapping; |
| |
| private final Map<String, PackageSetting> mPackages; |
| |
| private static long lastIssuedKeySetId = 0; |
| |
| private static long lastIssuedKeyId = 0; |
| |
| public KeySetManagerService(Map<String, PackageSetting> packages) { |
| mKeySets = new LongSparseArray<KeySetHandle>(); |
| mPublicKeys = new LongSparseArray<PublicKey>(); |
| mKeySetMapping = new LongSparseArray<ArraySet<Long>>(); |
| mPackages = packages; |
| } |
| |
| /** |
| * Determine if a package is signed by the given KeySet. |
| * |
| * Returns false if the package was not signed by all the |
| * keys in the KeySet. |
| * |
| * Returns true if the package was signed by at least the |
| * keys in the given KeySet. |
| * |
| * Note that this can return true for multiple KeySets. |
| */ |
| public boolean packageIsSignedByLPr(String packageName, KeySetHandle ks) { |
| PackageSetting pkg = mPackages.get(packageName); |
| if (pkg == null) { |
| throw new NullPointerException("Invalid package name"); |
| } |
| if (pkg.keySetData == null) { |
| throw new NullPointerException("Package has no KeySet data"); |
| } |
| long id = getIdByKeySetLPr(ks); |
| if (id == KEYSET_NOT_FOUND) { |
| return false; |
| } |
| return pkg.keySetData.packageIsSignedBy(id); |
| } |
| |
| /** |
| * Determine if a package is signed by the given KeySet. |
| * |
| * Returns false if the package was not signed by all the |
| * keys in the KeySet, or if the package was signed by keys |
| * not in the KeySet. |
| * |
| * Note that this can return only for one KeySet. |
| */ |
| public boolean packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks) { |
| PackageSetting pkg = mPackages.get(packageName); |
| if (pkg == null) { |
| throw new NullPointerException("Invalid package name"); |
| } |
| if (pkg.keySetData == null |
| || pkg.keySetData.getProperSigningKeySet() |
| == PackageKeySetData.KEYSET_UNASSIGNED) { |
| throw new NullPointerException("Package has no KeySet data"); |
| } |
| long id = getIdByKeySetLPr(ks); |
| return pkg.keySetData.getProperSigningKeySet() == id; |
| } |
| |
| /** |
| * This informs the system that the given package has defined a KeySet |
| * in its manifest that a) contains the given keys and b) is named |
| * alias by that package. |
| */ |
| public void addDefinedKeySetToPackageLPw(String packageName, |
| ArraySet<PublicKey> keys, String alias) { |
| if ((packageName == null) || (keys == null) || (alias == null)) { |
| Slog.w(TAG, "Got null argument for a defined keyset, ignoring!"); |
| return; |
| } |
| PackageSetting pkg = mPackages.get(packageName); |
| if (pkg == null) { |
| throw new NullPointerException("Unknown package"); |
| } |
| // Add to KeySets, then to package |
| KeySetHandle ks = addKeySetLPw(keys); |
| long id = getIdByKeySetLPr(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 addUpgradeKeySetToPackageLPw(String packageName, String alias) { |
| if ((packageName == null) || (alias == null)) { |
| Slog.w(TAG, "Got null argument for a defined keyset, ignoring!"); |
| return; |
| } |
| 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 addSigningKeySetToPackageLPw(String packageName, |
| ArraySet<PublicKey> signingKeys) { |
| if ((packageName == null) || (signingKeys == null)) { |
| Slog.w(TAG, "Got null argument for a signing keyset, ignoring!"); |
| return; |
| } |
| // add the signing KeySet |
| KeySetHandle ks = addKeySetLPw(signingKeys); |
| long id = getIdByKeySetLPr(ks); |
| ArraySet<Long> publicKeyIds = mKeySetMapping.get(id); |
| if (publicKeyIds == null) { |
| throw new NullPointerException("Got invalid KeySet id"); |
| } |
| // attach it to the package |
| PackageSetting pkg = mPackages.get(packageName); |
| if (pkg == null) { |
| throw new NullPointerException("No such package!"); |
| } |
| 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); |
| ArraySet<Long> definedKeys = mKeySetMapping.get(keySetID); |
| if (publicKeyIds.containsAll(definedKeys)) { |
| pkg.keySetData.addSigningKeySet(keySetID); |
| } |
| } |
| } |
| |
| /** |
| * Fetches the stable identifier associated with the given KeySet. Returns |
| * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found. |
| */ |
| private long getIdByKeySetLPr(KeySetHandle ks) { |
| for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) { |
| KeySetHandle value = mKeySets.valueAt(keySetIndex); |
| if (ks.equals(value)) { |
| return mKeySets.keyAt(keySetIndex); |
| } |
| } |
| return KEYSET_NOT_FOUND; |
| } |
| |
| /** |
| * Fetches the KeySet corresponding to the given stable identifier. |
| * |
| * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't |
| * identify a {@link KeySet}. |
| */ |
| public KeySetHandle getKeySetByIdLPr(long id) { |
| return mKeySets.get(id); |
| } |
| |
| /** |
| * Fetches the {@link KeySetHandle} that a given package refers to by the |
| * provided alias. Returns null if the package is unknown or does not have a |
| * KeySet corresponding to that alias. |
| */ |
| public KeySetHandle getKeySetByAliasAndPackageNameLPr(String packageName, String alias) { |
| PackageSetting p = mPackages.get(packageName); |
| if (p == null || p.keySetData == null) { |
| return null; |
| } |
| Long keySetId = p.keySetData.getAliases().get(alias); |
| if (keySetId == null) { |
| throw new IllegalArgumentException("Unknown KeySet alias: " + alias); |
| } |
| return mKeySets.get(keySetId); |
| } |
| |
| /** |
| * Fetches the {@link PublicKey public keys} which belong to the specified |
| * KeySet id. |
| * |
| * Returns {@code null} if the identifier doesn't |
| * identify a {@link KeySetHandle}. |
| */ |
| public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) { |
| if(mKeySetMapping.get(id) == null) { |
| return null; |
| } |
| ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>(); |
| for (long pkId : mKeySetMapping.get(id)) { |
| mPubKeys.add(mPublicKeys.get(pkId)); |
| } |
| return mPubKeys; |
| } |
| |
| /** |
| * Fetches the proper {@link KeySetHandle KeySet} that signed the given |
| * package. |
| * |
| * @throws IllegalArgumentException if the package has no keyset data. |
| * @throws NullPointerException if the package is unknown. |
| */ |
| public KeySetHandle getSigningKeySetByPackageNameLPr(String packageName) { |
| PackageSetting p = mPackages.get(packageName); |
| if (p == null |
| || p.keySetData == null |
| || p.keySetData.getProperSigningKeySet() |
| == PackageKeySetData.KEYSET_UNASSIGNED) { |
| return null; |
| } |
| return mKeySets.get(p.keySetData.getProperSigningKeySet()); |
| } |
| |
| /** |
| * Fetches all the known {@link KeySetHandle KeySets} that may upgrade the given |
| * package. |
| * |
| * @throws IllegalArgumentException if the package has no keyset data. |
| * @throws NullPointerException if the package is unknown. |
| */ |
| public ArraySet<KeySetHandle> getUpgradeKeySetsByPackageNameLPr(String packageName) { |
| ArraySet<KeySetHandle> upgradeKeySets = new ArraySet<KeySetHandle>(); |
| PackageSetting p = mPackages.get(packageName); |
| if (p == null) { |
| throw new NullPointerException("Unknown package"); |
| } |
| if (p.keySetData == null) { |
| throw new IllegalArgumentException("Package has no keySet data"); |
| } |
| if (p.keySetData.isUsingUpgradeKeySets()) { |
| for (long l : p.keySetData.getUpgradeKeySets()) { |
| upgradeKeySets.add(mKeySets.get(l)); |
| } |
| } |
| return upgradeKeySets; |
| } |
| |
| /** |
| * Creates a new KeySet corresponding to the given keys. |
| * |
| * If the {@link PublicKey PublicKeys} aren't known to the system, this |
| * adds them. Otherwise, they're deduped. |
| * |
| * 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 KeySetHandle addKeySetLPw(ArraySet<PublicKey> keys) { |
| if (keys == null) { |
| throw new NullPointerException("Provided keys cannot be null"); |
| } |
| // add each of the keys in the provided set |
| ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size()); |
| for (PublicKey k : keys) { |
| long id = addPublicKeyLPw(k); |
| addedKeyIds.add(id); |
| } |
| |
| // check to see if the resulting keyset is new |
| long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds); |
| if (existingKeySetId != KEYSET_NOT_FOUND) { |
| return mKeySets.get(existingKeySetId); |
| } |
| |
| // create the KeySet object |
| KeySetHandle ks = new KeySetHandle(); |
| // get the first unoccupied slot in mKeySets |
| long id = getFreeKeySetIDLPw(); |
| // add the KeySet object to it |
| 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) { |
| ArraySet<Long> pSigningKeys = mKeySetMapping.get(pProperSigning); |
| if (pSigningKeys.containsAll(addedKeyIds)) { |
| p.keySetData.addSigningKeySet(id); |
| } |
| } |
| } |
| } |
| // go home |
| return ks; |
| } |
| |
| /** |
| * Adds the given PublicKey to the system, deduping as it goes. |
| */ |
| private long addPublicKeyLPw(PublicKey key) { |
| // check if the public key is new |
| long existingKeyId = getIdForPublicKeyLPr(key); |
| if (existingKeyId != PUBLIC_KEY_NOT_FOUND) { |
| return existingKeyId; |
| } |
| // if it's new find the first unoccupied slot in the public keys |
| long id = getFreePublicKeyIdLPw(); |
| // add the public key to it |
| mPublicKeys.put(id, key); |
| // return the stable identifier |
| return id; |
| } |
| |
| /** |
| * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs. |
| * |
| * Returns KEYSET_NOT_FOUND if there isn't one. |
| */ |
| private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) { |
| for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) { |
| ArraySet<Long> value = mKeySetMapping.valueAt(keyMapIndex); |
| if (value.equals(publicKeyIds)) { |
| return mKeySetMapping.keyAt(keyMapIndex); |
| } |
| } |
| return KEYSET_NOT_FOUND; |
| } |
| |
| /** |
| * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND. |
| */ |
| private long getIdForPublicKeyLPr(PublicKey k) { |
| String encodedPublicKey = new String(k.getEncoded()); |
| for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) { |
| PublicKey value = mPublicKeys.valueAt(publicKeyIndex); |
| String encodedExistingKey = new String(value.getEncoded()); |
| if (encodedPublicKey.equals(encodedExistingKey)) { |
| return mPublicKeys.keyAt(publicKeyIndex); |
| } |
| } |
| return PUBLIC_KEY_NOT_FOUND; |
| } |
| |
| /** |
| * Gets an unused stable identifier for a KeySet. |
| */ |
| private long getFreeKeySetIDLPw() { |
| lastIssuedKeySetId += 1; |
| return lastIssuedKeySetId; |
| } |
| |
| /** |
| * Same as above, but for public keys. |
| */ |
| private long getFreePublicKeyIdLPw() { |
| lastIssuedKeyId += 1; |
| return lastIssuedKeyId; |
| } |
| |
| public void removeAppKeySetDataLPw(String packageName) { |
| // Get the package's known keys and KeySets |
| ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName); |
| ArraySet<Long> deletableKeys = new ArraySet<Long>(); |
| final int origDksSize = deletableKeySets.size(); |
| for (int i = 0; i < origDksSize; i++) { |
| ArraySet<Long> knownKeys = mKeySetMapping.get(deletableKeySets.valueAt(i)); |
| if (knownKeys != null) { |
| deletableKeys.addAll(knownKeys); |
| } |
| } |
| |
| // Now remove the keys and KeySets on which any other package relies |
| for (String pkgName : mPackages.keySet()) { |
| if (pkgName.equals(packageName)) { |
| continue; |
| } |
| ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName); |
| deletableKeySets.removeAll(knownKeySets); |
| final int kksSize = knownKeySets.size(); |
| for (int i = 0; i < kksSize; i++) { |
| ArraySet<Long> knownKeys = mKeySetMapping.get(knownKeySets.valueAt(i)); |
| if (knownKeys != null) { |
| deletableKeys.removeAll(knownKeys); |
| } |
| } |
| } |
| |
| // The remaining keys and KeySets are not relied on by any other |
| // application and so can be safely deleted. |
| final int dksSize = deletableKeySets.size(); |
| for (int i = 0; i < dksSize; i++) { |
| Long ks = deletableKeySets.valueAt(i); |
| mKeySets.delete(ks); |
| mKeySetMapping.delete(ks); |
| } |
| final int dkSize = deletableKeys.size(); |
| for (int i = 0; i < dkSize; i++) { |
| mPublicKeys.delete(deletableKeys.valueAt(i)); |
| } |
| |
| // Now remove the deleted KeySets from each package's signingKeySets |
| for (String pkgName : mPackages.keySet()) { |
| PackageSetting p = mPackages.get(pkgName); |
| for (int i = 0; i < dksSize; i++) { |
| Long ks = deletableKeySets.valueAt(i); |
| p.keySetData.removeSigningKeySet(ks); |
| } |
| } |
| // Finally, remove all KeySets from the original package |
| PackageSetting p = mPackages.get(packageName); |
| clearPackageKeySetDataLPw(p); |
| } |
| |
| private void clearPackageKeySetDataLPw(PackageSetting p) { |
| p.keySetData.removeAllSigningKeySets(); |
| p.keySetData.removeAllUpgradeKeySets(); |
| p.keySetData.removeAllDefinedKeySets(); |
| return; |
| } |
| |
| private ArraySet<Long> getOriginalKeySetsByPackageNameLPr(String packageName) { |
| PackageSetting p = mPackages.get(packageName); |
| if (p == null) { |
| throw new NullPointerException("Unknown package"); |
| } |
| if (p.keySetData == null) { |
| throw new IllegalArgumentException("Package has no keySet data"); |
| } |
| ArraySet<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; |
| } |
| |
| public String encodePublicKey(PublicKey k) throws IOException { |
| return new String(Base64.encode(k.getEncoded(), 0)); |
| } |
| |
| public void dumpLPr(PrintWriter pw, String packageName, |
| PackageManagerService.DumpState dumpState) { |
| boolean printedHeader = false; |
| for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) { |
| String keySetPackage = e.getKey(); |
| if (packageName != null && !packageName.equals(keySetPackage)) { |
| continue; |
| } |
| if (!printedHeader) { |
| if (dumpState.onTitlePrinted()) |
| pw.println(); |
| pw.println("Key Set Manager:"); |
| printedHeader = true; |
| } |
| PackageSetting pkg = e.getValue(); |
| pw.print(" ["); pw.print(keySetPackage); pw.println("]"); |
| if (pkg.keySetData != null) { |
| boolean printedLabel = false; |
| for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) { |
| if (!printedLabel) { |
| pw.print(" KeySets Aliases: "); |
| printedLabel = true; |
| } else { |
| pw.print(", "); |
| } |
| pw.print(entry.getKey()); |
| pw.print('='); |
| pw.print(Long.toString(entry.getValue())); |
| } |
| if (printedLabel) { |
| pw.println(""); |
| } |
| printedLabel = false; |
| 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)); |
| } |
| } |
| if (printedLabel) { |
| pw.println(""); |
| } |
| printedLabel = false; |
| final long[] signingKeySets = pkg.keySetData.getSigningKeySets(); |
| if (signingKeySets != null) { |
| for (long keySetId : signingKeySets) { |
| if (!printedLabel) { |
| pw.print(" Signing KeySets: "); |
| printedLabel = true; |
| } else { |
| pw.print(", "); |
| } |
| pw.print(Long.toString(keySetId)); |
| } |
| } |
| 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 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"); |
| serializer.attribute(null, "value", Long.toString(lastIssuedKeyId)); |
| serializer.endTag(null, "lastIssuedKeyId"); |
| serializer.startTag(null, "lastIssuedKeySetId"); |
| serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId)); |
| serializer.endTag(null, "lastIssuedKeySetId"); |
| serializer.endTag(null, "keyset-settings"); |
| } |
| |
| void writePublicKeysLPr(XmlSerializer serializer) throws IOException { |
| serializer.startTag(null, "keys"); |
| for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) { |
| long id = mPublicKeys.keyAt(pKeyIndex); |
| PublicKey key = mPublicKeys.valueAt(pKeyIndex); |
| String encodedKey = encodePublicKey(key); |
| serializer.startTag(null, "public-key"); |
| serializer.attribute(null, "identifier", Long.toString(id)); |
| serializer.attribute(null, "value", encodedKey); |
| serializer.endTag(null, "public-key"); |
| } |
| serializer.endTag(null, "keys"); |
| } |
| |
| void writeKeySetsLPr(XmlSerializer serializer) throws IOException { |
| serializer.startTag(null, "keysets"); |
| for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) { |
| long id = mKeySetMapping.keyAt(keySetIndex); |
| ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex); |
| serializer.startTag(null, "keyset"); |
| serializer.attribute(null, "identifier", Long.toString(id)); |
| for (long keyId : keys) { |
| serializer.startTag(null, "key-id"); |
| serializer.attribute(null, "identifier", Long.toString(keyId)); |
| serializer.endTag(null, "key-id"); |
| } |
| serializer.endTag(null, "keyset"); |
| } |
| serializer.endTag(null, "keysets"); |
| } |
| |
| void readKeySetsLPw(XmlPullParser parser) |
| throws XmlPullParserException, IOException { |
| int type; |
| long currentKeySetId = 0; |
| 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()) { |
| clearPackageKeySetDataLPw(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; |
| } |
| final String tagName = parser.getName(); |
| if (tagName.equals("keys")) { |
| 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")); |
| } |
| } |
| } |
| |
| void readKeysLPw(XmlPullParser parser) |
| throws XmlPullParserException, IOException { |
| int outerDepth = parser.getDepth(); |
| int type; |
| while ((type = parser.next()) != XmlPullParser.END_DOCUMENT |
| && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { |
| if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| continue; |
| } |
| final String tagName = parser.getName(); |
| if (tagName.equals("public-key")) { |
| readPublicKeyLPw(parser); |
| } |
| } |
| } |
| |
| void readKeySetListLPw(XmlPullParser parser) |
| throws XmlPullParserException, IOException { |
| int outerDepth = parser.getDepth(); |
| int type; |
| long currentKeySetId = 0; |
| while ((type = parser.next()) != XmlPullParser.END_DOCUMENT |
| && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { |
| if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| continue; |
| } |
| final String tagName = parser.getName(); |
| if (tagName.equals("keyset")) { |
| currentKeySetId = readIdentifierLPw(parser); |
| mKeySets.put(currentKeySetId, new KeySetHandle()); |
| mKeySetMapping.put(currentKeySetId, new ArraySet<Long>()); |
| } else if (tagName.equals("key-id")) { |
| long id = readIdentifierLPw(parser); |
| mKeySetMapping.get(currentKeySetId).add(id); |
| } |
| } |
| } |
| |
| long readIdentifierLPw(XmlPullParser parser) |
| throws XmlPullParserException { |
| return Long.parseLong(parser.getAttributeValue(null, "identifier")); |
| } |
| |
| void readPublicKeyLPw(XmlPullParser parser) |
| throws XmlPullParserException { |
| String encodedID = parser.getAttributeValue(null, "identifier"); |
| long identifier = Long.parseLong(encodedID); |
| String encodedPublicKey = parser.getAttributeValue(null, "value"); |
| PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey); |
| if (pub != null) { |
| mPublicKeys.put(identifier, pub); |
| } |
| } |
| } |