13e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom/* 23e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Copyright (C) 2011 The Android Open Source Project 33e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * 43e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License"); 53e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * you may not use this file except in compliance with the License. 63e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * You may obtain a copy of the License at 73e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * 83e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * http://www.apache.org/licenses/LICENSE-2.0 93e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * 103e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * Unless required by applicable law or agreed to in writing, software 113e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS, 123e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 133e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * See the License for the specific language governing permissions and 143e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom * limitations under the License. 153e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom */ 163e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 173e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrompackage com.android.keychain; 183e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 19fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.app.IntentService; 20fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.content.ContentValues; 213e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.content.Context; 223e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.content.Intent; 23fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.content.pm.PackageManager; 243d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Banimport android.content.pm.ParceledListSlice; 25fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.database.Cursor; 26fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.database.DatabaseUtils; 27fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.database.sqlite.SQLiteDatabase; 28fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanaimport android.database.sqlite.SQLiteOpenHelper; 296f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Rootimport android.os.Binder; 303e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.os.IBinder; 316f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Rootimport android.os.Process; 3293772c3bc4a51019792e88c2a2e451f20895d73aRobin Leeimport android.os.UserHandle; 333fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynoldsimport android.os.UserManager; 343e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.security.Credentials; 353e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.security.IKeyChainService; 3639e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurunimport android.security.KeyChain; 373e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.security.KeyStore; 383e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport android.util.Log; 393d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Banimport com.android.internal.util.ParcelableString; 403e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.io.ByteArrayInputStream; 41a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstromimport java.io.IOException; 423e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.cert.CertificateException; 433d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Banimport java.security.cert.CertificateEncodingException; 443e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.cert.CertificateFactory; 453e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstromimport java.security.cert.X509Certificate; 463d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Banimport java.util.Set; 473d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Banimport java.util.List; 483d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Banimport java.util.ArrayList; 493d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Banimport java.util.Collections; 50fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 513048b6c5826b82a4ba4dbadf4cd06d00c2a80b32Kenny Rootimport com.android.org.conscrypt.TrustedCertificateStore; 523e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 53fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintanapublic class KeyChainService extends IntentService { 5439e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun 55fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String TAG = "KeyChain"; 56fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 57fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String DATABASE_NAME = "grants.db"; 58fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final int DATABASE_VERSION = 1; 59fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String TABLE_GRANTS = "grants"; 60fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String GRANTS_ALIAS = "alias"; 61fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String GRANTS_GRANTEE_UID = "uid"; 623e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 63fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana /** created in onCreate(), closed in onDestroy() */ 64fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public DatabaseHelper mDatabaseHelper; 653e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 66fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String SELECTION_COUNT_OF_MATCHING_GRANTS = 67fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana "SELECT COUNT(*) FROM " + TABLE_GRANTS 68fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + " WHERE " + GRANTS_GRANTEE_UID + "=? AND " + GRANTS_ALIAS + "=?"; 693e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 70fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String SELECT_GRANTS_BY_UID_AND_ALIAS = 71fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana GRANTS_GRANTEE_UID + "=? AND " + GRANTS_ALIAS + "=?"; 72fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 73fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private static final String SELECTION_GRANTS_BY_UID = GRANTS_GRANTEE_UID + "=?"; 74fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 75fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public KeyChainService() { 76fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana super(KeyChainService.class.getSimpleName()); 77fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 783e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 793e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom @Override public void onCreate() { 803e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom super.onCreate(); 81fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana mDatabaseHelper = new DatabaseHelper(this); 823e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 833e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 84fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override 85fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public void onDestroy() { 86fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana super.onDestroy(); 87fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana mDatabaseHelper.close(); 88fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana mDatabaseHelper = null; 89fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 903e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 91fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private final IKeyChainService.Stub mIKeyChainService = new IKeyChainService.Stub() { 923e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom private final KeyStore mKeyStore = KeyStore.getInstance(); 93a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom private final TrustedCertificateStore mTrustedCertificateStore 94a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom = new TrustedCertificateStore(); 953e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 966f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root @Override 976f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root public String requestPrivateKey(String alias) { 986f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root checkArgs(alias); 996f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root 1006f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root final String keystoreAlias = Credentials.USER_PRIVATE_KEY + alias; 1016f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root final int uid = Binder.getCallingUid(); 1026f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root if (!mKeyStore.grant(keystoreAlias, uid)) { 1036f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root return null; 1046f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root } 10593772c3bc4a51019792e88c2a2e451f20895d73aRobin Lee final int userHandle = UserHandle.getUserId(uid); 10693772c3bc4a51019792e88c2a2e451f20895d73aRobin Lee final int systemUidForUser = UserHandle.getUid(userHandle, Process.SYSTEM_UID); 1076f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root 1086f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root final StringBuilder sb = new StringBuilder(); 10993772c3bc4a51019792e88c2a2e451f20895d73aRobin Lee sb.append(systemUidForUser); 1106f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root sb.append('_'); 1116f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root sb.append(keystoreAlias); 1126f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root 1136f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root return sb.toString(); 1143e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1153e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 116fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override public byte[] getCertificate(String alias) { 1176f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root checkArgs(alias); 1186f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root return mKeyStore.get(Credentials.USER_CERTIFICATE + alias); 1193e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1203e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 1216f1f03bcae70792bbd8bc0aecb90c7b9c43b76b5Kenny Root private void checkArgs(String alias) { 1223e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom if (alias == null) { 1233e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom throw new NullPointerException("alias == null"); 1243e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1254ff2296cb77305468531ae0c45f90b46f942a5a3Kenny Root if (!mKeyStore.isUnlocked()) { 126c8b0463643df1f1a4035d641e155f5e1cef8e1b0Nick Kralevich throw new IllegalStateException("keystore is " 127c8b0463643df1f1a4035d641e155f5e1cef8e1b0Nick Kralevich + mKeyStore.state().toString()); 1283e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 129c8b0463643df1f1a4035d641e155f5e1cef8e1b0Nick Kralevich 130fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final int callingUid = getCallingUid(); 131fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (!hasGrantInternal(mDatabaseHelper.getReadableDatabase(), callingUid, alias)) { 132fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana throw new IllegalStateException("uid " + callingUid 133fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + " doesn't have permission to access the requested alias"); 1343e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1353e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 1363e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 137a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom @Override public void installCaCertificate(byte[] caCertificate) { 13843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom checkCertInstallerOrSystemCaller(); 1393fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds checkUserRestriction(); 140a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom try { 141a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom synchronized (mTrustedCertificateStore) { 142a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom mTrustedCertificateStore.installCertificate(parseCertificate(caCertificate)); 143a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 144a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } catch (IOException e) { 145a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom throw new IllegalStateException(e); 146a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } catch (CertificateException e) { 147a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom throw new IllegalStateException(e); 148a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 14939e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun broadcastStorageChange(); 150a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 1515aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom 152d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer @Override public boolean installKeyPair(byte[] privateKey, byte[] userCertificate, 153d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer String alias) { 154d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer checkCertInstallerOrSystemCaller(); 155d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer if (!mKeyStore.importKey(Credentials.USER_PRIVATE_KEY + alias, privateKey, -1, 156d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer KeyStore.FLAG_ENCRYPTED)) { 157d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer Log.e(TAG, "Failed to import private key " + alias); 158d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer return false; 159d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer } 160d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer if (!mKeyStore.put(Credentials.USER_CERTIFICATE + alias, userCertificate, -1, 161d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer KeyStore.FLAG_ENCRYPTED)) { 162d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer Log.e(TAG, "Failed to import user certificate " + userCertificate); 163d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer if (!mKeyStore.delKey(Credentials.USER_PRIVATE_KEY + alias)) { 164d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer Log.e(TAG, "Failed to delete private key after certificate importing failed"); 165d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer } 166d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer return false; 167d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer } 168d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer broadcastStorageChange(); 169d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer return true; 170d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer } 171d300fc59cf229dd634f317c77af12000d0f09e7cBernhard Bauer 1725aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom private X509Certificate parseCertificate(byte[] bytes) throws CertificateException { 1735aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom CertificateFactory cf = CertificateFactory.getInstance("X.509"); 1745aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom return (X509Certificate) cf.generateCertificate(new ByteArrayInputStream(bytes)); 1755aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom } 1765aeadd9be22ea51ea2d638f7090618448ecc8ac7Brian Carlstrom 177a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom @Override public boolean reset() { 178a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom // only Settings should be able to reset 17943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom checkSystemCaller(); 1803fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds checkUserRestriction(); 181fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana removeAllGrants(mDatabaseHelper.getWritableDatabase()); 182a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom boolean ok = true; 183a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom synchronized (mTrustedCertificateStore) { 184a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom // delete user-installed CA certs 185a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom for (String alias : mTrustedCertificateStore.aliases()) { 186a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom if (TrustedCertificateStore.isUser(alias)) { 18743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom if (!deleteCertificateEntry(alias)) { 188a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom ok = false; 189a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 190a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 191a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 192a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 19339e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun broadcastStorageChange(); 19439e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun return ok; 195a58db5485e7b47880d9d565b036ae8b894ffdc48Brian Carlstrom } 19643f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom 19743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom @Override public boolean deleteCaCertificate(String alias) { 19843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom // only Settings should be able to delete 19943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom checkSystemCaller(); 2003fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds checkUserRestriction(); 20139e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun boolean ok = true; 20239e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun synchronized (mTrustedCertificateStore) { 20339e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun ok = deleteCertificateEntry(alias); 20439e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun } 20539e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun broadcastStorageChange(); 20639e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun return ok; 20743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 20843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom 20943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom private boolean deleteCertificateEntry(String alias) { 21043f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom try { 21143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom mTrustedCertificateStore.deleteCertificateEntry(alias); 21243f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return true; 21343f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } catch (IOException e) { 21443f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom Log.w(TAG, "Problem removing CA certificate " + alias, e); 21543f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return false; 21643f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } catch (CertificateException e) { 21743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom Log.w(TAG, "Problem removing CA certificate " + alias, e); 21843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return false; 21943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 22043f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 22143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom 22243f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom private void checkCertInstallerOrSystemCaller() { 22343f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom String actual = checkCaller("com.android.certinstaller"); 22443f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom if (actual == null) { 22543f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return; 22643f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 22743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom checkSystemCaller(); 22843f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 22943f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom private void checkSystemCaller() { 23043f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom String actual = checkCaller("android.uid.system:1000"); 23143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom if (actual != null) { 23243f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom throw new IllegalStateException(actual); 23343f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 23443f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 2353fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds private void checkUserRestriction() { 2363fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds UserManager um = (UserManager) getSystemService(USER_SERVICE); 2373fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds if (um.hasUserRestriction(UserManager.DISALLOW_CONFIG_CREDENTIALS)) { 2383fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds throw new SecurityException("User cannot modify credentials"); 2393fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds } 2403fb7449c95754dedca4220948561b5f8617b8b2cJulia Reynolds } 24143f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom /** 24243f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom * Returns null if actually caller is expected, otherwise return bad package to report 24343f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom */ 24443f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom private String checkCaller(String expectedPackage) { 24543f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom String actualPackage = getPackageManager().getNameForUid(getCallingUid()); 24643f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom return (!expectedPackage.equals(actualPackage)) ? actualPackage : null; 24743f5b77dbbff264f7f521dbf5361f07a5e253c70Brian Carlstrom } 2483e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 249fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override public boolean hasGrant(int uid, String alias) { 250fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana checkSystemCaller(); 251fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana return hasGrantInternal(mDatabaseHelper.getReadableDatabase(), uid, alias); 2523e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 2533e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 254fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override public void setGrant(int uid, String alias, boolean value) { 255fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana checkSystemCaller(); 256fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana setGrantInternal(mDatabaseHelper.getWritableDatabase(), uid, alias, value); 25739e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun broadcastStorageChange(); 2583e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 2593d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban 2603d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban private ParceledListSlice<ParcelableString> makeAliasesParcelableSynchronised( 2613d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban Set<String> aliasSet) { 2623d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban List<ParcelableString> aliases = new ArrayList<ParcelableString>(aliasSet.size()); 2633d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban for (String alias : aliasSet) { 2643d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban ParcelableString parcelableString = new ParcelableString(); 2653d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban parcelableString.string = alias; 2663d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban aliases.add(parcelableString); 2673d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 2683d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return new ParceledListSlice<ParcelableString>(aliases); 2693d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 2703d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban 2713d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban @Override 2723d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban public ParceledListSlice<ParcelableString> getUserCaAliases() { 2733d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban synchronized (mTrustedCertificateStore) { 2743d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban Set<String> aliasSet = mTrustedCertificateStore.userAliases(); 2753d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return makeAliasesParcelableSynchronised(aliasSet); 2763d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 2773d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 2783d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban 2793d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban @Override 2803d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban public ParceledListSlice<ParcelableString> getSystemCaAliases() { 2813d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban synchronized (mTrustedCertificateStore) { 2823d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban Set<String> aliasSet = mTrustedCertificateStore.allSystemAliases(); 2833d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return makeAliasesParcelableSynchronised(aliasSet); 2843d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 2853d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 2863d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban 2873d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban @Override 2883d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban public boolean containsCaAlias(String alias) { 2893d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return mTrustedCertificateStore.containsAlias(alias); 2903d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 2913d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban 2923d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban @Override 2933d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban public byte[] getEncodedCaCertificate(String alias, boolean includeDeletedSystem) { 2943d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban synchronized (mTrustedCertificateStore) { 2953d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban X509Certificate certificate = (X509Certificate) mTrustedCertificateStore 2963d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban .getCertificate(alias, includeDeletedSystem); 2973d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban if (certificate == null) { 2983d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban Log.w(TAG, "Could not find CA certificate " + alias); 2993d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return null; 3003d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 3013d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban try { 3023d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return certificate.getEncoded(); 3033d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } catch (CertificateEncodingException e) { 3043d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban Log.w(TAG, "Error while encoding CA certificate " + alias); 3053d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return null; 3063d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 3073d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 3083d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 3093d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban 3103d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban @Override 3113d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban public List<String> getCaCertificateChainAliases(String rootAlias, 3123d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban boolean includeDeletedSystem) { 3133d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban synchronized (mTrustedCertificateStore) { 3143d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban X509Certificate root = (X509Certificate) mTrustedCertificateStore.getCertificate( 3153d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban rootAlias, includeDeletedSystem); 3163d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban try { 3173d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban List<X509Certificate> chain = mTrustedCertificateStore.getCertificateChain( 3183d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban root); 3193d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban List<String> aliases = new ArrayList<String>(chain.size()); 3203d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban final int n = chain.size(); 3213d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban for (int i = 0; i < n; ++i) { 3223d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban String alias = mTrustedCertificateStore.getCertificateAlias(chain.get(i), 3233d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban true); 3243d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban if (alias != null) { 3253d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban aliases.add(alias); 3263d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 3273d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 3283d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return aliases; 3293d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } catch (CertificateException e) { 3303d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban Log.w(TAG, "Error retrieving cert chain for root " + rootAlias); 3313d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban return Collections.emptyList(); 3323d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 3333d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 3343d25b3144669ceb787dfd00f1e312516c8fe6173Zoltan Szatmary-Ban } 335fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana }; 3363e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 337fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private boolean hasGrantInternal(final SQLiteDatabase db, final int uid, final String alias) { 338fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final long numMatches = DatabaseUtils.longForQuery(db, SELECTION_COUNT_OF_MATCHING_GRANTS, 339fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana new String[]{String.valueOf(uid), alias}); 340fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana return numMatches > 0; 341fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 3423e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 343fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private void setGrantInternal(final SQLiteDatabase db, 344fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final int uid, final String alias, final boolean value) { 345fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (value) { 346fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (!hasGrantInternal(db, uid, alias)) { 347fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final ContentValues values = new ContentValues(); 348fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana values.put(GRANTS_ALIAS, alias); 349fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana values.put(GRANTS_GRANTEE_UID, uid); 350fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.insert(TABLE_GRANTS, GRANTS_ALIAS, values); 351fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 352fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } else { 353fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.delete(TABLE_GRANTS, SELECT_GRANTS_BY_UID_AND_ALIAS, 354fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana new String[]{String.valueOf(uid), alias}); 3553e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 356fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 3573e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 358fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private void removeAllGrants(final SQLiteDatabase db) { 359fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.delete(TABLE_GRANTS, null /* whereClause */, null /* whereArgs */); 360fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 3613e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 362fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private class DatabaseHelper extends SQLiteOpenHelper { 363fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public DatabaseHelper(Context context) { 364fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana super(context, DATABASE_NAME, null /* CursorFactory */, DATABASE_VERSION); 3653e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 3663e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 367fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override 368fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public void onCreate(final SQLiteDatabase db) { 369fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.execSQL("CREATE TABLE " + TABLE_GRANTS + " ( " 370fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + GRANTS_ALIAS + " STRING NOT NULL, " 371fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + GRANTS_GRANTEE_UID + " INTEGER NOT NULL, " 372fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + "UNIQUE (" + GRANTS_ALIAS + "," + GRANTS_GRANTEE_UID + "))"); 3733e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 3743e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 375fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override 376fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana public void onUpgrade(final SQLiteDatabase db, int oldVersion, final int newVersion) { 377fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion); 3783e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom 379fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (oldVersion == 1) { 380fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana // the first upgrade step goes here 381fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana oldVersion++; 3823e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 3837037b73962c34e884467d3d4a871ecdab9797fc3Brian Carlstrom } 384fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 385fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 386fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override public IBinder onBind(Intent intent) { 3877037b73962c34e884467d3d4a871ecdab9797fc3Brian Carlstrom if (IKeyChainService.class.getName().equals(intent.getAction())) { 3883e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom return mIKeyChainService; 3893e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 3903e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom return null; 3913e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom } 392fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 393fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana @Override 394fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana protected void onHandleIntent(final Intent intent) { 395fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) { 396fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana purgeOldGrants(); 397fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 398fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 399fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana 400fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana private void purgeOldGrants() { 401fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final PackageManager packageManager = getPackageManager(); 402fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final SQLiteDatabase db = mDatabaseHelper.getWritableDatabase(); 403fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana Cursor cursor = null; 404fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.beginTransaction(); 405fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana try { 406fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana cursor = db.query(TABLE_GRANTS, 407fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana new String[]{GRANTS_GRANTEE_UID}, null, null, GRANTS_GRANTEE_UID, null, null); 408fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana while (cursor.moveToNext()) { 409fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final int uid = cursor.getInt(0); 410fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana final boolean packageExists = packageManager.getPackagesForUid(uid) != null; 411fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (packageExists) { 412fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana continue; 413fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 414fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana Log.d(TAG, "deleting grants for UID " + uid 415fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana + " because its package is no longer installed"); 416fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.delete(TABLE_GRANTS, SELECTION_GRANTS_BY_UID, 417fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana new String[]{Integer.toString(uid)}); 418fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 419fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.setTransactionSuccessful(); 420fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } finally { 421fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana if (cursor != null) { 422fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana cursor.close(); 423fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 424fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana db.endTransaction(); 425fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 426fb2e18e112f9fb9f0620c0c0ff06377f52fe39a4Fred Quintana } 42739e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun 42839e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun private void broadcastStorageChange() { 42939e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun Intent intent = new Intent(KeyChain.ACTION_STORAGE_CHANGED); 4301f00eaf6936421542f139f1066bd4656af3a8b11Robin Lee sendBroadcastAsUser(intent, new UserHandle(UserHandle.myUserId())); 43139e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun } 43239e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun 4333e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom} 434