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);
43039e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun        sendBroadcast(intent);
43139e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun    }
43239e36e58a7fd0a4520af5467719dac73afc205b4Selim Gurun
4333e6251dedc92654476c70bdc413f24a4b31ce6a4Brian Carlstrom}
434