AccountManagerService.java revision 26ff6626fc4ee0ae46f01ad309b366921da589fe
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;
2104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport android.app.AppGlobals;
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;
35d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.content.pm.RegisteredServicesCache;
363ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanaimport android.content.pm.RegisteredServicesCacheListener;
3704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport android.content.pm.UserInfo;
3846703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstromimport android.content.res.Resources;
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;
5304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport android.os.UserId;
54a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.text.TextUtils;
55a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport android.util.Log;
56d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport android.util.Pair;
5704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport android.util.SparseArray;
58603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
59b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolacheimport com.android.internal.R;
6004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport com.android.internal.util.IndentingPrintWriter;
61b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache
62a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayorimport java.io.File;
63a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.FileDescriptor;
64a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.io.PrintWriter;
65a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.ArrayList;
6656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport java.util.Arrays;
67a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintanaimport java.util.Collection;
68d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.HashMap;
6956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintanaimport java.util.LinkedHashMap;
7004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasaniimport java.util.List;
712f36229db823d152f3efd879e751e81a601a75b0Andy McFaddenimport java.util.Map;
72d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicInteger;
73d4a1d2e14297a3387fdb5761090961e714370492Fred Quintanaimport java.util.concurrent.atomic.AtomicReference;
74603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
75603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana/**
76603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * A system service that provides  account, password, and authtoken management for all
77603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * accounts on the device. Some of these calls are implemented with the help of the corresponding
78603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * {@link IAccountAuthenticator} services. This service is not accessed by users directly,
79603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana * instead one uses an instance of {@link AccountManager}, which can be accessed as follows:
8046703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom *    AccountManager accountManager = AccountManager.get(context);
813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana * @hide
82603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana */
833ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintanapublic class AccountManagerService
843ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana        extends IAccountManager.Stub
855ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        implements RegisteredServicesCacheListener<AuthenticatorDescription> {
86603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TAG = "AccountManagerService";
87603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
88603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int TIMEOUT_DELAY_MS = 1000 * 60;
89603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String DATABASE_NAME = "accounts.db";
903348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache    private static final int DATABASE_VERSION = 4;
91603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
92603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final Context mContext;
93603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
9456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private final PackageManager mPackageManager;
9556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
96603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private HandlerThread mMessageThread;
97603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private final MessageHandler mMessageHandler;
98603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
99603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    // Messages that can be sent on mHandler
100603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final int MESSAGE_TIMED_OUT = 3;
101603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
10256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private final IAccountAuthenticatorCache mAuthenticatorCache;
103603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
104603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_ACCOUNTS = "accounts";
105603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_ID = "_id";
106603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_NAME = "name";
107603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_TYPE = "type";
1081cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String ACCOUNTS_TYPE_COUNT = "count(type)";
109603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String ACCOUNTS_PASSWORD = "password";
110603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
111603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_AUTHTOKENS = "authtokens";
112603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ID = "_id";
113603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_ACCOUNTS_ID = "accounts_id";
114603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_TYPE = "type";
115603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String AUTHTOKENS_AUTHTOKEN = "authtoken";
116603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
117d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String TABLE_GRANTS = "grants";
118d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_ACCOUNTS_ID = "accounts_id";
119d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_AUTH_TOKEN_TYPE = "auth_token_type";
120d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String GRANTS_GRANTEE_UID = "uid";
121d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
122603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_EXTRAS = "extras";
123603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ID = "_id";
124603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_ACCOUNTS_ID = "accounts_id";
125603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_KEY = "key";
126603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String EXTRAS_VALUE = "value";
127603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
128603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String TABLE_META = "meta";
129603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_KEY = "key";
130603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private static final String META_VALUE = "value";
131603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1321cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static final String[] ACCOUNT_TYPE_COUNT_PROJECTION =
1331cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            new String[] { ACCOUNTS_TYPE, ACCOUNTS_TYPE_COUNT};
1347be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private static final Intent ACCOUNTS_CHANGED_INTENT;
135a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
136d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static final String COUNT_OF_MATCHING_GRANTS = ""
137d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + "SELECT COUNT(*) FROM " + TABLE_GRANTS + ", " + TABLE_ACCOUNTS
138d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " WHERE " + GRANTS_ACCOUNTS_ID + "=" + ACCOUNTS_ID
139d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_GRANTEE_UID + "=?"
140d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + GRANTS_AUTH_TOKEN_TYPE + "=?"
141d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_NAME + "=?"
142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            + " AND " + ACCOUNTS_TYPE + "=?";
143d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
14456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String SELECTION_AUTHTOKENS_BY_ACCOUNT =
14556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            AUTHTOKENS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
14656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String[] COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN = {AUTHTOKENS_TYPE,
14756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            AUTHTOKENS_AUTHTOKEN};
14856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
14956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String SELECTION_USERDATA_BY_ACCOUNT =
15056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            EXTRAS_ACCOUNTS_ID + "=(select _id FROM accounts WHERE name=? AND type=?)";
15156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    private static final String[] COLUMNS_EXTRAS_KEY_AND_VALUE = {EXTRAS_KEY, EXTRAS_VALUE};
15256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
153a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private final LinkedHashMap<String, Session> mSessions = new LinkedHashMap<String, Session>();
154d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private final AtomicInteger mNotificationIds = new AtomicInteger(1);
155d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
15604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    static class UserAccounts {
15704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final int userId;
15804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final DatabaseHelper openHelper;
15904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final HashMap<Pair<Pair<Account, String>, Integer>, Integer>
16004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                credentialsPermissionNotificationIds =
16104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                new HashMap<Pair<Pair<Account, String>, Integer>, Integer>();
16204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final HashMap<Account, Integer> signinRequiredNotificationIds =
16304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                new HashMap<Account, Integer>();
16404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private final Object cacheLock = new Object();
16504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        /** protected by the {@link #cacheLock} */
166b483a99c6bdfee72fbb8fbcf893e63ef3f54658bAmith Yamasani        private final HashMap<String, Account[]> accountCache =
167b483a99c6bdfee72fbb8fbcf893e63ef3f54658bAmith Yamasani                new LinkedHashMap<String, Account[]>();
16804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        /** protected by the {@link #cacheLock} */
16904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private HashMap<Account, HashMap<String, String>> userDataCache =
17004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                new HashMap<Account, HashMap<String, String>>();
17104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        /** protected by the {@link #cacheLock} */
17204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        private HashMap<Account, HashMap<String, String>> authTokenCache =
17304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                new HashMap<Account, HashMap<String, String>>();
17404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
17504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts(Context context, int userId) {
17604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            this.userId = userId;
17704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (cacheLock) {
17804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                openHelper = new DatabaseHelper(context, userId);
17904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
18004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
18104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
18204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
18304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private final SparseArray<UserAccounts> mUsers = new SparseArray<UserAccounts>();
18404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
185d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private static AtomicReference<AccountManagerService> sThis =
186d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            new AtomicReference<AccountManagerService>();
18731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana    private static final Account[] EMPTY_ACCOUNT_ARRAY = new Account[]{};
1887be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
1897be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    static {
190f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana        ACCOUNTS_CHANGED_INTENT = new Intent(AccountManager.LOGIN_ACCOUNTS_CHANGED_ACTION);
1917be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        ACCOUNTS_CHANGED_INTENT.setFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT);
1927be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
1937be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
19456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
195d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
196d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * This should only be called by system code. One should only call this after the service
197d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * has started.
198d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @return a reference to the AccountManagerService instance
199d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
200d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
201d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    public static AccountManagerService getSingleton() {
202d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return sThis.get();
203d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
204603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
20556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    public AccountManagerService(Context context) {
20656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        this(context, context.getPackageManager(), new AccountAuthenticatorCache(context));
207603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
208603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
20956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    public AccountManagerService(Context context, PackageManager packageManager,
21056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            IAccountAuthenticatorCache authenticatorCache) {
211603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mContext = context;
21256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        mPackageManager = packageManager;
213603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
214603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread = new HandlerThread("AccountManagerService");
215603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageThread.start();
216603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        mMessageHandler = new MessageHandler(mMessageThread.getLooper());
217603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
21856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        mAuthenticatorCache = authenticatorCache;
2195ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana        mAuthenticatorCache.setListener(this, null /* Handler */);
220603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
221d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        sThis.set(this);
222afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana
223c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        IntentFilter intentFilter = new IntentFilter();
224c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        intentFilter.addAction(Intent.ACTION_PACKAGE_REMOVED);
225c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        intentFilter.addDataScheme("package");
226c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        mContext.registerReceiver(new BroadcastReceiver() {
227c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            @Override
228c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            public void onReceive(Context context1, Intent intent) {
22904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                purgeOldGrantsAll();
230c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            }
231c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        }, intentFilter);
232c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana
233135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        IntentFilter userFilter = new IntentFilter();
234135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        userFilter.addAction(Intent.ACTION_USER_REMOVED);
235135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        mContext.registerReceiver(new BroadcastReceiver() {
236135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            @Override
237135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            public void onReceive(Context context, Intent intent) {
238135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani                onUserRemoved(intent);
239135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            }
240135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }, userFilter);
241afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana    }
242afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana
24326ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    public void systemReady() {
24426ff6626fc4ee0ae46f01ad309b366921da589feKenny Root        mAuthenticatorCache.generateServicesMap();
24526ff6626fc4ee0ae46f01ad309b366921da589feKenny Root        initUser(0);
24626ff6626fc4ee0ae46f01ad309b366921da589feKenny Root    }
24726ff6626fc4ee0ae46f01ad309b366921da589feKenny Root
24804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private UserAccounts initUser(int userId) {
24904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (mUsers) {
25004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            UserAccounts accounts = mUsers.get(userId);
25104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            if (accounts == null) {
25204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts = new UserAccounts(mContext, userId);
25304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                mUsers.append(userId, accounts);
25404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                purgeOldGrants(accounts);
25504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                validateAccountsAndPopulateCache(accounts);
25604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
25704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return accounts;
25804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
25904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
26004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
26104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void purgeOldGrantsAll() {
26204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (mUsers) {
26304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            for (int i = 0; i < mUsers.size(); i++) {
26404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                purgeOldGrants(mUsers.valueAt(i));
26504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
26604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
26704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
26804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
26904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void purgeOldGrants(UserAccounts accounts) {
27004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
27104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
272c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            final Cursor cursor = db.query(TABLE_GRANTS,
273c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    new String[]{GRANTS_GRANTEE_UID},
274c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    null, null, GRANTS_GRANTEE_UID, null, null);
275c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            try {
276c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                while (cursor.moveToNext()) {
277c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    final int uid = cursor.getInt(0);
278c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    final boolean packageExists = mPackageManager.getPackagesForUid(uid) != null;
279c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    if (packageExists) {
280c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                        continue;
281c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    }
282c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    Log.d(TAG, "deleting grants for UID " + uid
283c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                            + " because its package is no longer installed");
284c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                    db.delete(TABLE_GRANTS, GRANTS_GRANTEE_UID + "=?",
285c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                            new String[]{Integer.toString(uid)});
286c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                }
287c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            } finally {
288c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana                cursor.close();
289c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana            }
290c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana        }
291c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana    }
292c1a4e5dc418d324f2fa2827d83002cc50e62c507Fred Quintana
29304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void validateAccountsAndPopulateCache(UserAccounts accounts) {
29404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
29504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
296f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            boolean accountDeleted = false;
297f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            Cursor cursor = db.query(TABLE_ACCOUNTS,
298f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    new String[]{ACCOUNTS_ID, ACCOUNTS_TYPE, ACCOUNTS_NAME},
299f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    null, null, null, null, null);
300f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
30104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.accountCache.clear();
30256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final HashMap<String, ArrayList<String>> accountNamesByType =
303b483a99c6bdfee72fbb8fbcf893e63ef3f54658bAmith Yamasani                        new LinkedHashMap<String, ArrayList<String>>();
30456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                while (cursor.moveToNext()) {
30556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final long accountId = cursor.getLong(0);
30656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountType = cursor.getString(1);
30756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountName = cursor.getString(2);
30856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (mAuthenticatorCache.getServiceInfo(
30956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            AuthenticatorDescription.newKey(accountType)) == null) {
31056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.d(TAG, "deleting account " + accountName + " because type "
31156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + accountType + " no longer has a registered authenticator");
31256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        db.delete(TABLE_ACCOUNTS, ACCOUNTS_ID + "=" + accountId, null);
31356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountDeleted = true;
31456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        final Account account = new Account(accountName, accountType);
31504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        accounts.userDataCache.remove(account);
31604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        accounts.authTokenCache.remove(account);
31756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    } else {
31856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        ArrayList<String> accountNames = accountNamesByType.get(accountType);
31956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (accountNames == null) {
32056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            accountNames = new ArrayList<String>();
32156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            accountNamesByType.put(accountType, accountNames);
32256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
32356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountNames.add(accountName);
32456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
32556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
3262f36229db823d152f3efd879e751e81a601a75b0Andy McFadden                for (Map.Entry<String, ArrayList<String>> cur
327f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        : accountNamesByType.entrySet()) {
32856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final String accountType = cur.getKey();
32956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final ArrayList<String> accountNames = cur.getValue();
33056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    final Account[] accountsForType = new Account[accountNames.size()];
33156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    int i = 0;
33256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    for (String accountName : accountNames) {
33356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        accountsForType[i] = new Account(accountName, accountType);
33456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        ++i;
33556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
33604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    accounts.accountCache.put(accountType, accountsForType);
337afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana                }
338f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
339f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                cursor.close();
340f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountDeleted) {
34104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    sendAccountsChangedBroadcast(accounts.userId);
342f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
343afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana            }
344afa92b8f3d8f85fe2dde309f8f778926396539eaFred Quintana        }
3453ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
3463ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
34704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private UserAccounts getUserAccountsForCaller() {
34804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        return getUserAccounts(UserId.getCallingUserId());
34904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
35004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
35104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected UserAccounts getUserAccounts(int userId) {
35204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (mUsers) {
35304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            UserAccounts accounts = mUsers.get(userId);
35404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            if (accounts == null) {
35504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts = initUser(userId);
35604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                mUsers.append(userId, accounts);
35704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
35804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return accounts;
35904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
36004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
36104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
362135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    private void onUserRemoved(Intent intent) {
363135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        int userId = intent.getIntExtra(Intent.EXTRA_USERID, -1);
364135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        if (userId < 1) return;
365135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
366135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        UserAccounts accounts;
367135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        synchronized (mUsers) {
368135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            accounts = mUsers.get(userId);
369135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            mUsers.remove(userId);
370135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
371135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        if (accounts == null) {
372135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            File dbFile = new File(getDatabaseName(userId));
373135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            dbFile.delete();
374135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            return;
375135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
376135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
377135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        synchronized (accounts.cacheLock) {
378135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            accounts.openHelper.close();
379135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            File dbFile = new File(getDatabaseName(userId));
380135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani            dbFile.delete();
381135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani        }
382135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani    }
383135936072b24b090fb63940aea41b408d855a4f3Amith Yamasani
38404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private List<UserInfo> getAllUsers() {
38504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        try {
38604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return AppGlobals.getPackageManager().getUsers();
38704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        } catch (RemoteException re) {
38804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            // Local to system process, shouldn't happen
38904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
39004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        return null;
39104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
39204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
3935ebbb4a6b3e16f711735ae0615b9a9ea64faad38Fred Quintana    public void onServiceChanged(AuthenticatorDescription desc, boolean removed) {
39404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        // Validate accounts for all users
39504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        List<UserInfo> users = getAllUsers();
39604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        if (users == null) {
39704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            validateAccountsAndPopulateCache(getUserAccountsForCaller());
39804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        } else {
39904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            for (UserInfo user : users) {
40004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                validateAccountsAndPopulateCache(getUserAccounts(user.id));
40104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
40204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
403603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
404603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
405a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getPassword(Account account) {
40656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
40756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getPassword: " + account
40856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
40956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
41056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
411382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
412d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
413d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
41404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
41526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
416603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
41704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return readPasswordInternal(accounts, account);
418603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
41926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
420603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
421603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
422603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
42304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private String readPasswordInternal(UserAccounts accounts, Account account) {
42431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
42531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return null;
42631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
42731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana
42804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
42904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
430f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_PASSWORD},
431f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
432f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    new String[]{account.name, account.type}, null, null, null);
433f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
434f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (cursor.moveToNext()) {
435f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return cursor.getString(0);
436f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
437f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return null;
438f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
439f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                cursor.close();
440ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
441ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
442ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
443ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
444a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String getUserData(Account account, String key) {
44556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
44656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getUserData: " + account
44756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", key " + key
44856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
44956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
45056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
451382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
452382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
453d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
45404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
45526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
456603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
45704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return readUserDataInternal(accounts, account, key);
458ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
459ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
460ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
461ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
462ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
4639788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana    public AuthenticatorDescription[] getAuthenticatorTypes() {
46456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
46556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAuthenticatorTypes: "
46656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + "caller's uid " + Binder.getCallingUid()
46756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
46856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
46926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
47026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
4719788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            Collection<AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription>>
4729788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    authenticatorCollection = mAuthenticatorCache.getAllServices();
4739788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            AuthenticatorDescription[] types =
4749788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana                    new AuthenticatorDescription[authenticatorCollection.size()];
47526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            int i = 0;
4769788976b1465ce982b5ae7c741345edd0ecd9322Fred Quintana            for (AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticator
477718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                    : authenticatorCollection) {
478718d8a2d7ff3e864a73879eb646f46c14ab74d07Fred Quintana                types[i] = authenticator.type;
47926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                i++;
48026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
48126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            return types;
48226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
48326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
484a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
485a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
486a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
487a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public boolean addAccount(Account account, String password, Bundle extras) {
48856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
48956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "addAccount: " + account
49056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
49156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
49256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
493382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
494d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
495d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
49604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
497603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        // fails if the account already exists
49826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
499603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
50004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return addAccountInternal(accounts, account, password, extras);
501ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
502ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
503ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
504ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
505ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
50604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private boolean addAccountInternal(UserAccounts accounts, Account account, String password,
50704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            Bundle extras) {
508743dfad2a51e016ddb741c104317637089187753Fred Quintana        if (account == null) {
509743dfad2a51e016ddb741c104317637089187753Fred Quintana            return false;
510743dfad2a51e016ddb741c104317637089187753Fred Quintana        }
51104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
51204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
513f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
514f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
515f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long numMatches = DatabaseUtils.longForQuery(db,
516f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        "select count(*) from " + TABLE_ACCOUNTS
517f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                                + " WHERE " + ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
518f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        new String[]{account.name, account.type});
519f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (numMatches > 0) {
520f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    Log.w(TAG, "insertAccountIntoDatabase: " + account
521f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            + ", skipping since the account already exists");
522f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return false;
523f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
524f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                ContentValues values = new ContentValues();
525f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(ACCOUNTS_NAME, account.name);
526f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(ACCOUNTS_TYPE, account.type);
527f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(ACCOUNTS_PASSWORD, password);
528f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = db.insert(TABLE_ACCOUNTS, ACCOUNTS_NAME, values);
529f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId < 0) {
530f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    Log.w(TAG, "insertAccountIntoDatabase: " + account
531f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            + ", skipping the DB insert failed");
532f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return false;
533f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
534f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (extras != null) {
535f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    for (String key : extras.keySet()) {
536f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        final String value = extras.getString(key);
537f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        if (insertExtraLocked(db, accountId, key, value) < 0) {
538f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            Log.w(TAG, "insertAccountIntoDatabase: " + account
539f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                                    + ", skipping since insertExtra failed for key " + key);
540f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            return false;
541f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        }
542603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    }
543603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
544f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.setTransactionSuccessful();
54504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                insertAccountIntoCacheLocked(accounts, account);
546f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
547f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
548603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
54904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            sendAccountsChangedBroadcast(accounts.userId);
550f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            return true;
551603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
552603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
553603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
554f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    private long insertExtraLocked(SQLiteDatabase db, long accountId, String key, String value) {
555603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        ContentValues values = new ContentValues();
556603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_KEY, key);
557603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_ACCOUNTS_ID, accountId);
558603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        values.put(EXTRAS_VALUE, value);
559603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return db.insert(TABLE_EXTRAS, EXTRAS_KEY, values);
560603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
561603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
5623084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana    public void hasFeatures(IAccountManagerResponse response,
563bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            Account account, String[] features) {
56456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
56556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "hasFeatures: " + account
56656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
56756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", features " + stringArrayToString(features)
56856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
56956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
57056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
571382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
572382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
573382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (features == null) throw new IllegalArgumentException("features is null");
574bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        checkReadAccountsPermission();
57504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
576bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        long identityToken = clearCallingIdentity();
577bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        try {
57804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new TestFeaturesSession(accounts, response, account, features).bind();
579bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        } finally {
580bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            restoreCallingIdentity(identityToken);
581bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
582bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
583bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
584bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    private class TestFeaturesSession extends Session {
585bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final String[] mFeatures;
586bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        private final Account mAccount;
587bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
58804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public TestFeaturesSession(UserAccounts accounts, IAccountManagerResponse response,
589bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                Account account, String[] features) {
59004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            super(accounts, response, account.type, false /* expectActivityLaunch */,
5918570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
592bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mFeatures = features;
593bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            mAccount = account;
594bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
595bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
596bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void run() throws RemoteException {
597bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            try {
598bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                mAuthenticator.hasFeatures(this, mAccount, mFeatures);
599bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            } catch (RemoteException e) {
600bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
601bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
602bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
603bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
604bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        public void onResult(Bundle result) {
605bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
606bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            if (response != null) {
607bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                try {
608bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (result == null) {
609166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
610bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        return;
611bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
61256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
61356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
61456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
61556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
616bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    final Bundle newResult = new Bundle();
617bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    newResult.putBoolean(AccountManager.KEY_BOOLEAN_RESULT,
618bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                            result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false));
619bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    response.onResult(newResult);
620bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                } catch (RemoteException e) {
621bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
622bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
623bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
624bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    }
625bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                }
626bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana            }
627bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
628bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana
629bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        protected String toDebugString(long now) {
6303084a6f80180506ce26fe4773d9a19f004b7f625Fred Quintana            return super.toDebugString(now) + ", hasFeatures"
631bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + mAccount
632bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
633bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana        }
634bb68a4fc54231e147d91fe3668d1409ccfd81a45Fred Quintana    }
635307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
636ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void removeAccount(IAccountManagerResponse response, Account account) {
63756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
63856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "removeAccount: " + account
63956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
64056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
64156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
64256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
643382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
644382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
645d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
64604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
64726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
648ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache
64904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        cancelNotification(getSigninRequiredNotificationId(accounts, account));
65004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized(accounts.credentialsPermissionNotificationIds) {
651ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache            for (Pair<Pair<Account, String>, Integer> pair:
65204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.credentialsPermissionNotificationIds.keySet()) {
653ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                if (account.equals(pair.first.first)) {
65404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    int id = accounts.credentialsPermissionNotificationIds.get(pair);
655ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                    cancelNotification(id);
656ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache                }
657ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache            }
658ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache        }
659ec0c4f4183630a64c2b2cc8f961dc7e11cc628caCostin Manolache
66026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
66104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new RemoveAccountSession(accounts, response, account).bind();
66226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
66326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
664a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
665603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
666603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
667ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    private class RemoveAccountSession extends Session {
668ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        final Account mAccount;
66904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public RemoveAccountSession(UserAccounts accounts, IAccountManagerResponse response,
67004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                Account account) {
67104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            super(accounts, response, account.type, false /* expectActivityLaunch */,
6728570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
673ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAccount = account;
674ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
675ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
676ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        protected String toDebugString(long now) {
677ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return super.toDebugString(now) + ", removeAccount"
678ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    + ", account " + mAccount;
679ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
680ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
681ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void run() throws RemoteException {
682ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            mAuthenticator.getAccountRemovalAllowed(this, mAccount);
683ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
684ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
685ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        public void onResult(Bundle result) {
686f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && result.containsKey(AccountManager.KEY_BOOLEAN_RESULT)
687f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && !result.containsKey(AccountManager.KEY_INTENT)) {
688f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                final boolean removalAllowed = result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT);
689ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (removalAllowed) {
69004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    removeAccountInternal(mAccounts, mAccount);
691ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
692ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                IAccountManagerResponse response = getResponseAndClose();
693ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                if (response != null) {
69456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
69556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
69656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
69756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
698ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    Bundle result2 = new Bundle();
699f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result2.putBoolean(AccountManager.KEY_BOOLEAN_RESULT, removalAllowed);
700ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    try {
701ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        response.onResult(result2);
702ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    } catch (RemoteException e) {
703ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                        // ignore
704ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    }
705ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                }
706ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
707ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            super.onResult(result);
708ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
709ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
710ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
71104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    /* For testing */
712f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    protected void removeAccountInternal(Account account) {
71304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        removeAccountInternal(getUserAccountsForCaller(), account);
71404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
71504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
71604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void removeAccountInternal(UserAccounts accounts, Account account) {
71704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
71804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
719f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.delete(TABLE_ACCOUNTS, ACCOUNTS_NAME + "=? AND " + ACCOUNTS_TYPE+ "=?",
720f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    new String[]{account.name, account.type});
72104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            removeAccountFromCacheLocked(accounts, account);
72204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            sendAccountsChangedBroadcast(accounts.userId);
723f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        }
724ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
725ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
726a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void invalidateAuthToken(String accountType, String authToken) {
72756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
72856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "invalidateAuthToken: accountType " + accountType
72956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
73056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
73156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
732382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
733382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authToken == null) throw new IllegalArgumentException("authToken is null");
734b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        checkManageAccountsOrUseCredentialsPermissions();
73504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
73626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
737603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
73804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (accounts.cacheLock) {
73904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
740f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.beginTransaction();
741f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                try {
74204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    invalidateAuthTokenLocked(accounts, db, accountType, authToken);
743f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
744f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                } finally {
745f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.endTransaction();
746f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
74726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
748603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
74926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
750603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
751603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
752603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
75304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void invalidateAuthTokenLocked(UserAccounts accounts, SQLiteDatabase db,
75404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String accountType, String authToken) {
755ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        if (authToken == null || accountType == null) {
756ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            return;
757ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
7583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        Cursor cursor = db.rawQuery(
7593326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                "SELECT " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_ID
7603326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_ACCOUNTS + "." + ACCOUNTS_NAME
7613326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + ", " + TABLE_AUTHTOKENS + "." + AUTHTOKENS_TYPE
7623326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " FROM " + TABLE_ACCOUNTS
7633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " JOIN " + TABLE_AUTHTOKENS
7643326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " ON " + TABLE_ACCOUNTS + "." + ACCOUNTS_ID
7653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " = " + AUTHTOKENS_ACCOUNTS_ID
7663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + " WHERE " + AUTHTOKENS_AUTHTOKEN + " = ? AND "
7673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        + TABLE_ACCOUNTS + "." + ACCOUNTS_TYPE + " = ?",
7683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                new String[]{authToken, accountType});
7693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
7703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            while (cursor.moveToNext()) {
7713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                long authTokenId = cursor.getLong(0);
7723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String accountName = cursor.getString(1);
7733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                String authTokenType = cursor.getString(2);
7743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ID + "=" + authTokenId, null);
77504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                writeAuthTokenIntoCacheLocked(accounts, db, new Account(accountName, accountType),
776f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        authTokenType, null);
777603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
7783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
7793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            cursor.close();
780603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
781603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
782603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
78304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private boolean saveAuthTokenToDatabase(UserAccounts accounts, Account account, String type,
78404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String authToken) {
78531957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || type == null) {
78631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return false;
78731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
78804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        cancelNotification(getSigninRequiredNotificationId(accounts, account));
78904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
79004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
791f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
792f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
793f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = getAccountIdLocked(db, account);
794f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId < 0) {
795f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return false;
796f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
797f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.delete(TABLE_AUTHTOKENS,
798f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        AUTHTOKENS_ACCOUNTS_ID + "=" + accountId + " AND " + AUTHTOKENS_TYPE + "=?",
799f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        new String[]{type});
800f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                ContentValues values = new ContentValues();
801f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(AUTHTOKENS_ACCOUNTS_ID, accountId);
802f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(AUTHTOKENS_TYPE, type);
803f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(AUTHTOKENS_AUTHTOKEN, authToken);
804f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (db.insert(TABLE_AUTHTOKENS, AUTHTOKENS_AUTHTOKEN, values) >= 0) {
805f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
80604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    writeAuthTokenIntoCacheLocked(accounts, db, account, type, authToken);
807f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    return true;
808f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
8093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return false;
810f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
811f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
8123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
813603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
814603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
815603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
816a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public String peekAuthToken(Account account, String authTokenType) {
81756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
81856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "peekAuthToken: " + account
81956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
82056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
82156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
82256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
823382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
824382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
825d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
82604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
82726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
82826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
82904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            return readAuthTokenInternal(accounts, account, authTokenType);
83026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
83126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
832603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
833603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
834603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
835a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setAuthToken(Account account, String authTokenType, String authToken) {
83656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
83756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setAuthToken: " + account
83856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
83956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
84056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
84156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
842382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
843382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
844d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
84504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
84626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
84726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
84804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            saveAuthTokenToDatabase(accounts, account, authTokenType, authToken);
84926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
85026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
85126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
852603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
853603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
854a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setPassword(Account account, String password) {
85556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
85656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setAuthToken: " + account
85756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
85856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
85956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
860382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
861d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
86204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
86326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
86426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
86504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            setPasswordInternal(accounts, account, password);
86626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
86726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
86826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
869603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
870603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
87104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void setPasswordInternal(UserAccounts accounts, Account account, String password) {
87231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null) {
87331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
87431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
87504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
87604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
877f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
878f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
879f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                final ContentValues values = new ContentValues();
880f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                values.put(ACCOUNTS_PASSWORD, password);
881f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                final long accountId = getAccountIdLocked(db, account);
882f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId >= 0) {
883f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    final String[] argsAccountId = {String.valueOf(accountId)};
884f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.update(TABLE_ACCOUNTS, values, ACCOUNTS_ID + "=?", argsAccountId);
885f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.delete(TABLE_AUTHTOKENS, AUTHTOKENS_ACCOUNTS_ID + "=?", argsAccountId);
88604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    accounts.authTokenCache.remove(account);
887f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
888f5ffe89e736caee1419f0acb469565d5100b8fb8Costin Manolache                }
889f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
890f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
891d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana            }
89204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            sendAccountsChangedBroadcast(accounts.userId);
893d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana        }
8943ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana    }
8953ecd5f437580e49d80beecd29489d5fb1f7a7db0Fred Quintana
89604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void sendAccountsChangedBroadcast(int userId) {
89756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Log.i(TAG, "the accounts changed, sending broadcast of "
89856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                + ACCOUNTS_CHANGED_INTENT.getAction());
89904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        mContext.sendBroadcast(ACCOUNTS_CHANGED_INTENT, userId);
9003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
9013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
902a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void clearPassword(Account account) {
90356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
90456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "clearPassword: " + account
90556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
90656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
90756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
908382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
909d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
91004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
91126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
91226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
91304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            setPasswordInternal(accounts, account, null);
91426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
91526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
91626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
917603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
918603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
919a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void setUserData(Account account, String key, String value) {
92056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
92156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "setUserData: " + account
92256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", key " + key
92356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
92456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
92556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
926382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (key == null) throw new IllegalArgumentException("key is null");
927382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
928d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkAuthenticateAccountsPermission(account);
92904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
93026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
931603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
93204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            setUserdataInternal(accounts, account, key, value);
933ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
934ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
935ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
936ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
937ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
93804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void setUserdataInternal(UserAccounts accounts, Account account, String key,
93904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String value) {
94031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || key == null) {
94131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
94231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
94304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
94404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
945f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
946f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
947f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = getAccountIdLocked(db, account);
948f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId < 0) {
949ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                    return;
95026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
951f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long extrasId = getExtrasIdLocked(db, accountId, key);
952f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (extrasId < 0 ) {
953f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    extrasId = insertExtraLocked(db, accountId, key, value);
954f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    if (extrasId < 0) {
955f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        return;
956f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
957f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                } else {
958f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    ContentValues values = new ContentValues();
959f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    values.put(EXTRAS_VALUE, value);
960f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    if (1 != db.update(TABLE_EXTRAS, values, EXTRAS_ID + "=" + extrasId, null)) {
961f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        return;
962f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
963ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
964f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
96504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                writeUserDataIntoCacheLocked(accounts, db, account, key, value);
966f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.setTransactionSuccessful();
967f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
968f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
969603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
970603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
971603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
972603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
973d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void onResult(IAccountManagerResponse response, Bundle result) {
97456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (result == null) {
97556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.e(TAG, "the result is unexpectedly null", new Exception());
97656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
97756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
97856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
97956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + response);
98056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
981d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
982d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            response.onResult(result);
983d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (RemoteException e) {
984d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller is dead then there is no one to care about remote
985d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // exceptions
986d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
987d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Log.v(TAG, "failure while notifying response", e);
988d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
989d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
990d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
991d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
992d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    public void getAuthTokenLabel(IAccountManagerResponse response, final String accountType,
993d9640ec712806508877868d08aafaa2d715ff441Fred Quintana                                  final String authTokenType)
994d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            throws RemoteException {
995d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
9965f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
9975f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
998d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        final int callingUid = getCallingUid();
999d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        clearCallingIdentity();
1000d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        if (callingUid != android.os.Process.SYSTEM_UID) {
1001d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            throw new SecurityException("can only call from system");
1002d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        }
1003d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        UserAccounts accounts = getUserAccounts(UserId.getUserId(callingUid));
10045f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        long identityToken = clearCallingIdentity();
10055f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        try {
1006d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            new Session(accounts, response, accountType, false,
10075f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    false /* stripAuthTokenFromResult */) {
10085f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                protected String toDebugString(long now) {
10095f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    return super.toDebugString(now) + ", getAuthTokenLabel"
1010d9640ec712806508877868d08aafaa2d715ff441Fred Quintana                            + ", " + accountType
10115f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                            + ", authTokenType " + authTokenType;
10125f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
10135f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
10145f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                public void run() throws RemoteException {
10155f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    mAuthenticator.getAuthTokenLabel(this, authTokenType);
10165f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
10175f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
10185f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                public void onResult(Bundle result) {
10195f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    if (result != null) {
10205f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        String label = result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL);
10215f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        Bundle bundle = new Bundle();
10225f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        bundle.putString(AccountManager.KEY_AUTH_TOKEN_LABEL, label);
10235f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        super.onResult(bundle);
10245f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        return;
10255f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    } else {
10265f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                        super.onResult(result);
10275f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    }
10285f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                }
10295f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            }.bind();
10305f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        } finally {
10315f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            restoreCallingIdentity(identityToken);
10325f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache        }
10335f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    }
10345f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1035a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void getAuthToken(IAccountManagerResponse response, final Account account,
1036a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean notifyOnAuthFailure,
1037c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache            final boolean expectActivityLaunch, Bundle loginOptionsIn) {
103856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
103956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAuthToken: " + account
104056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
104156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
104256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", notifyOnAuthFailure " + notifyOnAuthFailure
104356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
104456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
104556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
104656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1047382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1048382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1049382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1050d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.USE_CREDENTIALS);
105104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
1052a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
1053a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            mAuthenticatorCache.getServiceInfo(
1054a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                    AuthenticatorDescription.newKey(account.type));
1055a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        final boolean customTokens =
1056a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            authenticatorInfo != null && authenticatorInfo.type.customTokens;
1057a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache
1058a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        // skip the check if customTokens
1059b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        final int callerUid = Binder.getCallingUid();
1060a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        final boolean permissionGranted = customTokens ||
1061a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            permissionIsGranted(account, authTokenType, callerUid);
1062a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache
1063c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache        final Bundle loginOptions = (loginOptionsIn == null) ? new Bundle() :
1064c6684f9e9790e92960504e9b32f20f27003d9f37Costin Manolache            loginOptionsIn;
1065b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        // let authenticator know the identity of the caller
1066b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        loginOptions.putInt(AccountManager.KEY_CALLER_UID, callerUid);
1067b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        loginOptions.putInt(AccountManager.KEY_CALLER_PID, Binder.getCallingPid());
1068b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        if (notifyOnAuthFailure) {
1069b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache            loginOptions.putBoolean(AccountManager.KEY_NOTIFY_ON_FAILURE, true);
1070a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache        }
1071b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache
107226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
107326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
1074d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // if the caller has permission, do the peek. otherwise go the more expensive
1075d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            // route of starting a Session
1076a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache            if (!customTokens && permissionGranted) {
107704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                String authToken = readAuthTokenInternal(accounts, account, authTokenType);
1078d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (authToken != null) {
107926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    Bundle result = new Bundle();
1080f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_AUTHTOKEN, authToken);
1081f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_NAME, account.name);
1082f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putString(AccountManager.KEY_ACCOUNT_TYPE, account.type);
1083d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    onResult(response, result);
1084d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    return;
1085a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1086a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1087603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
108804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, account.type, expectActivityLaunch,
10898570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    false /* stripAuthTokenFromResult */) {
109026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
109126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
109226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", getAuthToken"
109326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
109426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
109526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions
109626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", notifyOnAuthFailure " + notifyOnAuthFailure;
109726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
1098a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
109926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
1100d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // If the caller doesn't have permission then create and return the
1101d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    // "grant permission" intent instead of the "getAuthToken" intent.
1102d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    if (!permissionGranted) {
1103d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthTokenLabel(this, authTokenType);
1104d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    } else {
1105d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mAuthenticator.getAuthToken(this, account, authTokenType, loginOptions);
1106d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    }
110726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
1108a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
110926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void onResult(Bundle result) {
111026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (result != null) {
1111f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        if (result.containsKey(AccountManager.KEY_AUTH_TOKEN_LABEL)) {
1112d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Intent intent = newGrantCredentialsPermissionIntent(account, callerUid,
1113d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    new AccountAuthenticatorResponse(this),
1114d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                                    authTokenType,
1115f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    result.getString(AccountManager.KEY_AUTH_TOKEN_LABEL));
1116d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            Bundle bundle = new Bundle();
1117f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            bundle.putParcelable(AccountManager.KEY_INTENT, intent);
1118d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            onResult(bundle);
1119d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            return;
1120d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        }
1121f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        String authToken = result.getString(AccountManager.KEY_AUTHTOKEN);
112226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        if (authToken != null) {
1123f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String name = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1124f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                            String type = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
112526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            if (TextUtils.isEmpty(type) || TextUtils.isEmpty(name)) {
1126f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
112726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                        "the type and name should not be empty");
112826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                return;
112926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            }
1130a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                            if (!customTokens) {
113104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                                saveAuthTokenToDatabase(mAccounts, new Account(name, type),
1132a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                                        authTokenType, authToken);
1133a40c6304deb860f10a51ce950ac1abc21a23d08bCostin Manolache                            }
1134a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        }
1135603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1136f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        Intent intent = result.getParcelable(AccountManager.KEY_INTENT);
1137d606045070dcf6a011e49a7711d2f17d8f2de8c1Costin Manolache                        if (intent != null && notifyOnAuthFailure && !customTokens) {
113804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                            doNotification(mAccounts,
1139f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                                    account, result.getString(AccountManager.KEY_AUTH_FAILED_MESSAGE),
114026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                                    intent);
114126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                        }
1142a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
114326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    super.onResult(result);
1144a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
114526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
114626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
114726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
114826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1149603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1150603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1151d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void createNoCredentialsPermissionNotification(Account account, Intent intent) {
1152d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        int uid = intent.getIntExtra(
1153d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, -1);
1154d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenType = intent.getStringExtra(
1155d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE);
1156d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        String authTokenLabel = intent.getStringExtra(
1157d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_LABEL);
1158d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1159d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
1160d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                0 /* when */);
1161ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final String titleAndSubtitle =
1162ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                mContext.getString(R.string.permission_request_notification_with_subtitle,
1163ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                account.name);
1164ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer        final int index = titleAndSubtitle.indexOf('\n');
116585e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache        String title = titleAndSubtitle;
116685e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache        String subtitle = "";
116785e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache        if (index > 0) {
116885e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache            title = titleAndSubtitle.substring(0, index);
116985e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache            subtitle = titleAndSubtitle.substring(index + 1);
117085e7279d9cc1ee8e4dd1f993a9e61a9eb547ecbcCostin Manolache        }
1171d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        n.setLatestEventInfo(mContext,
1172ee452ee5359cdfa3c3fbf6783722d3aaa2ec5ca6Eric Fischer                title, subtitle,
1173d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                PendingIntent.getActivity(mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
117456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        installNotification(getCredentialPermissionNotificationId(account, authTokenType, uid), n);
1175d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1176d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
11775f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    String getAccountLabel(String accountType) {
1178d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo =
11795f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            mAuthenticatorCache.getServiceInfo(
11805f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    AuthenticatorDescription.newKey(accountType));
1181d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (serviceInfo == null) {
11825f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            throw new IllegalArgumentException("unknown account type: " + accountType);
1183d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1184d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1185d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final Context authContext;
1186d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        try {
1187d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            authContext = mContext.createPackageContext(
11885f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache                    serviceInfo.type.packageName, 0);
1189d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        } catch (PackageManager.NameNotFoundException e) {
11905f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            throw new IllegalArgumentException("unknown account type: " + accountType);
1191d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
119246703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        try {
119346703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom            return authContext.getString(serviceInfo.type.labelId);
119446703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        } catch (Resources.NotFoundException e) {
119546703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom            throw new IllegalArgumentException("unknown account type: " + accountType);
119646703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        }
11975f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    }
11985f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
11995f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache    private Intent newGrantCredentialsPermissionIntent(Account account, int uid,
12005f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache            AccountAuthenticatorResponse response, String authTokenType, String authTokenLabel) {
1201d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1202d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Intent intent = new Intent(mContext, GrantCredentialsPermissionActivity.class);
120346703b099516c383a6882815bcf9cd4df0ec538dBrian Carlstrom        // See FLAG_ACTIVITY_NEW_TASK docs for limitations and benefits of the flag.
12049ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        // Since it was set in Eclair+ we can't change it without breaking apps using
12059ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        // the intent from a non-Activity context.
12069ec17366c17efd14c643ee88fa1132ab05197349Costin Manolache        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
1207d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.addCategory(
1208d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                String.valueOf(getCredentialPermissionNotificationId(account, authTokenType, uid)));
12095f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1210d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_ACCOUNT, account);
1211d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_AUTH_TOKEN_TYPE, authTokenType);
1212d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_RESPONSE, response);
1213d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        intent.putExtra(GrantCredentialsPermissionActivity.EXTRAS_REQUESTING_UID, uid);
12145f383ad9695a62d6c1aeb97c8e550d7fffe26244Costin Manolache
1215d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return intent;
1216d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1217d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1218d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private Integer getCredentialPermissionNotificationId(Account account, String authTokenType,
1219d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            int uid) {
1220d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
122104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccounts(UserId.getUserId(uid));
122204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.credentialsPermissionNotificationIds) {
1223d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            final Pair<Pair<Account, String>, Integer> key =
1224d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    new Pair<Pair<Account, String>, Integer>(
1225d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            new Pair<Account, String>(account, authTokenType), uid);
122604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            id = accounts.credentialsPermissionNotificationIds.get(key);
1227d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
1228d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
122904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.credentialsPermissionNotificationIds.put(key, id);
1230d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1231d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1232d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
1233d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1234d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
123504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private Integer getSigninRequiredNotificationId(UserAccounts accounts, Account account) {
1236d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        Integer id;
123704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.signinRequiredNotificationIds) {
123804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            id = accounts.signinRequiredNotificationIds.get(account);
1239d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (id == null) {
1240d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                id = mNotificationIds.incrementAndGet();
124104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.signinRequiredNotificationIds.put(account, id);
1242d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1243d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1244d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return id;
1245d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
1246d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
12473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    public void addAcount(final IAccountManagerResponse response, final String accountType,
12483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            final String authTokenType, final String[] requiredFeatures,
1249b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache            final boolean expectActivityLaunch, final Bundle optionsIn) {
125056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
125156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "addAccount: accountType " + accountType
125256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
125356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
125456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", requiredFeatures " + stringArrayToString(requiredFeatures)
125556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
125656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
125756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
125856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1259382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1260382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
1261d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
1262b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache
126304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
1264b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        final int pid = Binder.getCallingPid();
1265b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        final int uid = Binder.getCallingUid();
1266b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        final Bundle options = (optionsIn == null) ? new Bundle() : optionsIn;
1267b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        options.putInt(AccountManager.KEY_CALLER_UID, uid);
1268b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache        options.putInt(AccountManager.KEY_CALLER_PID, pid);
1269b61e8fbabea2cc40ad65bf4f372a32d526cfc7acCostin Manolache
127026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
127126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
127204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, accountType, expectActivityLaunch,
12738570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
127426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
12753348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                    mAuthenticator.addAccount(this, mAccountType, authTokenType, requiredFeatures,
12763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            options);
127726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
1278a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
127926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
128026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", addAccount"
12813326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", accountType " + accountType
12823326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + ", requiredFeatures "
12833326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                            + (requiredFeatures != null
12843326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              ? TextUtils.join(",", requiredFeatures)
12853326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                              : null);
128626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
128726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
128826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
128926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
129026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1291603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1292603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1293a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void confirmCredentials(IAccountManagerResponse response,
1294f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            final Account account, final Bundle options, final boolean expectActivityLaunch) {
129556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
129656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "confirmCredentials: " + account
129756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
129856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
129956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
130056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
130156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1302382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1303382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1304d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
130504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
130626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
130726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
130804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, account.type, expectActivityLaunch,
13098570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
131026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
1311f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    mAuthenticator.confirmCredentials(this, account, options);
131226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
131326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
131426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", confirmCredentials"
131526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account;
131626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
131726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
131826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
131926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
132026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1321603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1322603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1323a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void updateCredentials(IAccountManagerResponse response, final Account account,
1324a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final String authTokenType, final boolean expectActivityLaunch,
1325a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final Bundle loginOptions) {
132656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
132756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "updateCredentials: " + account
132856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
132956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", authTokenType " + authTokenType
133056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
133156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
133256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
133356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1334382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1335382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null) throw new IllegalArgumentException("account is null");
1336382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (authTokenType == null) throw new IllegalArgumentException("authTokenType is null");
1337d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
133804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
133926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
134026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
134104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, account.type, expectActivityLaunch,
13428570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
134326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
134426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.updateCredentials(this, account, authTokenType, loginOptions);
134526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
134626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
134726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    if (loginOptions != null) loginOptions.keySet();
134826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", updateCredentials"
134926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", " + account
135026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", authTokenType " + authTokenType
135126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", loginOptions " + loginOptions;
135226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
135326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
135426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
135526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
135626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1357603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1358603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1359a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    public void editProperties(IAccountManagerResponse response, final String accountType,
1360a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            final boolean expectActivityLaunch) {
136156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
136256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "editProperties: accountType " + accountType
136356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
136456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", expectActivityLaunch " + expectActivityLaunch
136556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
136656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
136756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1368382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1369382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (accountType == null) throw new IllegalArgumentException("accountType is null");
1370d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkManageAccountsPermission();
137104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
137226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
137326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
137404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new Session(accounts, response, accountType, expectActivityLaunch,
13758570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */) {
137626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                public void run() throws RemoteException {
137726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    mAuthenticator.editProperties(this, mAccountType);
137826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
137926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                protected String toDebugString(long now) {
138026fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                    return super.toDebugString(now) + ", editProperties"
138126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                            + ", accountType " + accountType;
138226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                }
138326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }.bind();
138426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
138526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
138626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
1387603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1388603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
13893326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    private class GetAccountsByTypeAndFeatureSession extends Session {
13903326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private final String[] mFeatures;
13913326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile Account[] mAccountsOfType = null;
13923326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile ArrayList<Account> mAccountsWithFeatures = null;
13933326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        private volatile int mCurrentAccount = 0;
13943326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
139504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public GetAccountsByTypeAndFeatureSession(UserAccounts accounts,
139604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                IAccountManagerResponse response, String type, String[] features) {
139704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            super(accounts, response, type, false /* expectActivityLaunch */,
13988570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                    true /* stripAuthTokenFromResult */);
13993326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mFeatures = features;
14003326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14013326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14023326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void run() throws RemoteException {
140304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (mAccounts.cacheLock) {
140404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                mAccountsOfType = getAccountsFromCacheLocked(mAccounts, mAccountType);
1405f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
14063326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            // check whether each account matches the requested features
14073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mAccountsWithFeatures = new ArrayList<Account>(mAccountsOfType.length);
14083326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount = 0;
14093326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14103326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
14113326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14123326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14133326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void checkAccount() {
14143326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (mCurrentAccount >= mAccountsOfType.length) {
14153326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                sendResult();
14163326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
14173326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
14183326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
141929e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            final IAccountAuthenticator accountAuthenticator = mAuthenticator;
142029e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            if (accountAuthenticator == null) {
142129e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // It is possible that the authenticator has died, which is indicated by
142229e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // mAuthenticator being set to null. If this happens then just abort.
142329e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // There is no need to send back a result or error in this case since
142429e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                // that already happened when mAuthenticator was cleared.
142529e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
142629e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                    Log.v(TAG, "checkAccount: aborting session since we are no longer"
142729e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                            + " connected to the authenticator, " + toDebugString());
142829e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                }
142929e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                return;
143029e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana            }
14313326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            try {
143229e94b81c7e145a5cb21f8c862e8d05b077b3548Fred Quintana                accountAuthenticator.hasFeatures(this, mAccountsOfType[mCurrentAccount], mFeatures);
14333326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            } catch (RemoteException e) {
1434f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "remote exception");
1435a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1436603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1437603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
14383326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void onResult(Bundle result) {
14393326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mNumResults++;
14403326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (result == null) {
1441f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_INVALID_RESPONSE, "null bundle");
14423326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                return;
14433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
1444f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result.getBoolean(AccountManager.KEY_BOOLEAN_RESULT, false)) {
14453326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                mAccountsWithFeatures.add(mAccountsOfType[mCurrentAccount]);
14463326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
14473326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            mCurrentAccount++;
14483326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            checkAccount();
1449a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
14503326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14513326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public void sendResult() {
14523326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
14533326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (response != null) {
14543326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                try {
14553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Account[] accounts = new Account[mAccountsWithFeatures.size()];
14563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    for (int i = 0; i < accounts.length; i++) {
14573326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        accounts[i] = mAccountsWithFeatures.get(i);
14583326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
145956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
146056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        Log.v(TAG, getClass().getSimpleName() + " calling onResult() on response "
146156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                + response);
146256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    }
14633326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    Bundle result = new Bundle();
1464f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
14653326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    response.onResult(result);
14663326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                } catch (RemoteException e) {
14673326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
14683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
14693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
14703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    }
14713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                }
14723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            }
14733326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14743326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14753326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
14763326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        protected String toDebugString(long now) {
14773326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            return super.toDebugString(now) + ", getAccountsByTypeAndFeatures"
14783326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana                    + ", " + (mFeatures != null ? TextUtils.join(",", mFeatures) : null);
14793326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
14803326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
1481ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
148204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    /**
148304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani     * Returns the accounts for a specific user
148404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani     * @hide
148504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani     */
148604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    public Account[] getAccounts(int userId) {
148704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        checkReadAccountsPermission();
148804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccounts(userId);
148904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        long identityToken = clearCallingIdentity();
149004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        try {
149104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (accounts.cacheLock) {
149204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                return getAccountsFromCacheLocked(accounts, null);
149304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
149404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        } finally {
149504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            restoreCallingIdentity(identityToken);
149604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
149704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
149804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani
1499f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani    /**
1500f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani     * Returns all the accounts qualified by user.
1501f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani     * @hide
1502f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani     */
1503f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani    public AccountAndUser[] getAllAccounts() {
1504f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani        ArrayList<AccountAndUser> allAccounts = new ArrayList<AccountAndUser>();
1505f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani        List<UserInfo> users = getAllUsers();
1506f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani        if (users == null)  return new AccountAndUser[0];
1507f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani
1508f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani        synchronized(mUsers) {
1509f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani            for (UserInfo user : users) {
1510f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                UserAccounts userAccounts = getUserAccounts(user.id);
1511f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                if (userAccounts == null) continue;
1512f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                synchronized (userAccounts.cacheLock) {
1513f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                    Account[] accounts = getAccountsFromCacheLocked(userAccounts, null);
1514f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                    for (int a = 0; a < accounts.length; a++) {
1515f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                        allAccounts.add(new AccountAndUser(accounts[a], user.id));
1516f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                    }
1517f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani                }
1518f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani            }
1519f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani        }
1520f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani        AccountAndUser[] accountsArray = new AccountAndUser[allAccounts.size()];
1521f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani        return allAccounts.toArray(accountsArray);
1522f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani    }
1523f29f2369cf4e1de090c985ed53d3f5e59535986aAmith Yamasani
1524ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public Account[] getAccounts(String type) {
152556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
152656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAccounts: accountType " + type
152756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
152856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
152956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1530ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        checkReadAccountsPermission();
153104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
1532ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        long identityToken = clearCallingIdentity();
1533ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        try {
153404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            synchronized (accounts.cacheLock) {
153504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                return getAccountsFromCacheLocked(accounts, type);
1536f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
1537ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        } finally {
1538ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            restoreCallingIdentity(identityToken);
1539ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana        }
1540ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    }
1541ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana
1542ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana    public void getAccountsByFeatures(IAccountManagerResponse response,
15433326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            String type, String[] features) {
154456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
154556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            Log.v(TAG, "getAccounts: accountType " + type
154656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", response " + response
154756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", features " + stringArrayToString(features)
154856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", caller's uid " + Binder.getCallingUid()
154956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + ", pid " + Binder.getCallingPid());
155056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
1551382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (response == null) throw new IllegalArgumentException("response is null");
1552382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (type == null) throw new IllegalArgumentException("accountType is null");
1553d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkReadAccountsPermission();
155404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts userAccounts = getUserAccountsForCaller();
15553326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        long identityToken = clearCallingIdentity();
15563326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        try {
1557ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            if (features == null || features.length == 0) {
1558f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                Account[] accounts;
155904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                synchronized (userAccounts.cacheLock) {
156004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    accounts = getAccountsFromCacheLocked(userAccounts, type);
1561f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
1562d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                Bundle result = new Bundle();
1563d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                result.putParcelableArray(AccountManager.KEY_ACCOUNTS, accounts);
1564d4a9d6c42bb412e27a8383aaacd051419d98a662Fred Quintana                onResult(response, result);
1565ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return;
1566ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana            }
156704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            new GetAccountsByTypeAndFeatureSession(userAccounts, response, type, features).bind();
15683326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        } finally {
15693326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            restoreCallingIdentity(identityToken);
15703326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        }
15713326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana    }
15723326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana
1573f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    private long getAccountIdLocked(SQLiteDatabase db, Account account) {
1574603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_ACCOUNTS, new String[]{ACCOUNTS_ID},
1575ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                "name=? AND type=?", new String[]{account.name, account.type}, null, null, null);
1576603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1577603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1578603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1579603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1580603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1581603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1582603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1583603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1584603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1585603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1586f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    private long getExtrasIdLocked(SQLiteDatabase db, long accountId, String key) {
1587603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        Cursor cursor = db.query(TABLE_EXTRAS, new String[]{EXTRAS_ID},
1588603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                EXTRAS_ACCOUNTS_ID + "=" + accountId + " AND " + EXTRAS_KEY + "=?",
1589603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                new String[]{key}, null, null, null);
1590603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        try {
1591603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (cursor.moveToNext()) {
1592603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return cursor.getLong(0);
1593603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1594603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            return -1;
1595603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        } finally {
1596603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cursor.close();
1597603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1598603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1599603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1600a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    private abstract class Session extends IAccountAuthenticatorResponse.Stub
1601b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            implements IBinder.DeathRecipient, ServiceConnection {
1602603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountManagerResponse mResponse;
1603603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        final String mAccountType;
1604a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final boolean mExpectActivityLaunch;
1605a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        final long mCreationTime;
1606a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
16073326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana        public int mNumResults = 0;
1608a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumRequestContinued = 0;
1609a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private int mNumErrors = 0;
1610a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1611603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1612603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        IAccountAuthenticator mAuthenticator = null;
1613603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
16148570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana        private final boolean mStripAuthTokenFromResult;
161504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        protected final UserAccounts mAccounts;
16168570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana
161704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public Session(UserAccounts accounts, IAccountManagerResponse response, String accountType,
16188570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                boolean expectActivityLaunch, boolean stripAuthTokenFromResult) {
1619603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super();
1620a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response == null) throw new IllegalArgumentException("response is null");
16213326920329cecb57c7ff1fc5c6add5c98aab9ed9Fred Quintana            if (accountType == null) throw new IllegalArgumentException("accountType is null");
162204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            mAccounts = accounts;
16238570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana            mStripAuthTokenFromResult = stripAuthTokenFromResult;
1624603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = response;
1625603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAccountType = accountType;
1626a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mExpectActivityLaunch = expectActivityLaunch;
1627a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mCreationTime = SystemClock.elapsedRealtime();
1628a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1629a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mSessions.put(toString(), this);
1630a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1631a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1632a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response.asBinder().linkToDeath(this, 0 /* flags */);
1633a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1634a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1635a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                binderDied();
1636a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1637603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1638603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1639a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        IAccountManagerResponse getResponseAndClose() {
1640603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mResponse == null) {
1641603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                // this session has already been closed
1642603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                return null;
1643603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1644a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = mResponse;
1645a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close(); // this clears mResponse so we need to save the response before this call
1646a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return response;
1647a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1648a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1649a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        private void close() {
1650a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            synchronized (mSessions) {
1651a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (mSessions.remove(toString()) == null) {
1652a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // the session was already closed, so bail out now
1653a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    return;
1654a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1655a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1656a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mResponse != null) {
1657a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // stop listening for response deaths
1658a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse.asBinder().unlinkToDeath(this, 0 /* flags */);
1659a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1660a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                // clear this so that we don't accidentally send any further results
1661a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                mResponse = null;
1662a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1663603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            cancelTimeout();
1664603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            unbind();
1665a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1666a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1667a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void binderDied() {
1668603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mResponse = null;
1669a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            close();
1670a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1671a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1672a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString() {
1673a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return toDebugString(SystemClock.elapsedRealtime());
1674a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
1675a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1676a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        protected String toDebugString(long now) {
1677a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            return "Session: expectLaunch " + mExpectActivityLaunch
1678a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", connected " + (mAuthenticator != null)
1679a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", stats (" + mNumResults + "/" + mNumRequestContinued
1680a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "/" + mNumErrors + ")"
1681a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + ", lifetime " + ((now - mCreationTime) / 1000.0);
1682603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1683603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1684603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        void bind() {
1685a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1686a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
1687a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1688b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (!bindToAuthenticator(mAccountType)) {
1689a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                Log.d(TAG, "bind attempt failed for " + toDebugString());
1690f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
1691603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1692603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1693603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1694603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        private void unbind() {
1695603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (mAuthenticator != null) {
1696603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                mAuthenticator = null;
1697b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                mContext.unbindService(this);
1698603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1699603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1700603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1701603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void scheduleTimeout() {
1702603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.sendMessageDelayed(
1703603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    mMessageHandler.obtainMessage(MESSAGE_TIMED_OUT, this), TIMEOUT_DELAY_MS);
1704603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1705603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1706603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void cancelTimeout() {
1707603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
1708603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1709603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1710b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceConnected(ComponentName name, IBinder service) {
1711603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
1712a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            try {
1713a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                run();
1714a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } catch (RemoteException e) {
1715f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1716a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        "remote exception");
1717a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
1718603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1719603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1720b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public void onServiceDisconnected(ComponentName name) {
1721a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mAuthenticator = null;
1722a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1723603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1724166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                try {
1725166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1726166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                            "disconnected");
1727166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                } catch (RemoteException e) {
1728166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1729166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                        Log.v(TAG, "Session.onServiceDisconnected: "
1730166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                                + "caught RemoteException while responding", e);
1731166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    }
1732166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                }
1733603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1734603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1735603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1736b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        public abstract void run() throws RemoteException;
1737b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1738603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onTimedOut() {
1739a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1740603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1741166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                try {
1742166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    response.onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION,
1743166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                            "timeout");
1744166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                } catch (RemoteException e) {
1745166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1746166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                        Log.v(TAG, "Session.onTimedOut: caught RemoteException while responding",
1747166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                                e);
1748166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                    }
1749166466d483cc3d57e7d3d465fd92ce62409c8455Fred Quintana                }
1750603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1751603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1752603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1753a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onResult(Bundle result) {
1754a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumResults++;
1755f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana            if (result != null && !TextUtils.isEmpty(result.getString(AccountManager.KEY_AUTHTOKEN))) {
1756f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountName = result.getString(AccountManager.KEY_ACCOUNT_NAME);
1757f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                String accountType = result.getString(AccountManager.KEY_ACCOUNT_TYPE);
1758d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                if (!TextUtils.isEmpty(accountName) && !TextUtils.isEmpty(accountType)) {
1759d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    Account account = new Account(accountName, accountType);
176004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                    cancelNotification(getSigninRequiredNotificationId(mAccounts, account));
1761d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                }
1762603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1763a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response;
1764a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (mExpectActivityLaunch && result != null
1765f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                    && result.containsKey(AccountManager.KEY_INTENT)) {
1766a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = mResponse;
1767a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1768a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                response = getResponseAndClose();
1769603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1770603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (response != null) {
1771603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                try {
1772a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (result == null) {
177356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
177456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            Log.v(TAG, getClass().getSimpleName()
177556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                    + " calling onError() on response " + response);
177656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
1777f7ae77cd67f1a3993b8e56c1af4720a7adf4e69dFred Quintana                        response.onError(AccountManager.ERROR_CODE_INVALID_RESPONSE,
1778a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                                "null bundle returned");
1779a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    } else {
17808570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        if (mStripAuthTokenFromResult) {
17818570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                            result.remove(AccountManager.KEY_AUTHTOKEN);
17828570f7440780db5c9b410e033e843b0e80e2fd27Fred Quintana                        }
178356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        if (Log.isLoggable(TAG, Log.VERBOSE)) {
178456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            Log.v(TAG, getClass().getSimpleName()
178556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                                    + " calling onResult() on response " + response);
178656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        }
1787a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        response.onResult(result);
1788a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1789603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                } catch (RemoteException e) {
1790a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    // if the caller is dead then there is no one to care about remote exceptions
1791a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1792a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "failure while notifying response", e);
1793a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1794603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                }
1795603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1796603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1797603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1798a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        public void onRequestContinued() {
1799a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumRequestContinued++;
1800603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1801603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1802603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onError(int errorCode, String errorMessage) {
1803a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            mNumErrors++;
1804a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            IAccountManagerResponse response = getResponseAndClose();
1805a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (response != null) {
1806a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
180756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    Log.v(TAG, getClass().getSimpleName()
180856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                            + " calling onError() on response " + response);
1809a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1810a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                try {
1811a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    response.onError(errorCode, errorMessage);
1812a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                } catch (RemoteException e) {
1813a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    if (Log.isLoggable(TAG, Log.VERBOSE)) {
1814a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                        Log.v(TAG, "Session.onError: caught RemoteException while responding", e);
1815a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    }
1816a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1817a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            } else {
1818a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1819a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    Log.v(TAG, "Session.onError: already closed");
1820a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                }
1821603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1822603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1823b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1824b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        /**
1825b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * find the component name for the authenticator and initiate a bind
1826b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         * if no authenticator or the bind fails then return false, otherwise return true
1827b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana         */
1828b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        private boolean bindToAuthenticator(String authenticatorType) {
1829b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
1830b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    mAuthenticatorCache.getServiceInfo(
1831b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            AuthenticatorDescription.newKey(authenticatorType));
1832b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (authenticatorInfo == null) {
1833b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1834b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "there is no authenticator for " + authenticatorType
1835b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                            + ", bailing out");
1836b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1837b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1838b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1839b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1840b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            Intent intent = new Intent();
1841b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
1842b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            intent.setComponent(authenticatorInfo.componentName);
1843b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
1844b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
1845b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
184634daa75260c9aebe791819ff6134b4c47146c5c0Amith Yamasani            if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE, mAccounts.userId)) {
1847b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
1848b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                    Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
1849b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                }
1850b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana                return false;
1851b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            }
1852b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1853b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana
1854b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana            return true;
1855b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        }
1856603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1857603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1858603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    private class MessageHandler extends Handler {
1859603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        MessageHandler(Looper looper) {
1860603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            super(looper);
1861603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
18623348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
1863603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void handleMessage(Message msg) {
1864603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            switch (msg.what) {
1865603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                case MESSAGE_TIMED_OUT:
1866603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    Session session = (Session)msg.obj;
1867603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    session.onTimedOut();
1868603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    break;
1869603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1870603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                default:
1871603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    throw new IllegalStateException("unhandled message: " + msg.what);
1872603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            }
1873603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1874603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1875603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
187604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private static String getDatabaseName(int userId) {
187704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        File systemDir = Environment.getSystemSecureDirectory();
187804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        File databaseFile = new File(systemDir, "users/" + userId + "/" + DATABASE_NAME);
187904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        if (userId == 0) {
1880a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            // Migrate old file, if it exists, to the new location.
1881a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            // Make sure the new file doesn't already exist. A dummy file could have been
1882a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            // accidentally created in the old location, causing the new one to become corrupted
1883a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            // as well.
188404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            File oldFile = new File(systemDir, DATABASE_NAME);
1885a23bb38628ac1f5dc4ebe6847faedc424dd5fce1Amith Yamasani            if (oldFile.exists() && !databaseFile.exists()) {
1886c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                // Check for use directory; create if it doesn't exist, else renameTo will fail
1887c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                File userDir = new File(systemDir, "users/" + userId);
1888c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                if (!userDir.exists()) {
1889c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                    if (!userDir.mkdirs()) {
1890c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                        throw new IllegalStateException("User dir cannot be created: " + userDir);
1891c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                    }
1892c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                }
1893c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                if (!oldFile.renameTo(databaseFile)) {
1894c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                    throw new IllegalStateException("User dir cannot be migrated: " + databaseFile);
1895c6b0f99bb31405902b40a96f6491a9adcaaac169Marc Blank                }
189604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
1897a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor        }
189804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        return databaseFile.getPath();
1899a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor    }
1900a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
190104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    static class DatabaseHelper extends SQLiteOpenHelper {
1902a8529f68671a8a118751cb6ad577f44eaf076b96Oscar Montemayor
190304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        public DatabaseHelper(Context context, int userId) {
190404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            super(context, AccountManagerService.getDatabaseName(userId), null, DATABASE_VERSION);
1905603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1906603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1907f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        /**
1908f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana         * This call needs to be made while the mCacheLock is held. The way to
1909f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana         * ensure this is to get the lock any time a method is called ont the DatabaseHelper
1910f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana         * @param db The database.
1911f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana         */
1912603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1913603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onCreate(SQLiteDatabase db) {
1914603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_ACCOUNTS + " ( "
1915603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1916603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_NAME + " TEXT NOT NULL, "
1917603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_TYPE + " TEXT NOT NULL, "
1918603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + ACCOUNTS_PASSWORD + " TEXT, "
1919603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + ACCOUNTS_NAME + "," + ACCOUNTS_TYPE + "))");
1920603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1921603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_AUTHTOKENS + " (  "
1922603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT,  "
1923603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1924603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_TYPE + " TEXT NOT NULL,  "
1925603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + AUTHTOKENS_AUTHTOKEN + " TEXT,  "
1926603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE (" + AUTHTOKENS_ACCOUNTS_ID + "," + AUTHTOKENS_TYPE + "))");
1927603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1928d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createGrantsTable(db);
1929d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1930603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_EXTRAS + " ( "
1931603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, "
1932603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_ACCOUNTS_ID + " INTEGER, "
1933603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_KEY + " TEXT NOT NULL, "
1934603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + EXTRAS_VALUE + " TEXT, "
1935603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + "UNIQUE(" + EXTRAS_ACCOUNTS_ID + "," + EXTRAS_KEY + "))");
1936603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1937603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            db.execSQL("CREATE TABLE " + TABLE_META + " ( "
1938603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_KEY + " TEXT PRIMARY KEY NOT NULL, "
1939603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana                    + META_VALUE + " TEXT)");
1940a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
1941d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            createAccountsDeletionTrigger(db);
1942d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1943d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1944d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createAccountsDeletionTrigger(SQLiteDatabase db) {
1945a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            db.execSQL(""
1946a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " CREATE TRIGGER " + TABLE_ACCOUNTS + "Delete DELETE ON " + TABLE_ACCOUNTS
1947a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " BEGIN"
1948a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_AUTHTOKENS
1949a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + AUTHTOKENS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1950a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "   DELETE FROM " + TABLE_EXTRAS
1951a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + "     WHERE " + EXTRAS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1952d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "   DELETE FROM " + TABLE_GRANTS
1953d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "     WHERE " + GRANTS_ACCOUNTS_ID + "=OLD." + ACCOUNTS_ID + " ;"
1954a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                    + " END");
1955603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1956603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1957d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        private void createGrantsTable(SQLiteDatabase db) {
1958d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            db.execSQL("CREATE TABLE " + TABLE_GRANTS + " (  "
1959d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_ACCOUNTS_ID + " INTEGER NOT NULL, "
1960d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_AUTH_TOKEN_TYPE + " STRING NOT NULL,  "
1961d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + GRANTS_GRANTEE_UID + " INTEGER NOT NULL,  "
1962d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + "UNIQUE (" + GRANTS_ACCOUNTS_ID + "," + GRANTS_AUTH_TOKEN_TYPE
1963d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    +   "," + GRANTS_GRANTEE_UID + "))");
1964d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
1965d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1966603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1967603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
1968a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            Log.e(TAG, "upgrade from version " + oldVersion + " to version " + newVersion);
1969603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1970a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            if (oldVersion == 1) {
1971d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // no longer need to do anything since the work is done
1972d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                // when upgrading from version 2
1973d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                oldVersion++;
1974d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
1975d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
1976d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (oldVersion == 2) {
1977d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createGrantsTable(db);
1978d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                db.execSQL("DROP TRIGGER " + TABLE_ACCOUNTS + "Delete");
1979d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createAccountsDeletionTrigger(db);
1980a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana                oldVersion++;
1981a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
19823348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache
19833348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            if (oldVersion == 3) {
19843348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                db.execSQL("UPDATE " + TABLE_ACCOUNTS + " SET " + ACCOUNTS_TYPE +
19853348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                        " = 'com.google' WHERE " + ACCOUNTS_TYPE + " == 'com.google.GAIA'");
19863348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache                oldVersion++;
19873348f14b3d46b172a5b557f81aac526b7e8bf5fbCostin Manolache            }
1988603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1989603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1990603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        @Override
1991603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        public void onOpen(SQLiteDatabase db) {
1992603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) Log.v(TAG, "opened database " + DATABASE_NAME);
1993603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        }
1994603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1995603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana
1996603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    public IBinder onBind(Intent intent) {
1997603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana        return asBinder();
1998603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana    }
1999a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
20001cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    /**
20011cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * Searches array of arguments for the specified string
20021cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param args array of argument strings
20031cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @param value value to search for
20041cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     * @return true if the value is contained in the array
20051cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks     */
20061cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    private static boolean scanArgs(String[] args, String value) {
20071cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        if (args != null) {
20081cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks            for (String arg : args) {
20091cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                if (value.equals(arg)) {
20101cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                    return true;
20111cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
2012a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana            }
2013a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana        }
20141cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        return false;
20151cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    }
2016a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
20171cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks    protected void dump(FileDescriptor fd, PrintWriter fout, String[] args) {
20183abd75ba3a981850cac43a401d0014a836559cb0Kenny Root        if (mContext.checkCallingOrSelfPermission(android.Manifest.permission.DUMP)
20193abd75ba3a981850cac43a401d0014a836559cb0Kenny Root                != PackageManager.PERMISSION_GRANTED) {
20203abd75ba3a981850cac43a401d0014a836559cb0Kenny Root            fout.println("Permission Denial: can't dump AccountsManager from from pid="
20213abd75ba3a981850cac43a401d0014a836559cb0Kenny Root                    + Binder.getCallingPid() + ", uid=" + Binder.getCallingUid()
20223abd75ba3a981850cac43a401d0014a836559cb0Kenny Root                    + " without permission " + android.Manifest.permission.DUMP);
20233abd75ba3a981850cac43a401d0014a836559cb0Kenny Root            return;
20243abd75ba3a981850cac43a401d0014a836559cb0Kenny Root        }
202504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        final boolean isCheckinRequest = scanArgs(args, "--checkin") || scanArgs(args, "-c");
20263abd75ba3a981850cac43a401d0014a836559cb0Kenny Root
202704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        fout = new IndentingPrintWriter(fout, "  ");
202804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        int size = mUsers.size();
202904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        for (int i = 0; i < size; i++) {
203004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            fout.println("User " + mUsers.keyAt(i) + ":");
203104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            ((IndentingPrintWriter) fout).increaseIndent();
203204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            dumpUser(mUsers.valueAt(i), fd, fout, args, isCheckinRequest);
203304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            ((IndentingPrintWriter) fout).decreaseIndent();
203404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            if (i < size - 1) {
203504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                fout.println();
203604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            }
203704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        }
203804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    }
20391cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
204004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void dumpUser(UserAccounts userAccounts, FileDescriptor fd, PrintWriter fout,
204104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String[] args, boolean isCheckinRequest) {
204204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (userAccounts.cacheLock) {
204304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = userAccounts.openHelper.getReadableDatabase();
2044a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
2045f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (isCheckinRequest) {
2046f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                // This is a checkin request. *Only* upload the account types and the count of each.
2047f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                Cursor cursor = db.query(TABLE_ACCOUNTS, ACCOUNT_TYPE_COUNT_PROJECTION,
2048f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        null, null, ACCOUNTS_TYPE, null, null);
2049f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                try {
2050f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    while (cursor.moveToNext()) {
2051f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        // print type,count
2052f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        fout.println(cursor.getString(0) + "," + cursor.getString(1));
2053f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
2054f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                } finally {
2055f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    if (cursor != null) {
2056f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        cursor.close();
2057f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
20581cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
2059f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } else {
206004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                Account[] accounts = getAccountsFromCacheLocked(userAccounts, null /* type */);
2061f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                fout.println("Accounts: " + accounts.length);
2062f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                for (Account account : accounts) {
2063f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    fout.println("  " + account);
20641cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
2065307da1a46b4c9b711bafe8fbaaa6b98e8868c18eFred Quintana
2066f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                fout.println();
2067f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                synchronized (mSessions) {
2068f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    final long now = SystemClock.elapsedRealtime();
2069f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    fout.println("Active Sessions: " + mSessions.size());
2070f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    for (Session session : mSessions.values()) {
2071f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        fout.println("  " + session.toDebugString(now));
2072f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    }
20731cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks                }
20741cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks
2075f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                fout.println();
2076f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                mAuthenticatorCache.dump(fd, fout, args);
2077f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
20781cd7d0e591b61a1e5d0be4073e9b9f976279cc84Jason Parks        }
2079a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
2080a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
208104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void doNotification(UserAccounts accounts, Account account, CharSequence message,
208204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            Intent intent) {
208326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
208426fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
208526fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            if (Log.isLoggable(TAG, Log.VERBOSE)) {
208626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana                Log.v(TAG, "doNotification: " + message + " intent:" + intent);
208726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            }
2088a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
2089d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (intent.getComponent() != null &&
2090d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    GrantCredentialsPermissionActivity.class.getName().equals(
2091d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                            intent.getComponent().getClassName())) {
2092d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                createNoCredentialsPermissionNotification(account, intent);
2093d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            } else {
209404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                final Integer notificationId = getSigninRequiredNotificationId(accounts, account);
209533f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                intent.addCategory(String.valueOf(notificationId));
2096d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                Notification n = new Notification(android.R.drawable.stat_sys_warning, null,
2097d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        0 /* when */);
209833f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                final String notificationTitleFormat =
209933f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        mContext.getText(R.string.notification_title).toString();
210033f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                n.setLatestEventInfo(mContext,
210133f889ae270f888f8fdc084f5f1f3d443532a46aFred Quintana                        String.format(notificationTitleFormat, account.name),
2102d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        message, PendingIntent.getActivity(
2103d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                        mContext, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT));
210456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                installNotification(notificationId, n);
2105d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
210626fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
210726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
210826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
2109a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
2110a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana
211156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected void installNotification(final int notificationId, final Notification n) {
211256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
211356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                .notify(notificationId, n);
211456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
211556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
211656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    protected void cancelNotification(int id) {
211726fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        long identityToken = clearCallingIdentity();
211826fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        try {
211926fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            ((NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE))
2120d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                .cancel(id);
212126fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        } finally {
212226fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana            restoreCallingIdentity(identityToken);
212326fc5eba506bf29f7f5343e836484a43702c8deaFred Quintana        }
2124a698f4276968d078b1b9e2f3738c4f559a3307b2Fred Quintana    }
2125d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2126b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    /** Succeeds if any of the specified permissions are granted. */
2127b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    private void checkBinderPermission(String... permissions) {
2128d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
2129b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
2130b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        for (String perm : permissions) {
2131b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana            if (mContext.checkCallingOrSelfPermission(perm) == PackageManager.PERMISSION_GRANTED) {
2132b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                if (Log.isLoggable(TAG, Log.VERBOSE)) {
213356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    Log.v(TAG, "  caller uid " + uid + " has " + perm);
2134b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                }
2135b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                return;
2136b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana            }
2137d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2138b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
2139b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        String msg = "caller uid " + uid + " lacks any of " + TextUtils.join(",", permissions);
214056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Log.w(TAG, "  " + msg);
2141b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        throw new SecurityException(msg);
2142d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2143d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
21447be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    private boolean inSystemImage(int callerUid) {
214556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        String[] packages = mPackageManager.getPackagesForUid(callerUid);
21467be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        for (String name : packages) {
21477be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            try {
214856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                PackageInfo packageInfo = mPackageManager.getPackageInfo(name, 0 /* flags */);
214956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                if (packageInfo != null
215056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        && (packageInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0) {
21517be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                    return true;
21527be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                }
21537be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            } catch (PackageManager.NameNotFoundException e) {
21547be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana                return false;
21557be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana            }
21567be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        }
21577be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana        return false;
21587be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana    }
21597be5964e74978ebc7d5fd24562de5738d31cf009Fred Quintana
2160d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
2161b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        final boolean inSystemImage = inSystemImage(callerUid);
216231957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean fromAuthenticator = account != null
216331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana                && hasAuthenticatorUid(account.type, callerUid);
216431957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        final boolean hasExplicitGrants = account != null
216504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                && hasExplicitlyGrantedPermission(account, authTokenType, callerUid);
2166d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2167d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
216856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                    + callerUid + ", " + account
2169d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ": is authenticator? " + fromAuthenticator
2170d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                    + ", has explicit permission? " + hasExplicitGrants);
2171d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2172b839afc33ea4a7b549b6dd703e5c48858ce877d0Fred Quintana        return fromAuthenticator || hasExplicitGrants || inSystemImage;
2173d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2174d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
21751a23191bbde11505d6e0c25c04a60b41cb27fd31Fred Quintana    private boolean hasAuthenticatorUid(String accountType, int callingUid) {
2176d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
2177d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana                mAuthenticatorCache.getAllServices()) {
2178d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            if (serviceInfo.type.type.equals(accountType)) {
2179ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                return (serviceInfo.uid == callingUid) ||
218056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                        (mPackageManager.checkSignatures(serviceInfo.uid, callingUid)
2181ffd0cb04f97e62d286d185c520580d81a9c328b1Fred Quintana                                == PackageManager.SIGNATURE_MATCH);
2182d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
2183d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2184d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        return false;
2185d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2186d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
218704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private boolean hasExplicitlyGrantedPermission(Account account, String authTokenType,
218804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            int callerUid) {
218904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        if (callerUid == android.os.Process.SYSTEM_UID) {
2190d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            return true;
2191d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
219204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccountsForCaller();
219304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
219404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
219504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String[] args = { String.valueOf(callerUid), authTokenType,
2196f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    account.name, account.type};
2197f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            final boolean permissionGranted =
2198f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    DatabaseUtils.longForQuery(db, COUNT_OF_MATCHING_GRANTS, args) != 0;
2199f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (!permissionGranted && ActivityManager.isRunningInTestHarness()) {
2200f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                // TODO: Skip this check when running automated tests. Replace this
2201f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                // with a more general solution.
2202f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                Log.d(TAG, "no credentials permission for usage of " + account + ", "
220304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                        + authTokenType + " by uid " + callerUid
2204f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        + " but ignoring since device is in test harness.");
2205f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return true;
2206f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
2207f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            return permissionGranted;
2208d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2209d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2210d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2211d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkCallingUidAgainstAuthenticator(Account account) {
2212d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        final int uid = Binder.getCallingUid();
221331957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        if (account == null || !hasAuthenticatorUid(account.type, uid)) {
2214d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            String msg = "caller uid " + uid + " is different than the authenticator's uid";
2215d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.w(TAG, msg);
2216d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            throw new SecurityException(msg);
2217d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2218d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        if (Log.isLoggable(TAG, Log.VERBOSE)) {
2219d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            Log.v(TAG, "caller uid " + uid + " is the same as the authenticator's uid");
2220d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2221d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2222d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2223d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkAuthenticateAccountsPermission(Account account) {
2224d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.AUTHENTICATE_ACCOUNTS);
2225d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkCallingUidAgainstAuthenticator(account);
2226d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2227d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2228d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkReadAccountsPermission() {
2229d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.GET_ACCOUNTS);
2230d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2231d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2232d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    private void checkManageAccountsPermission() {
2233d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS);
2234d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2235d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2236b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    private void checkManageAccountsOrUseCredentialsPermissions() {
2237b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana        checkBinderPermission(Manifest.permission.MANAGE_ACCOUNTS,
2238b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana                Manifest.permission.USE_CREDENTIALS);
2239b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana    }
2240b38eb14dbf58c8230f5b54c481b85587d9ef7c78Fred Quintana
2241d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
2242d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            throws RemoteException {
2243d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        final int callingUid = getCallingUid();
2244d9640ec712806508877868d08aafaa2d715ff441Fred Quintana
2245d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        if (callingUid != android.os.Process.SYSTEM_UID) {
2246d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            throw new SecurityException();
2247d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        }
2248d9640ec712806508877868d08aafaa2d715ff441Fred Quintana
2249d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        if (value) {
2250d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            grantAppPermission(account, authTokenType, uid);
2251d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        } else {
2252d9640ec712806508877868d08aafaa2d715ff441Fred Quintana            revokeAppPermission(account, authTokenType, uid);
2253d9640ec712806508877868d08aafaa2d715ff441Fred Quintana        }
2254d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    }
2255d9640ec712806508877868d08aafaa2d715ff441Fred Quintana
2256d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
2257d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Allow callers with the given uid permission to get credentials for account/authTokenType.
2258d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
2259d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
2260d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
2261d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
2262d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
2263d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    private void grantAppPermission(Account account, String authTokenType, int uid) {
2264382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null || authTokenType == null) {
2265382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            Log.e(TAG, "grantAppPermission: called with invalid arguments", new Exception());
226631957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
226731957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
226804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccounts(UserId.getUserId(uid));
226904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
227004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
2271f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
2272f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
2273f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = getAccountIdLocked(db, account);
2274f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId >= 0) {
2275f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    ContentValues values = new ContentValues();
2276f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    values.put(GRANTS_ACCOUNTS_ID, accountId);
2277f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    values.put(GRANTS_AUTH_TOKEN_TYPE, authTokenType);
2278f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    values.put(GRANTS_GRANTEE_UID, uid);
2279f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.insert(TABLE_GRANTS, GRANTS_ACCOUNTS_ID, values);
2280f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
2281f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
2282f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
2283f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
2284d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
2285f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
2286d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2287d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
2288d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana
2289d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    /**
2290d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Don't allow callers with the given uid permission to get credentials for
2291d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * account/authTokenType.
2292d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * <p>
2293d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * Although this is public it can only be accessed via the AccountManagerService object
2294d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * which is in the system. This means we don't need to protect it with permissions.
2295d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     * @hide
2296d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana     */
2297d9640ec712806508877868d08aafaa2d715ff441Fred Quintana    private void revokeAppPermission(Account account, String authTokenType, int uid) {
2298382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana        if (account == null || authTokenType == null) {
2299382601fc8babccee0d0b953ecd9bef745d126996Fred Quintana            Log.e(TAG, "revokeAppPermission: called with invalid arguments", new Exception());
230031957f1badbb900bbfe211317e1ea992d650a72dFred Quintana            return;
230131957f1badbb900bbfe211317e1ea992d650a72dFred Quintana        }
230204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        UserAccounts accounts = getUserAccounts(UserId.getUserId(uid));
230304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
230404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final SQLiteDatabase db = accounts.openHelper.getWritableDatabase();
2305f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            db.beginTransaction();
2306f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            try {
2307f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                long accountId = getAccountIdLocked(db, account);
2308f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (accountId >= 0) {
2309f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.delete(TABLE_GRANTS,
2310f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            GRANTS_ACCOUNTS_ID + "=? AND " + GRANTS_AUTH_TOKEN_TYPE + "=? AND "
2311f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                                    + GRANTS_GRANTEE_UID + "=?",
2312f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                            new String[]{String.valueOf(accountId), authTokenType,
2313f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                                    String.valueOf(uid)});
2314f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    db.setTransactionSuccessful();
2315f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                }
2316f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } finally {
2317f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                db.endTransaction();
2318d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana            }
2319f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            cancelNotification(getCredentialPermissionNotificationId(account, authTokenType, uid));
2320d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana        }
2321d4a1d2e14297a3387fdb5761090961e714370492Fred Quintana    }
232256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
232356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    static final private String stringArrayToString(String[] value) {
232456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return value != null ? ("[" + TextUtils.join(",", value) + "]") : null;
232556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
232656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
232704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void removeAccountFromCacheLocked(UserAccounts accounts, Account account) {
232804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        final Account[] oldAccountsForType = accounts.accountCache.get(account.type);
2329f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (oldAccountsForType != null) {
2330f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            ArrayList<Account> newAccountsList = new ArrayList<Account>();
2331f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            for (Account curAccount : oldAccountsForType) {
2332f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                if (!curAccount.equals(account)) {
2333f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                    newAccountsList.add(curAccount);
233456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                }
233556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
2336f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (newAccountsList.isEmpty()) {
233704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.accountCache.remove(account.type);
2338f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            } else {
2339f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                Account[] newAccountsForType = new Account[newAccountsList.size()];
2340f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                newAccountsForType = newAccountsList.toArray(newAccountsForType);
234104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.accountCache.put(account.type, newAccountsForType);
2342f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
234356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
234404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        accounts.userDataCache.remove(account);
234504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        accounts.authTokenCache.remove(account);
234656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
234756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
234856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    /**
234956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana     * This assumes that the caller has already checked that the account is not already present.
235056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana     */
235104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    private void insertAccountIntoCacheLocked(UserAccounts accounts, Account account) {
235204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        Account[] accountsForType = accounts.accountCache.get(account.type);
2353f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        int oldLength = (accountsForType != null) ? accountsForType.length : 0;
2354f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        Account[] newAccountsForType = new Account[oldLength + 1];
2355f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (accountsForType != null) {
2356f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            System.arraycopy(accountsForType, 0, newAccountsForType, 0, oldLength);
2357f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        }
2358f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        newAccountsForType[oldLength] = account;
235904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        accounts.accountCache.put(account.type, newAccountsForType);
2360f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    }
2361f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana
236204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected Account[] getAccountsFromCacheLocked(UserAccounts userAccounts, String accountType) {
2363f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (accountType != null) {
236404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            final Account[] accounts = userAccounts.accountCache.get(accountType);
2365f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (accounts == null) {
2366f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return EMPTY_ACCOUNT_ARRAY;
236756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            } else {
2368f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return Arrays.copyOf(accounts, accounts.length);
2369f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
2370f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        } else {
2371f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            int totalLength = 0;
237204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            for (Account[] accounts : userAccounts.accountCache.values()) {
2373f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                totalLength += accounts.length;
2374f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
2375f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            if (totalLength == 0) {
2376f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                return EMPTY_ACCOUNT_ARRAY;
2377f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            }
2378f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            Account[] accounts = new Account[totalLength];
2379f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            totalLength = 0;
238004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            for (Account[] accountsOfType : userAccounts.accountCache.values()) {
2381f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                System.arraycopy(accountsOfType, 0, accounts, totalLength,
2382f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                        accountsOfType.length);
2383f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                totalLength += accountsOfType.length;
238456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
2385f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            return accounts;
238656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
238756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
238856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
238904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected void writeUserDataIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
239004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            Account account, String key, String value) {
239104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
2392f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (userDataForAccount == null) {
2393f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
239404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            accounts.userDataCache.put(account, userDataForAccount);
2395f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        }
2396f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (value == null) {
2397f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            userDataForAccount.remove(key);
2398f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        } else {
2399f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            userDataForAccount.put(key, value);
240056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
240156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
240256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
240304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected void writeAuthTokenIntoCacheLocked(UserAccounts accounts, final SQLiteDatabase db,
240404e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            Account account, String key, String value) {
240504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
2406f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (authTokensForAccount == null) {
2407f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
240804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            accounts.authTokenCache.put(account, authTokensForAccount);
2409f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        }
2410f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        if (value == null) {
2411f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            authTokensForAccount.remove(key);
2412f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana        } else {
2413f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            authTokensForAccount.put(key, value);
241456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
241556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
241656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
241704e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected String readAuthTokenInternal(UserAccounts accounts, Account account,
241804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            String authTokenType) {
241904e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
242004e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            HashMap<String, String> authTokensForAccount = accounts.authTokenCache.get(account);
242156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (authTokensForAccount == null) {
242256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                // need to populate the cache for this account
242304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
2424f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                authTokensForAccount = readAuthTokensForAccountFromDatabaseLocked(db, account);
242504e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.authTokenCache.put(account, authTokensForAccount);
242656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
242756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return authTokensForAccount.get(authTokenType);
242856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
242956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
243056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
243104e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani    protected String readUserDataInternal(UserAccounts accounts, Account account, String key) {
243204e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani        synchronized (accounts.cacheLock) {
243304e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani            HashMap<String, String> userDataForAccount = accounts.userDataCache.get(account);
243456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            if (userDataForAccount == null) {
243556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                // need to populate the cache for this account
243604e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                final SQLiteDatabase db = accounts.openHelper.getReadableDatabase();
2437f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana                userDataForAccount = readUserDataForAccountFromDatabaseLocked(db, account);
243804e0d265e3385e9d1fbc35e43c4e8caffbbe3290Amith Yamasani                accounts.userDataCache.put(account, userDataForAccount);
243956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
244056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            return userDataForAccount.get(key);
244156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
244256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
244356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
2444f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    protected HashMap<String, String> readUserDataForAccountFromDatabaseLocked(
2445f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            final SQLiteDatabase db, Account account) {
244656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        HashMap<String, String> userDataForAccount = new HashMap<String, String>();
244756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Cursor cursor = db.query(TABLE_EXTRAS,
244856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                COLUMNS_EXTRAS_KEY_AND_VALUE,
244956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                SELECTION_USERDATA_BY_ACCOUNT,
245056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                new String[]{account.name, account.type},
245156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                null, null, null);
245256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        try {
245356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            while (cursor.moveToNext()) {
245456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String tmpkey = cursor.getString(0);
245556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String value = cursor.getString(1);
245656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                userDataForAccount.put(tmpkey, value);
245756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
245856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        } finally {
245956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            cursor.close();
246056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
246156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return userDataForAccount;
246256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
246356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana
2464f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana    protected HashMap<String, String> readAuthTokensForAccountFromDatabaseLocked(
2465f9f240e3ad5ff5eeaa32fbb2dd65ef7f3b06af32Fred Quintana            final SQLiteDatabase db, Account account) {
246656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        HashMap<String, String> authTokensForAccount = new HashMap<String, String>();
246756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        Cursor cursor = db.query(TABLE_AUTHTOKENS,
246856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                COLUMNS_AUTHTOKENS_TYPE_AND_AUTHTOKEN,
246956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                SELECTION_AUTHTOKENS_BY_ACCOUNT,
247056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                new String[]{account.name, account.type},
247156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                null, null, null);
247256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        try {
247356285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            while (cursor.moveToNext()) {
247456285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String type = cursor.getString(0);
247556285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                final String authToken = cursor.getString(1);
247656285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana                authTokensForAccount.put(type, authToken);
247756285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            }
247856285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        } finally {
247956285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana            cursor.close();
248056285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        }
248156285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana        return authTokensForAccount;
248256285a60e83138bb4b4f2d3bdec91b2f3ca11aa2Fred Quintana    }
2483603073430bbcb1bd29db7afb9b14e2732ad589fbFred Quintana}
2484