blob: f45a1e62fa78c4ff40b396999680f4d51c7e2219 [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;
Robin Lee7e9d0452017-02-20 20:57:41 +000025import android.content.pm.StringParceledListSlice;
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;
40import java.io.ByteArrayInputStream;
Brian Carlstroma58db542011-05-11 23:02:20 -070041import java.io.IOException;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070042import java.security.cert.CertificateException;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010043import java.security.cert.CertificateEncodingException;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070044import java.security.cert.CertificateFactory;
45import java.security.cert.X509Certificate;
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +010046import java.util.Set;
47import java.util.List;
48import java.util.ArrayList;
49import java.util.Collections;
Fred Quintanafb2e18e2011-07-13 14:54:05 -070050
Kenny Root3048b6c2013-04-23 22:38:11 -070051import com.android.org.conscrypt.TrustedCertificateStore;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070052
Fred Quintanafb2e18e2011-07-13 14:54:05 -070053public class KeyChainService extends IntentService {
Selim Gurun39e36e52012-02-14 10:50:42 -080054
Fred Quintanafb2e18e2011-07-13 14:54:05 -070055 private static final String TAG = "KeyChain";
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070056
Fred Quintanafb2e18e2011-07-13 14:54:05 -070057 private static final String DATABASE_NAME = "grants.db";
58 private static final int DATABASE_VERSION = 1;
59 private static final String TABLE_GRANTS = "grants";
60 private static final String GRANTS_ALIAS = "alias";
61 private static final String GRANTS_GRANTEE_UID = "uid";
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070062
Fred Quintanafb2e18e2011-07-13 14:54:05 -070063 /** created in onCreate(), closed in onDestroy() */
64 public DatabaseHelper mDatabaseHelper;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070065
Fred Quintanafb2e18e2011-07-13 14:54:05 -070066 private static final String SELECTION_COUNT_OF_MATCHING_GRANTS =
67 "SELECT COUNT(*) FROM " + TABLE_GRANTS
68 + " WHERE " + GRANTS_GRANTEE_UID + "=? AND " + GRANTS_ALIAS + "=?";
69
70 private static final String SELECT_GRANTS_BY_UID_AND_ALIAS =
71 GRANTS_GRANTEE_UID + "=? AND " + GRANTS_ALIAS + "=?";
72
73 private static final String SELECTION_GRANTS_BY_UID = GRANTS_GRANTEE_UID + "=?";
74
Robin Leeba755b12016-02-24 15:27:43 +000075 private static final String SELECTION_GRANTS_BY_ALIAS = GRANTS_ALIAS + "=?";
76
Fred Quintanafb2e18e2011-07-13 14:54:05 -070077 public KeyChainService() {
78 super(KeyChainService.class.getSimpleName());
79 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070080
81 @Override public void onCreate() {
82 super.onCreate();
Fred Quintanafb2e18e2011-07-13 14:54:05 -070083 mDatabaseHelper = new DatabaseHelper(this);
84 }
85
86 @Override
87 public void onDestroy() {
88 super.onDestroy();
89 mDatabaseHelper.close();
90 mDatabaseHelper = null;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070091 }
92
93 private final IKeyChainService.Stub mIKeyChainService = new IKeyChainService.Stub() {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070094 private final KeyStore mKeyStore = KeyStore.getInstance();
Brian Carlstroma58db542011-05-11 23:02:20 -070095 private final TrustedCertificateStore mTrustedCertificateStore
96 = new TrustedCertificateStore();
Brian Carlstrom3e6251d2011-04-11 09:05:06 -070097
Kenny Root6f1f03b2012-03-08 10:30:39 -080098 @Override
99 public String requestPrivateKey(String alias) {
100 checkArgs(alias);
101
102 final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias;
103 final int uid = Binder.getCallingUid();
Janis Danisevskisc394aea2017-06-07 10:20:45 -0700104 return mKeyStore.grant(keystoreAlias, uid);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700105 }
106
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700107 @Override public byte[] getCertificate(String alias) {
Kenny Root6f1f03b2012-03-08 10:30:39 -0800108 checkArgs(alias);
109 return mKeyStore.get(Credentials.USER_CERTIFICATE + alias);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700110 }
111
Rubin Xu8714f062016-03-23 12:37:10 +0000112 @Override public byte[] getCaCertificates(String alias) {
113 checkArgs(alias);
114 return mKeyStore.get(Credentials.CA_CERTIFICATE + alias);
115 }
116
Kenny Root6f1f03b2012-03-08 10:30:39 -0800117 private void checkArgs(String alias) {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700118 if (alias == null) {
119 throw new NullPointerException("alias == null");
120 }
Kenny Root4ff22962013-02-14 10:17:06 -0800121 if (!mKeyStore.isUnlocked()) {
Nick Kralevichc8b04632012-05-21 15:13:07 -0700122 throw new IllegalStateException("keystore is "
123 + mKeyStore.state().toString());
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700124 }
Nick Kralevichc8b04632012-05-21 15:13:07 -0700125
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700126 final int callingUid = getCallingUid();
127 if (!hasGrantInternal(mDatabaseHelper.getReadableDatabase(), callingUid, alias)) {
128 throw new IllegalStateException("uid " + callingUid
129 + " doesn't have permission to access the requested alias");
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700130 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700131 }
132
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100133 @Override public String installCaCertificate(byte[] caCertificate) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700134 checkCertInstallerOrSystemCaller();
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100135 final String alias;
Brian Carlstroma58db542011-05-11 23:02:20 -0700136 try {
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100137 final X509Certificate cert = parseCertificate(caCertificate);
Brian Carlstroma58db542011-05-11 23:02:20 -0700138 synchronized (mTrustedCertificateStore) {
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100139 mTrustedCertificateStore.installCertificate(cert);
140 alias = mTrustedCertificateStore.getCertificateAlias(cert);
Brian Carlstroma58db542011-05-11 23:02:20 -0700141 }
142 } catch (IOException e) {
143 throw new IllegalStateException(e);
144 } catch (CertificateException e) {
145 throw new IllegalStateException(e);
146 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700147 broadcastLegacyStorageChange();
148 broadcastTrustStoreChange();
Bartosz Fabianowski9bacf2b2017-02-10 02:26:45 +0100149 return alias;
Brian Carlstroma58db542011-05-11 23:02:20 -0700150 }
Brian Carlstrom5aeadd92011-05-17 00:40:33 -0700151
Rubin Xu8714f062016-03-23 12:37:10 +0000152 /**
153 * Install a key pair to the keystore.
154 *
155 * @param privateKey The private key associated with the client certificate
156 * @param userCertificate The client certificate to be installed
157 * @param userCertificateChain The rest of the chain for the client certificate
158 * @param alias The alias under which the key pair is installed
159 * @return Whether the operation succeeded or not.
160 */
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100161 @Override public boolean installKeyPair(byte[] privateKey, byte[] userCertificate,
Rubin Xu8714f062016-03-23 12:37:10 +0000162 byte[] userCertificateChain, String alias) {
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100163 checkCertInstallerOrSystemCaller();
Robin Lee8847b122015-07-27 12:50:28 +0100164 if (!mKeyStore.isUnlocked()) {
165 Log.e(TAG, "Keystore is " + mKeyStore.state().toString() + ". Credentials cannot"
166 + " be installed until device is unlocked");
167 return false;
168 }
Robin Leeba755b12016-02-24 15:27:43 +0000169 if (!removeKeyPair(alias)) {
170 return false;
171 }
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100172 if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, privateKey, -1,
173 KeyStore.FLAG_ENCRYPTED)) {
174 Log.e(TAG, "Failed to import private key " + alias);
175 return false;
176 }
177 if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, -1,
178 KeyStore.FLAG_ENCRYPTED)) {
179 Log.e(TAG, "Failed to import user certificate " + userCertificate);
Alex Klyubin44c777b2015-06-08 09:46:15 -0700180 if (!mKeyStore.delete(Credentials.USER_PRIVATE_KEY + alias)) {
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100181 Log.e(TAG, "Failed to delete private key after certificate importing failed");
182 }
183 return false;
184 }
Rubin Xu8714f062016-03-23 12:37:10 +0000185 if (userCertificateChain != null && userCertificateChain.length > 0) {
186 if (!mKeyStore.put(Credentials.CA_CERTIFICATE + alias, userCertificateChain, -1,
187 KeyStore.FLAG_ENCRYPTED)) {
188 Log.e(TAG, "Failed to import certificate chain" + userCertificateChain);
189 if (!removeKeyPair(alias)) {
190 Log.e(TAG, "Failed to clean up key chain after certificate chain"
191 + " importing failed");
192 }
193 return false;
194 }
195 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700196 broadcastKeychainChange();
197 broadcastLegacyStorageChange();
Bernhard Bauerd300fc52014-07-21 15:32:30 +0100198 return true;
199 }
200
Robin Leef44a5192015-08-03 17:18:02 +0100201 @Override public boolean removeKeyPair(String alias) {
202 checkCertInstallerOrSystemCaller();
Robin Leeba755b12016-02-24 15:27:43 +0000203 if (!Credentials.deleteAllTypesForAlias(mKeyStore, alias)) {
204 return false;
205 }
206 removeGrantsForAlias(alias);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700207 broadcastKeychainChange();
208 broadcastLegacyStorageChange();
Robin Leeba755b12016-02-24 15:27:43 +0000209 return true;
Robin Leef44a5192015-08-03 17:18:02 +0100210 }
211
Brian Carlstrom5aeadd92011-05-17 00:40:33 -0700212 private X509Certificate parseCertificate(byte[] bytes) throws CertificateException {
213 CertificateFactory cf = CertificateFactory.getInstance("X.509");
214 return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes));
215 }
216
Brian Carlstroma58db542011-05-11 23:02:20 -0700217 @Override public boolean reset() {
218 // only Settings should be able to reset
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700219 checkSystemCaller();
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700220 removeAllGrants(mDatabaseHelper.getWritableDatabase());
Brian Carlstroma58db542011-05-11 23:02:20 -0700221 boolean ok = true;
Brian Carlstroma58db542011-05-11 23:02:20 -0700222 synchronized (mTrustedCertificateStore) {
223 // delete user-installed CA certs
224 for (String alias : mTrustedCertificateStore.aliases()) {
225 if (TrustedCertificateStore.isUser(alias)) {
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700226 if (!deleteCertificateEntry(alias)) {
Brian Carlstroma58db542011-05-11 23:02:20 -0700227 ok = false;
228 }
229 }
230 }
Brian Carlstroma58db542011-05-11 23:02:20 -0700231 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700232 broadcastTrustStoreChange();
Chad Brubaker8df30b52017-03-10 13:02:48 -0800233 broadcastKeychainChange();
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700234 broadcastLegacyStorageChange();
Selim Gurun39e36e52012-02-14 10:50:42 -0800235 return ok;
Brian Carlstroma58db542011-05-11 23:02:20 -0700236 }
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700237
238 @Override public boolean deleteCaCertificate(String alias) {
239 // only Settings should be able to delete
240 checkSystemCaller();
Selim Gurun39e36e52012-02-14 10:50:42 -0800241 boolean ok = true;
242 synchronized (mTrustedCertificateStore) {
243 ok = deleteCertificateEntry(alias);
244 }
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700245 broadcastTrustStoreChange();
246 broadcastLegacyStorageChange();
Selim Gurun39e36e52012-02-14 10:50:42 -0800247 return ok;
Brian Carlstrom43f5b772011-06-27 02:27:16 -0700248 }
249
250 private boolean deleteCertificateEntry(String alias) {
251 try {
252 mTrustedCertificateStore.deleteCertificateEntry(alias);
253 return true;
254 } catch (IOException e) {
255 Log.w(TAG, "Problem removing CA certificate " + alias, e);
256 return false;
257 } catch (CertificateException e) {
258 Log.w(TAG, "Problem removing CA certificate " + alias, e);
259 return false;
260 }
261 }
262
263 private void checkCertInstallerOrSystemCaller() {
264 String actual = checkCaller("com.android.certinstaller");
265 if (actual == null) {
266 return;
267 }
268 checkSystemCaller();
269 }
270 private void checkSystemCaller() {
271 String actual = checkCaller("android.uid.system:1000");
272 if (actual != null) {
273 throw new IllegalStateException(actual);
274 }
275 }
276 /**
277 * Returns null if actually caller is expected, otherwise return bad package to report
278 */
279 private String checkCaller(String expectedPackage) {
280 String actualPackage = getPackageManager().getNameForUid(getCallingUid());
281 return (!expectedPackage.equals(actualPackage)) ? actualPackage : null;
282 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700283
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700284 @Override public boolean hasGrant(int uid, String alias) {
285 checkSystemCaller();
286 return hasGrantInternal(mDatabaseHelper.getReadableDatabase(), uid, alias);
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700287 }
288
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700289 @Override public void setGrant(int uid, String alias, boolean value) {
290 checkSystemCaller();
291 setGrantInternal(mDatabaseHelper.getWritableDatabase(), uid, alias, value);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700292 broadcastPermissionChange(uid, alias, value);
293 broadcastLegacyStorageChange();
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700294 }
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100295
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100296 @Override
Robin Lee7e9d0452017-02-20 20:57:41 +0000297 public StringParceledListSlice getUserCaAliases() {
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100298 synchronized (mTrustedCertificateStore) {
Robin Lee7e9d0452017-02-20 20:57:41 +0000299 return new StringParceledListSlice(new ArrayList<String>(
300 mTrustedCertificateStore.userAliases()));
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100301 }
302 }
303
304 @Override
Robin Lee7e9d0452017-02-20 20:57:41 +0000305 public StringParceledListSlice getSystemCaAliases() {
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100306 synchronized (mTrustedCertificateStore) {
Robin Lee7e9d0452017-02-20 20:57:41 +0000307 return new StringParceledListSlice(new ArrayList<String>(
308 mTrustedCertificateStore.allSystemAliases()));
Zoltan Szatmary-Ban3d25b312014-08-18 10:54:19 +0100309 }
310 }
311
312 @Override
313 public boolean containsCaAlias(String alias) {
314 return mTrustedCertificateStore.containsAlias(alias);
315 }
316
317 @Override
318 public byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem) {
319 synchronized (mTrustedCertificateStore) {
320 X509Certificate certificate = (X509Certificate) mTrustedCertificateStore
321 .getCertificate(alias, includeDeletedSystem);
322 if (certificate == null) {
323 Log.w(TAG, "Could not find CA certificate " + alias);
324 return null;
325 }
326 try {
327 return certificate.getEncoded();
328 } catch (CertificateEncodingException e) {
329 Log.w(TAG, "Error while encoding CA certificate " + alias);
330 return null;
331 }
332 }
333 }
334
335 @Override
336 public List<String> getCaCertificateChainAliases(String rootAlias,
337 boolean includeDeletedSystem) {
338 synchronized (mTrustedCertificateStore) {
339 X509Certificate root = (X509Certificate) mTrustedCertificateStore.getCertificate(
340 rootAlias, includeDeletedSystem);
341 try {
342 List<X509Certificate> chain = mTrustedCertificateStore.getCertificateChain(
343 root);
344 List<String> aliases = new ArrayList<String>(chain.size());
345 final int n = chain.size();
346 for (int i = 0; i < n; ++i) {
347 String alias = mTrustedCertificateStore.getCertificateAlias(chain.get(i),
348 true);
349 if (alias != null) {
350 aliases.add(alias);
351 }
352 }
353 return aliases;
354 } catch (CertificateException e) {
355 Log.w(TAG, "Error retrieving cert chain for root " + rootAlias);
356 return Collections.emptyList();
357 }
358 }
359 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700360 };
361
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700362 private boolean hasGrantInternal(final SQLiteDatabase db, final int uid, final String alias) {
363 final long numMatches = DatabaseUtils.longForQuery(db, SELECTION_COUNT_OF_MATCHING_GRANTS,
364 new String[]{String.valueOf(uid), alias});
365 return numMatches > 0;
366 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700367
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700368 private void setGrantInternal(final SQLiteDatabase db,
369 final int uid, final String alias, final boolean value) {
370 if (value) {
371 if (!hasGrantInternal(db, uid, alias)) {
372 final ContentValues values = new ContentValues();
373 values.put(GRANTS_ALIAS, alias);
374 values.put(GRANTS_GRANTEE_UID, uid);
375 db.insert(TABLE_GRANTS, GRANTS_ALIAS, values);
376 }
377 } else {
378 db.delete(TABLE_GRANTS, SELECT_GRANTS_BY_UID_AND_ALIAS,
379 new String[]{String.valueOf(uid), alias});
380 }
381 }
382
Robin Leeba755b12016-02-24 15:27:43 +0000383 private void removeGrantsForAlias(String alias) {
384 final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
385 db.delete(TABLE_GRANTS, SELECTION_GRANTS_BY_ALIAS, new String[] {alias});
386 }
387
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700388 private void removeAllGrants(final SQLiteDatabase db) {
389 db.delete(TABLE_GRANTS, null /* whereClause */, null /* whereArgs */);
390 }
391
392 private class DatabaseHelper extends SQLiteOpenHelper {
393 public DatabaseHelper(Context context) {
394 super(context, DATABASE_NAME, null /* CursorFactory */, DATABASE_VERSION);
395 }
396
397 @Override
398 public void onCreate(final SQLiteDatabase db) {
399 db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( "
400 + GRANTS_ALIAS + " STRING NOT NULL, "
401 + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, "
402 + "UNIQUE (" + GRANTS_ALIAS + "," + GRANTS_GRANTEE_UID + "))");
403 }
404
405 @Override
406 public void onUpgrade(final SQLiteDatabase db, int oldVersion, final int newVersion) {
407 Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
408
409 if (oldVersion == 1) {
410 // the first upgrade step goes here
411 oldVersion++;
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700412 }
Brian Carlstrom7037b732011-06-30 15:04:49 -0700413 }
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700414 }
415
416 @Override public IBinder onBind(Intent intent) {
Brian Carlstrom7037b732011-06-30 15:04:49 -0700417 if (IKeyChainService.class.getName().equals(intent.getAction())) {
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700418 return mIKeyChainService;
419 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700420 return null;
421 }
Fred Quintanafb2e18e2011-07-13 14:54:05 -0700422
423 @Override
424 protected void onHandleIntent(final Intent intent) {
425 if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
426 purgeOldGrants();
427 }
428 }
429
430 private void purgeOldGrants() {
431 final PackageManager packageManager = getPackageManager();
432 final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase();
433 Cursor cursor = null;
434 db.beginTransaction();
435 try {
436 cursor = db.query(TABLE_GRANTS,
437 new String[]{GRANTS_GRANTEE_UID}, null, null, GRANTS_GRANTEE_UID, null, null);
438 while (cursor.moveToNext()) {
439 final int uid = cursor.getInt(0);
440 final boolean packageExists = packageManager.getPackagesForUid(uid) != null;
441 if (packageExists) {
442 continue;
443 }
444 Log.d(TAG, "deleting grants for UID " + uid
445 + " because its package is no longer installed");
446 db.delete(TABLE_GRANTS, SELECTION_GRANTS_BY_UID,
447 new String[]{Integer.toString(uid)});
448 }
449 db.setTransactionSuccessful();
450 } finally {
451 if (cursor != null) {
452 cursor.close();
453 }
454 db.endTransaction();
455 }
456 }
Selim Gurun39e36e52012-02-14 10:50:42 -0800457
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700458 private void broadcastLegacyStorageChange() {
Selim Gurun39e36e52012-02-14 10:50:42 -0800459 Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED);
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700460 BroadcastOptions opts = BroadcastOptions.makeBasic();
Chad Brubaker04028072016-07-08 10:48:54 -0700461 opts.setMaxManifestReceiverApiLevel(Build.VERSION_CODES.N_MR1);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700462 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()), null, opts.toBundle());
Selim Gurun39e36e52012-02-14 10:50:42 -0800463 }
464
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700465 private void broadcastKeychainChange() {
466 Intent intent = new Intent(KeyChain.ACTION_KEYCHAIN_CHANGED);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700467 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700468 }
469
470 private void broadcastTrustStoreChange() {
471 Intent intent = new Intent(KeyChain.ACTION_TRUST_STORE_CHANGED);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700472 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700473 }
474
475 private void broadcastPermissionChange(int uid, String alias, boolean access) {
476 // Since the permission change only impacts one uid only send to that uid's packages.
477 final PackageManager packageManager = getPackageManager();
478 String[] packages = packageManager.getPackagesForUid(uid);
479 if (packages == null) {
480 return;
481 }
482 for (String pckg : packages) {
483 Intent intent = new Intent(KeyChain.ACTION_KEY_ACCESS_CHANGED);
484 intent.putExtra(KeyChain.EXTRA_KEY_ALIAS, alias);
485 intent.putExtra(KeyChain.EXTRA_KEY_ACCESSIBLE, access);
486 intent.setPackage(pckg);
Chad Brubakere5a5dd12016-07-25 14:34:54 -0700487 sendBroadcastAsUser(intent, UserHandle.of(UserHandle.myUserId()));
Chad Brubaker2099a7d2016-05-02 13:13:23 -0700488 }
489 }
Brian Carlstrom3e6251d2011-04-11 09:05:06 -0700490}