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 static com.android.server.pm.PackageManagerService.SCAN_INITIAL;
     22 
     23 import com.android.internal.util.Preconditions;
     24 import android.content.pm.PackageParser;
     25 import android.util.ArrayMap;
     26 import android.util.ArraySet;
     27 import android.util.Base64;
     28 import android.util.Slog;
     29 import android.util.LongSparseArray;
     30 
     31 import java.io.IOException;
     32 import java.io.PrintWriter;
     33 import java.security.PublicKey;
     34 import java.util.Set;
     35 
     36 import org.xmlpull.v1.XmlPullParser;
     37 import org.xmlpull.v1.XmlPullParserException;
     38 import org.xmlpull.v1.XmlSerializer;
     39 
     40 /*
     41  * Manages system-wide KeySet state.
     42  */
     43 public 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.mSigningDetails.publicKeys;
    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.mSigningDetails.publicKeys);
    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.mSigningDetails.publicKeys.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