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