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