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