Home | History | Annotate | Download | only in pm
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.android.server.pm;
     18 
     19 import android.content.pm.PackageParser;
     20 import android.os.Binder;
     21 import android.util.ArraySet;
     22 import android.util.Base64;
     23 import android.util.Slog;
     24 import android.util.LongSparseArray;
     25 
     26 import java.io.IOException;
     27 import java.io.PrintWriter;
     28 import java.security.PublicKey;
     29 import java.util.Map;
     30 import java.util.Set;
     31 
     32 import org.xmlpull.v1.XmlPullParser;
     33 import org.xmlpull.v1.XmlPullParserException;
     34 import org.xmlpull.v1.XmlSerializer;
     35 
     36 /*
     37  * Manages system-wide KeySet state.
     38  */
     39 public class KeySetManagerService {
     40 
     41     static final String TAG = "KeySetManagerService";
     42 
     43     /* original keysets implementation had no versioning info, so this is the first */
     44     public static final int FIRST_VERSION = 1;
     45 
     46     public static final int CURRENT_VERSION = FIRST_VERSION;
     47 
     48     /** Sentinel value returned when a {@code KeySet} is not found. */
     49     public static final long KEYSET_NOT_FOUND = -1;
     50 
     51     /** Sentinel value returned when public key is not found. */
     52     protected static final long PUBLIC_KEY_NOT_FOUND = -1;
     53 
     54     private final LongSparseArray<KeySetHandle> mKeySets;
     55 
     56     private final LongSparseArray<PublicKey> mPublicKeys;
     57 
     58     protected final LongSparseArray<ArraySet<Long>> mKeySetMapping;
     59 
     60     private final Map<String, PackageSetting> mPackages;
     61 
     62     private static long lastIssuedKeySetId = 0;
     63 
     64     private static long lastIssuedKeyId = 0;
     65 
     66     public KeySetManagerService(Map<String, PackageSetting> packages) {
     67         mKeySets = new LongSparseArray<KeySetHandle>();
     68         mPublicKeys = new LongSparseArray<PublicKey>();
     69         mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
     70         mPackages = packages;
     71     }
     72 
     73     /**
     74      * Determine if a package is signed by the given KeySet.
     75      *
     76      * Returns false if the package was not signed by all the
     77      * keys in the KeySet.
     78      *
     79      * Returns true if the package was signed by at least the
     80      * keys in the given KeySet.
     81      *
     82      * Note that this can return true for multiple KeySets.
     83      */
     84     public boolean packageIsSignedByLPr(String packageName, KeySetHandle ks) {
     85         PackageSetting pkg = mPackages.get(packageName);
     86         if (pkg == null) {
     87             throw new NullPointerException("Invalid package name");
     88         }
     89         if (pkg.keySetData == null) {
     90             throw new NullPointerException("Package has no KeySet data");
     91         }
     92         long id = getIdByKeySetLPr(ks);
     93         if (id == KEYSET_NOT_FOUND) {
     94                 return false;
     95         }
     96         return pkg.keySetData.packageIsSignedBy(id);
     97     }
     98 
     99     /**
    100      * Determine if a package is signed by the given KeySet.
    101      *
    102      * Returns false if the package was not signed by all the
    103      * keys in the KeySet, or if the package was signed by keys
    104      * not in the KeySet.
    105      *
    106      * Note that this can return only for one KeySet.
    107      */
    108     public boolean packageIsSignedByExactlyLPr(String packageName, KeySetHandle ks) {
    109         PackageSetting pkg = mPackages.get(packageName);
    110         if (pkg == null) {
    111             throw new NullPointerException("Invalid package name");
    112         }
    113         if (pkg.keySetData == null
    114             || pkg.keySetData.getProperSigningKeySet()
    115             == PackageKeySetData.KEYSET_UNASSIGNED) {
    116             throw new NullPointerException("Package has no KeySet data");
    117         }
    118         long id = getIdByKeySetLPr(ks);
    119         return pkg.keySetData.getProperSigningKeySet() == id;
    120     }
    121 
    122     /**
    123      * This informs the system that the given package has defined a KeySet
    124      * in its manifest that a) contains the given keys and b) is named
    125      * alias by that package.
    126      */
    127     public void addDefinedKeySetToPackageLPw(String packageName,
    128             ArraySet<PublicKey> keys, String alias) {
    129         if ((packageName == null) || (keys == null) || (alias == null)) {
    130             Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
    131             return;
    132         }
    133         PackageSetting pkg = mPackages.get(packageName);
    134         if (pkg == null) {
    135             throw new NullPointerException("Unknown package");
    136         }
    137         // Add to KeySets, then to package
    138         KeySetHandle ks = addKeySetLPw(keys);
    139         long id = getIdByKeySetLPr(ks);
    140         pkg.keySetData.addDefinedKeySet(id, alias);
    141     }
    142 
    143     /**
    144      * This informs the system that the given package has defined a KeySet
    145      * alias in its manifest to be an upgradeKeySet.  This must be called
    146      * after all of the defined KeySets have been added.
    147      */
    148     public void addUpgradeKeySetToPackageLPw(String packageName, String alias) {
    149         if ((packageName == null) || (alias == null)) {
    150             Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
    151             return;
    152         }
    153         PackageSetting pkg = mPackages.get(packageName);
    154         if (pkg == null) {
    155             throw new NullPointerException("Unknown package");
    156         }
    157         pkg.keySetData.addUpgradeKeySet(alias);
    158     }
    159 
    160     /**
    161      * Similar to the above, this informs the system that the given package
    162      * was signed by the provided KeySet.
    163      */
    164     public void addSigningKeySetToPackageLPw(String packageName,
    165             ArraySet<PublicKey> signingKeys) {
    166         if ((packageName == null) || (signingKeys == null)) {
    167             Slog.w(TAG, "Got null argument for a signing keyset, ignoring!");
    168             return;
    169         }
    170         // add the signing KeySet
    171         KeySetHandle ks = addKeySetLPw(signingKeys);
    172         long id = getIdByKeySetLPr(ks);
    173         ArraySet<Long> publicKeyIds = mKeySetMapping.get(id);
    174         if (publicKeyIds == null) {
    175             throw new NullPointerException("Got invalid KeySet id");
    176         }
    177         // attach it to the package
    178         PackageSetting pkg = mPackages.get(packageName);
    179         if (pkg == null) {
    180             throw new NullPointerException("No such package!");
    181         }
    182         pkg.keySetData.setProperSigningKeySet(id);
    183         // for each KeySet which is a subset of the one above, add the
    184         // KeySet id to the package's signing KeySets
    185         for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
    186             long keySetID = mKeySets.keyAt(keySetIndex);
    187             ArraySet<Long> definedKeys = mKeySetMapping.get(keySetID);
    188             if (publicKeyIds.containsAll(definedKeys)) {
    189                 pkg.keySetData.addSigningKeySet(keySetID);
    190             }
    191         }
    192     }
    193 
    194     /**
    195      * Fetches the stable identifier associated with the given KeySet. Returns
    196      * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.
    197      */
    198     private long getIdByKeySetLPr(KeySetHandle ks) {
    199         for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
    200             KeySetHandle value = mKeySets.valueAt(keySetIndex);
    201             if (ks.equals(value)) {
    202                 return mKeySets.keyAt(keySetIndex);
    203             }
    204         }
    205         return KEYSET_NOT_FOUND;
    206     }
    207 
    208     /**
    209      * Fetches the KeySet corresponding to the given stable identifier.
    210      *
    211      * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't
    212      * identify a {@link KeySet}.
    213      */
    214     public KeySetHandle getKeySetByIdLPr(long id) {
    215         return mKeySets.get(id);
    216     }
    217 
    218     /**
    219      * Fetches the {@link KeySetHandle} that a given package refers to by the
    220      * provided alias. Returns null if the package is unknown or does not have a
    221      * KeySet corresponding to that alias.
    222      */
    223     public KeySetHandle getKeySetByAliasAndPackageNameLPr(String packageName, String alias) {
    224         PackageSetting p = mPackages.get(packageName);
    225         if (p == null || p.keySetData == null) {
    226                 return null;
    227         }
    228         Long keySetId = p.keySetData.getAliases().get(alias);
    229         if (keySetId == null) {
    230             throw new IllegalArgumentException("Unknown KeySet alias: " + alias);
    231         }
    232         return mKeySets.get(keySetId);
    233     }
    234 
    235     /**
    236      * Fetches the {@link PublicKey public keys} which belong to the specified
    237      * KeySet id.
    238      *
    239      * Returns {@code null} if the identifier doesn't
    240      * identify a {@link KeySetHandle}.
    241      */
    242     public ArraySet<PublicKey> getPublicKeysFromKeySetLPr(long id) {
    243         if(mKeySetMapping.get(id) == null) {
    244             return null;
    245         }
    246         ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>();
    247         for (long pkId : mKeySetMapping.get(id)) {
    248             mPubKeys.add(mPublicKeys.get(pkId));
    249         }
    250         return mPubKeys;
    251     }
    252 
    253     /**
    254      * Fetches the proper {@link KeySetHandle KeySet} that signed the given
    255      * package.
    256      *
    257      * @throws IllegalArgumentException if the package has no keyset data.
    258      * @throws NullPointerException if the package is unknown.
    259      */
    260     public KeySetHandle  getSigningKeySetByPackageNameLPr(String packageName) {
    261         PackageSetting p = mPackages.get(packageName);
    262         if (p == null
    263             || p.keySetData == null
    264             || p.keySetData.getProperSigningKeySet()
    265             == PackageKeySetData.KEYSET_UNASSIGNED) {
    266             return null;
    267         }
    268         return mKeySets.get(p.keySetData.getProperSigningKeySet());
    269     }
    270 
    271     /**
    272      * Fetches all the known {@link KeySetHandle KeySets} that may upgrade the given
    273      * package.
    274      *
    275      * @throws IllegalArgumentException if the package has no keyset data.
    276      * @throws NullPointerException if the package is unknown.
    277      */
    278     public ArraySet<KeySetHandle> getUpgradeKeySetsByPackageNameLPr(String packageName) {
    279         ArraySet<KeySetHandle> upgradeKeySets = new ArraySet<KeySetHandle>();
    280         PackageSetting p = mPackages.get(packageName);
    281         if (p == null) {
    282             throw new NullPointerException("Unknown package");
    283         }
    284         if (p.keySetData == null) {
    285             throw new IllegalArgumentException("Package has no keySet data");
    286         }
    287         if (p.keySetData.isUsingUpgradeKeySets()) {
    288             for (long l : p.keySetData.getUpgradeKeySets()) {
    289                 upgradeKeySets.add(mKeySets.get(l));
    290             }
    291         }
    292         return upgradeKeySets;
    293     }
    294 
    295     /**
    296      * Creates a new KeySet corresponding to the given keys.
    297      *
    298      * If the {@link PublicKey PublicKeys} aren't known to the system, this
    299      * adds them. Otherwise, they're deduped.
    300      *
    301      * If the KeySet isn't known to the system, this adds that and creates the
    302      * mapping to the PublicKeys. If it is known, then it's deduped.
    303      *
    304      * If the KeySet isn't known to the system, this adds it to all appropriate
    305      * signingKeySets
    306      *
    307      * Throws if the provided set is {@code null}.
    308      */
    309     private KeySetHandle addKeySetLPw(ArraySet<PublicKey> keys) {
    310         if (keys == null) {
    311             throw new NullPointerException("Provided keys cannot be null");
    312         }
    313         // add each of the keys in the provided set
    314         ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size());
    315         for (PublicKey k : keys) {
    316             long id = addPublicKeyLPw(k);
    317             addedKeyIds.add(id);
    318         }
    319 
    320         // check to see if the resulting keyset is new
    321         long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds);
    322         if (existingKeySetId != KEYSET_NOT_FOUND) {
    323             return mKeySets.get(existingKeySetId);
    324         }
    325 
    326         // create the KeySet object
    327         KeySetHandle ks = new KeySetHandle();
    328         // get the first unoccupied slot in mKeySets
    329         long id = getFreeKeySetIDLPw();
    330         // add the KeySet object to it
    331         mKeySets.put(id, ks);
    332         // add the stable key ids to the mapping
    333         mKeySetMapping.put(id, addedKeyIds);
    334         // add this KeySet id to all packages which are signed by it
    335         for (String pkgName : mPackages.keySet()) {
    336             PackageSetting p = mPackages.get(pkgName);
    337             if (p.keySetData != null) {
    338                 long pProperSigning = p.keySetData.getProperSigningKeySet();
    339                 if (pProperSigning != PackageKeySetData.KEYSET_UNASSIGNED) {
    340                     ArraySet<Long> pSigningKeys = mKeySetMapping.get(pProperSigning);
    341                     if (pSigningKeys.containsAll(addedKeyIds)) {
    342                         p.keySetData.addSigningKeySet(id);
    343                     }
    344                 }
    345             }
    346         }
    347         // go home
    348         return ks;
    349     }
    350 
    351     /**
    352      * Adds the given PublicKey to the system, deduping as it goes.
    353      */
    354     private long addPublicKeyLPw(PublicKey key) {
    355         // check if the public key is new
    356         long existingKeyId = getIdForPublicKeyLPr(key);
    357         if (existingKeyId != PUBLIC_KEY_NOT_FOUND) {
    358             return existingKeyId;
    359         }
    360         // if it's new find the first unoccupied slot in the public keys
    361         long id = getFreePublicKeyIdLPw();
    362         // add the public key to it
    363         mPublicKeys.put(id, key);
    364         // return the stable identifier
    365         return id;
    366     }
    367 
    368     /**
    369      * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs.
    370      *
    371      * Returns KEYSET_NOT_FOUND if there isn't one.
    372      */
    373     private long getIdFromKeyIdsLPr(Set<Long> publicKeyIds) {
    374         for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) {
    375             ArraySet<Long> value = mKeySetMapping.valueAt(keyMapIndex);
    376             if (value.equals(publicKeyIds)) {
    377                 return mKeySetMapping.keyAt(keyMapIndex);
    378             }
    379         }
    380         return KEYSET_NOT_FOUND;
    381     }
    382 
    383     /**
    384      * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.
    385      */
    386     private long getIdForPublicKeyLPr(PublicKey k) {
    387         String encodedPublicKey = new String(k.getEncoded());
    388         for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
    389             PublicKey value = mPublicKeys.valueAt(publicKeyIndex);
    390             String encodedExistingKey = new String(value.getEncoded());
    391             if (encodedPublicKey.equals(encodedExistingKey)) {
    392                 return mPublicKeys.keyAt(publicKeyIndex);
    393             }
    394         }
    395         return PUBLIC_KEY_NOT_FOUND;
    396     }
    397 
    398     /**
    399      * Gets an unused stable identifier for a KeySet.
    400      */
    401     private long getFreeKeySetIDLPw() {
    402         lastIssuedKeySetId += 1;
    403         return lastIssuedKeySetId;
    404     }
    405 
    406     /**
    407      * Same as above, but for public keys.
    408      */
    409     private long getFreePublicKeyIdLPw() {
    410         lastIssuedKeyId += 1;
    411         return lastIssuedKeyId;
    412     }
    413 
    414     public void removeAppKeySetDataLPw(String packageName) {
    415         // Get the package's known keys and KeySets
    416         ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
    417         ArraySet<Long> deletableKeys = new ArraySet<Long>();
    418         ArraySet<Long> knownKeys = null;
    419         for (Long ks : deletableKeySets) {
    420             knownKeys = mKeySetMapping.get(ks);
    421             if (knownKeys != null) {
    422                 deletableKeys.addAll(knownKeys);
    423             }
    424         }
    425 
    426         // Now remove the keys and KeySets on which any other package relies
    427         for (String pkgName : mPackages.keySet()) {
    428             if (pkgName.equals(packageName)) {
    429                 continue;
    430             }
    431             ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
    432             deletableKeySets.removeAll(knownKeySets);
    433             knownKeys = new ArraySet<Long>();
    434             for (Long ks : knownKeySets) {
    435                 knownKeys = mKeySetMapping.get(ks);
    436                 if (knownKeys != null) {
    437                     deletableKeys.removeAll(knownKeys);
    438                 }
    439             }
    440         }
    441 
    442         // The remaining keys and KeySets are not relied on by any other
    443         // application and so can be safely deleted.
    444         for (Long ks : deletableKeySets) {
    445             mKeySets.delete(ks);
    446             mKeySetMapping.delete(ks);
    447         }
    448         for (Long keyId : deletableKeys) {
    449             mPublicKeys.delete(keyId);
    450         }
    451 
    452         // Now remove the deleted KeySets from each package's signingKeySets
    453         for (String pkgName : mPackages.keySet()) {
    454             PackageSetting p = mPackages.get(pkgName);
    455             for (Long ks : deletableKeySets) {
    456                 p.keySetData.removeSigningKeySet(ks);
    457             }
    458         }
    459         // Finally, remove all KeySets from the original package
    460         PackageSetting p = mPackages.get(packageName);
    461         clearPackageKeySetDataLPw(p);
    462     }
    463 
    464     private void clearPackageKeySetDataLPw(PackageSetting p) {
    465         p.keySetData.removeAllSigningKeySets();
    466         p.keySetData.removeAllUpgradeKeySets();
    467         p.keySetData.removeAllDefinedKeySets();
    468         return;
    469     }
    470 
    471     private ArraySet<Long> getOriginalKeySetsByPackageNameLPr(String packageName) {
    472         PackageSetting p = mPackages.get(packageName);
    473         if (p == null) {
    474             throw new NullPointerException("Unknown package");
    475         }
    476         if (p.keySetData == null) {
    477             throw new IllegalArgumentException("Package has no keySet data");
    478         }
    479         ArraySet<Long> knownKeySets = new ArraySet<Long>();
    480         knownKeySets.add(p.keySetData.getProperSigningKeySet());
    481         if (p.keySetData.isUsingDefinedKeySets()) {
    482             for (long ks : p.keySetData.getDefinedKeySets()) {
    483                 knownKeySets.add(ks);
    484             }
    485         }
    486         return knownKeySets;
    487     }
    488 
    489     public String encodePublicKey(PublicKey k) throws IOException {
    490         return new String(Base64.encode(k.getEncoded(), 0));
    491     }
    492 
    493     public void dumpLPr(PrintWriter pw, String packageName,
    494                         PackageManagerService.DumpState dumpState) {
    495         boolean printedHeader = false;
    496         for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) {
    497             String keySetPackage = e.getKey();
    498             if (packageName != null && !packageName.equals(keySetPackage)) {
    499                 continue;
    500             }
    501             if (!printedHeader) {
    502                 if (dumpState.onTitlePrinted())
    503                     pw.println();
    504                 pw.println("Key Set Manager:");
    505                 printedHeader = true;
    506             }
    507             PackageSetting pkg = e.getValue();
    508             pw.print("  ["); pw.print(keySetPackage); pw.println("]");
    509             if (pkg.keySetData != null) {
    510                 boolean printedLabel = false;
    511                 for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
    512                     if (!printedLabel) {
    513                         pw.print("      KeySets Aliases: ");
    514                         printedLabel = true;
    515                     } else {
    516                         pw.print(", ");
    517                     }
    518                     pw.print(entry.getKey());
    519                     pw.print('=');
    520                     pw.print(Long.toString(entry.getValue()));
    521                 }
    522                 if (printedLabel) {
    523                     pw.println("");
    524                 }
    525                 printedLabel = false;
    526                 if (pkg.keySetData.isUsingDefinedKeySets()) {
    527                     for (long keySetId : pkg.keySetData.getDefinedKeySets()) {
    528                         if (!printedLabel) {
    529                             pw.print("      Defined KeySets: ");
    530                             printedLabel = true;
    531                         } else {
    532                             pw.print(", ");
    533                         }
    534                         pw.print(Long.toString(keySetId));
    535                     }
    536                 }
    537                 if (printedLabel) {
    538                     pw.println("");
    539                 }
    540                 printedLabel = false;
    541                 final long[] signingKeySets = pkg.keySetData.getSigningKeySets();
    542                 if (signingKeySets != null) {
    543                     for (long keySetId : signingKeySets) {
    544                         if (!printedLabel) {
    545                             pw.print("      Signing KeySets: ");
    546                             printedLabel = true;
    547                         } else {
    548                             pw.print(", ");
    549                         }
    550                         pw.print(Long.toString(keySetId));
    551                     }
    552                 }
    553                 if (printedLabel) {
    554                     pw.println("");
    555                 }
    556                 printedLabel = false;
    557                 if (pkg.keySetData.isUsingUpgradeKeySets()) {
    558                     for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
    559                         if (!printedLabel) {
    560                             pw.print("      Upgrade KeySets: ");
    561                             printedLabel = true;
    562                         } else {
    563                             pw.print(", ");
    564                         }
    565                         pw.print(Long.toString(keySetId));
    566                     }
    567                 }
    568                 if (printedLabel) {
    569                     pw.println("");
    570                 }
    571             }
    572         }
    573     }
    574 
    575     void writeKeySetManagerServiceLPr(XmlSerializer serializer) throws IOException {
    576         serializer.startTag(null, "keyset-settings");
    577         serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
    578         writePublicKeysLPr(serializer);
    579         writeKeySetsLPr(serializer);
    580         serializer.startTag(null, "lastIssuedKeyId");
    581         serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
    582         serializer.endTag(null, "lastIssuedKeyId");
    583         serializer.startTag(null, "lastIssuedKeySetId");
    584         serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
    585         serializer.endTag(null, "lastIssuedKeySetId");
    586         serializer.endTag(null, "keyset-settings");
    587     }
    588 
    589     void writePublicKeysLPr(XmlSerializer serializer) throws IOException {
    590         serializer.startTag(null, "keys");
    591         for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
    592             long id = mPublicKeys.keyAt(pKeyIndex);
    593             PublicKey key = mPublicKeys.valueAt(pKeyIndex);
    594             String encodedKey = encodePublicKey(key);
    595             serializer.startTag(null, "public-key");
    596             serializer.attribute(null, "identifier", Long.toString(id));
    597             serializer.attribute(null, "value", encodedKey);
    598             serializer.endTag(null, "public-key");
    599         }
    600         serializer.endTag(null, "keys");
    601     }
    602 
    603     void writeKeySetsLPr(XmlSerializer serializer) throws IOException {
    604         serializer.startTag(null, "keysets");
    605         for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
    606             long id = mKeySetMapping.keyAt(keySetIndex);
    607             ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex);
    608             serializer.startTag(null, "keyset");
    609             serializer.attribute(null, "identifier", Long.toString(id));
    610             for (long keyId : keys) {
    611                 serializer.startTag(null, "key-id");
    612                 serializer.attribute(null, "identifier", Long.toString(keyId));
    613                 serializer.endTag(null, "key-id");
    614             }
    615             serializer.endTag(null, "keyset");
    616         }
    617         serializer.endTag(null, "keysets");
    618     }
    619 
    620     void readKeySetsLPw(XmlPullParser parser)
    621             throws XmlPullParserException, IOException {
    622         int type;
    623         long currentKeySetId = 0;
    624         int outerDepth = parser.getDepth();
    625         String recordedVersion = parser.getAttributeValue(null, "version");
    626         if (recordedVersion == null || Integer.parseInt(recordedVersion) != CURRENT_VERSION) {
    627             while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    628                     && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    629                 // Our version is different than the one which generated the old keyset data.
    630                 // We don't want any of the old data, but we must advance the parser
    631                 continue;
    632             }
    633             // The KeySet information read previously from packages.xml is invalid.
    634             // Destroy it all.
    635             for (PackageSetting p : mPackages.values()) {
    636                 clearPackageKeySetDataLPw(p);
    637             }
    638             return;
    639         }
    640         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    641                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    642             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    643                 continue;
    644             }
    645             final String tagName = parser.getName();
    646             if (tagName.equals("keys")) {
    647                 readKeysLPw(parser);
    648             } else if (tagName.equals("keysets")) {
    649                 readKeySetListLPw(parser);
    650             } else if (tagName.equals("lastIssuedKeyId")) {
    651                 lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
    652             } else if (tagName.equals("lastIssuedKeySetId")) {
    653                 lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
    654             }
    655         }
    656     }
    657 
    658     void readKeysLPw(XmlPullParser parser)
    659             throws XmlPullParserException, IOException {
    660         int outerDepth = parser.getDepth();
    661         int type;
    662         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    663                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    664             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    665                 continue;
    666             }
    667             final String tagName = parser.getName();
    668             if (tagName.equals("public-key")) {
    669                 readPublicKeyLPw(parser);
    670             }
    671         }
    672     }
    673 
    674     void readKeySetListLPw(XmlPullParser parser)
    675             throws XmlPullParserException, IOException {
    676         int outerDepth = parser.getDepth();
    677         int type;
    678         long currentKeySetId = 0;
    679         while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
    680                 && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
    681             if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
    682                 continue;
    683             }
    684             final String tagName = parser.getName();
    685             if (tagName.equals("keyset")) {
    686                 currentKeySetId = readIdentifierLPw(parser);
    687                 mKeySets.put(currentKeySetId, new KeySetHandle());
    688                 mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
    689             } else if (tagName.equals("key-id")) {
    690                 long id = readIdentifierLPw(parser);
    691                 mKeySetMapping.get(currentKeySetId).add(id);
    692             }
    693         }
    694     }
    695 
    696     long readIdentifierLPw(XmlPullParser parser)
    697             throws XmlPullParserException {
    698         return Long.parseLong(parser.getAttributeValue(null, "identifier"));
    699     }
    700 
    701     void readPublicKeyLPw(XmlPullParser parser)
    702             throws XmlPullParserException {
    703         String encodedID = parser.getAttributeValue(null, "identifier");
    704         long identifier = Long.parseLong(encodedID);
    705         String encodedPublicKey = parser.getAttributeValue(null, "value");
    706         PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
    707         if (pub != null) {
    708             mPublicKeys.put(identifier, pub);
    709         }
    710     }
    711 }
    712