Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 1 | /* |
| 2 | * Copyright (C) 2013 The Android Open Source Project |
| 3 | * |
| 4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
| 5 | * you may not use this file except in compliance with the License. |
| 6 | * You may obtain a copy of the License at |
| 7 | * |
| 8 | * http://www.apache.org/licenses/LICENSE-2.0 |
| 9 | * |
| 10 | * Unless required by applicable law or agreed to in writing, software |
| 11 | * distributed under the License is distributed on an "AS IS" BASIS, |
| 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 13 | * See the License for the specific language governing permissions and |
| 14 | * limitations under the License. |
| 15 | */ |
| 16 | |
| 17 | package com.android.server.pm; |
| 18 | |
| 19 | import android.content.pm.KeySet; |
| 20 | import android.content.pm.PackageParser; |
| 21 | import android.os.Binder; |
| 22 | import android.util.Base64; |
| 23 | import android.util.Log; |
| 24 | import android.util.LongSparseArray; |
| 25 | |
| 26 | import java.io.IOException; |
| 27 | import java.io.PrintWriter; |
| 28 | import java.security.PublicKey; |
| 29 | import java.util.HashMap; |
| 30 | import java.util.HashSet; |
| 31 | import java.util.Map; |
| 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 KeySetManager { |
| 42 | |
| 43 | static final String TAG = "KeySetManager"; |
| 44 | |
Kenny Root | 9a995f5 | 2013-07-08 09:33:22 -0700 | [diff] [blame] | 45 | /** Sentinel value returned when a {@code KeySet} is not found. */ |
| 46 | public static final long KEYSET_NOT_FOUND = -1; |
| 47 | |
| 48 | /** Sentinel value returned when public key is not found. */ |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 49 | private static final long PUBLIC_KEY_NOT_FOUND = -1; |
| 50 | |
| 51 | private final Object mLockObject = new Object(); |
| 52 | |
| 53 | private final LongSparseArray<KeySet> mKeySets; |
| 54 | |
| 55 | private final LongSparseArray<PublicKey> mPublicKeys; |
| 56 | |
| 57 | private final LongSparseArray<Set<Long>> mKeySetMapping; |
| 58 | |
| 59 | private final Map<String, PackageSetting> mPackages; |
| 60 | |
| 61 | private static long lastIssuedKeySetId = 0; |
| 62 | |
| 63 | private static long lastIssuedKeyId = 0; |
| 64 | |
| 65 | public KeySetManager(Map<String, PackageSetting> packages) { |
| 66 | mKeySets = new LongSparseArray<KeySet>(); |
| 67 | mPublicKeys = new LongSparseArray<PublicKey>(); |
| 68 | mKeySetMapping = new LongSparseArray<Set<Long>>(); |
| 69 | mPackages = packages; |
| 70 | } |
| 71 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 72 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 73 | * Determine if a package is signed by the given KeySet. |
| 74 | * |
| 75 | * Returns false if the package was not signed by all the |
| 76 | * keys in the KeySet. |
| 77 | * |
| 78 | * Returns true if the package was signed by at least the |
| 79 | * keys in the given KeySet. |
| 80 | * |
| 81 | * Note that this can return true for multiple KeySets. |
| 82 | */ |
| 83 | public boolean packageIsSignedBy(String packageName, KeySet ks) { |
| 84 | synchronized (mLockObject) { |
| 85 | PackageSetting pkg = mPackages.get(packageName); |
| 86 | if (pkg == null) { |
| 87 | throw new NullPointerException("Invalid package name"); |
| 88 | } |
| 89 | if (pkg.keySetData == null) { |
| 90 | throw new NullPointerException("Package has no KeySet data"); |
| 91 | } |
| 92 | long id = getIdByKeySetLocked(ks); |
| 93 | return pkg.keySetData.packageIsSignedBy(id); |
| 94 | } |
| 95 | } |
| 96 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 97 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 98 | * This informs the system that the given package has defined a KeySet |
| 99 | * in its manifest that a) contains the given keys and b) is named |
| 100 | * alias by that package. |
| 101 | */ |
| 102 | public void addDefinedKeySetToPackage(String packageName, |
| 103 | Set<PublicKey> keys, String alias) { |
| 104 | if ((packageName == null) || (keys == null) || (alias == null)) { |
Geremy Condra | bf7b1f4 | 2013-06-18 10:38:27 -0700 | [diff] [blame] | 105 | Log.d(TAG, "Got null argument for a defined keyset, ignoring!"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 106 | return; |
| 107 | } |
| 108 | synchronized (mLockObject) { |
| 109 | KeySet ks = addKeySetLocked(keys); |
| 110 | PackageSetting pkg = mPackages.get(packageName); |
| 111 | if (pkg == null) { |
| 112 | throw new NullPointerException("Unknown package"); |
| 113 | } |
| 114 | long id = getIdByKeySetLocked(ks); |
| 115 | pkg.keySetData.addDefinedKeySet(id, alias); |
| 116 | } |
| 117 | } |
| 118 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 119 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 120 | * Similar to the above, this informs the system that the given package |
| 121 | * was signed by the provided KeySet. |
| 122 | */ |
| 123 | public void addSigningKeySetToPackage(String packageName, |
| 124 | Set<PublicKey> signingKeys) { |
| 125 | if ((packageName == null) || (signingKeys == null)) { |
Geremy Condra | bf7b1f4 | 2013-06-18 10:38:27 -0700 | [diff] [blame] | 126 | Log.d(TAG, "Got null argument for a signing keyset, ignoring!"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 127 | return; |
| 128 | } |
| 129 | synchronized (mLockObject) { |
| 130 | // add the signing KeySet |
| 131 | KeySet ks = addKeySetLocked(signingKeys); |
| 132 | long id = getIdByKeySetLocked(ks); |
| 133 | Set<Long> publicKeyIds = mKeySetMapping.get(id); |
| 134 | if (publicKeyIds == null) { |
| 135 | throw new NullPointerException("Got invalid KeySet id"); |
| 136 | } |
| 137 | |
| 138 | // attach it to the package |
| 139 | PackageSetting pkg = mPackages.get(packageName); |
| 140 | if (pkg == null) { |
| 141 | throw new NullPointerException("No such package!"); |
| 142 | } |
| 143 | pkg.keySetData.addSigningKeySet(id); |
| 144 | |
| 145 | // for each KeySet the package defines which is a subset of |
| 146 | // the one above, add the KeySet id to the package's signing KeySets |
| 147 | for (Long keySetID : pkg.keySetData.getDefinedKeySets()) { |
| 148 | Set<Long> definedKeys = mKeySetMapping.get(keySetID); |
| 149 | if (publicKeyIds.contains(definedKeys)) { |
| 150 | pkg.keySetData.addSigningKeySet(keySetID); |
| 151 | } |
| 152 | } |
| 153 | } |
| 154 | } |
| 155 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 156 | /** |
| 157 | * Fetches the stable identifier associated with the given KeySet. Returns |
| 158 | * {@link #KEYSET_NOT_FOUND} if the KeySet... wasn't found. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 159 | */ |
| 160 | public long getIdByKeySet(KeySet ks) { |
| 161 | synchronized (mLockObject) { |
| 162 | return getIdByKeySetLocked(ks); |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | private long getIdByKeySetLocked(KeySet ks) { |
| 167 | for (int keySetIndex = 0; keySetIndex < mKeySets.size(); keySetIndex++) { |
| 168 | KeySet value = mKeySets.valueAt(keySetIndex); |
| 169 | if (ks.equals(value)) { |
| 170 | return mKeySets.keyAt(keySetIndex); |
| 171 | } |
| 172 | } |
| 173 | return KEYSET_NOT_FOUND; |
| 174 | } |
| 175 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 176 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 177 | * Fetches the KeySet corresponding to the given stable identifier. |
| 178 | * |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 179 | * Returns {@link #KEYSET_NOT_FOUND} if the identifier doesn't |
| 180 | * identify a {@link KeySet}. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 181 | */ |
| 182 | public KeySet getKeySetById(long id) { |
| 183 | synchronized (mLockObject) { |
| 184 | return mKeySets.get(id); |
| 185 | } |
| 186 | } |
| 187 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 188 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 189 | * Fetches the KeySet that a given package refers to by the provided alias. |
| 190 | * |
| 191 | * If the package isn't known to us, throws an IllegalArgumentException. |
| 192 | * Returns null if the alias isn't known to us. |
| 193 | */ |
| 194 | public KeySet getKeySetByAliasAndPackageName(String packageName, String alias) { |
| 195 | synchronized (mLockObject) { |
| 196 | PackageSetting p = mPackages.get(packageName); |
| 197 | if (p == null) { |
| 198 | throw new NullPointerException("Unknown package"); |
| 199 | } |
| 200 | if (p.keySetData == null) { |
| 201 | throw new IllegalArgumentException("Package has no keySet data"); |
| 202 | } |
| 203 | long keySetId = p.keySetData.getAliases().get(alias); |
| 204 | return mKeySets.get(keySetId); |
| 205 | } |
| 206 | } |
| 207 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 208 | /** |
| 209 | * Fetches all the known {@link KeySet KeySets} that signed the given |
| 210 | * package. Returns {@code null} if package is unknown. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 211 | */ |
| 212 | public Set<KeySet> getSigningKeySetsByPackageName(String packageName) { |
| 213 | synchronized (mLockObject) { |
| 214 | Set<KeySet> signingKeySets = new HashSet<KeySet>(); |
| 215 | PackageSetting p = mPackages.get(packageName); |
| 216 | if (p == null) { |
| 217 | throw new NullPointerException("Unknown package"); |
| 218 | } |
| 219 | if (p.keySetData == null) { |
| 220 | throw new IllegalArgumentException("Package has no keySet data"); |
| 221 | } |
| 222 | for (long l : p.keySetData.getSigningKeySets()) { |
| 223 | signingKeySets.add(mKeySets.get(l)); |
| 224 | } |
| 225 | return signingKeySets; |
| 226 | } |
| 227 | } |
| 228 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 229 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 230 | * Creates a new KeySet corresponding to the given keys. |
| 231 | * |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 232 | * If the {@link PublicKey PublicKeys} aren't known to the system, this |
| 233 | * adds them. Otherwise, they're deduped. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 234 | * |
| 235 | * If the KeySet isn't known to the system, this adds that and creates the |
| 236 | * mapping to the PublicKeys. If it is known, then it's deduped. |
| 237 | * |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 238 | * Throws if the provided set is {@code null}. |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 239 | */ |
| 240 | private KeySet addKeySetLocked(Set<PublicKey> keys) { |
| 241 | if (keys == null) { |
| 242 | throw new NullPointerException("Provided keys cannot be null"); |
| 243 | } |
| 244 | // add each of the keys in the provided set |
| 245 | Set<Long> addedKeyIds = new HashSet<Long>(keys.size()); |
| 246 | for (PublicKey k : keys) { |
| 247 | long id = addPublicKeyLocked(k); |
| 248 | addedKeyIds.add(id); |
| 249 | } |
| 250 | |
| 251 | // check to see if the resulting keyset is new |
| 252 | long existingKeySetId = getIdFromKeyIdsLocked(addedKeyIds); |
| 253 | if (existingKeySetId != KEYSET_NOT_FOUND) { |
| 254 | return mKeySets.get(existingKeySetId); |
| 255 | } |
| 256 | |
| 257 | // create the KeySet object |
| 258 | KeySet ks = new KeySet(new Binder()); |
| 259 | // get the first unoccupied slot in mKeySets |
| 260 | long id = getFreeKeySetIDLocked(); |
| 261 | // add the KeySet object to it |
| 262 | mKeySets.put(id, ks); |
| 263 | // add the stable key ids to the mapping |
| 264 | mKeySetMapping.put(id, addedKeyIds); |
| 265 | // go home |
| 266 | return ks; |
| 267 | } |
| 268 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 269 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 270 | * Adds the given PublicKey to the system, deduping as it goes. |
| 271 | */ |
| 272 | private long addPublicKeyLocked(PublicKey key) { |
| 273 | // check if the public key is new |
| 274 | long existingKeyId = getIdForPublicKeyLocked(key); |
| 275 | if (existingKeyId != PUBLIC_KEY_NOT_FOUND) { |
| 276 | return existingKeyId; |
| 277 | } |
| 278 | // if it's new find the first unoccupied slot in the public keys |
| 279 | long id = getFreePublicKeyIdLocked(); |
| 280 | // add the public key to it |
| 281 | mPublicKeys.put(id, key); |
| 282 | // return the stable identifier |
| 283 | return id; |
| 284 | } |
| 285 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 286 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 287 | * Finds the stable identifier for a KeySet based on a set of PublicKey stable IDs. |
| 288 | * |
| 289 | * Returns KEYSET_NOT_FOUND if there isn't one. |
| 290 | */ |
| 291 | private long getIdFromKeyIdsLocked(Set<Long> publicKeyIds) { |
| 292 | for (int keyMapIndex = 0; keyMapIndex < mKeySetMapping.size(); keyMapIndex++) { |
| 293 | Set<Long> value = mKeySetMapping.valueAt(keyMapIndex); |
| 294 | if (value.equals(publicKeyIds)) { |
| 295 | return mKeySetMapping.keyAt(keyMapIndex); |
| 296 | } |
| 297 | } |
| 298 | return KEYSET_NOT_FOUND; |
| 299 | } |
| 300 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 301 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 302 | * Finds the stable identifier for a PublicKey or PUBLIC_KEY_NOT_FOUND. |
| 303 | */ |
| 304 | private long getIdForPublicKeyLocked(PublicKey k) { |
| 305 | String encodedPublicKey = new String(k.getEncoded()); |
| 306 | for (int publicKeyIndex = 0; publicKeyIndex < mPublicKeys.size(); publicKeyIndex++) { |
| 307 | PublicKey value = mPublicKeys.valueAt(publicKeyIndex); |
| 308 | String encodedExistingKey = new String(value.getEncoded()); |
| 309 | if (encodedPublicKey.equals(encodedExistingKey)) { |
| 310 | return mPublicKeys.keyAt(publicKeyIndex); |
| 311 | } |
| 312 | } |
| 313 | return PUBLIC_KEY_NOT_FOUND; |
| 314 | } |
| 315 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 316 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 317 | * Gets an unused stable identifier for a KeySet. |
| 318 | */ |
| 319 | private long getFreeKeySetIDLocked() { |
| 320 | lastIssuedKeySetId += 1; |
| 321 | return lastIssuedKeySetId; |
| 322 | } |
| 323 | |
Kenny Root | 2042e9d | 2013-07-08 09:31:31 -0700 | [diff] [blame^] | 324 | /** |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 325 | * Same as above, but for public keys. |
| 326 | */ |
| 327 | private long getFreePublicKeyIdLocked() { |
| 328 | lastIssuedKeyId += 1; |
| 329 | return lastIssuedKeyId; |
| 330 | } |
| 331 | |
| 332 | public void removeAppKeySetData(String packageName) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 333 | synchronized (mLockObject) { |
| 334 | // Get the package's known keys and KeySets |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 335 | Set<Long> deletableKeySets = getKnownKeySetsByPackageNameLocked(packageName); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 336 | Set<Long> deletableKeys = new HashSet<Long>(); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 337 | Set<Long> knownKeys = null; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 338 | for (Long ks : deletableKeySets) { |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 339 | knownKeys = mKeySetMapping.get(ks); |
| 340 | if (knownKeys != null) { |
| 341 | deletableKeys.addAll(knownKeys); |
| 342 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 343 | } |
| 344 | |
| 345 | // Now remove the keys and KeySets known to any other package |
| 346 | for (String pkgName : mPackages.keySet()) { |
| 347 | if (pkgName.equals(packageName)) { |
| 348 | continue; |
| 349 | } |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 350 | Set<Long> knownKeySets = getKnownKeySetsByPackageNameLocked(pkgName); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 351 | deletableKeySets.removeAll(knownKeySets); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 352 | knownKeys = new HashSet<Long>(); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 353 | for (Long ks : knownKeySets) { |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 354 | knownKeys = mKeySetMapping.get(ks); |
| 355 | if (knownKeys != null) { |
| 356 | deletableKeys.removeAll(knownKeys); |
| 357 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 358 | } |
| 359 | } |
| 360 | |
| 361 | // The remaining keys and KeySets are not known to any other |
| 362 | // application and so can be safely deleted. |
| 363 | for (Long ks : deletableKeySets) { |
| 364 | mKeySets.delete(ks); |
| 365 | mKeySetMapping.delete(ks); |
| 366 | } |
| 367 | for (Long keyId : deletableKeys) { |
| 368 | mPublicKeys.delete(keyId); |
| 369 | } |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 370 | |
| 371 | // Now remove them from the KeySets known to each package |
| 372 | for (String pkgName : mPackages.keySet()) { |
Kenny Root | 92179bc | 2013-07-02 11:55:27 -0700 | [diff] [blame] | 373 | PackageSetting p = mPackages.get(pkgName); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 374 | for (Long ks : deletableKeySets) { |
| 375 | p.keySetData.removeSigningKeySet(ks); |
| 376 | p.keySetData.removeDefinedKeySet(ks); |
| 377 | } |
| 378 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 379 | } |
| 380 | } |
| 381 | |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 382 | private Set<Long> getKnownKeySetsByPackageNameLocked(String packageName) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 383 | PackageSetting p = mPackages.get(packageName); |
| 384 | if (p == null) { |
| 385 | throw new NullPointerException("Unknown package"); |
| 386 | } |
| 387 | if (p.keySetData == null) { |
| 388 | throw new IllegalArgumentException("Package has no keySet data"); |
| 389 | } |
| 390 | Set<Long> knownKeySets = new HashSet<Long>(); |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 391 | for (long ks : p.keySetData.getSigningKeySets()) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 392 | knownKeySets.add(ks); |
| 393 | } |
Geremy Condra | cdb5789 | 2013-03-26 16:22:36 -0700 | [diff] [blame] | 394 | for (long ks : p.keySetData.getDefinedKeySets()) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 395 | knownKeySets.add(ks); |
| 396 | } |
| 397 | return knownKeySets; |
| 398 | } |
| 399 | |
| 400 | public String encodePublicKey(PublicKey k) throws IOException { |
| 401 | return new String(Base64.encode(k.getEncoded(), 0)); |
| 402 | } |
| 403 | |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 404 | public void dump(PrintWriter pw, String packageName, |
| 405 | PackageManagerService.DumpState dumpState) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 406 | synchronized (mLockObject) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 407 | boolean printedHeader = false; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 408 | for (Map.Entry<String, PackageSetting> e : mPackages.entrySet()) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 409 | String keySetPackage = e.getKey(); |
| 410 | if (packageName != null && !packageName.equals(keySetPackage)) { |
| 411 | continue; |
| 412 | } |
| 413 | if (!printedHeader) { |
| 414 | if (dumpState.onTitlePrinted()) |
| 415 | pw.println(); |
| 416 | pw.println("Key Set Manager:"); |
| 417 | printedHeader = true; |
| 418 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 419 | PackageSetting pkg = e.getValue(); |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 420 | pw.print(" ["); pw.print(keySetPackage); pw.println("]"); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 421 | if (pkg.keySetData != null) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 422 | boolean printedLabel = false; |
Ying Wang | fb236b5 | 2013-07-08 10:53:58 -0700 | [diff] [blame] | 423 | for (Map.Entry<String, Long> entry : pkg.keySetData.getAliases().entrySet()) { |
Kenny Root | df0e6ab | 2013-07-03 13:38:31 -0700 | [diff] [blame] | 424 | if (!printedLabel) { |
| 425 | pw.print(" KeySets Aliases: "); |
| 426 | printedLabel = true; |
| 427 | } else { |
| 428 | pw.print(", "); |
| 429 | } |
| 430 | pw.print(entry.getKey()); |
| 431 | pw.print('='); |
| 432 | pw.print(Long.toString(entry.getValue())); |
| 433 | } |
| 434 | if (printedLabel) { |
| 435 | pw.println(""); |
| 436 | } |
| 437 | printedLabel = false; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 438 | for (long keySetId : pkg.keySetData.getDefinedKeySets()) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 439 | if (!printedLabel) { |
| 440 | pw.print(" Defined KeySets: "); |
| 441 | printedLabel = true; |
| 442 | } else { |
| 443 | pw.print(", "); |
| 444 | } |
| 445 | pw.print(Long.toString(keySetId)); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 446 | } |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 447 | if (printedLabel) { |
| 448 | pw.println(""); |
| 449 | } |
| 450 | printedLabel = false; |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 451 | for (long keySetId : pkg.keySetData.getSigningKeySets()) { |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 452 | if (!printedLabel) { |
Kenny Root | df0e6ab | 2013-07-03 13:38:31 -0700 | [diff] [blame] | 453 | pw.print(" Signing KeySets: "); |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 454 | printedLabel = true; |
| 455 | } else { |
| 456 | pw.print(", "); |
| 457 | } |
Kenny Root | df0e6ab | 2013-07-03 13:38:31 -0700 | [diff] [blame] | 458 | pw.print(Long.toString(keySetId)); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 459 | } |
Dianne Hackborn | cbfd23e | 2013-06-11 14:26:53 -0700 | [diff] [blame] | 460 | if (printedLabel) { |
| 461 | pw.println(""); |
| 462 | } |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 463 | } |
| 464 | } |
| 465 | } |
| 466 | } |
| 467 | |
| 468 | void writeKeySetManagerLPr(XmlSerializer serializer) throws IOException { |
| 469 | serializer.startTag(null, "keyset-settings"); |
| 470 | writePublicKeysLPr(serializer); |
| 471 | writeKeySetsLPr(serializer); |
| 472 | serializer.startTag(null, "lastIssuedKeyId"); |
| 473 | serializer.attribute(null, "value", Long.toString(lastIssuedKeyId)); |
| 474 | serializer.endTag(null, "lastIssuedKeyId"); |
| 475 | serializer.startTag(null, "lastIssuedKeySetId"); |
| 476 | serializer.attribute(null, "value", Long.toString(lastIssuedKeySetId)); |
| 477 | serializer.endTag(null, "lastIssuedKeySetId"); |
| 478 | serializer.endTag(null, "keyset-settings"); |
| 479 | } |
| 480 | |
| 481 | void writePublicKeysLPr(XmlSerializer serializer) throws IOException { |
| 482 | serializer.startTag(null, "keys"); |
| 483 | for (int pKeyIndex = 0; pKeyIndex < mPublicKeys.size(); pKeyIndex++) { |
| 484 | long id = mPublicKeys.keyAt(pKeyIndex); |
| 485 | PublicKey key = mPublicKeys.valueAt(pKeyIndex); |
| 486 | String encodedKey = encodePublicKey(key); |
| 487 | serializer.startTag(null, "public-key"); |
| 488 | serializer.attribute(null, "identifier", Long.toString(id)); |
| 489 | serializer.attribute(null, "value", encodedKey); |
| 490 | serializer.endTag(null, "public-key"); |
| 491 | } |
| 492 | serializer.endTag(null, "keys"); |
| 493 | } |
| 494 | |
| 495 | void writeKeySetsLPr(XmlSerializer serializer) throws IOException { |
| 496 | serializer.startTag(null, "keysets"); |
| 497 | for (int keySetIndex = 0; keySetIndex < mKeySetMapping.size(); keySetIndex++) { |
| 498 | long id = mKeySetMapping.keyAt(keySetIndex); |
| 499 | Set<Long> keys = mKeySetMapping.valueAt(keySetIndex); |
| 500 | serializer.startTag(null, "keyset"); |
| 501 | serializer.attribute(null, "identifier", Long.toString(id)); |
| 502 | for (long keyId : keys) { |
| 503 | serializer.startTag(null, "key-id"); |
| 504 | serializer.attribute(null, "identifier", Long.toString(keyId)); |
| 505 | serializer.endTag(null, "key-id"); |
| 506 | } |
| 507 | serializer.endTag(null, "keyset"); |
| 508 | } |
| 509 | serializer.endTag(null, "keysets"); |
| 510 | } |
| 511 | |
| 512 | void readKeySetsLPw(XmlPullParser parser) |
| 513 | throws XmlPullParserException, IOException { |
| 514 | int type; |
| 515 | long currentKeySetId = 0; |
| 516 | while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) { |
| 517 | if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| 518 | continue; |
| 519 | } |
| 520 | final String tagName = parser.getName(); |
| 521 | if (tagName.equals("keys")) { |
| 522 | readKeysLPw(parser); |
| 523 | } else if (tagName.equals("keysets")) { |
| 524 | readKeySetListLPw(parser); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 525 | } |
| 526 | } |
| 527 | } |
| 528 | |
| 529 | void readKeysLPw(XmlPullParser parser) |
| 530 | throws XmlPullParserException, IOException { |
| 531 | int outerDepth = parser.getDepth(); |
| 532 | int type; |
| 533 | while ((type = parser.next()) != XmlPullParser.END_DOCUMENT |
| 534 | && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { |
| 535 | if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| 536 | continue; |
| 537 | } |
| 538 | final String tagName = parser.getName(); |
| 539 | if (tagName.equals("public-key")) { |
| 540 | readPublicKeyLPw(parser); |
| 541 | } else if (tagName.equals("lastIssuedKeyId")) { |
| 542 | lastIssuedKeyId = Long.parseLong(parser.getAttributeValue(null, "value")); |
| 543 | } else if (tagName.equals("lastIssuedKeySetId")) { |
| 544 | lastIssuedKeySetId = Long.parseLong(parser.getAttributeValue(null, "value")); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 545 | } |
| 546 | } |
| 547 | } |
| 548 | |
| 549 | void readKeySetListLPw(XmlPullParser parser) |
| 550 | throws XmlPullParserException, IOException { |
| 551 | int outerDepth = parser.getDepth(); |
| 552 | int type; |
| 553 | long currentKeySetId = 0; |
| 554 | while ((type = parser.next()) != XmlPullParser.END_DOCUMENT |
| 555 | && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) { |
| 556 | if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) { |
| 557 | continue; |
| 558 | } |
| 559 | final String tagName = parser.getName(); |
| 560 | if (tagName.equals("keyset")) { |
| 561 | currentKeySetId = readIdentifierLPw(parser); |
| 562 | mKeySets.put(currentKeySetId, new KeySet(new Binder())); |
| 563 | mKeySetMapping.put(currentKeySetId, new HashSet<Long>()); |
| 564 | } else if (tagName.equals("key-id")) { |
| 565 | long id = readIdentifierLPw(parser); |
| 566 | mKeySetMapping.get(currentKeySetId).add(id); |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 567 | } |
| 568 | } |
| 569 | } |
| 570 | |
| 571 | long readIdentifierLPw(XmlPullParser parser) |
| 572 | throws XmlPullParserException { |
| 573 | return Long.parseLong(parser.getAttributeValue(null, "identifier")); |
| 574 | } |
| 575 | |
| 576 | void readPublicKeyLPw(XmlPullParser parser) |
| 577 | throws XmlPullParserException { |
| 578 | String encodedID = parser.getAttributeValue(null, "identifier"); |
| 579 | long identifier = Long.parseLong(encodedID); |
| 580 | String encodedPublicKey = parser.getAttributeValue(null, "value"); |
| 581 | PublicKey pub = PackageParser.parsePublicKey(encodedPublicKey); |
Geremy Condra | a2d8eae | 2013-06-21 16:59:42 -0700 | [diff] [blame] | 582 | if (pub != null) { |
Geremy Condra | f1bcca8 | 2013-01-07 22:35:24 -0800 | [diff] [blame] | 583 | mPublicKeys.put(identifier, pub); |
| 584 | } |
| 585 | } |
Ying Wang | fb236b5 | 2013-07-08 10:53:58 -0700 | [diff] [blame] | 586 | } |