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