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