1603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/*
2603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Copyright (C) 2009 The Android Open Source Project
3603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
4603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Licensed under the Apache License, Version 2.0 (the "License");
5603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * you may not use this file except in compliance with the License.
6603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * You may obtain a copy of the License at
7603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
8603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *      http://www.apache.org/licenses/LICENSE-2.0
9603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana *
10603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * Unless required by applicable law or agreed to in writing, software
11603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * distributed under the License is distributed on an "AS IS" BASIS,
12603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * See the License for the specific language governing permissions and
14603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * limitations under the License.
15603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
16603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
17603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanapackage android.accounts;
18603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
19885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.Manifest;
203b4fcbc9f13bab6a2e9e5c37cc5e18fec7341c04Brett Chabotimport android.app.ActivityManager;
216ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.app.ActivityManagerNative;
22885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.Notification;
23885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.NotificationManager;
24885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.app.PendingIntent;
25a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.BroadcastReceiver;
26885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.ComponentName;
27a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.ContentValues;
28a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Context;
29a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.Intent;
30a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.content.IntentFilter;
31b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintanaimport android.content.ServiceConnection;
32885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.pm.ApplicationInfo;
33885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.content.pm.PackageInfo;
34d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.PackageManager;
356ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport android.content.pm.PackageManager.NameNotFoundException;
36d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.RegisteredServicesCache;
373ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanaimport android.content.pm.RegisteredServicesCacheListener;
386eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkeyimport android.content.pm.UserInfo;
39603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.Cursor;
40603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintanaimport android.database.DatabaseUtils;
41a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteDatabase;
42a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.database.sqlite.SQLiteOpenHelper;
43885cfc23a42f2a4f8578e6a2182af4d9a0a78b1fDoug Zongkerimport android.os.Binder;
44a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Bundle;
45a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayorimport android.os.Environment;
46a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Handler;
47a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.HandlerThread;
48a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.IBinder;
49a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Looper;
50a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.Message;
51a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.RemoteException;
52a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.os.SystemClock;
53f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackbornimport android.os.UserHandle;
54258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasaniimport android.os.UserManager;
55a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.text.TextUtils;
56a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.util.Log;
57d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.util.Pair;
586eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkeyimport android.util.Slog;
5904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport android.util.SparseArray;
60603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
61b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolacheimport com.android.internal.R;
6204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport com.android.internal.util.IndentingPrintWriter;
636ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport com.google.android.collect.Lists;
646ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport com.google.android.collect.Sets;
65b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache
66a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayorimport java.io.File;
67a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.FileDescriptor;
68a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.PrintWriter;
69a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.ArrayList;
7056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport java.util.Arrays;
71a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.Collection;
72d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.HashMap;
736ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkeyimport java.util.HashSet;
7456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport java.util.LinkedHashMap;
756eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkeyimport java.util.List;
762f36229db823d152f3efd879e751e81a601a75b0Andy McFaddenimport java.util.Map;
77d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicInteger;
78d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicReference;
79603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
80603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
81603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * A system service that provides  account, password, and authtoken management for all
82603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * accounts on the device. Some of these calls are implemented with the help of the corresponding
83603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
84603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
8546703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom *    AccountManager accountManager = AccountManager.get(context);
863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana * @hide
87603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
883ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanapublic class AccountManagerService
893ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        extends IAccountManager.Stub
905ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        implements RegisteredServicesCacheListener<AuthenticatorDescription> {
91603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "AccountManagerService";
92603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
93603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int TIMEOUT_DELAY_MS = 1000 * 60;
94603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String DATABASE_NAME = "accounts.db";
953348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache    private static final int DATABASE_VERSION = 4;
96603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
97603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
98603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private final PackageManager mPackageManager;
100258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani    private UserManager mUserManager;
10156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
102603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private HandlerThread mMessageThread;
103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final MessageHandler mMessageHandler;
104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    // Messages that can be sent on mHandler
106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_TIMED_OUT = 3;
107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
10856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private final IAccountAuthenticatorCache mAuthenticatorCache;
109603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
110603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_ACCOUNTS = "accounts";
111603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_ID = "_id";
112603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_NAME = "name";
113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_TYPE = "type";
1141cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
115603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_PASSWORD = "password";
116603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
117603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_AUTHTOKENS = "authtokens";
118603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ID = "_id";
119603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
120603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_TYPE = "type";
121603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
123d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String TABLE_GRANTS = "grants";
124d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
125d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
126d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_GRANTEE_UID = "uid";
127d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
128603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_EXTRAS = "extras";
129603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ID = "_id";
130603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
131603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_KEY = "key";
132603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_VALUE = "value";
133603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
134603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_META = "meta";
135603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_KEY = "key";
136603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_VALUE = "value";
137603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1381cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
1391cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
1407be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private static final Intent ACCOUNTS_CHANGED_INTENT;
141a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String COUNT_OF_MATCHING_GRANTS = ""
143d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
144d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
145d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_GRANTEE_UID + "=?"
146d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
147d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_NAME + "=?"
148d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_TYPE + "=?";
149d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
15056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
15156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
15256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
15356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            AUTHTOKENS_AUTHTOKEN};
15456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
15556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String SELECTION_USERDATA_BY_ACCOUNT =
15656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
15756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
15856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
159a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
160d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final AtomicInteger mNotificationIds = new AtomicInteger(1);
161d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
16204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    static class UserAccounts {
16304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final int userId;
16404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final DatabaseHelper openHelper;
16504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
16604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                credentialsPermissionNotificationIds =
16704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
16804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final HashMap<Account, Integer> signinRequiredNotificationIds =
16904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                new HashMap<Account, Integer>();
17004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final Object cacheLock = new Object();
17104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        /** protected by the {@link #cacheLock} */
172b483a99c6bdfee72fbb8fbcf893e63ef3f54658bAmith Yamasani        private final HashMap<String, Account[]> accountCache =
173b483a99c6bdfee72fbb8fbcf893e63ef3f54658bAmith Yamasani                new LinkedHashMap<String, Account[]>();
17404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        /** protected by the {@link #cacheLock} */
17504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private HashMap<Account, HashMap<String, String>> userDataCache =
17604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                new HashMap<Account, HashMap<String, String>>();
17704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        /** protected by the {@link #cacheLock} */
17804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private HashMap<Account, HashMap<String, String>> authTokenCache =
17904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                new HashMap<Account, HashMap<String, String>>();
18004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
18104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts(Context context, int userId) {
18204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            this.userId = userId;
18304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (cacheLock) {
18404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                openHelper = new DatabaseHelper(context, userId);
18504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
18604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
18704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
18804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
18904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private final SparseArray<UserAccounts> mUsers = new SparseArray<UserAccounts>();
19004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
191d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static AtomicReference<AccountManagerService> sThis =
192d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new AtomicReference<AccountManagerService>();
19331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana    private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
1947be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1957be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    static {
196f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
1977be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1987be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
1997be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
20056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
201d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
202d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * This should only be called by system code. One should only call this after the service
203d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * has started.
204d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @return a reference to the AccountManagerService instance
205d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
206d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
207d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public static AccountManagerService getSingleton() {
208d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return sThis.get();
209d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
210603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
21156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    public AccountManagerService(Context context) {
21256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        this(context, context.getPackageManager(), new AccountAuthenticatorCache(context));
213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
21556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    public AccountManagerService(Context context, PackageManager packageManager,
21656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            IAccountAuthenticatorCache authenticatorCache) {
217603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
21856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        mPackageManager = packageManager;
219603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread = new HandlerThread("AccountManagerService");
221603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread.start();
222603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
223603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
22456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        mAuthenticatorCache = authenticatorCache;
2255ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        mAuthenticatorCache.setListener(this, null /* Handler */);
226603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
227d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        sThis.set(this);
228afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana
229c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        IntentFilter intentFilter = new IntentFilter();
230c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
231c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        intentFilter.addDataScheme("package");
232c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        mContext.registerReceiver(new BroadcastReceiver() {
233c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            @Override
234c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            public void onReceive(Context context1, Intent intent) {
23504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                purgeOldGrantsAll();
236c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            }
237c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        }, intentFilter);
238c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana
239135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        IntentFilter userFilter = new IntentFilter();
240135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        userFilter.addAction(Intent.ACTION_USER_REMOVED);
241135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        mContext.registerReceiver(new BroadcastReceiver() {
242135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            @Override
243135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            public void onReceive(Context context, Intent intent) {
244135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani                onUserRemoved(intent);
245135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            }
246135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }, userFilter);
247afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana    }
248afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana
24926ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    public void systemReady() {
25026ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    }
25126ff6626fc4ee0ae46f01ad309b366921da589feKenny Root
252258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani    private UserManager getUserManager() {
253258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani        if (mUserManager == null) {
254258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani            mUserManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
255258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani        }
256258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani        return mUserManager;
257258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani    }
258258848d2ae04f447ff1c18023fa76b139fcc0862Amith Yamasani
25904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private UserAccounts initUser(int userId) {
26004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (mUsers) {
26104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            UserAccounts accounts = mUsers.get(userId);
26204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            if (accounts == null) {
26304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts = new UserAccounts(mContext, userId);
26404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                mUsers.append(userId, accounts);
26504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                purgeOldGrants(accounts);
2666eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey                validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
26704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
26804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return accounts;
26904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
27004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
27104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
27204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void purgeOldGrantsAll() {
27304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (mUsers) {
27404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            for (int i = 0; i < mUsers.size(); i++) {
27504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                purgeOldGrants(mUsers.valueAt(i));
27604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
27704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
27804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
27904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
28004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void purgeOldGrants(UserAccounts accounts) {
28104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
28204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
283c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            final Cursor cursor = db.query(TABLE_GRANTS,
284c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    new String[]{GRANTS_GRANTEE_UID},
285c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    null, null, GRANTS_GRANTEE_UID, null, null);
286c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            try {
287c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                while (cursor.moveToNext()) {
288c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    final int uid = cursor.getInt(0);
289c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
290c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    if (packageExists) {
291c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                        continue;
292c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    }
293c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    Log.d(TAG, "deleting grants for UID " + uid
294c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                            + " because its package is no longer installed");
295c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
296c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                            new String[]{Integer.toString(uid)});
297c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                }
298c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            } finally {
299c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                cursor.close();
300c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            }
301c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        }
302c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana    }
303c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana
3046eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    /**
3056eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey     * Validate internal set of accounts against installed authenticators for
3066eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey     * given user. Clears cached authenticators before validating.
3076eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey     */
3086eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    public void validateAccounts(int userId) {
3096eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        final UserAccounts accounts = getUserAccounts(userId);
3106eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey
3116eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        // Invalidate user-specific cache to make sure we catch any
3126eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        // removed authenticators.
3136eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        validateAccountsInternal(accounts, true /* invalidateAuthenticatorCache */);
3146eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    }
3156eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey
3166eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    /**
3176eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey     * Validate internal set of accounts against installed authenticators for
3186eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey     * given user. Clear cached authenticators before validating when requested.
3196eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey     */
3206eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    private void validateAccountsInternal(
3216eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            UserAccounts accounts, boolean invalidateAuthenticatorCache) {
3226eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        if (invalidateAuthenticatorCache) {
3236eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            mAuthenticatorCache.invalidateCache(accounts.userId);
3246eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        }
3256eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey
3266ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final HashSet<AuthenticatorDescription> knownAuth = Sets.newHashSet();
3276ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> service :
3286ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                mAuthenticatorCache.getAllServices(accounts.userId)) {
3296ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            knownAuth.add(service.type);
3306ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        }
3316ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
33204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
33304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
334f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            boolean accountDeleted = false;
335f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            Cursor cursor = db.query(TABLE_ACCOUNTS,
336f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
337f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    null, null, null, null, null);
338f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
33904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.accountCache.clear();
34056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final HashMap<String, ArrayList<String>> accountNamesByType =
341b483a99c6bdfee72fbb8fbcf893e63ef3f54658bAmith Yamasani                        new LinkedHashMap<String, ArrayList<String>>();
34256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                while (cursor.moveToNext()) {
34356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final long accountId = cursor.getLong(0);
34456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountType = cursor.getString(1);
34556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountName = cursor.getString(2);
3466ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
3476ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                    if (!knownAuth.contains(AuthenticatorDescription.newKey(accountType))) {
3486eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey                        Slog.w(TAG, "deleting account " + accountName + " because type "
34956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + accountType + " no longer has a registered authenticator");
35056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
35156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountDeleted = true;
35256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        final Account account = new Account(accountName, accountType);
35304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        accounts.userDataCache.remove(account);
35404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        accounts.authTokenCache.remove(account);
35556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    } else {
35656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        ArrayList<String> accountNames = accountNamesByType.get(accountType);
35756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (accountNames == null) {
35856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            accountNames = new ArrayList<String>();
35956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            accountNamesByType.put(accountType, accountNames);
36056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
36156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountNames.add(accountName);
36256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
36356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
3642f36229db823d152f3efd879e751e81a601a75b0Andy McFadden                for (Map.Entry<String, ArrayList<String>> cur
365f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        : accountNamesByType.entrySet()) {
36656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountType = cur.getKey();
36756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final ArrayList<String> accountNames = cur.getValue();
36856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final Account[] accountsForType = new Account[accountNames.size()];
36956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    int i = 0;
37056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    for (String accountName : accountNames) {
37156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountsForType[i] = new Account(accountName, accountType);
37256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        ++i;
37356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
37404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    accounts.accountCache.put(accountType, accountsForType);
375afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                }
376f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
377f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                cursor.close();
378f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountDeleted) {
37904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    sendAccountsChangedBroadcast(accounts.userId);
380f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
381afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            }
382afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        }
3833ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
3843ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
38504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private UserAccounts getUserAccountsForCaller() {
386f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        return getUserAccounts(UserHandle.getCallingUserId());
38704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
38804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
38904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected UserAccounts getUserAccounts(int userId) {
39004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (mUsers) {
39104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            UserAccounts accounts = mUsers.get(userId);
39204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            if (accounts == null) {
39304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts = initUser(userId);
39404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                mUsers.append(userId, accounts);
39504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
39604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return accounts;
39704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
39804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
39904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
400135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    private void onUserRemoved(Intent intent) {
4012a00329c6d55c6cd9166e01963d7410e95d80d21Amith Yamasani        int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, -1);
402135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        if (userId < 1) return;
403135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
404135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        UserAccounts accounts;
405135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        synchronized (mUsers) {
406135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            accounts = mUsers.get(userId);
407135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            mUsers.remove(userId);
408135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
409135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        if (accounts == null) {
410135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            File dbFile = new File(getDatabaseName(userId));
411135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            dbFile.delete();
412135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            return;
413135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
414135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
415135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        synchronized (accounts.cacheLock) {
416135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            accounts.openHelper.close();
417135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            File dbFile = new File(getDatabaseName(userId));
418135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            dbFile.delete();
419135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
420135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    }
421135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
4226ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    @Override
4236ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    public void onServiceChanged(AuthenticatorDescription desc, int userId, boolean removed) {
4246eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        Slog.d(TAG, "onServiceChanged() for userId " + userId);
4256eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        validateAccountsInternal(getUserAccounts(userId), false /* invalidateAuthenticatorCache */);
426603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
427603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
428a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getPassword(Account account) {
42956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
43056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getPassword: " + account
43156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
43256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
43356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
434382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
435d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
436d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
43704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
43826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
439603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
44004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return readPasswordInternal(accounts, account);
441603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
44226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
443603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
444603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
445603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
44604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private String readPasswordInternal(UserAccounts accounts, Account account) {
44731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
44831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
44931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
45031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
45104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
45204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
453f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
454f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
455f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    new String[]{account.name, account.type}, null, null, null);
456f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
457f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (cursor.moveToNext()) {
458f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return cursor.getString(0);
459f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
460f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return null;
461f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
462f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                cursor.close();
463ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
464ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
465ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
466ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
467a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
46856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
46956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getUserData: " + account
47056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", key " + key
47156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
47256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
47356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
474382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
475382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
476d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
47704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
47826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
479603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
48004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return readUserDataInternal(accounts, account, key);
481ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
482ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
483ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
484ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
485ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
4869788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
48756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
48856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAuthenticatorTypes: "
48956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + "caller's uid " + Binder.getCallingUid()
49056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
49156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
4926ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final int userId = UserHandle.getCallingUserId();
4936ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final long identityToken = clearCallingIdentity();
49426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
4959788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
4966ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                    authenticatorCollection = mAuthenticatorCache.getAllServices(userId);
4979788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
4989788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
49926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
5009788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
501718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
502718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
50326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
50426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
50526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
50626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
50726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
508a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
509a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
510a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
511a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
51256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
51356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "addAccount: " + account
51456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
51556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
51656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
517382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
518d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
519d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
52004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
521603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
52226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
523603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
52404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return addAccountInternal(accounts, account, password, extras);
525ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
526ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
527ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
528ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
529ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
53004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
53104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            Bundle extras) {
532743dfad2a51e016ddb741c104317637089187753Fred Quintana        if (account == null) {
533743dfad2a51e016ddb741c104317637089187753Fred Quintana            return false;
534743dfad2a51e016ddb741c104317637089187753Fred Quintana        }
53504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
53604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
537f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
538f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
539f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long numMatches = DatabaseUtils.longForQuery(db,
540f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        "select count(*) from " + TABLE_ACCOUNTS
541f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                                + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
542f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        new String[]{account.name, account.type});
543f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (numMatches > 0) {
544f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    Log.w(TAG, "insertAccountIntoDatabase: " + account
545f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            + ", skipping since the account already exists");
546f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return false;
547f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
548f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                ContentValues values = new ContentValues();
549f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(ACCOUNTS_NAME, account.name);
550f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(ACCOUNTS_TYPE, account.type);
551f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(ACCOUNTS_PASSWORD, password);
552f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
553f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId < 0) {
554f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    Log.w(TAG, "insertAccountIntoDatabase: " + account
555f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            + ", skipping the DB insert failed");
556f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return false;
557f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
558f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (extras != null) {
559f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    for (String key : extras.keySet()) {
560f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        final String value = extras.getString(key);
561f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        if (insertExtraLocked(db, accountId, key, value) < 0) {
562f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            Log.w(TAG, "insertAccountIntoDatabase: " + account
563f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                                    + ", skipping since insertExtra failed for key " + key);
564f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            return false;
565f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        }
566603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
567603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
568f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.setTransactionSuccessful();
56904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                insertAccountIntoCacheLocked(accounts, account);
570f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
571f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
572603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
57304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            sendAccountsChangedBroadcast(accounts.userId);
574f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            return true;
575603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
576603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
577603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
578f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    private long insertExtraLocked(SQLiteDatabase db, long accountId, String key, String value) {
579603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
580603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
581603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
582603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
583603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
584603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
585603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
5863084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana    public void hasFeatures(IAccountManagerResponse response,
587bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            Account account, String[] features) {
58856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
58956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "hasFeatures: " + account
59056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
59156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", features " + stringArrayToString(features)
59256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
59356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
59456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
595382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
596382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
597382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (features == null) throw new IllegalArgumentException("features is null");
598bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        checkReadAccountsPermission();
59904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
600bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        long identityToken = clearCallingIdentity();
601bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        try {
60204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new TestFeaturesSession(accounts, response, account, features).bind();
603bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        } finally {
604bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            restoreCallingIdentity(identityToken);
605bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
606bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
607bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
608bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    private class TestFeaturesSession extends Session {
609bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final String[] mFeatures;
610bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final Account mAccount;
611bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
61204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
613bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                Account account, String[] features) {
61404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            super(accounts, response, account.type, false /* expectActivityLaunch */,
6158570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
616bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mFeatures = features;
617bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mAccount = account;
618bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
619bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
620bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void run() throws RemoteException {
621bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            try {
622bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                mAuthenticator.hasFeatures(this, mAccount, mFeatures);
623bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            } catch (RemoteException e) {
624bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
625bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
626bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
627bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
628bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void onResult(Bundle result) {
629bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
630bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            if (response != null) {
631bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                try {
632bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (result == null) {
633166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
634bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        return;
635bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
63656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
63756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
63856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
63956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
640bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    final Bundle newResult = new Bundle();
641bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
642bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                            result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
643bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    response.onResult(newResult);
644bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                } catch (RemoteException e) {
645bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
646bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
647bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
648bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
649bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                }
650bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
651bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
652bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
653bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        protected String toDebugString(long now) {
6543084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana            return super.toDebugString(now) + ", hasFeatures"
655bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + mAccount
656bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
657bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
658bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
659307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
660ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
66156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
66256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "removeAccount: " + account
66356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
66456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
66556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
66656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
667382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
668382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
669d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
67050cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn        UserHandle user = Binder.getCallingUserHandle();
67104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
67226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
673ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache
67450cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn        cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
67504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized(accounts.credentialsPermissionNotificationIds) {
676ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache            for (Pair<Pair<Account, String>, Integer> pair:
67704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.credentialsPermissionNotificationIds.keySet()) {
678ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                if (account.equals(pair.first.first)) {
67904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    int id = accounts.credentialsPermissionNotificationIds.get(pair);
68050cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                    cancelNotification(id, user);
681ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                }
682ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache            }
683ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache        }
684ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache
68526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
68604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new RemoveAccountSession(accounts, response, account).bind();
68726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
68826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
689a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
690603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
691603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
692ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
693ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
69404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
69504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                Account account) {
69604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            super(accounts, response, account.type, false /* expectActivityLaunch */,
6978570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
698ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
699ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
700ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
701ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
702ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
703ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
704ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
705ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
706ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
707ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
708ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
709ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
710ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
711f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
712f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && !result.containsKey(AccountManager.KEY_INTENT)) {
713f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
714ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
71504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    removeAccountInternal(mAccounts, mAccount);
716ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
717ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
718ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
71956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
72056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
72156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
72256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
723ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
724f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
725ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
726ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
727ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
728ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
729ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
730ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
731ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
732ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
733ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
734ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
735ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
73604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    /* For testing */
737f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    protected void removeAccountInternal(Account account) {
73804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        removeAccountInternal(getUserAccountsForCaller(), account);
73904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
74004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
74104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void removeAccountInternal(UserAccounts accounts, Account account) {
74204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
74304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
744f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
745f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    new String[]{account.name, account.type});
74604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            removeAccountFromCacheLocked(accounts, account);
74704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            sendAccountsChangedBroadcast(accounts.userId);
748f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        }
749ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
750ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
751a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
75256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
75356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "invalidateAuthToken: accountType " + accountType
75456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
75556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
75656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
757382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
758382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authToken == null) throw new IllegalArgumentException("authToken is null");
759b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        checkManageAccountsOrUseCredentialsPermissions();
76004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
76126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
762603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
76304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (accounts.cacheLock) {
76404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
765f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.beginTransaction();
766f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                try {
76704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    invalidateAuthTokenLocked(accounts, db, accountType, authToken);
768f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
769f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                } finally {
770f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.endTransaction();
771f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
77226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
773603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
77426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
775603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
776603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
777603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
77804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void invalidateAuthTokenLocked(UserAccounts accounts, SQLiteDatabase db,
77904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String accountType, String authToken) {
780ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
781ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
782ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
7833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
7843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
7853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
7863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
7873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
7883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
7893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
7903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
7913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
7923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
7933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
7943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
7953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
7963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
7973326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
7983326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
7993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
80004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                writeAuthTokenIntoCacheLocked(accounts, db, new Account(accountName, accountType),
801f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        authTokenType, null);
802603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
8033326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
8043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
805603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
806603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
807603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
80804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
80904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String authToken) {
81031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || type == null) {
81131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return false;
81231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
81350cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn        cancelNotification(getSigninRequiredNotificationId(accounts, account),
81450cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                new UserHandle(accounts.userId));
81504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
81604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
817f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
818f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
819f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = getAccountIdLocked(db, account);
820f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId < 0) {
821f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return false;
822f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
823f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.delete(TABLE_AUTHTOKENS,
824f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
825f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        new String[]{type});
826f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                ContentValues values = new ContentValues();
827f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
828f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(AUTHTOKENS_TYPE, type);
829f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(AUTHTOKENS_AUTHTOKEN, authToken);
830f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
831f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
83204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
833f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return true;
834f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
8353326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
836f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
837f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
8383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
839603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
840603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
841603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
842a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
84356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
84456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "peekAuthToken: " + account
84556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
84656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
84756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
84856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
849382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
850382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
851d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
85204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
85326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
85426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
85504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return readAuthTokenInternal(accounts, account, authTokenType);
85626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
85726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
858603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
859603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
860603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
861a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
86256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
86356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setAuthToken: " + account
86456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
86556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
86656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
86756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
868382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
869382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
870d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
87104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
87226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
87326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
87404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
87526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
87626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
87726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
878603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
879603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
880a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
88156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
88256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setAuthToken: " + account
88356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
88456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
88556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
886382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
887d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
88804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
88926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
89026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
89104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            setPasswordInternal(accounts, account, password);
89226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
89326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
89426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
895603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
896603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
89704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void setPasswordInternal(UserAccounts accounts, Account account, String password) {
89831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
89931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
90031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
90104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
90204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
903f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
904f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
905f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                final ContentValues values = new ContentValues();
906f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(ACCOUNTS_PASSWORD, password);
907f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                final long accountId = getAccountIdLocked(db, account);
908f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId >= 0) {
909f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    final String[] argsAccountId = {String.valueOf(accountId)};
910f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
911f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
91204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    accounts.authTokenCache.remove(account);
913f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
914f5ffe89e736caee1419f0acb469565d5100b8fb8Costin Manolache                }
915f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
916f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
917d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            }
91804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            sendAccountsChangedBroadcast(accounts.userId);
919d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        }
9203ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
9213ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
92204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void sendAccountsChangedBroadcast(int userId) {
92356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Log.i(TAG, "the accounts changed, sending broadcast of "
92456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                + ACCOUNTS_CHANGED_INTENT.getAction());
92579af1dd54c16cde063152922b42c96d72ae9eca8Dianne Hackborn        mContext.sendBroadcastAsUser(ACCOUNTS_CHANGED_INTENT, new UserHandle(userId));
9263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
9273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
928a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
92956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
93056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "clearPassword: " + account
93156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
93256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
93356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
934382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
935d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
93604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
93726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
93826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
93904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            setPasswordInternal(accounts, account, null);
94026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
94126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
94226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
943603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
944603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
945a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
94656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
94756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setUserData: " + account
94856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", key " + key
94956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
95056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
95156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
952382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
953382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
954d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
95504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
95626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
957603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
95804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            setUserdataInternal(accounts, account, key, value);
959ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
960ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
961ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
962ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
963ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
96404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void setUserdataInternal(UserAccounts accounts, Account account, String key,
96504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String value) {
96631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || key == null) {
96731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
96831957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
96904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
97004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
971f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
972f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
973f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = getAccountIdLocked(db, account);
974f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId < 0) {
975ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
97626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
977f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long extrasId = getExtrasIdLocked(db, accountId, key);
978f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (extrasId < 0 ) {
979f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    extrasId = insertExtraLocked(db, accountId, key, value);
980f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    if (extrasId < 0) {
981f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        return;
982f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
983f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                } else {
984f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    ContentValues values = new ContentValues();
985f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    values.put(EXTRAS_VALUE, value);
986f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
987f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        return;
988f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
989ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
990f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
99104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                writeUserDataIntoCacheLocked(accounts, db, account, key, value);
992f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.setTransactionSuccessful();
993f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
994f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
995603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
996603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
997603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
998603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
999d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
100056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (result == null) {
100156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.e(TAG, "the result is unexpectedly null", new Exception());
100256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
100356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
100456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
100556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + response);
100656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1007d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1008d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
1009d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
1010d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
1011d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
1012d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1013d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
1014d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1015d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1016d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1017d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1018d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
1019d9640ec712806508877868d08aafaa2d715ff441Fred Quintana                                  final String authTokenType)
1020d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            throws RemoteException {
1021d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
10225f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
10235f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1024d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        final int callingUid = getCallingUid();
1025d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        clearCallingIdentity();
1026d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        if (callingUid != android.os.Process.SYSTEM_UID) {
1027d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            throw new SecurityException("can only call from system");
1028d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        }
1029f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(callingUid));
10305f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        long identityToken = clearCallingIdentity();
10315f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        try {
1032d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            new Session(accounts, response, accountType, false,
10335f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    false /* stripAuthTokenFromResult */) {
10345f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                protected String toDebugString(long now) {
10355f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    return super.toDebugString(now) + ", getAuthTokenLabel"
1036d9640ec712806508877868d08aafaa2d715ff441Fred Quintana                            + ", " + accountType
10375f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                            + ", authTokenType " + authTokenType;
10385f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
10395f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
10405f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                public void run() throws RemoteException {
10415f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    mAuthenticator.getAuthTokenLabel(this, authTokenType);
10425f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
10435f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
10445f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                public void onResult(Bundle result) {
10455f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    if (result != null) {
10465f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
10475f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        Bundle bundle = new Bundle();
10485f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
10495f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        super.onResult(bundle);
10505f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        return;
10515f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    } else {
10525f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        super.onResult(result);
10535f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    }
10545f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
10555f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            }.bind();
10565f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        } finally {
10575f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            restoreCallingIdentity(identityToken);
10585f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        }
10595f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    }
10605f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1061a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
1062a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
1063c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache            final boolean expectActivityLaunch, Bundle loginOptionsIn) {
106456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
106556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAuthToken: " + account
106656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
106756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
106856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", notifyOnAuthFailure " + notifyOnAuthFailure
106956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
107056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
107156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
107256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1073382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1074382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1075382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1076d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
10774120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn        final UserAccounts accounts = getUserAccountsForCaller();
10786ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
10796ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        authenticatorInfo = mAuthenticatorCache.getServiceInfo(
10806ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                AuthenticatorDescription.newKey(account.type), accounts.userId);
1081a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        final boolean customTokens =
1082a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            authenticatorInfo != null && authenticatorInfo.type.customTokens;
1083a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache
1084a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        // skip the check if customTokens
1085b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        final int callerUid = Binder.getCallingUid();
1086a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        final boolean permissionGranted = customTokens ||
1087a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            permissionIsGranted(account, authTokenType, callerUid);
1088a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache
1089c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache        final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
1090c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache            loginOptionsIn;
1091b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        // let authenticator know the identity of the caller
1092b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
1093b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
1094b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        if (notifyOnAuthFailure) {
1095b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache            loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
1096a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        }
10976ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
109826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
109926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
1100d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
1101d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
1102a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            if (!customTokens && permissionGranted) {
110304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                String authToken = readAuthTokenInternal(accounts, account, authTokenType);
1104d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
110526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
1106f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
1107f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
1108f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
1109d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
1110d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
1111a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1112a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
111404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, account.type, expectActivityLaunch,
11158570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    false /* stripAuthTokenFromResult */) {
111626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
111726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
111826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
111926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
112026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
112126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
112226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
112326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
1124a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
112526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
1126d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
1127d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
1128d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
1129d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
1130d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
1131d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
1132d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
113326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
1134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
113526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
113626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
1137f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
1138d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
1139d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
1140d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
1141f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL));
1142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
1143f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
1144d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
1145d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
1146d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
1147f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
114826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
1149f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1150f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
115126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
1152f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
115326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
115426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
115526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
1156a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                            if (!customTokens) {
115704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                saveAuthTokenToDatabase(mAccounts, new Account(name, type),
1158a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                                        authTokenType, authToken);
1159a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                            }
1160a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
1161603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1162f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
1163d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache                        if (intent != null && notifyOnAuthFailure && !customTokens) {
116404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            doNotification(mAccounts,
1165f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
11664120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                                    intent, accounts.userId);
116726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
1168a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
116926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
1170a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
117126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
117226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
117326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
117426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1175603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1176603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
11774120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn    private void createNoCredentialsPermissionNotification(Account account, Intent intent,
11784120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn            int userId) {
1179d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
1180d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
1181d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
1182d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
1183d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
1184d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
1185d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1186d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1187d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
1188ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String titleAndSubtitle =
1189ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                mContext.getString(R.string.permission_request_notification_with_subtitle,
1190ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                account.name);
1191ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final int index = titleAndSubtitle.indexOf('\n');
119285e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache        String title = titleAndSubtitle;
119385e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache        String subtitle = "";
119485e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache        if (index > 0) {
119585e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache            title = titleAndSubtitle.substring(0, index);
119685e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache            subtitle = titleAndSubtitle.substring(index + 1);
119785e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache        }
119850cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn        UserHandle user = new UserHandle(userId);
11994120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn        n.setLatestEventInfo(mContext, title, subtitle,
12004120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                PendingIntent.getActivityAsUser(mContext, 0, intent,
120150cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                        PendingIntent.FLAG_CANCEL_CURRENT, null, user));
120250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn        installNotification(getCredentialPermissionNotificationId(
120350cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                account, authTokenType, uid), n, user);
1204d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1205d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
12065f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
12075f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
1208d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1209d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
121046703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
12119ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        // Since it was set in Eclair+ we can't change it without breaking apps using
12129ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        // the intent from a non-Activity context.
12139ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1214d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
1215d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
12165f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1217d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
1218d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
1219d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
1220d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
12215f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1222d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
1223d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1224d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1225d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
1226d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
1227d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
1228f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
122904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.credentialsPermissionNotificationIds) {
1230d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
1231d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
1232d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
123304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            id = accounts.credentialsPermissionNotificationIds.get(key);
1234d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
1235d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
123604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.credentialsPermissionNotificationIds.put(key, id);
1237d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1238d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1239d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
1240d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1241d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
124204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
1243d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
124404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.signinRequiredNotificationIds) {
124504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            id = accounts.signinRequiredNotificationIds.get(account);
1246d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
1247d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
124804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.signinRequiredNotificationIds.put(account, id);
1249d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1250d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1251d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
1252d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1253d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
12543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
12553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
1256b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache            final boolean expectActivityLaunch, final Bundle optionsIn) {
125756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
125856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "addAccount: accountType " + accountType
125956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
126056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
126156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", requiredFeatures " + stringArrayToString(requiredFeatures)
126256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
126356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
126456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
126556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1266382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1267382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
1268d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
1269b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache
127004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
1271b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        final int pid = Binder.getCallingPid();
1272b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        final int uid = Binder.getCallingUid();
1273b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
1274b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        options.putInt(AccountManager.KEY_CALLER_UID, uid);
1275b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        options.putInt(AccountManager.KEY_CALLER_PID, pid);
1276b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache
127726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
127826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
127904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, accountType, expectActivityLaunch,
12808570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
128126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
12823348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
12833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
128426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
1285a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
128626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
128726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
12883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
12893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
12903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
12913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
12923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
129326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
129426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
129526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
129626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
129726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1298603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1299603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
13002c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani    @Override
13012c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani    public void confirmCredentialsAsUser(IAccountManagerResponse response,
13022c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani            final Account account, final Bundle options, final boolean expectActivityLaunch,
13032c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani            int userId) {
13042c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        // Only allow the system process to read accounts of other users
13052c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        if (userId != UserHandle.getCallingUserId()
13062c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani                && Binder.getCallingUid() != android.os.Process.myUid()) {
13072c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani            throw new SecurityException("User " + UserHandle.getCallingUserId()
13082c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani                    + " trying to confirm account credentials for " + userId);
13092c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        }
13102c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani
131156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
131256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "confirmCredentials: " + account
131356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
131456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
131556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
131656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
131756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1318382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1319382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1320d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
13212c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        UserAccounts accounts = getUserAccounts(userId);
132226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
132326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
132404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, account.type, expectActivityLaunch,
13258570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
132626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
1327f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    mAuthenticator.confirmCredentials(this, account, options);
132826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
132926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
133026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
133126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
133226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
133326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
133426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
133526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
133626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1337603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1338603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1339a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
1340a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
1341a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
134256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
134356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "updateCredentials: " + account
134456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
134556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
134656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
134756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
134856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
134956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1350382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1351382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1352382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1353d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
135404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
135526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
135626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
135704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, account.type, expectActivityLaunch,
13588570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
135926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
136026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
136126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
136226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
136326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
136426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
136526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
136626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
136726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
136826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
136926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
137026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
137126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
137226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1373603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1374603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1375a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
1376a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
137756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
137856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "editProperties: accountType " + accountType
137956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
138056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
138156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
138256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
138356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1384382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1385382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
1386d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
138704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
138826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
138926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
139004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, accountType, expectActivityLaunch,
13918570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
139226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
139326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
139426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
139526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
139626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
139726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
139826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
139926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
140026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
140126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
140226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
14053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
14063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
14073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
14083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
14093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
14103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
141104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
141204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                IAccountManagerResponse response, String type, String[] features) {
141304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            super(accounts, response, type, false /* expectActivityLaunch */,
14148570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
14153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
14163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
141904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (mAccounts.cacheLock) {
142004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType);
1421f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
14223326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
14233326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
14243326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
14253326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14263326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
14273326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14283326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14293326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
14303326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
14313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
14323326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
14333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
14343326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
143529e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            final IAccountAuthenticator accountAuthenticator = mAuthenticator;
143629e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            if (accountAuthenticator == null) {
143729e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // It is possible that the authenticator has died, which is indicated by
143829e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // mAuthenticator being set to null. If this happens then just abort.
143929e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // There is no need to send back a result or error in this case since
144029e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // that already happened when mAuthenticator was cleared.
144129e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
144229e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                    Log.v(TAG, "checkAccount: aborting session since we are no longer"
144329e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                            + " connected to the authenticator, " + toDebugString());
144429e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                }
144529e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                return;
144629e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            }
14473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
144829e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
14493326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
1450f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1451a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1452603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1453603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
14543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
14553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
14563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
1457f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
14583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
14593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
1460f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
14613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
14623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
14633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
14643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
1465a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
14663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
14683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
14693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
14703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
14713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
14723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
14733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
14743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
147556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
147656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
147756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
147856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
14793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
1480f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
14813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
14823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
14833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
14843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
14853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
14863326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
14873326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
14883326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
14893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
14933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
14943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
14953326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14963326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1497ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
149804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    /**
149904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani     * Returns the accounts for a specific user
150004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani     * @hide
150104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani     */
150204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    public Account[] getAccounts(int userId) {
150304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        checkReadAccountsPermission();
150404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccounts(userId);
150504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        long identityToken = clearCallingIdentity();
150604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        try {
150704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (accounts.cacheLock) {
150804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                return getAccountsFromCacheLocked(accounts, null);
150904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
151004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        } finally {
151104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            restoreCallingIdentity(identityToken);
151204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
151304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
151404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
1515f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani    /**
15166ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey     * Returns accounts for all running users.
15176ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey     *
1518f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani     * @hide
1519f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani     */
15206ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    public AccountAndUser[] getRunningAccounts() {
15216ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final int[] runningUserIds;
15226ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        try {
15236ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            runningUserIds = ActivityManagerNative.getDefault().getRunningUserIds();
15246ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        } catch (RemoteException e) {
15256ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            // Running in system_server; should never happen
15266ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            throw new RuntimeException(e);
15276ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        }
15286eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        return getAccounts(runningUserIds);
15296eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    }
15306eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey
15316eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    /** {@hide} */
15326eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    public AccountAndUser[] getAllAccounts() {
15336eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        final List<UserInfo> users = getUserManager().getUsers();
15346eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        final int[] userIds = new int[users.size()];
15356eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        for (int i = 0; i < userIds.length; i++) {
15366eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            userIds[i] = users.get(i).id;
15376eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        }
15386eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        return getAccounts(userIds);
15396eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    }
15406ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
15416eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    private AccountAndUser[] getAccounts(int[] userIds) {
15426ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final ArrayList<AccountAndUser> runningAccounts = Lists.newArrayList();
15436ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        synchronized (mUsers) {
15446eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            for (int userId : userIds) {
15456ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                UserAccounts userAccounts = getUserAccounts(userId);
1546f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                if (userAccounts == null) continue;
1547f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                synchronized (userAccounts.cacheLock) {
1548f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                    Account[] accounts = getAccountsFromCacheLocked(userAccounts, null);
1549f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                    for (int a = 0; a < accounts.length; a++) {
15506ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                        runningAccounts.add(new AccountAndUser(accounts[a], userId));
1551f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                    }
1552f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                }
1553f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani            }
1554f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani        }
15556ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
15566ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        AccountAndUser[] accountsArray = new AccountAndUser[runningAccounts.size()];
15576ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        return runningAccounts.toArray(accountsArray);
1558f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani    }
1559f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani
15602c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani    @Override
15612c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani    public Account[] getAccountsAsUser(String type, int userId) {
15622c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        // Only allow the system process to read accounts of other users
15632c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        if (userId != UserHandle.getCallingUserId()
15642c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani                && Binder.getCallingUid() != android.os.Process.myUid()) {
15652c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani            throw new SecurityException("User " + UserHandle.getCallingUserId()
15662c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani                    + " trying to get account for " + userId);
15672c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        }
15682c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani
156956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
157056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAccounts: accountType " + type
157156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
157256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
157356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1574ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
15752c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        UserAccounts accounts = getUserAccounts(userId);
1576ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
1577ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
157804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (accounts.cacheLock) {
157904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                return getAccountsFromCacheLocked(accounts, type);
1580f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
1581ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
1582ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
1583ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1584ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1585ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
15862c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani    @Override
15872c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani    public Account[] getAccounts(String type) {
15882c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani        return getAccountsAsUser(type, UserHandle.getCallingUserId());
15892c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani    }
15902c7bc26a7447e6ac9eadcf328259aa3bb1be2949Amith Yamasani
1591ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
15923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
159356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
159456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAccounts: accountType " + type
159556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
159656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", features " + stringArrayToString(features)
159756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
159856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
159956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1600382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1601382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (type == null) throw new IllegalArgumentException("accountType is null");
1602d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
160304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts userAccounts = getUserAccountsForCaller();
16043326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
16053326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
1606ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
1607f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                Account[] accounts;
160804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                synchronized (userAccounts.cacheLock) {
160904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    accounts = getAccountsFromCacheLocked(userAccounts, type);
1610f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
1611d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                Bundle result = new Bundle();
1612d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
1613d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                onResult(response, result);
1614ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
1615ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
161604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new GetAccountsByTypeAndFeatureSession(userAccounts, response, type, features).bind();
16173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
16183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
16193326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
16203326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
16213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1622f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    private long getAccountIdLocked(SQLiteDatabase db, Account account) {
1623603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1624ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1625603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1626603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1627603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1628603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1629603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1630603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1631603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1632603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1633603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1634603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1635f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
1636603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1637603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1638603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1639603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1640603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1641603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1642603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1643603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1644603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1645603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1646603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1647603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1648603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1649a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1650b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            implements IBinder.DeathRecipient, ServiceConnection {
1651603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1652603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1653a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1654a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1655a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
16563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1657a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1658a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1659a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1660603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1661603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1662603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
16638570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana        private final boolean mStripAuthTokenFromResult;
166404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        protected final UserAccounts mAccounts;
16658570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana
166604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
16678570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                boolean expectActivityLaunch, boolean stripAuthTokenFromResult) {
1668603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1669a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
16703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
167104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            mAccounts = accounts;
16728570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            mStripAuthTokenFromResult = stripAuthTokenFromResult;
1673603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1674603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1675a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1676a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1677a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1678a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1679a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1680a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1681a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1682a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1683a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1684a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1685a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1686603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1687603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1688a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1689603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1690603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1691603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1692603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1693a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1694a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1695a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1696a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1697a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1698a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1699a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1700a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1701a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1702a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1703a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1704a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1705a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1706a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1707a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1708a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1709a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1710a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1711a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1712603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1713603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1714a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1715a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1716a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1717603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1718a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1719a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1720a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1721a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1722a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1723a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1724a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1725a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1726a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1727a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1728a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1729a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1730a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1731603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1732603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1733603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1734a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1735a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1736a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1737b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (!bindToAuthenticator(mAccountType)) {
1738a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1739f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1740603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1741603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1742603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1743603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1744603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1745603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1746b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                mContext.unbindService(this);
1747603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1748603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1749603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1750603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1751603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1752603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1753603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1754603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1755603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1756603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1757603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1758603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1759b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceConnected(ComponentName name, IBinder service) {
1760603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1761a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1762a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1763a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1764f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1765a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1766a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1767603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1768603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1769b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceDisconnected(ComponentName name) {
1770a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1771a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1772603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1773166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                try {
1774166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1775166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                            "disconnected");
1776166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                } catch (RemoteException e) {
1777166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1778166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                        Log.v(TAG, "Session.onServiceDisconnected: "
1779166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                                + "caught RemoteException while responding", e);
1780166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    }
1781166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                }
1782603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1783603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1784603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1785b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public abstract void run() throws RemoteException;
1786b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1787603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1788a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1789603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1790166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                try {
1791166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1792166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                            "timeout");
1793166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                } catch (RemoteException e) {
1794166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1795166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                        Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
1796166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                                e);
1797166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    }
1798166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                }
1799603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1800603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1801603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1802a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1803a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1804f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
1805f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1806f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
1807d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1808d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
180950cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                    cancelNotification(getSigninRequiredNotificationId(mAccounts, account),
181050cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                            new UserHandle(mAccounts.userId));
1811d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1812603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1813a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1814a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1815f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && result.containsKey(AccountManager.KEY_INTENT)) {
1816a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1817a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1818a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1819603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1820603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1821603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1822a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
182356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
182456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            Log.v(TAG, getClass().getSimpleName()
182556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                    + " calling onError() on response " + response);
182656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
1827f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
1828a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1829a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
18308570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        if (mStripAuthTokenFromResult) {
18318570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                            result.remove(AccountManager.KEY_AUTHTOKEN);
18328570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        }
183356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
183456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            Log.v(TAG, getClass().getSimpleName()
183556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                    + " calling onResult() on response " + response);
183656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
1837a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1838a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1839603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1840a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1841a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1842a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1843a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1844603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1845603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1846603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1847603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1848a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1849a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1850603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1851603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1852603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1853a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1854a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1855a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1856a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
185756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    Log.v(TAG, getClass().getSimpleName()
185856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            + " calling onError() on response " + response);
1859a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1860a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1861a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1862a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1863a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1864a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1865a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1866a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1867a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1868a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1869a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1870a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1871603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1872603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1873b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1874b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        /**
1875b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * find the component name for the authenticator and initiate a bind
1876b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * if no authenticator or the bind fails then return false, otherwise return true
1877b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         */
1878b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        private boolean bindToAuthenticator(String authenticatorType) {
18796ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            final AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo;
18806ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            authenticatorInfo = mAuthenticatorCache.getServiceInfo(
18816ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                    AuthenticatorDescription.newKey(authenticatorType), mAccounts.userId);
1882b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (authenticatorInfo == null) {
1883b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1884b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "there is no authenticator for " + authenticatorType
1885b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            + ", bailing out");
1886b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1887b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1888b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1889b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1890b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            Intent intent = new Intent();
1891b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
1892b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setComponent(authenticatorInfo.componentName);
1893b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1894b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
1895b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
189634daa75260c9aebe791819ff6134b4c47146c5c0Amith Yamasani            if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE, mAccounts.userId)) {
1897b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1898b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
1899b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1900b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1901b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1902b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1903b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1904b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            return true;
1905b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        }
1906603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1907603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1908603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1909603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1910603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1911603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
19123348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1913603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1914603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1915603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1916603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1917603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1918603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1919603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1920603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1921603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1922603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1923603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1924603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1925603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
192604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private static String getDatabaseName(int userId) {
192704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        File systemDir = Environment.getSystemSecureDirectory();
192861f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani        File databaseFile = new File(Environment.getUserSystemDirectory(userId), DATABASE_NAME);
192904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        if (userId == 0) {
1930a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            // Migrate old file, if it exists, to the new location.
1931a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            // Make sure the new file doesn't already exist. A dummy file could have been
1932a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            // accidentally created in the old location, causing the new one to become corrupted
1933a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            // as well.
193404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            File oldFile = new File(systemDir, DATABASE_NAME);
1935a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            if (oldFile.exists() && !databaseFile.exists()) {
1936c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                // Check for use directory; create if it doesn't exist, else renameTo will fail
193761f57379ca2c5b6290c8da7548fa17128f7ab24fAmith Yamasani                File userDir = Environment.getUserSystemDirectory(userId);
1938c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                if (!userDir.exists()) {
1939c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                    if (!userDir.mkdirs()) {
1940c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                        throw new IllegalStateException("User dir cannot be created: " + userDir);
1941c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                    }
1942c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                }
1943c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                if (!oldFile.renameTo(databaseFile)) {
1944c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                    throw new IllegalStateException("User dir cannot be migrated: " + databaseFile);
1945c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                }
194604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
1947a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor        }
194804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        return databaseFile.getPath();
1949a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor    }
1950a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
195104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    static class DatabaseHelper extends SQLiteOpenHelper {
1952a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
195304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public DatabaseHelper(Context context, int userId) {
195404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            super(context, AccountManagerService.getDatabaseName(userId), null, DATABASE_VERSION);
1955603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1956603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1957f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        /**
1958f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana         * This call needs to be made while the mCacheLock is held. The way to
1959f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana         * ensure this is to get the lock any time a method is called ont the DatabaseHelper
1960f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana         * @param db The database.
1961f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana         */
1962603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1963603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1964603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1965603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1966603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1967603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1968603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1969603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1970603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1971603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1972603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1973603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1974603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1975603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1976603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1977603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1978d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1979d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1980603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1981603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1982603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1983603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1984603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1985603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1986603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1987603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1988603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1989603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1990a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1991d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1992d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1993d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1994d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1995a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1996a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1997a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1998a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1999a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
2000a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
2001a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
2002d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
2003d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
2004a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
2005603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
2006603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
2007d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
2008d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
2009d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
2010d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
2011d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
2012d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
2013d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
2014d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2015d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2016603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
2017603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
2018a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
2019603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
2020a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
2021d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
2022d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
2023d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
2024d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
2025d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2026d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
2027d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
2028d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
2029d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
2030a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
2031a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
20323348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
20333348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            if (oldVersion == 3) {
20343348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
20353348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
20363348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                oldVersion++;
20373348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            }
2038603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
2039603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
2040603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
2041603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
2042603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
2043603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
2044603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
2045603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
2046603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
2047603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
2048603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
2049a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
20501cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    /**
20511cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * Searches array of arguments for the specified string
20521cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param args array of argument strings
20531cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param value value to search for
20541cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @return true if the value is contained in the array
20551cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     */
20561cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static boolean scanArgs(String[] args, String value) {
20571cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (args != null) {
20581cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            for (String arg : args) {
20591cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (value.equals(arg)) {
20601cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    return true;
20611cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
2062a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
2063a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
20641cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        return false;
20651cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    }
2066a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
20676eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey    @Override
20681cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
20693abd75ba3a981850cac43a401d0014a836559cb0Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
20703abd75ba3a981850cac43a401d0014a836559cb0Kenny Root                != PackageManager.PERMISSION_GRANTED) {
20713abd75ba3a981850cac43a401d0014a836559cb0Kenny Root            fout.println("Permission Denial: can't dump AccountsManager from from pid="
20723abd75ba3a981850cac43a401d0014a836559cb0Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
20733abd75ba3a981850cac43a401d0014a836559cb0Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
20743abd75ba3a981850cac43a401d0014a836559cb0Kenny Root            return;
20753abd75ba3a981850cac43a401d0014a836559cb0Kenny Root        }
207604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
20776eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        final IndentingPrintWriter ipw = new IndentingPrintWriter(fout, "  ");
20786eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey
20796eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        final List<UserInfo> users = getUserManager().getUsers();
20806eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey        for (UserInfo user : users) {
20816eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            ipw.println("User " + user + ":");
20826eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            ipw.increaseIndent();
20836eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            dumpUser(getUserAccounts(user.id), fd, ipw, args, isCheckinRequest);
20846eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            ipw.println();
20856eb9620ff289105c3fc4a1be28a8eebb17d044e0Jeff Sharkey            ipw.decreaseIndent();
208604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
208704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
20881cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
208904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
209004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String[] args, boolean isCheckinRequest) {
209104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (userAccounts.cacheLock) {
209204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = userAccounts.openHelper.getReadableDatabase();
2093a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
2094f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (isCheckinRequest) {
2095f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                // This is a checkin request. *Only* upload the account types and the count of each.
2096f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
2097f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        null, null, ACCOUNTS_TYPE, null, null);
2098f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                try {
2099f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    while (cursor.moveToNext()) {
2100f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        // print type,count
2101f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        fout.println(cursor.getString(0) + "," + cursor.getString(1));
2102f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
2103f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                } finally {
2104f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    if (cursor != null) {
2105f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        cursor.close();
2106f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
21071cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
2108f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } else {
210904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */);
2110f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                fout.println("Accounts: " + accounts.length);
2111f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                for (Account account : accounts) {
2112f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    fout.println("  " + account);
21131cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
2114307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
2115f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                fout.println();
2116f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                synchronized (mSessions) {
2117f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    final long now = SystemClock.elapsedRealtime();
2118f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    fout.println("Active Sessions: " + mSessions.size());
2119f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    for (Session session : mSessions.values()) {
2120f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        fout.println("  " + session.toDebugString(now));
2121f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
21221cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
21231cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
2124f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                fout.println();
21256ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                mAuthenticatorCache.dump(fd, fout, args, userAccounts.userId);
2126f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
21271cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        }
2128a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
2129a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
213004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void doNotification(UserAccounts accounts, Account account, CharSequence message,
21314120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn            Intent intent, int userId) {
213226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
213326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
213426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
213526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
213626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
2137a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
2138d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
2139d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
2140d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
21414120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                createNoCredentialsPermissionNotification(account, intent, userId);
2142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
214304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
214433f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                intent.addCategory(String.valueOf(notificationId));
2145d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
2146d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
214750cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                UserHandle user = new UserHandle(userId);
214833f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final String notificationTitleFormat =
214933f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        mContext.getText(R.string.notification_title).toString();
215033f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                n.setLatestEventInfo(mContext,
215133f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        String.format(notificationTitleFormat, account.name),
21524120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                        message, PendingIntent.getActivityAsUser(
21534120375d46091df8527bb701882e056fbb0e6b06Dianne Hackborn                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT,
215450cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                        null, user));
215550cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                installNotification(notificationId, n, user);
2156d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
215726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
215826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
215926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
2160a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
2161a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
216250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn    protected void installNotification(final int notificationId, final Notification n,
216350cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            UserHandle user) {
216456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
216550cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                .notifyAsUser(null, notificationId, n, user);
216656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
216756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
216850cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn    protected void cancelNotification(int id, UserHandle user) {
216926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
217026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
217126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
217250cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                .cancelAsUser(null, id, user);
217326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
217426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
217526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
2176a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
2177d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2178b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    /** Succeeds if any of the specified permissions are granted. */
2179b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    private void checkBinderPermission(String... permissions) {
2180d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
2181b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
2182b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        for (String perm : permissions) {
2183b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana            if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
2184b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
218556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    Log.v(TAG, "  caller uid " + uid + " has " + perm);
2186b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                }
2187b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                return;
2188b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana            }
2189d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2190b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
2191b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        String msg = "caller uid " + uid + " lacks any of " + TextUtils.join(",", permissions);
219256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Log.w(TAG, "  " + msg);
2193b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        throw new SecurityException(msg);
2194d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2195d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
21966ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey    private boolean inSystemImage(int callingUid) {
21976ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final int callingUserId = UserHandle.getUserId(callingUid);
21986ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
21996ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final PackageManager userPackageManager;
22006ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        try {
22016ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            userPackageManager = mContext.createPackageContextAsUser(
22026ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                    "android", 0, new UserHandle(callingUserId)).getPackageManager();
22036ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        } catch (NameNotFoundException e) {
22046ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey            return false;
22056ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        }
22066ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey
22076ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        String[] packages = userPackageManager.getPackagesForUid(callingUid);
22087be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
22097be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
22106ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                PackageInfo packageInfo = userPackageManager.getPackageInfo(name, 0 /* flags */);
221156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                if (packageInfo != null
221256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
22137be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
22147be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
22157be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
22167be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
22177be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
22187be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
22197be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
22207be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
22217be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
2222d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
2223b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        final boolean inSystemImage = inSystemImage(callerUid);
222431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean fromAuthenticator = account != null
222531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasAuthenticatorUid(account.type, callerUid);
222631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean hasExplicitGrants = account != null
222704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
2228d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2229d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
223056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + callerUid + ", " + account
2231d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
2232d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
2233d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2234b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage;
2235d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2236d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
22371a23191bbde11505d6e0c25c04a60b41cb27fd31Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
22386ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey        final int callingUserId = UserHandle.getUserId(callingUid);
2239d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
22406ab72d74b86e5f4ec3c3909366fd46c225a66bd7Jeff Sharkey                mAuthenticatorCache.getAllServices(callingUserId)) {
2241d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
2242ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
224356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        (mPackageManager.checkSignatures(serviceInfo.uid, callingUid)
2244ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
2245d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
2246d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2247d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
2248d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2249d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
225004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
225104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            int callerUid) {
225204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        if (callerUid == android.os.Process.SYSTEM_UID) {
2253d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
2254d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
225504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
225604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
225704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
225804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String[] args = { String.valueOf(callerUid), authTokenType,
2259f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    account.name, account.type};
2260f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            final boolean permissionGranted =
2261f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
2262f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
2263f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                // TODO: Skip this check when running automated tests. Replace this
2264f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                // with a more general solution.
2265f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                Log.d(TAG, "no credentials permission for usage of " + account + ", "
226604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        + authTokenType + " by uid " + callerUid
2267f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        + " but ignoring since device is in test harness.");
2268f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return true;
2269f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
2270f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            return permissionGranted;
2271d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2272d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2273d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2274d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
2275d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
227631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || !hasAuthenticatorUid(account.type, uid)) {
2277d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
2278d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
2279d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
2280d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2281d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2282d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
2283d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2284d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2285d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2286d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
2287d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
2288d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
2289d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2290d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2291d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
2292d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
2293d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2294d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2295d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
2296d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
2297d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2298d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2299b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    private void checkManageAccountsOrUseCredentialsPermissions() {
2300b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS,
2301b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                Manifest.permission.USE_CREDENTIALS);
2302b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    }
2303b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
2304d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
2305d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            throws RemoteException {
2306d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        final int callingUid = getCallingUid();
2307d9640ec712806508877868d08aafaa2d715ff441Fred Quintana
2308d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        if (callingUid != android.os.Process.SYSTEM_UID) {
2309d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            throw new SecurityException();
2310d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        }
2311d9640ec712806508877868d08aafaa2d715ff441Fred Quintana
2312d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        if (value) {
2313d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            grantAppPermission(account, authTokenType, uid);
2314d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        } else {
2315d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            revokeAppPermission(account, authTokenType, uid);
2316d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        }
2317d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    }
2318d9640ec712806508877868d08aafaa2d715ff441Fred Quintana
2319d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
2320d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
2321d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
2322d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
2323d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
2324d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
2325d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
2326d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    private void grantAppPermission(Account account, String authTokenType, int uid) {
2327382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null || authTokenType == null) {
2328382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
232931957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
233031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
2331f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
233204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
233304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
2334f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
2335f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
2336f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = getAccountIdLocked(db, account);
2337f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId >= 0) {
2338f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    ContentValues values = new ContentValues();
2339f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    values.put(GRANTS_ACCOUNTS_ID, accountId);
2340f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
2341f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    values.put(GRANTS_GRANTEE_UID, uid);
2342f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
2343f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
2344f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
2345f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
2346f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
2347d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
234850cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
234950cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                    new UserHandle(accounts.userId));
2350d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2351d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2352d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2353d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
2354d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
2355d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
2356d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
2357d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
2358d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
2359d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
2360d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
2361d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    private void revokeAppPermission(Account account, String authTokenType, int uid) {
2362382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null || authTokenType == null) {
2363382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
236431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
236531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
2366f02b60aa4f367516f40cf3d60fffae0c6fe3e1b8Dianne Hackborn        UserAccounts accounts = getUserAccounts(UserHandle.getUserId(uid));
236704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
236804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
2369f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
2370f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
2371f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = getAccountIdLocked(db, account);
2372f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId >= 0) {
2373f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.delete(TABLE_GRANTS,
2374f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
2375f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                                    + GRANTS_GRANTEE_UID + "=?",
2376f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            new String[]{String.valueOf(accountId), authTokenType,
2377f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                                    String.valueOf(uid)});
2378f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
2379f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
2380f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
2381f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
2382d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
238350cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn            cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid),
238450cdf7c3069eb2cf82acbad73c322b7a5f3af4b1Dianne Hackborn                    new UserHandle(accounts.userId));
2385d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2386d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
238756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
238856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    static final private String stringArrayToString(String[] value) {
238956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return value != null ? ("[" + TextUtils.join(",", value) + "]") : null;
239056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
239156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
239204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
239304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
2394f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (oldAccountsForType != null) {
2395f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            ArrayList<Account> newAccountsList = new ArrayList<Account>();
2396f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            for (Account curAccount : oldAccountsForType) {
2397f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (!curAccount.equals(account)) {
2398f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    newAccountsList.add(curAccount);
239956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
240056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
2401f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (newAccountsList.isEmpty()) {
240204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.accountCache.remove(account.type);
2403f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } else {
2404f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                Account[] newAccountsForType = new Account[newAccountsList.size()];
2405f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                newAccountsForType = newAccountsList.toArray(newAccountsForType);
240604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.accountCache.put(account.type, newAccountsForType);
2407f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
240856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
240904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        accounts.userDataCache.remove(account);
241004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        accounts.authTokenCache.remove(account);
241156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
241256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
241356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    /**
241456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana     * This assumes that the caller has already checked that the account is not already present.
241556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana     */
241604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
241704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        Account[] accountsForType = accounts.accountCache.get(account.type);
2418f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        int oldLength = (accountsForType != null) ? accountsForType.length : 0;
2419f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        Account[] newAccountsForType = new Account[oldLength + 1];
2420f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (accountsForType != null) {
2421f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
2422f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        }
2423f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        newAccountsForType[oldLength] = account;
242404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        accounts.accountCache.put(account.type, newAccountsForType);
2425f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    }
2426f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana
242704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType) {
2428f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (accountType != null) {
242904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final Account[] accounts = userAccounts.accountCache.get(accountType);
2430f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (accounts == null) {
2431f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return EMPTY_ACCOUNT_ARRAY;
243256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            } else {
2433f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return Arrays.copyOf(accounts, accounts.length);
2434f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
2435f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        } else {
2436f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            int totalLength = 0;
243704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            for (Account[] accounts : userAccounts.accountCache.values()) {
2438f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                totalLength += accounts.length;
2439f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
2440f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (totalLength == 0) {
2441f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return EMPTY_ACCOUNT_ARRAY;
2442f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
2443f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            Account[] accounts = new Account[totalLength];
2444f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            totalLength = 0;
244504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            for (Account[] accountsOfType : userAccounts.accountCache.values()) {
2446f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                System.arraycopy(accountsOfType, 0, accounts, totalLength,
2447f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        accountsOfType.length);
2448f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                totalLength += accountsOfType.length;
244956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
2450f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            return accounts;
245156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
245256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
245356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
245404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected void writeUserDataIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
245504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            Account account, String key, String value) {
245604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
2457f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (userDataForAccount == null) {
2458f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
245904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            accounts.userDataCache.put(account, userDataForAccount);
2460f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        }
2461f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (value == null) {
2462f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            userDataForAccount.remove(key);
2463f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        } else {
2464f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            userDataForAccount.put(key, value);
246556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
246656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
246756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
246804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
246904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            Account account, String key, String value) {
247004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
2471f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (authTokensForAccount == null) {
2472f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
247304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            accounts.authTokenCache.put(account, authTokensForAccount);
2474f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        }
2475f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (value == null) {
2476f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            authTokensForAccount.remove(key);
2477f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        } else {
2478f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            authTokensForAccount.put(key, value);
247956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
248056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
248156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
248204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected String readAuthTokenInternal(UserAccounts accounts, Account account,
248304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String authTokenType) {
248404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
248504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
248656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (authTokensForAccount == null) {
248756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                // need to populate the cache for this account
248804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
2489f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
249004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.authTokenCache.put(account, authTokensForAccount);
249156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
249256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return authTokensForAccount.get(authTokenType);
249356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
249456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
249556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
249604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected String readUserDataInternal(UserAccounts accounts, Account account, String key) {
249704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
249804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
249956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (userDataForAccount == null) {
250056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                // need to populate the cache for this account
250104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
2502f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
250304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.userDataCache.put(account, userDataForAccount);
250456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
250556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return userDataForAccount.get(key);
250656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
250756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
250856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
2509f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
2510f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            final SQLiteDatabase db, Account account) {
251156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        HashMap<String, String> userDataForAccount = new HashMap<String, String>();
251256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Cursor cursor = db.query(TABLE_EXTRAS,
251356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                COLUMNS_EXTRAS_KEY_AND_VALUE,
251456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                SELECTION_USERDATA_BY_ACCOUNT,
251556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                new String[]{account.name, account.type},
251656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                null, null, null);
251756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        try {
251856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            while (cursor.moveToNext()) {
251956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String tmpkey = cursor.getString(0);
252056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String value = cursor.getString(1);
252156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                userDataForAccount.put(tmpkey, value);
252256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
252356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        } finally {
252456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            cursor.close();
252556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
252656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return userDataForAccount;
252756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
252856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
2529f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
2530f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            final SQLiteDatabase db, Account account) {
253156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
253256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS,
253356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
253456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                SELECTION_AUTHTOKENS_BY_ACCOUNT,
253556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                new String[]{account.name, account.type},
253656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                null, null, null);
253756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        try {
253856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            while (cursor.moveToNext()) {
253956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String type = cursor.getString(0);
254056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String authToken = cursor.getString(1);
254156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                authTokensForAccount.put(type, authToken);
254256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
254356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        } finally {
254456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            cursor.close();
254556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
254656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return authTokensForAccount;
254756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
2548603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
2549