blob: c1eb8052357874638792c39c500e0bd2249d489e [file] [log] [blame]
Brian Carlstrom3e6251d2011-04-11 09:05:06 -07001/*
2 * Copyright (C) 2011 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
17package com.android.keychain;
18
Chad Brubaker2099a7d2016-05-02 13:13:23 -070019import android.app.BroadcastOptions;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070020import android.app.IntentService;
21import android.content.ContentValues;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070022import android.content.Context;
23import android.content.Intent;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070024import android.content.pm.PackageManager;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010025import android.content.pm.ParceledListSlice;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070026import android.database.Cursor;
27import android.database.DatabaseUtils;
28import android.database.sqlite.SQLiteDatabase;
29import android.database.sqlite.SQLiteOpenHelper;
Kenny Root6f1f03b2012-03-08 10:30:39 -080030import android.os.Binder;
Chad Brubaker2099a7d2016-05-02 13:13:23 -070031import android.os.Build;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070032import android.os.IBinder;
Kenny Root6f1f03b2012-03-08 10:30:39 -080033import android.os.Process;
Robin Lee93772c32014-09-02 14:53:50 +010034import android.os.UserHandle;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070035import android.security.Credentials;
36import android.security.IKeyChainService;
Selim Gurun39e36e52012-02-14 10:50:42 -080037import android.security.KeyChain;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070038import android.security.KeyStore;
39import android.util.Log;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010040import com.android.internal.util.ParcelableString;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070041import java.io.ByteArrayInputStream;
Brian Carlstroma58db542011-05-11 23:02:20 -070042import java.io.IOException;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070043import java.security.cert.CertificateException;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010044import java.security.cert.CertificateEncodingException;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070045import java.security.cert.CertificateFactory;
46import java.security.cert.X509Certificate;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010047import java.util.Set;
48import java.util.List;
49import java.util.ArrayList;
50import java.util.Collections;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070051
Kenny Root3048b6c2013-04-23 22:38:11 -070052import com.android.org.conscrypt.TrustedCertificateStore;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070053
Fred Quintanafb2e18e2011-07-13 14:54:05 -070054public class KeyChainService extends IntentService {
Selim Gurun39e36e52012-02-14 10:50:42 -080055
Fred Quintanafb2e18e2011-07-13 14:54:05 -070056 private static final String TAG = "KeyChain";
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070057
Fred Quintanafb2e18e2011-07-13 14:54:05 -070058 private static final String DATABASE_NAME = "grants.db";
59 private static final int DATABASE_VERSION = 1;
60 private static final String TABLE_GRANTS = "grants";
61 private static final String GRANTS_ALIAS = "alias";
62 private static final String GRANTS_GRANTEE_UID = "uid";
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070063
Fred Quintanafb2e18e2011-07-13 14:54:05 -070064 /** created in onCreate(), closed in onDestroy() */
65 public DatabaseHelper mDatabaseHelper;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070066
Fred Quintanafb2e18e2011-07-13 14:54:05 -070067 private static final String SELECTION_COUNT_OF_MATCHING_GRANTS =
68 "SELECT COUNT(*) FROM " + TABLE_GRANTS
69 + " WHERE " + GRANTS_GRANTEE_UID + "=? AND " + GRANTS_ALIAS + "=?";
70
71 private static final String SELECT_GRANTS_BY_UID_AND_ALIAS =
72 GRANTS_GRANTEE_UID + "=? AND " + GRANTS_ALIAS + "=?";
73
74 private static final String SELECTION_GRANTS_BY_UID = GRANTS_GRANTEE_UID + "=?";
75
Robin Leeba755b12016-02-24 15:27:43 +000076 private static final String SELECTION_GRANTS_BY_ALIAS = GRANTS_ALIAS + "=?";
77
Fred Quintanafb2e18e2011-07-13 14:54:05 -070078 public KeyChainService() {
79 super(KeyChainService.class.getSimpleName());
80 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070081
82 @Override public void onCreate() {
83 super.onCreate();
Fred Quintanafb2e18e2011-07-13 14:54:05 -070084 mDatabaseHelper = new DatabaseHelper(this);
85 }
86
87 @Override
88 public void onDestroy() {
89 super.onDestroy();
90 mDatabaseHelper.close();
91 mDatabaseHelper = null;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070092 }
93
94 private final IKeyChainService.Stub mIKeyChainService = new IKeyChainService.Stub() {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070095 private final KeyStore mKeyStore = KeyStore.getInstance();
Brian Carlstroma58db542011-05-11 23:02:20 -070096 private final TrustedCertificateStore mTrustedCertificateStore
97 = new TrustedCertificateStore();
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070098
Kenny Root6f1f03b2012-03-08 10:30:39 -080099 @Override
100 public String requestPrivateKey(String alias) {
101 checkArgs(alias);
102
103 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias;
104 final int uid = Binder.getCallingUid();
105 if (!mKeyStore.grant(keystoreAlias, uid)) {
106 return null;
107 }
Robin Lee93772c32014-09-02 14:53:50 +0100108 final int userHandle = UserHandle.getUserId(uid);
109 final int systemUidForUser = UserHandle.getUid(userHandle, Process.SYSTEM_UID);
Kenny Root6f1f03b2012-03-08 10:30:39 -0800110
111 final StringBuilder sb = new StringBuilder();
Robin Lee93772c32014-09-02 14:53:50 +0100112 sb.append(systemUidForUser);
Kenny Root6f1f03b2012-03-08 10:30:39 -0800113 sb.append('_');
114 sb.append(keystoreAlias);
115
116 return sb.toString();
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700117 }
118
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700119 @Override public byte[] getCertificate(String alias) {
Kenny Root6f1f03b2012-03-08 10:30:39 -0800120 checkArgs(alias);
121 return mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700122 }
123
Rubin Xu8714f062016-03-23 12:37:10 +0000124 @Override public byte[] getCaCertificates(String alias) {
125 checkArgs(alias);
126 return mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
127 }
128
Kenny Root6f1f03b2012-03-08 10:30:39 -0800129 private void checkArgs(String alias) {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700130 if (alias == null) {
131 throw new NullPointerException("alias == null");
132 }
Kenny Root4ff22962013-02-14 10:17:06 -0800133 if (!mKeyStore.isUnlocked()) {
Nick Kralevichc8b04632012-05-21 15:13:07 -0700134 throw new IllegalStateException("keystore is "
135 + mKeyStore.state().toString());
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700136 }
Nick Kralevichc8b04632012-05-21 15:13:07 -0700137
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700138 final int callingUid = getCallingUid();
139 if (!hasGrantInternal(mDatabaseHelper.getReadableDatabase(), callingUid, alias)) {
140 throw new IllegalStateException("uid " + callingUid
141 + " doesn't have permission to access the requested alias");
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700142 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700143 }
144
Brian Carlstroma58db542011-05-11 23:02:20 -0700145 @Override public void installCaCertificate(byte[] caCertificate) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700146 checkCertInstallerOrSystemCaller();
Brian Carlstroma58db542011-05-11 23:02:20 -0700147 try {
148 synchronized (mTrustedCertificateStore) {
149 mTrustedCertificateStore.installCertificate(parseCertificate(caCertificate));
150 }
151 } catch (IOException e) {
152 throw new IllegalStateException(e);
153 } catch (CertificateException e) {
154 throw new IllegalStateException(e);
155 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700156 broadcastLegacyStorageChange();
157 broadcastTrustStoreChange();
Brian Carlstroma58db542011-05-11 23:02:20 -0700158 }
Brian Carlstrom5aeadd92011-05-17 00:40:33 -0700159
Rubin Xu8714f062016-03-23 12:37:10 +0000160 /**
161 * Install a key pair to the keystore.
162 *
163 * @param privateKey The private key associated with the client certificate
164 * @param userCertificate The client certificate to be installed
165 * @param userCertificateChain The rest of the chain for the client certificate
166 * @param alias The alias under which the key pair is installed
167 * @return Whether the operation succeeded or not.
168 */
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100169 @Override public boolean installKeyPair(byte[] privateKey, byte[] userCertificate,
Rubin Xu8714f062016-03-23 12:37:10 +0000170 byte[] userCertificateChain, String alias) {
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100171 checkCertInstallerOrSystemCaller();
Robin Lee8847b122015-07-27 12:50:28 +0100172 if (!mKeyStore.isUnlocked()) {
173 Log.e(TAG, "Keystore is " + mKeyStore.state().toString() + ". Credentials cannot"
174 + " be installed until device is unlocked");
175 return false;
176 }
Robin Leeba755b12016-02-24 15:27:43 +0000177 if (!removeKeyPair(alias)) {
178 return false;
179 }
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100180 if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, privateKey, -1,
181 KeyStore.FLAG_ENCRYPTED)) {
182 Log.e(TAG, "Failed to import private key " + alias);
183 return false;
184 }
185 if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, -1,
186 KeyStore.FLAG_ENCRYPTED)) {
187 Log.e(TAG, "Failed to import user certificate " + userCertificate);
Alex Klyubin44c777b2015-06-08 09:46:15 -0700188 if (!mKeyStore.delete(Credentials.USER_PRIVATE_KEY + alias)) {
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100189 Log.e(TAG, "Failed to delete private key after certificate importing failed");
190 }
191 return false;
192 }
Rubin Xu8714f062016-03-23 12:37:10 +0000193 if (userCertificateChain != null && userCertificateChain.length > 0) {
194 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain, -1,
195 KeyStore.FLAG_ENCRYPTED)) {
196 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain);
197 if (!removeKeyPair(alias)) {
198 Log.e(TAG, "Failed to clean up key chain after certificate chain"
199 + " importing failed");
200 }
201 return false;
202 }
203 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700204 broadcastKeychainChange();
205 broadcastLegacyStorageChange();
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100206 return true;
207 }
208
Robin Leef44a5192015-08-03 17:18:02 +0100209 @Override public boolean removeKeyPair(String alias) {
210 checkCertInstallerOrSystemCaller();
Robin Leeba755b12016-02-24 15:27:43 +0000211 if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
212 return false;
213 }
214 removeGrantsForAlias(alias);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700215 broadcastKeychainChange();
216 broadcastLegacyStorageChange();
Robin Leeba755b12016-02-24 15:27:43 +0000217 return true;
Robin Leef44a5192015-08-03 17:18:02 +0100218 }
219
Brian Carlstrom5aeadd92011-05-17 00:40:33 -0700220 private X509Certificate parseCertificate(byte[] bytes) throws CertificateException {
221 CertificateFactory cf = CertificateFactory.getInstance("X.509");
222 return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes));
223 }
224
Brian Carlstroma58db542011-05-11 23:02:20 -0700225 @Override public boolean reset() {
226 // only Settings should be able to reset
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700227 checkSystemCaller();
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700228 removeAllGrants(mDatabaseHelper.getWritableDatabase());
Brian Carlstroma58db542011-05-11 23:02:20 -0700229 boolean ok = true;
Brian Carlstroma58db542011-05-11 23:02:20 -0700230 synchronized (mTrustedCertificateStore) {
231 // delete user-installed CA certs
232 for (String alias : mTrustedCertificateStore.aliases()) {
233 if (TrustedCertificateStore.isUser(alias)) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700234 if (!deleteCertificateEntry(alias)) {
Brian Carlstroma58db542011-05-11 23:02:20 -0700235 ok = false;
236 }
237 }
238 }
Brian Carlstroma58db542011-05-11 23:02:20 -0700239 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700240 broadcastTrustStoreChange();
241 broadcastLegacyStorageChange();
Selim Gurun39e36e52012-02-14 10:50:42 -0800242 return ok;
Brian Carlstroma58db542011-05-11 23:02:20 -0700243 }
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700244
245 @Override public boolean deleteCaCertificate(String alias) {
246 // only Settings should be able to delete
247 checkSystemCaller();
Selim Gurun39e36e52012-02-14 10:50:42 -0800248 boolean ok = true;
249 synchronized (mTrustedCertificateStore) {
250 ok = deleteCertificateEntry(alias);
251 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700252 broadcastTrustStoreChange();
253 broadcastLegacyStorageChange();
Selim Gurun39e36e52012-02-14 10:50:42 -0800254 return ok;
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700255 }
256
257 private boolean deleteCertificateEntry(String alias) {
258 try {
259 mTrustedCertificateStore.deleteCertificateEntry(alias);
260 return true;
261 } catch (IOException e) {
262 Log.w(TAG, "Problem removing CA certificate " + alias, e);
263 return false;
264 } catch (CertificateException e) {
265 Log.w(TAG, "Problem removing CA certificate " + alias, e);
266 return false;
267 }
268 }
269
270 private void checkCertInstallerOrSystemCaller() {
271 String actual = checkCaller("com.android.certinstaller");
272 if (actual == null) {
273 return;
274 }
275 checkSystemCaller();
276 }
277 private void checkSystemCaller() {
278 String actual = checkCaller("android.uid.system:1000");
279 if (actual != null) {
280 throw new IllegalStateException(actual);
281 }
282 }
283 /**
284 * Returns null if actually caller is expected, otherwise return bad package to report
285 */
286 private String checkCaller(String expectedPackage) {
287 String actualPackage = getPackageManager().getNameForUid(getCallingUid());
288 return (!expectedPackage.equals(actualPackage)) ? actualPackage : null;
289 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700290
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700291 @Override public boolean hasGrant(int uid, String alias) {
292 checkSystemCaller();
293 return hasGrantInternal(mDatabaseHelper.getReadableDatabase(), uid, alias);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700294 }
295
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700296 @Override public void setGrant(int uid, String alias, boolean value) {
297 checkSystemCaller();
298 setGrantInternal(mDatabaseHelper.getWritableDatabase(), uid, alias, value);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700299 broadcastPermissionChange(uid, alias, value);
300 broadcastLegacyStorageChange();
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700301 }
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100302
303 private ParceledListSlice<ParcelableString> makeAliasesParcelableSynchronised(
304 Set<String> aliasSet) {
305 List<ParcelableString> aliases = new ArrayList<ParcelableString>(aliasSet.size());
306 for (String alias : aliasSet) {
307 ParcelableString parcelableString = new ParcelableString();
308 parcelableString.string = alias;
309 aliases.add(parcelableString);
310 }
311 return new ParceledListSlice<ParcelableString>(aliases);
312 }
313
314 @Override
315 public ParceledListSlice<ParcelableString> getUserCaAliases() {
316 synchronized (mTrustedCertificateStore) {
317 Set<String> aliasSet = mTrustedCertificateStore.userAliases();
318 return makeAliasesParcelableSynchronised(aliasSet);
319 }
320 }
321
322 @Override
323 public ParceledListSlice<ParcelableString> getSystemCaAliases() {
324 synchronized (mTrustedCertificateStore) {
325 Set<String> aliasSet = mTrustedCertificateStore.allSystemAliases();
326 return makeAliasesParcelableSynchronised(aliasSet);
327 }
328 }
329
330 @Override
331 public boolean containsCaAlias(String alias) {
332 return mTrustedCertificateStore.containsAlias(alias);
333 }
334
335 @Override
336 public byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem) {
337 synchronized (mTrustedCertificateStore) {
338 X509Certificate certificate = (X509Certificate) mTrustedCertificateStore
339 .getCertificate(alias, includeDeletedSystem);
340 if (certificate == null) {
341 Log.w(TAG, "Could not find CA certificate " + alias);
342 return null;
343 }
344 try {
345 return certificate.getEncoded();
346 } catch (CertificateEncodingException e) {
347 Log.w(TAG, "Error while encoding CA certificate " + alias);
348 return null;
349 }
350 }
351 }
352
353 @Override
354 public List<String> getCaCertificateChainAliases(String rootAlias,
355 boolean includeDeletedSystem) {
356 synchronized (mTrustedCertificateStore) {
357 X509Certificate root = (X509Certificate) mTrustedCertificateStore.getCertificate(
358 rootAlias, includeDeletedSystem);
359 try {
360 List<X509Certificate> chain = mTrustedCertificateStore.getCertificateChain(
361 root);
362 List<String> aliases = new ArrayList<String>(chain.size());
363 final int n = chain.size();
364 for (int i = 0; i < n; ++i) {
365 String alias = mTrustedCertificateStore.getCertificateAlias(chain.get(i),
366 true);
367 if (alias != null) {
368 aliases.add(alias);
369 }
370 }
371 return aliases;
372 } catch (CertificateException e) {
373 Log.w(TAG, "Error retrieving cert chain for root " + rootAlias);
374 return Collections.emptyList();
375 }
376 }
377 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700378 };
379
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700380 private boolean hasGrantInternal(final SQLiteDatabase db, final int uid, final String alias) {
381 final long numMatches = DatabaseUtils.longForQuery(db, SELECTION_COUNT_OF_MATCHING_GRANTS,
382 new String[]{String.valueOf(uid), alias});
383 return numMatches > 0;
384 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700385
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700386 private void setGrantInternal(final SQLiteDatabase db,
387 final int uid, final String alias, final boolean value) {
388 if (value) {
389 if (!hasGrantInternal(db, uid, alias)) {
390 final ContentValues values = new ContentValues();
391 values.put(GRANTS_ALIAS, alias);
392 values.put(GRANTS_GRANTEE_UID, uid);
393 db.insert(TABLE_GRANTS, GRANTS_ALIAS, values);
394 }
395 } else {
396 db.delete(TABLE_GRANTS, SELECT_GRANTS_BY_UID_AND_ALIAS,
397 new String[]{String.valueOf(uid), alias});
398 }
399 }
400
Robin Leeba755b12016-02-24 15:27:43 +0000401 private void removeGrantsForAlias(String alias) {
402 final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
403 db.delete(TABLE_GRANTS, SELECTION_GRANTS_BY_ALIAS, new String[] {alias});
404 }
405
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700406 private void removeAllGrants(final SQLiteDatabase db) {
407 db.delete(TABLE_GRANTS, null /* whereClause */, null /* whereArgs */);
408 }
409
410 private class DatabaseHelper extends SQLiteOpenHelper {
411 public DatabaseHelper(Context context) {
412 super(context, DATABASE_NAME, null /* CursorFactory */, DATABASE_VERSION);
413 }
414
415 @Override
416 public void onCreate(final SQLiteDatabase db) {
417 db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
418 + GRANTS_ALIAS + " STRING NOT NULL, "
419 + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
420 + "UNIQUE (" + GRANTS_ALIAS + "," + GRANTS_GRANTEE_UID + "))");
421 }
422
423 @Override
424 public void onUpgrade(final SQLiteDatabase db, int oldVersion, final int newVersion) {
425 Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
426
427 if (oldVersion == 1) {
428 // the first upgrade step goes here
429 oldVersion++;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700430 }
Brian Carlstrom7037b732011-06-30 15:04:49 -0700431 }
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700432 }
433
434 @Override public IBinder onBind(Intent intent) {
Brian Carlstrom7037b732011-06-30 15:04:49 -0700435 if (IKeyChainService.class.getName().equals(intent.getAction())) {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700436 return mIKeyChainService;
437 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700438 return null;
439 }
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700440
441 @Override
442 protected void onHandleIntent(final Intent intent) {
443 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
444 purgeOldGrants();
445 }
446 }
447
448 private void purgeOldGrants() {
449 final PackageManager packageManager = getPackageManager();
450 final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
451 Cursor cursor = null;
452 db.beginTransaction();
453 try {
454 cursor = db.query(TABLE_GRANTS,
455 new String[]{GRANTS_GRANTEE_UID}, null, null, GRANTS_GRANTEE_UID, null, null);
456 while (cursor.moveToNext()) {
457 final int uid = cursor.getInt(0);
458 final boolean packageExists = packageManager.getPackagesForUid(uid) != null;
459 if (packageExists) {
460 continue;
461 }
462 Log.d(TAG, "deleting grants for UID " + uid
463 + " because its package is no longer installed");
464 db.delete(TABLE_GRANTS, SELECTION_GRANTS_BY_UID,
465 new String[]{Integer.toString(uid)});
466 }
467 db.setTransactionSuccessful();
468 } finally {
469 if (cursor != null) {
470 cursor.close();
471 }
472 db.endTransaction();
473 }
474 }
Selim Gurun39e36e52012-02-14 10:50:42 -0800475
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700476 private void broadcastLegacyStorageChange() {
Selim Gurun39e36e52012-02-14 10:50:42 -0800477 Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700478 BroadcastOptions opts = BroadcastOptions.makeBasic();
Chad Brubaker04028072016-07-08 10:48:54 -0700479 opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.N_MR1);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700480 sendBroadcast(intent, null, opts.toBundle());
Selim Gurun39e36e52012-02-14 10:50:42 -0800481 }
482
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700483 private void broadcastKeychainChange() {
484 Intent intent = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
485 sendBroadcast(intent);
486 }
487
488 private void broadcastTrustStoreChange() {
489 Intent intent = new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED);
490 sendBroadcast(intent);
491 }
492
493 private void broadcastPermissionChange(int uid, String alias, boolean access) {
494 // Since the permission change only impacts one uid only send to that uid's packages.
495 final PackageManager packageManager = getPackageManager();
496 String[] packages = packageManager.getPackagesForUid(uid);
497 if (packages == null) {
498 return;
499 }
500 for (String pckg : packages) {
501 Intent intent = new Intent(KeyChain.ACTION_KEY_ACCESS_CHANGED);
502 intent.putExtra(KeyChain.EXTRA_KEY_ALIAS, alias);
503 intent.putExtra(KeyChain.EXTRA_KEY_ACCESSIBLE, access);
504 intent.setPackage(pckg);
505 sendBroadcast(intent);
506 }
507 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700508}