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