FileDocCategorySizeDatePackage
KeySetManagerService.javaAPI DocAndroid 5.1 API27692Thu Mar 12 22:22:42 GMT 2015com.android.server.pm

KeySetManagerService

public class KeySetManagerService extends Object

Fields Summary
static final String
TAG
public static final int
FIRST_VERSION
public static final int
CURRENT_VERSION
public static final long
KEYSET_NOT_FOUND
Sentinel value returned when a {@code KeySet} is not found.
protected static final long
PUBLIC_KEY_NOT_FOUND
Sentinel value returned when public key is not found.
private final android.util.LongSparseArray
mKeySets
private final android.util.LongSparseArray
mPublicKeys
protected final android.util.LongSparseArray
mKeySetMapping
private final Map
mPackages
private static long
lastIssuedKeySetId
private static long
lastIssuedKeyId
Constructors Summary
public KeySetManagerService(Map packages)


        
        mKeySets = new LongSparseArray<KeySetHandle>();
        mPublicKeys = new LongSparseArray<PublicKey>();
        mKeySetMapping = new LongSparseArray<ArraySet<Long>>();
        mPackages = packages;
    
Methods Summary
public voidaddDefinedKeySetToPackageLPw(java.lang.String packageName, android.util.ArraySet keys, java.lang.String alias)
This informs the system that the given package has defined a KeySet in its manifest that a) contains the given keys and b) is named alias by that package.

        if ((packageName == null) || (keys == null) || (alias == null)) {
            Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
            return;
        }
        PackageSetting pkg = mPackages.get(packageName);
        if (pkg == null) {
            throw new NullPointerException("Unknown package");
        }
        // Add to KeySets, then to package
        KeySetHandle ks = addKeySetLPw(keys);
        long id = getIdByKeySetLPr(ks);
        pkg.keySetData.addDefinedKeySet(id, alias);
    
private KeySetHandleaddKeySetLPw(android.util.ArraySet keys)
Creates a new KeySet corresponding to the given keys. If the {@link PublicKey PublicKeys} aren't known to the system, this adds them. Otherwise, they're deduped. If the KeySet isn't known to the system, this adds that and creates the mapping to the PublicKeys. If it is known, then it's deduped. If the KeySet isn't known to the system, this adds it to all appropriate signingKeySets Throws if the provided set is {@code null}.

        if (keys == null) {
            throw new NullPointerException("Provided keys cannot be null");
        }
        // add each of the keys in the provided set
        ArraySet<Long> addedKeyIds = new ArraySet<Long>(keys.size());
        for (PublicKey k : keys) {
            long id = addPublicKeyLPw(k);
            addedKeyIds.add(id);
        }

        // check to see if the resulting keyset is new
        long existingKeySetId = getIdFromKeyIdsLPr(addedKeyIds);
        if (existingKeySetId != KEYSET_NOT_FOUND) {
            return mKeySets.get(existingKeySetId);
        }

        // create the KeySet object
        KeySetHandle ks = new KeySetHandle();
        // get the first unoccupied slot in mKeySets
        long id = getFreeKeySetIDLPw();
        // add the KeySet object to it
        mKeySets.put(id, ks);
        // add the stable key ids to the mapping
        mKeySetMapping.put(id, addedKeyIds);
        // add this KeySet id to all packages which are signed by it
        for (String pkgName : mPackages.keySet()) {
            PackageSetting p = mPackages.get(pkgName);
            if (p.keySetData != null) {
                long pProperSigning = p.keySetData.getProperSigningKeySet();
                if (pProperSigning != PackageKeySetData.KEYSET_UNASSIGNED) {
                    ArraySet<Long> pSigningKeys = mKeySetMapping.get(pProperSigning);
                    if (pSigningKeys.containsAll(addedKeyIds)) {
                        p.keySetData.addSigningKeySet(id);
                    }
                }
            }
        }
        // go home
        return ks;
    
private longaddPublicKeyLPw(java.security.PublicKey key)
Adds the given PublicKey to the system, deduping as it goes.

        // check if the public key is new
        long existingKeyId = getIdForPublicKeyLPr(key);
        if (existingKeyId != PUBLIC_KEY_NOT_FOUND) {
            return existingKeyId;
        }
        // if it's new find the first unoccupied slot in the public keys
        long id = getFreePublicKeyIdLPw();
        // add the public key to it
        mPublicKeys.put(id, key);
        // return the stable identifier
        return id;
    
public voidaddSigningKeySetToPackageLPw(java.lang.String packageName, android.util.ArraySet signingKeys)
Similar to the above, this informs the system that the given package was signed by the provided KeySet.

        if ((packageName == null) || (signingKeys == null)) {
            Slog.w(TAG, "Got null argument for a signing keyset, ignoring!");
            return;
        }
        // add the signing KeySet
        KeySetHandle ks = addKeySetLPw(signingKeys);
        long id = getIdByKeySetLPr(ks);
        ArraySet<Long> publicKeyIds = mKeySetMapping.get(id);
        if (publicKeyIds == null) {
            throw new NullPointerException("Got invalid KeySet id");
        }
        // attach it to the package
        PackageSetting pkg = mPackages.get(packageName);
        if (pkg == null) {
            throw new NullPointerException("No such package!");
        }
        pkg.keySetData.setProperSigningKeySet(id);
        // for each KeySet which is a subset of the one above, add the
        // KeySet id to the package's signing KeySets
        for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
            long keySetID = mKeySets.keyAt(keySetIndex);
            ArraySet<Long> definedKeys = mKeySetMapping.get(keySetID);
            if (publicKeyIds.containsAll(definedKeys)) {
                pkg.keySetData.addSigningKeySet(keySetID);
            }
        }
    
public voidaddUpgradeKeySetToPackageLPw(java.lang.String packageName, java.lang.String alias)
This informs the system that the given package has defined a KeySet alias in its manifest to be an upgradeKeySet. This must be called after all of the defined KeySets have been added.

        if ((packageName == null) || (alias == null)) {
            Slog.w(TAG, "Got null argument for a defined keyset, ignoring!");
            return;
        }
        PackageSetting pkg = mPackages.get(packageName);
        if (pkg == null) {
            throw new NullPointerException("Unknown package");
        }
        pkg.keySetData.addUpgradeKeySet(alias);
    
private voidclearPackageKeySetDataLPw(PackageSetting p)

        p.keySetData.removeAllSigningKeySets();
        p.keySetData.removeAllUpgradeKeySets();
        p.keySetData.removeAllDefinedKeySets();
        return;
    
public voiddumpLPr(java.io.PrintWriter pw, java.lang.String packageName, PackageManagerService.DumpState dumpState)

        boolean printedHeader = false;
        for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) {
            String keySetPackage = e.getKey();
            if (packageName != null && !packageName.equals(keySetPackage)) {
                continue;
            }
            if (!printedHeader) {
                if (dumpState.onTitlePrinted())
                    pw.println();
                pw.println("Key Set Manager:");
                printedHeader = true;
            }
            PackageSetting pkg = e.getValue();
            pw.print("  ["); pw.print(keySetPackage); pw.println("]");
            if (pkg.keySetData != null) {
                boolean printedLabel = false;
                for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) {
                    if (!printedLabel) {
                        pw.print("      KeySets Aliases: ");
                        printedLabel = true;
                    } else {
                        pw.print(", ");
                    }
                    pw.print(entry.getKey());
                    pw.print('=");
                    pw.print(Long.toString(entry.getValue()));
                }
                if (printedLabel) {
                    pw.println("");
                }
                printedLabel = false;
                if (pkg.keySetData.isUsingDefinedKeySets()) {
                    for (long keySetId : pkg.keySetData.getDefinedKeySets()) {
                        if (!printedLabel) {
                            pw.print("      Defined KeySets: ");
                            printedLabel = true;
                        } else {
                            pw.print(", ");
                        }
                        pw.print(Long.toString(keySetId));
                    }
                }
                if (printedLabel) {
                    pw.println("");
                }
                printedLabel = false;
                final long[] signingKeySets = pkg.keySetData.getSigningKeySets();
                if (signingKeySets != null) {
                    for (long keySetId : signingKeySets) {
                        if (!printedLabel) {
                            pw.print("      Signing KeySets: ");
                            printedLabel = true;
                        } else {
                            pw.print(", ");
                        }
                        pw.print(Long.toString(keySetId));
                    }
                }
                if (printedLabel) {
                    pw.println("");
                }
                printedLabel = false;
                if (pkg.keySetData.isUsingUpgradeKeySets()) {
                    for (long keySetId : pkg.keySetData.getUpgradeKeySets()) {
                        if (!printedLabel) {
                            pw.print("      Upgrade KeySets: ");
                            printedLabel = true;
                        } else {
                            pw.print(", ");
                        }
                        pw.print(Long.toString(keySetId));
                    }
                }
                if (printedLabel) {
                    pw.println("");
                }
            }
        }
    
public java.lang.StringencodePublicKey(java.security.PublicKey k)

        return new String(Base64.encode(k.getEncoded(), 0));
    
private longgetFreeKeySetIDLPw()
Gets an unused stable identifier for a KeySet.

        lastIssuedKeySetId += 1;
        return lastIssuedKeySetId;
    
private longgetFreePublicKeyIdLPw()
Same as above, but for public keys.

        lastIssuedKeyId += 1;
        return lastIssuedKeyId;
    
private longgetIdByKeySetLPr(KeySetHandle ks)
Fetches the stable identifier associated with the given KeySet. Returns {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found.

        for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) {
            KeySetHandle value = mKeySets.valueAt(keySetIndex);
            if (ks.equals(value)) {
                return mKeySets.keyAt(keySetIndex);
            }
        }
        return KEYSET_NOT_FOUND;
    
private longgetIdForPublicKeyLPr(java.security.PublicKey k)
Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND.

        String encodedPublicKey = new String(k.getEncoded());
        for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) {
            PublicKey value = mPublicKeys.valueAt(publicKeyIndex);
            String encodedExistingKey = new String(value.getEncoded());
            if (encodedPublicKey.equals(encodedExistingKey)) {
                return mPublicKeys.keyAt(publicKeyIndex);
            }
        }
        return PUBLIC_KEY_NOT_FOUND;
    
private longgetIdFromKeyIdsLPr(java.util.Set publicKeyIds)
Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs. Returns KEYSET_NOT_FOUND if there isn't one.

        for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) {
            ArraySet<Long> value = mKeySetMapping.valueAt(keyMapIndex);
            if (value.equals(publicKeyIds)) {
                return mKeySetMapping.keyAt(keyMapIndex);
            }
        }
        return KEYSET_NOT_FOUND;
    
public KeySetHandlegetKeySetByAliasAndPackageNameLPr(java.lang.String packageName, java.lang.String alias)
Fetches the {@link KeySetHandle} that a given package refers to by the provided alias. Returns null if the package is unknown or does not have a KeySet corresponding to that alias.

        PackageSetting p = mPackages.get(packageName);
        if (p == null || p.keySetData == null) {
                return null;
        }
        Long keySetId = p.keySetData.getAliases().get(alias);
        if (keySetId == null) {
            throw new IllegalArgumentException("Unknown KeySet alias: " + alias);
        }
        return mKeySets.get(keySetId);
    
public KeySetHandlegetKeySetByIdLPr(long id)
Fetches the KeySet corresponding to the given stable identifier. Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't identify a {@link KeySet}.

        return mKeySets.get(id);
    
private android.util.ArraySetgetOriginalKeySetsByPackageNameLPr(java.lang.String packageName)

        PackageSetting p = mPackages.get(packageName);
        if (p == null) {
            throw new NullPointerException("Unknown package");
        }
        if (p.keySetData == null) {
            throw new IllegalArgumentException("Package has no keySet data");
        }
        ArraySet<Long> knownKeySets = new ArraySet<Long>();
        knownKeySets.add(p.keySetData.getProperSigningKeySet());
        if (p.keySetData.isUsingDefinedKeySets()) {
            for (long ks : p.keySetData.getDefinedKeySets()) {
                knownKeySets.add(ks);
            }
        }
        return knownKeySets;
    
public android.util.ArraySetgetPublicKeysFromKeySetLPr(long id)
Fetches the {@link PublicKey public keys} which belong to the specified KeySet id. Returns {@code null} if the identifier doesn't identify a {@link KeySetHandle}.

        if(mKeySetMapping.get(id) == null) {
            return null;
        }
        ArraySet<PublicKey> mPubKeys = new ArraySet<PublicKey>();
        for (long pkId : mKeySetMapping.get(id)) {
            mPubKeys.add(mPublicKeys.get(pkId));
        }
        return mPubKeys;
    
public KeySetHandlegetSigningKeySetByPackageNameLPr(java.lang.String packageName)
Fetches the proper {@link KeySetHandle KeySet} that signed the given package.

throws
IllegalArgumentException if the package has no keyset data.
throws
NullPointerException if the package is unknown.

        PackageSetting p = mPackages.get(packageName);
        if (p == null
            || p.keySetData == null
            || p.keySetData.getProperSigningKeySet()
            == PackageKeySetData.KEYSET_UNASSIGNED) {
            return null;
        }
        return mKeySets.get(p.keySetData.getProperSigningKeySet());
    
public android.util.ArraySetgetUpgradeKeySetsByPackageNameLPr(java.lang.String packageName)
Fetches all the known {@link KeySetHandle KeySets} that may upgrade the given package.

throws
IllegalArgumentException if the package has no keyset data.
throws
NullPointerException if the package is unknown.

        ArraySet<KeySetHandle> upgradeKeySets = new ArraySet<KeySetHandle>();
        PackageSetting p = mPackages.get(packageName);
        if (p == null) {
            throw new NullPointerException("Unknown package");
        }
        if (p.keySetData == null) {
            throw new IllegalArgumentException("Package has no keySet data");
        }
        if (p.keySetData.isUsingUpgradeKeySets()) {
            for (long l : p.keySetData.getUpgradeKeySets()) {
                upgradeKeySets.add(mKeySets.get(l));
            }
        }
        return upgradeKeySets;
    
public booleanpackageIsSignedByExactlyLPr(java.lang.String packageName, KeySetHandle ks)
Determine if a package is signed by the given KeySet. Returns false if the package was not signed by all the keys in the KeySet, or if the package was signed by keys not in the KeySet. Note that this can return only for one KeySet.

        PackageSetting pkg = mPackages.get(packageName);
        if (pkg == null) {
            throw new NullPointerException("Invalid package name");
        }
        if (pkg.keySetData == null
            || pkg.keySetData.getProperSigningKeySet()
            == PackageKeySetData.KEYSET_UNASSIGNED) {
            throw new NullPointerException("Package has no KeySet data");
        }
        long id = getIdByKeySetLPr(ks);
        return pkg.keySetData.getProperSigningKeySet() == id;
    
public booleanpackageIsSignedByLPr(java.lang.String packageName, KeySetHandle ks)
Determine if a package is signed by the given KeySet. Returns false if the package was not signed by all the keys in the KeySet. Returns true if the package was signed by at least the keys in the given KeySet. Note that this can return true for multiple KeySets.

        PackageSetting pkg = mPackages.get(packageName);
        if (pkg == null) {
            throw new NullPointerException("Invalid package name");
        }
        if (pkg.keySetData == null) {
            throw new NullPointerException("Package has no KeySet data");
        }
        long id = getIdByKeySetLPr(ks);
        if (id == KEYSET_NOT_FOUND) {
                return false;
        }
        return pkg.keySetData.packageIsSignedBy(id);
    
longreadIdentifierLPw(org.xmlpull.v1.XmlPullParser parser)

        return Long.parseLong(parser.getAttributeValue(null, "identifier"));
    
voidreadKeySetListLPw(org.xmlpull.v1.XmlPullParser parser)

        int outerDepth = parser.getDepth();
        int type;
        long currentKeySetId = 0;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }
            final String tagName = parser.getName();
            if (tagName.equals("keyset")) {
                currentKeySetId = readIdentifierLPw(parser);
                mKeySets.put(currentKeySetId, new KeySetHandle());
                mKeySetMapping.put(currentKeySetId, new ArraySet<Long>());
            } else if (tagName.equals("key-id")) {
                long id = readIdentifierLPw(parser);
                mKeySetMapping.get(currentKeySetId).add(id);
            }
        }
    
voidreadKeySetsLPw(org.xmlpull.v1.XmlPullParser parser)

        int type;
        long currentKeySetId = 0;
        int outerDepth = parser.getDepth();
        String recordedVersion = parser.getAttributeValue(null, "version");
        if (recordedVersion == null || Integer.parseInt(recordedVersion) != CURRENT_VERSION) {
            while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                    && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
                // Our version is different than the one which generated the old keyset data.
                // We don't want any of the old data, but we must advance the parser
                continue;
            }
            // The KeySet information read previously from packages.xml is invalid.
            // Destroy it all.
            for (PackageSetting p : mPackages.values()) {
                clearPackageKeySetDataLPw(p);
            }
            return;
        }
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
               && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }
            final String tagName = parser.getName();
            if (tagName.equals("keys")) {
                readKeysLPw(parser);
            } else if (tagName.equals("keysets")) {
                readKeySetListLPw(parser);
            } else if (tagName.equals("lastIssuedKeyId")) {
                lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value"));
            } else if (tagName.equals("lastIssuedKeySetId")) {
                lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value"));
            }
        }
    
voidreadKeysLPw(org.xmlpull.v1.XmlPullParser parser)

        int outerDepth = parser.getDepth();
        int type;
        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
                continue;
            }
            final String tagName = parser.getName();
            if (tagName.equals("public-key")) {
                readPublicKeyLPw(parser);
            }
        }
    
voidreadPublicKeyLPw(org.xmlpull.v1.XmlPullParser parser)

        String encodedID = parser.getAttributeValue(null, "identifier");
        long identifier = Long.parseLong(encodedID);
        String encodedPublicKey = parser.getAttributeValue(null, "value");
        PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey);
        if (pub != null) {
            mPublicKeys.put(identifier, pub);
        }
    
public voidremoveAppKeySetDataLPw(java.lang.String packageName)

        // Get the package's known keys and KeySets
        ArraySet<Long> deletableKeySets = getOriginalKeySetsByPackageNameLPr(packageName);
        ArraySet<Long> deletableKeys = new ArraySet<Long>();
        ArraySet<Long> knownKeys = null;
        for (Long ks : deletableKeySets) {
            knownKeys = mKeySetMapping.get(ks);
            if (knownKeys != null) {
                deletableKeys.addAll(knownKeys);
            }
        }

        // Now remove the keys and KeySets on which any other package relies
        for (String pkgName : mPackages.keySet()) {
            if (pkgName.equals(packageName)) {
                continue;
            }
            ArraySet<Long> knownKeySets = getOriginalKeySetsByPackageNameLPr(pkgName);
            deletableKeySets.removeAll(knownKeySets);
            knownKeys = new ArraySet<Long>();
            for (Long ks : knownKeySets) {
                knownKeys = mKeySetMapping.get(ks);
                if (knownKeys != null) {
                    deletableKeys.removeAll(knownKeys);
                }
            }
        }

        // The remaining keys and KeySets are not relied on by any other
        // application and so can be safely deleted.
        for (Long ks : deletableKeySets) {
            mKeySets.delete(ks);
            mKeySetMapping.delete(ks);
        }
        for (Long keyId : deletableKeys) {
            mPublicKeys.delete(keyId);
        }

        // Now remove the deleted KeySets from each package's signingKeySets
        for (String pkgName : mPackages.keySet()) {
            PackageSetting p = mPackages.get(pkgName);
            for (Long ks : deletableKeySets) {
                p.keySetData.removeSigningKeySet(ks);
            }
        }
        // Finally, remove all KeySets from the original package
        PackageSetting p = mPackages.get(packageName);
        clearPackageKeySetDataLPw(p);
    
voidwriteKeySetManagerServiceLPr(org.xmlpull.v1.XmlSerializer serializer)

        serializer.startTag(null, "keyset-settings");
        serializer.attribute(null, "version", Integer.toString(CURRENT_VERSION));
        writePublicKeysLPr(serializer);
        writeKeySetsLPr(serializer);
        serializer.startTag(null, "lastIssuedKeyId");
        serializer.attribute(null, "value", Long.toString(lastIssuedKeyId));
        serializer.endTag(null, "lastIssuedKeyId");
        serializer.startTag(null, "lastIssuedKeySetId");
        serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId));
        serializer.endTag(null, "lastIssuedKeySetId");
        serializer.endTag(null, "keyset-settings");
    
voidwriteKeySetsLPr(org.xmlpull.v1.XmlSerializer serializer)

        serializer.startTag(null, "keysets");
        for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) {
            long id = mKeySetMapping.keyAt(keySetIndex);
            ArraySet<Long> keys = mKeySetMapping.valueAt(keySetIndex);
            serializer.startTag(null, "keyset");
            serializer.attribute(null, "identifier", Long.toString(id));
            for (long keyId : keys) {
                serializer.startTag(null, "key-id");
                serializer.attribute(null, "identifier", Long.toString(keyId));
                serializer.endTag(null, "key-id");
            }
            serializer.endTag(null, "keyset");
        }
        serializer.endTag(null, "keysets");
    
voidwritePublicKeysLPr(org.xmlpull.v1.XmlSerializer serializer)

        serializer.startTag(null, "keys");
        for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) {
            long id = mPublicKeys.keyAt(pKeyIndex);
            PublicKey key = mPublicKeys.valueAt(pKeyIndex);
            String encodedKey = encodePublicKey(key);
            serializer.startTag(null, "public-key");
            serializer.attribute(null, "identifier", Long.toString(id));
            serializer.attribute(null, "value", encodedKey);
            serializer.endTag(null, "public-key");
        }
        serializer.endTag(null, "keys");